October 22, 2014
Hot Topics:
RSS RSS feed Download our iPhone app

Expose Your C/C++ Program's Internal API with a Quick SWIG

  • December 12, 2005
  • By Victor Volkman
  • Send Email »
  • More Articles »

My previous installment, "Add Embedded Scripting to Your C++ Application," showed how you can use the C Scripting Language (CSL) to move your application from a strictly GUI- or command line-based system to one that fully embraces end-user programmability. In the spirit of a Zen koan, this article looks at an example of the "opposite" of adding scripting to your application: making your application's internal API callable from within Perl scripts. Fortunately, you can do this without resorting to obscure Interface Definition Languages (IDLs), CORBA, COM, RPC, stubs, or any of those legacy framework generators.

The Simplified Wrapper and Interface Generator (SWIG) is a software development tool that connects programs written in C and C++ with a variety of scripting languages. SWIG is used with different types of languages, including all your favorites: Perl, PHP, Python, Tcl, Ruby, and most recently Lua. The list of supported languages even includes non-scripting languages such as C#, Common Lisp variants, Scheme, Java, Modula-3, and Objective Caml. However, SWIG is most commonly used to create high-level interpreted or compiled programming environments, user interfaces, and as a tool for testing and prototyping C/C++ software. SWIG also can export its parse tree in the form of XML and Lisp s-expressions.

You can freely use, distribute, and modify SWIG for commercial and non-commercial use.

The Simplified Wrapper and Interface Generator

SWIG opens up a lot more possibilities than just API automation. Lok briefly at some these before digging into the details of making SWIG work for you:

  • Building more powerful C/C++ programs: By using SWIG, you can get rid of that clunky main() function and replace it with a scripting interpreter to control the application. This opens your app and makes it programmable. You immediately get a scripting interface allowing users and developers to modify the app without having to modify low-level C/C++ code. With some design forethought, you can eliminate the need for a custom macro language, config files, or another embedded scripting engine.
  • Rapid prototyping and QA automation: SWIG allows C/C++ programs to be placed in a scripting environment that can be used for testing and debugging. For example, you might test a library with a collection of scripts or use the scripting interpreter as an interactive debugger. Because SWIG requires no modifications to the underlying C/C++ code, you can use it even if the final product does not rely on scripting.
  • Integrating diverse systems: We all know that scripting languages work fairly well for controlling and gluing together loosely-coupled software components. By turning different C/C++ programs into scripting language extension modules, you can create new and never before possible apps. For example, game developers could write gameplay logic in Perl and yet still integrate advanced math and physics libraries from C++.

Your First SWIG: A Probability Library

Suppose you want to expose the functions in a Probability Library for use with a Perl script. The probability functions compute factorials, permutations, and probably a lot of other boring stuff. To show off a bit, you wrap the legendary Win32 API's MessageBox() function from the venerable user32.lib as well. Written in C, it looks like stats.c in Listing 1.

Listing 1. stats.c

double pi = 3.14159;    //not used yet
int factorial(int n) {
   if (n <= 1)
      return 1;
   else
      return n*factorial(n-1);
}
int permutation(n,r)
{
   return factorial(n) / factorial(n-r);
}
#include <windows.h>
int ShowAMessage(long hWnd, char *lpText, char *lpCaption,
                 unsigned int uType)
{
   //WIN32 API call
   return MessageBox(hWnd, lpText, lpCaption, uType);
}

Next, in lieu of an obfuscatory IDL, COM, CORBA, or other type specification of interfaces, you use (gasp!) the slightly enhanced header file (stats.i) shown in Listing 2.

Listing 2. stats.i Enhanced Header File

/* stats.i */
%module stats
%{
   /* Put header files here or function declarations like below */
   extern double pi;
   extern int factorial(int n);
   extern int permutation(int n,int r);
   extern int ShowAMessage(long hWnd, char *lpText,
                           char *lpCaption,
                           unsigned int uType);
%}
extern double pi;
extern int factorial(int n);
extern int permutation(int n,int r);
extern int ShowAMessage(long hWnd, char *lpText, char *lpCaption,
                        unsigned int uType);

