Monday, 11 May 2009

The basics of SWIG

[caption id="attachment_535" align="alignleft" width="240" caption="Image from sketch22"]Image from sketch22[/caption]

Simplified Wrapper and Interface Generator, or SWIG for short, is a tool that provides a way to interface C/C++ with a variety of high level programming languages (notably Python, R but not Matlab - which has it's own way of linking to C). It generates wrapper methods that allow the two languages to talk to each other. If you have legacy C code that you want to use in your shiny new R program or if some of your code needs to be re-written in C++ for a speed boost then SWIG can help you out.



The theory
Any language worthy of the name has a way to call code in other modules or libraries. You can use this ability create a module or library that wraps around C/C++ code to provide an interface the target language can understand.

These wrappers are written in C/C++ and call the low level parts of the target language. This exposes the interface into the target language, allowing the C/C++ code to be used just like the native target code.

For example, in Python, to expose a C function you would do this: (this example is taken from the SWIG documentation)

/* A simple C function */
double square(double x) {
return x*x;
}

PyObject *py_square(PyObject *self, PyObject *args) {
double x, result;
if (!PyArg_ParseTuple(self,"d",&x)) {
return NULL;
}
result = square(x);
return Py_BuildValue("d",result);
}


When this code, and some extra initialization code, are compiled into a Python module, the C function can be accessed exactly like a Python method.

>>> import ext
>>> ext.square(4)
16.0
>>>


This is hardly onerous but if you are exposing multiple functions, classes, structures etc. then it quickly becomes time consuming and error prone especially if the source code is constantly changing and the wrapper classes must be kept up to date.


What makes the process complicated is that you must decide what the type of data from the source language should become in the target language and vis-a-versa. For something simple, like an integer, it is easy but C/C++ types can get complicated and deciding what to convert them to is tricky and relies on deep knowledge of the type systems of both languages.

What makes SWIG interesting is that, for simple cases, it does all this work with almost no intervention from the programmer and provides wrapping for various languages by changing a parameter.

The practice
SWIG works by defining a .i interface file which tells SWIG what parts of the C/C++ code you would like exposed to your target language.


Here is a sample file: (again taken from the documentation)
%module sample
%{
#include "myheader.h"
#include "otherheader.h"
%}

#define PI 3.14159;

int foo(int x, int y);
double bar(const char *s);

struct Spam {
int a, b;
};


The % defines SWIG specific parts of the file. Otherwise it looks a lot like a stripped down C/C++ header file. This similarity is not a coincidence because SWIG contains a fully featured C parser and a nearly fully featured C++ parser.
After you have created your .i file you run SWIG, passing it the name of the interface file and the target language and it will generate the wrapper code. Once you have compiled the wrapper code you are left with a module in your target language ready to use in your program.


If you are wrapping existing C/C++ code then doing this by hand is fine as the source file isn't changing, however SWIG is best used as part of a build process. This way whenever the source C/C++ code or interface file changes the target module will be automatically built.

Things to watch out for
For simple wrapper modules using SWIG is almost unbelievably simple however there is great deal going on beneath the surface and you must tread careful when you start trying more complex things.


SWIG was originally written to create wrappers for C and it does this very well. The support for C++ is impressive considering how complex C++ can be (see Template Metaprogramming) but there are still gaps and if you are using complex C++ you will need to read the documentation carefully to make sure everything is supported, or has a known work around.

The learning curve of the more complex features is steep and isn't helped by the documentation, which is extensive but usually out of date or incomplete. There is developer documentation for the newer versions but it expects a familiarity with the system that the novice may not possess. A really good overview of how SWIG works can be found here in a presentation the original author did at a Python Conference in 2008.

Summary
SWIG helps reduce the time and complexity of creating wrapper code around C/C++. By supporting lots of target languages, all of C and most of C++, it allows the developer to take advantage of existing code and makes it easier to move code in C/C++ when a speed boost, or other advantage, is needed.


Reblog this post [with Zemanta]

2 comments:

  1. [...] Weave that makes it easier to include C++ code in Python. This compliments other solutions such as SWIG and F2Py (Fortran to Python binding)Matplotlib is a plotting library that provides an interface [...]

    ReplyDelete