Before you go any further, you need to install some form of SWIG. If you are working from a Windows or Mac platform, you probably want to start with some precompiled binaries from the SourceForge site. SWIG for Win32 (or SWIGWIN) doesn't come with a fancy installer: you simply unzip it and set some environment variables. You can retarget SWIG to the Cygwin or MinGW Unix-for-Windows environments by recompiling the system. I use Cygwin Perl for most workaday Perl scripting, but because you likely will be integrating with Visual Studio C++-built Win32 apps, I chose to try the nsPerl 5.005_03 that the docs recommended. For nsPerl, my environment is as follows:

set PERL5_INCLUDE=D:\nsPerl5.005_03\lib\CORE
set PERL5_LIB=D:\nsPerl5.005_03\lib\CORE\perl.lib

Next, you need to discover which compiler flags your nsPerl was built with to produce linkable code later:

perl -MExtUtils::Embed -e ccopts
-Od -MD -DNDEBUG -DWIN32 -D_CONSOLE -DNO_STRICT -
IF:/nsPerl/netsite/nsPerl/WINNT/lib/nsPerl5.005_03\lib\
   MSWin32-x86/CORE

Now, you can invoke the SWIGWIN generator to produce the stats_wrap.c wrapper based on the stats.i interface file (from Listing 2):

swig -perl5 stats.i

Lastly, you compile and link both your original code and the wrapper code in one step, using the ccopts discovered above:

cl -Od -MD -DNDEBUG -DWIN32 -D_CONSOLE -DNO_STRICT stats.c
stats_wrap.c /link user32.lib d:\nsPerl5.005_03\lib\MSWin32-x86\
   CORE\perl.lib
/DLL /out:stats.dll

Calling Your C Functions from Perl

Now, step back and look at what you've actually produced so far. Based on your two input files (stats.c and stats.i), you have churned out the following:

  • stats_wrap.c: Perl-callable function stubs, which call through to stats.c
  • stats.dll: a DLL loadable by Perl
  • stats.pm: a Perl module, which painlessly imports the stats.dll for your Perl apps (see Listing 3)

Listing 3. Generated stats.pm File

# This file was automatically generated by SWIG:
package stats;
require Exporter;
require DynaLoader;
@ISA = qw(Exporter DynaLoader);
package stats;
bootstrap stats;
package stats;
@EXPORT = qw( );
1;

Now, you finally can have some fun and call your "new" stats library from Perl. Construct the simple Perl program in Listing 4, which should be obvious to any coder:

Listing 4. A Simple Perl Program for Our Stats Library

use stats;
$answer = stats::factorial(5);
stats::ShowAMessage(0,"5! is $answer","SWIG Testing",0);

The output is the dialog box shown below!

Give Your C/C++ Program's Internal API Full Exposure

What I've demonstrated thus far (I hope) is a relatively quick and painless way of exposing your C/C++ program's internal API to the machinations of any scripting language. Although I chose to use Perl, you could easily generate corresponding modules for Python, Java, and Lua in just a few minutes more.

SWIG covers the vast majority of C++ classes and language features: references, pointers to members, multiple inheritance, overloaded functions and operators, smart pointers, STL data types, namespaces, and much more. The only known hole currently is the wrapping of nested classes, but the nearly all C/C++ programs are eminently "SWIGable." So what are you waiting for?

About the Author

Victor Volkman has been writing for C/C++ Users Journal and other programming journals since the late 1980s. He is a graduate of Michigan Tech and a faculty advisor board member for Washtenaw Community College CIS department. Volkman is the editor of numerous books, including C/C++ Treasure Chest and is the owner of Loving Healing Press. He can help you in your quest for open source tools and libraries, just drop an e-mail to sysop@HAL9K.com.






Comment and Contribute

 


(Maximum characters: 1200). You have characters left.

 

 


Sitemap | Contact Us

Rocket Fuel