Whole document tree 3 SWIG Basics
Running SWIGSWIG is invoked by the swig command. This command has a number of options including:
This is only a partial list of options. A full listing of options can be obtained by invoking "swig -help". Each target language may have additional options which can be displayed using "swig -lang -help" where -lang is one of the target languages above.swig <options> filename -tcl Generate Tcl wrappers -tcl8 Generate Tcl 8.0 wrappers -perl Generate Perl5 wrappers -python Generate Python wrappers -perl4 Generate Perl4 wrappers -guile Generate Guile wrappers -dascii ASCII documentation -dlatex LaTeX documentation -dhtml HTML documentation -dnone No documentation -c++ Enable C++ handling -objc Enable Objective-C handling. -Idir Set SWIG include directory -lfile Include a SWIG library file. -c Generate raw wrapper code (omit supporting code) -v Verbose mode (perhaps overly verbose) -o outfile Name of output file -d docfile Set name of documentation file (without suffix) -module name Set name of SWIG module -Dsymbol Define a symbol -version Show SWIG's version number -help Display all options Input formatAs input, SWIG takes a file containing ANSI C/C++ declarations. This file may be a special "interface file" (usually given a .i suffix), a C header file or a C source file. The most common method of using SWIG is with a special interface file. These files contain ANSI C declarations like a header file, but also contain SWIG directives and documentation. Interface files usually have the following format :
The name of the module (if supplied) must always appear before the first C declaration or be supplied on the SWIG command line using the -module option (When the module name is specified on the command line, it will override any module name present in a file). Everything inside the %{,%} block is copied verbatim into the resulting output file. The %{,%} block is optional, but most interface files use one to include the proper header files.%module mymodule %{ #include "myheader.h" %} // Now list ANSI C variable and function declarations SWIG OutputBy default an interface file with the name myfile.i will be transformed into a file called myfile_wrap.c. The name of the output file can be changed using the -o option. When working with some C++ compilers, the -o option can be used to give the output file a proper C++ suffix. The output file usually contains everything that is needed to build a working module for the target scripting language. Compile it along with your C program, link it, and you should be ready to run.CommentsC and C++ style comments may be placed in interface files, but these are used to support the automatic documentation system. Please see the documentation section for more details on this. Otherwise, SWIG throws out all comments so you can use a C++ style comment even if the resulting wrapper file is compiled with the C compiler.C Preprocessor directivesSWIG does not run the C preprocessor. If your input file makes extensive use of the C preprocessor, SWIG will probably hate it. However, SWIG does recognize a few C preprocessor constructs that are quite common in C code :
All other C preprocessor directives are ignored by SWIG (including macros created using #define). SWIG DirectivesSWIG directives are always preceded by a "%" to distinguish them from normal C directives and declarations. There are about two dozen different directives that can be used to give SWIG hints, provide annotation, and change SWIG's behavior in some way or another.Limitations in the Parser (and various things to keep in mind)It was never my intent to write a full C/C++ parser. Therefore SWIG has a number of limitations to keep in mind.
Many of these limitations may be eliminated in future releases. It is worth noting that many of the problems associated with complex declarations can sometimes be fixed by clever use of typedef.
If you are not sure whether SWIG can handle a particular declaration, the best thing to do is try it and see. SWIG will complain loudly if it can't figure out what's going on. When errors occur, you can either remove the offending declaration, conditionally compile it out (SWIG defines a symbol SWIG that can be used for this), or write a helper function to work around the problem. Simple C functions, variables, and constantsSWIG supports just about any C function, variable, or constant involving built-in C datatypes. For example :
will create two commands called "sin" and "strcmp", a global variable "My_variable", and two constants "STATUS" and "VERSION". Things work about like you would expect. For example, in Tcl :%module example extern double sin(double x); extern int strcmp(const char *, const char *); extern int My_variable; #define STATUS 50 const char *VERSION="1.1";
The main concern when working with simple functions is SWIG's treatment of basic datatypes. This is described next.% sin 3 5.2335956 % strcmp Dave Mike -1 % puts $My_variable 42 % puts $STATUS 50 % puts $VERSION 1.1 IntegersSWIG maps the following C datatypes into integers in the target scripting language.
int short long unsigned signed unsigned short unsigned long unsigned char signed char bool Scripting languages usually only support a single integer type that corresponds to either the int or long datatype in C. When converting from C, all of the above datatypes are cast into the representation used by the target scripting language. Thus, a 16 bit short in C may be converted to a 32 bit integer. When integers are converted from the scripting language back into C, the value will be cast into the appropriate type. The value will be truncated if it is too large to fit into the corresponding C datatype. This truncation is not currently checked.
The unsigned char and signed char datatypes are special cases that are treated as integers by SWIG. Normally, the char datatype is mapped as an ASCII string.
The bool datatype is cast to and from an integer value of 0 and 1.
Some care is in order for large integer values. Most scripting language use 32 bit integers so mapping a 64 bit long integer may lead to truncation errors. Similar problems may arise with 32 bit unsigned integers that may show up as negative numbers. As a rule of thumb, the int datatype and all variations of char and short datatypes are safe to use. For unsigned int and long datatypes, you should verify the correct operation of your program after wrapping it with SWIG. Floating PointSWIG recognizes the following floating point types :
float double Floating point numbers are mapped to and from the natural representation of floats in the target language. This is almost always a double except in Tcl 7.x which uses character strings. The rarely used datatype of "long double" is not supported by SWIG. Character StringsThe char datatype is mapped into a NULL terminated ASCII string with a single character. When used in a scripting language it will show up as a tiny string containing the character value. When converting the value back into C, SWIG will take a character string from the scripting language and strip off the first character as the char value. Thus if you try to assigned the value "foo" to a char datatype, it will get the value `f'.
The char * datatype is assumed to be a NULL-terminated ASCII string. SWIG maps this into a character string in the target language. SWIG converts character strings in the target language to NULL terminated strings before passing them into C/C++. It is illegal for these strings to have embedded NULL bytes although there are ways to work around this problem.
The signed char and unsigned char datatypes are mapped into integer values. The following example illustrates the mapping of char datatypes.
%{ #include <stdio.h> #include <ctype.h> #include <string.h> signed char sum(signed char a, signed char b) { return a+b;} %} int strcmp(char *, char *); char toupper(char); signed char sum(signed char a, signed char b); A Tcl script using these functions (and the resulting output) might be as follows.
tclsh > strcmp Mike John 1 tclsh > toupper g G tclsh > sum 17 -8 9 VariablesSWIG attempts to map C/C++ global variables into scripting language variables. For example:
will result in a scripting language variable that can be used as follows :%module example double foo;
Whenever this "special" variable is used, the underlying C global variable will be accessed. As it turns out, working with global variables is one of the most tricky aspects of SWIG. Whenever possible, you should try to avoid the use of globals. Fortunately, most modular programs make limited (or no) use of globals.# Tcl set foo [3.5] ;# Set foo to 3.5 puts $foo ;# Print the value of foo # Python cvar.foo = 3.5 ;# Set foo to 3.5 print cvar.foo ;# Print value of foo # Perl $foo = 3.5; ;# Set foo to 3.5 print $foo,"\n"; ;# Print value of foo ConstantsConstants can be created using #define, const, or enumerations. Constant expressions are also allowed. The following interface file shows a few valid constant declarations :
In #define declarations, the type of a constant is inferred by syntax or can be explicitly set using a cast. For example, a number with a decimal point is assumed to be floating point. When no explicit value is available for a constant, SWIG will use the value assigned by the C compiler. For example, no values are given to the months enumeration, but this is no problem---SWIG will use whatever the C compiler picks.#define I_CONST 5 // An integer constant #define F_CONST 3.14159 // A Floating point constant #define S_CONST "hello world" // A string constant #define NEWLINE '\n' // Character constant #define MODE DEBUG // Sets MODE to DEBUG. // DEBUG is assumed to be an // int unless declared earlier enum boolean {NO=0, YES=1}; enum months {JAN, FEB, MAR, APR, MAY, JUN, JUL, AUG, SEP, OCT, NOV, DEC}; const double PI 3.141592654; #define F_CONST (double) 5 // A floating pointer constant with cast #define PI_4 PI/4 #define FLAGS 0x04 | 0x08 | 0x40
The use of constant expressions is allowed, but SWIG does not evaluate them. Rather, it passes them through to the output file and lets the C compiler perform the final evaluation (SWIG does perform a limited form of type-checking however).
For enumerations, it is critical that the original enum definition be included somewhere in the interface file (either in a header file or in the %{,%} block). SWIG only translates the enumeration into code needed to add the constants to a scripting language. It needs the original enumeration declaration to retrieve the correct enum values. Pointers and complex objectsAs we all know, most C programs have much more than just integers, floating point numbers, and character strings. There may be pointers, arrays, structures, and other objects floating around. Fortunately, this is usually not a problem for SWIG.Simple pointersPointers to basic C datatypes such as
int * double *** char ** can be used freely in an interface file. SWIG encodes pointers into a representation containing the actual value of the pointer and a string representing the datatype. Thus, the SWIG representation of the above pointers (in Tcl), might look like the following :
_10081012_int_p _1008e124_double_ppp _f8ac_char_pp A NULL pointer is represented by the string "NULL" or the value 0 encoded with type information.
All pointers are treated as opaque objects by SWIG. A pointer may be returned by a function and passed around to other C functions as needed. For all practical purposes, the scripting language interface works in exactly the same way as you would write a C program (well, with a few limitations).
The scripting language representation of a pointer should never be manipulated directly (although nothing prevents this). SWIG does not normally map pointers into high-level objects such as associative arrays or lists (for example, it might be desirable to convert an int * into an list of integers). There are several reasons for this :
As it turns out, you can remap any C datatype to behave in new ways so these rules are not set in stone. Interested readers should look at the chapter on typemaps. Run time pointer type checkingBy allowing pointers to be manipulated interactively in a scripting language, we have effectively bypassed the type-checker in the C/C++ compiler. By encoding pointer values with a datatype, SWIG is able to perform run-time type-checking in order to prevent mysterious system crashes and other anomalies. By default, SWIG uses a strict-type checking model that checks the datatype of all pointers before passing them to C/C++. However, you can change the handling of pointers using the -strict option:
Strict type checking is the recommended default since is the most reliable and most closely follows the type checking rules of C. In fact, at this time, the other two modes should be considered to be outdated SWIG features that are supported, but no longer necessary.-strict 0 No type-checking (living on the edge) -strict 1 Generate warning messages (somewhat annoying) -strict 2 Strict type checking (the default)
By default, SWIG allows "NULL" pointers to be passed to C/C++. This has the potential to crash code and cause other problems if you are not careful. Checks can be placed on certain values to prevent this but this requires the use of typemaps (described in later chapters).
Like C, it should also be noted that functions involving void pointers can accept any kind of pointer object. Derived types, structs, and classesFor everything else (structs, classes, arrays, etc...) SWIG applies a very simple rule :
All complex datatypes are pointers
In other words, SWIG manipulates everything else by reference. This model makes sense because most C/C++ programs make heavy use of pointers and we can use the type-checked pointer mechanism already present for handling pointers to basic datatypes.
While all of this probably sounds complicated, it's really quite simple. Suppose you have an interface file like this :
In this file, SWIG doesn't know what a FILE is, but it's used as a pointer, so it doesn't really matter what it is. If you wrapped this module into Python, you could use the functions just like you would expect :%module fileio FILE *fopen(char *, char *); int fclose(FILE *); unsigned fread(void *ptr, unsigned size, unsigned nobj, FILE *); unsigned fwrite(void *ptr, unsigned size, unsigned nobj, FILE *); void *malloc(int nbytes); void free(void *);
In this case f1, f2, and buffer are all opaque objects containing C pointers. It doesn't matter what value they contain--our program works just fine without this knowledge.# Copy a file def filecopy(source,target): f1 = fopen(source,"r") f2 = fopen(target,"w") buffer = malloc(8192) nbytes = fread(buffer,8192,1,f1) while (nbytes > 0): fwrite(buffer,8192,1,f2) nbytes = fread(buffer,8192,1,f1) free(buffer) What happens when SWIG encounters an unknown datatype?When SWIG encounters an unknown datatype, it automatically assumes that it is some sort of complex datatype. For example, suppose the following function appeared in a SWIG input file:
void matrix_multiply(Matrix *a, Matrix *b, Matrix *c); SWIG has no idea what a "Matrix" is so it will assume that you know what you are doing and map it into a pointer. This makes perfect sense because the underlying C function is using pointers in the first place. Unlike C or C++, SWIG does not actually care whether Matrix has been previously defined in the interface file or not. While this may sound strange, it makes it possible for SWIG to generate interfaces from only partial information. In many cases, you may not care what a Matrix really is as long as you can pass references to one around in the scripting language interface. The downside to this relaxed approach is that typos may go completely undetected by SWIG. You can also end up shooting yourself in the foot, but presumably you've passed your programming safety course if you've made it this far.
As a debugging tool, SWIG will report a list of used, but undefined datatypes, if you run it with the -stat option.
[beazley@guinness SWIG1.1b6]$ swig -stat matrix.i Making wrappers for Tcl Wrapped 1 functions Wrapped 0 variables Wrapped 0 constants The following datatypes were used, but undefined. Matrix [beazley@guinness SWIG1.1b6]$ Typedeftypedef can be used to remap datatypes within SWIG. For example :
This makes SWIG treat size_t like an unsigned int. Use of typedef is fairly critical in most applications. Without it, SWIG would consider size_t to be a complex object (which would be incorrectly converted into a pointer).typedef unsigned int size_t; Getting down to businessSo far, you know just about everything you need to know to use SWIG to build interfaces. In fact, using nothing but basic datatypes and opaque pointers it is possible to build scripting language interfaces to most kinds of C/C++ packages. However, as the novelty wears off, you will want to do more. This section describes SWIG's treatment of more sophsticated issues.Passing complex datatypes by valueUnfortunately, not all C programs manipulate complex objects by reference. When encountered, SWIG will transform the corresponding C/C++ declaration to use references instead. For example, suppose you had the following function :
double dot_product(Vector a, Vector b); SWIG will transform this function call into the equivalent of the following :
double wrap_dot_product(Vector *a, Vector *b) { return dot_product(*a,*b); } In the scripting language, dot_product will now take references to Vectors instead of Vectors, although you may not notice the change. Return by valueC functions that return complex datatypes by value are more difficult to handle. Consider the following function:
This function is returning a complex object, yet SWIG only likes to work with references. Clearly, something must be done with the return result, or it will be lost forever. As a result, SWIG transforms this function into the following code :Vector cross(Vector v1, Vector v2);
Vector *wrap_cross(Vector *v1, Vector *v2) { Vector *result; result = (Vector *) malloc(sizeof(Vector)); *(result) = cross(*v1,*v2); return result; } or if using C++ :
Vector *wrap_cross(Vector *v1, Vector *v2) { Vector *result = new Vector(cross(*v1,*v2)); // Uses default copy constructor return result; } SWIG is forced to create a new object and return a reference to it. It is up to the user to delete the returned object when it is no longer in use. When used improperly, this can lead to memory leaks and other problems. Personally, I'd rather live with a potential memory leak than forbid the use of such a function. Needless to say, some care is probably in order (you need to be aware of this behavior in any case). Linking to complex variablesWhen global variables or class members involving complex datatypes are encountered, SWIG converts them into references. For example, a global variable like this :
Vector unit_i; gets mapped to a pair of set/get functions like this :
Vector *unit_i_get() { return &unit_i; } Vector *unit_i_set(Vector *value) { unit_i = *value; return &unit_i; } Returning a reference to the variable makes it accessible like any other object of this type. When setting the value, we simply make a copy of some other Vector reference. Again some caution is in order. A global variable created in this manner will show up as a reference in the target scripting language. It would be an extremely bad idea to free or destroy such a reference. Similarly, one can run into problems when copying complex C++ objects in this manner. Fortunately, in well-written modular code, excessive use (or abuse) of global variables is rare. ArraysThe use of arrays in the current version of SWIG is supported, but with caution. If simple arrays appear, they will be mapped into a pointer representation. Thus, the following declarations :
int foobar(int a[40]); void grok(char *argv[]); void transpose(double a[20][20]); will be processed as if they were declared like this:
int foobar(int *a); void grok(char **argv); void transpose(double (*a)[20]); Multi-dimensional arrays are transformed into a single pointer since a[][] and **a are not the same thing (even though they can be used in similar ways). Rather, a[][] is mapped to *a, where *a is the equivalent of &a[0][0]. The reader is encouraged to dust off their C book and look at the section on arrays before using them with SWIG.
Be aware that use of arrays may cause compiler warnings or errors when compiling SWIG generated modules. While every attempt has been made to eliminate these problems, handling of arrays can be somewhat problematic due to the subtle differences between an array and a pointer. Creating read-only variablesA read-only variable can be created by using the %readonly directive as shown :
// File : interface.i int a; // Can read/write %readonly int b,c,d // Read only variables %readwrite double x,y // read/write The %readonly directive enables read-only mode until it is explicitly disabled using the %readwrite directive. Renaming declarationsNormally, the name of a C function is used as the name of the command added to the target scripting language. Unfortunately, this name may conflict with a keyword or already existing function in the scripting language. Naming conflicts can be resolved using the %name directive as shown :
SWIG still calls the correct C functions, but in this case the function print() will really be called "my_print()" in the scripting language.// interface.i %name(my_print) extern void print(char *); %name(foo) extern int a_really_long_and_annoying_name;
A more powerful renaming operation can be performed with the %rename directive as follows :
%rename applies a renaming operation to all future occurrences of a name. The renaming applies to functions, variables, class and structure names, member functions, and member data. For example, if you had two-dozen C++ classes, all with a member function named `print' (which is a keyword in Python), you could rename them all to `output' by specifying :%rename oldname newname;
%rename print output; // Rename all `print' functions to `output' SWIG does not perform any checks to see if the functions it adds are already defined in the target scripting language. However, if you are careful about namespaces and your use of modules, you can usually avoid these problems. Overriding call by referenceSWIG is quite literal in its interpretation of datatypes. If you give it a pointer, it will use pointers. For example, if you're trying to call a function in a Fortran library (through its C interface) all function parameters will have to be passed by reference. Similarly, some C functions may use pointers in unusual ways. The %val directive can be used to change the calling mechanism for a C function. For example :
The localtime() function takes a pointer to a time_t value, but we have forced it to take a value instead in order to match up nicely with the return value of the time() function. When used in Perl, this allows us to do something like this :// interface.i %{ #include <time.h> %} typedef long time_t; time_t time(time_t *t); struct tm *localtime(%val time_t *t); char *asctime(struct tm *);
Internally, the %val directive creates a temporary variable. The argument value is stored in this variable and a function call is made using a pointer to the temporary variable. Of course, if the function returns a value in this temporary variable, it will be lost forever.$t = time(0); $tm = localtime($t); # Note passing $t by value here print $asctime($tm); Default/optional argumentsSWIG allows default arguments to be used in both C/C++ code as follows :
To specify a default argument, simply specify it the function prototype as shown. SWIG will generate wrapper code in which the default arguments are optional. For example, this function could be used in Tcl as follows :int plot(double x, double y, int color=WHITE);
While the ANSI C standard does not specify default arguments, default arguments used in a SWIG generated interface work with both C and C++.% plot -3.4 7.5 # Use default value % plot -3.4 7.5 10 # set color to 10 instead Pointers to functionsAt the moment, the SWIG parser has difficulty handling pointers to functions (a deficiency that is being corrected). However, having function pointers is useful for managing C callback functions and other things. To properly handle function pointers, it is currently necessary to use typedef. For example, the function
void do_operation(double (*op)(double,double), double a, double b); should be handled as follows :
SWIG understands both the typedef declaration and the later function call. It will treat OP_FUNC just like any other complex datatype. In order for this approach to work, it is necessary that the typedef declaration be present in the original C code--otherwise, the C compiler will complain. If you are building a separate interface file to an existing C program and do not want to make changes to the C source, you can also do the following :typedef double (*OP_FUNC)(double,double); void do_operation(OP_FUNC op, double a, double b);
// File : interface.i %typedef double (*OP_FUNC)(double,double); double do_operation(OP_FUNC op, double a, double b); %typedef forces SWIG to generate a typedef in the C output code for you. This would allow the interface file shown to work with the original unmodified C function declaration.
Constants containing the addresses of C functions can also be created. For example, suppose you have the following callback functions :
The addresses of these functions could be installed as scripting language constants as follows :extern double op_add(double a, double b); extern double op_sub(double a, double b); extern double op_mul(double a, double b);
When wrapped, this would create the constants ADD,SUB, and MUL containing the addresses of C callback functions. We could then pass these to other C functions expecting such function pointers as arguments as shown (for Tcl) :// interface.i typedef double (*OP_FUNC)(double,double); ... const OP_FUNC ADD = op_add; const OP_FUNC SUB = op_sub; const OP_FUNC MUL = op_mul; ...
%do_operation $ADD 3 4 7 % Structures, unions, and object oriented C programmingIf SWIG encounters the definition of a structure or union, it will create a set of accessor functions for you. While SWIG does not need structure definitions to build an interface, providing definitions make it possible to access structure members. The accessor functions generated by SWIG simply take a pointer to an object and allow access to an individual member. For example, the declaration :
gets mapped into the following set of accessor functions :struct Vector { double x,y,z; }
double Vector_x_get(Vector *obj) { return obj->x; } double Vector_y_get(Vector *obj) { return obj->y; } double Vector_z_get(Vector *obj) { return obj->z; } double Vector_x_set(Vector *obj, double value) { obj->x = value; return value; } double Vector_y_set(Vector *obj, double value) { obj->y = value; return value; } double Vector_z_set(Vector *obj, double value) { obj->z = value; return value; } Typedef and structuresSWIG supports the following construct which is quite common in C programs :
When encountered, SWIG will assume that the name of the object is `Vector' and create accessor functions like before. If two different names are used like this :typedef struct { double x,y,z; } Vector;
the name `Vector' will still be used instead of "vector_struct".typedef struct vector_struct { double x,y,z; } Vector; Character strings and structuresStructures involving character strings require some care. SWIG assumes that all members of type char * have been dynamically allocated using malloc() and that they are NULL-terminated ASCII strings. When such a member is modified, the previously contents will be released, and the new contents allocated. For example :
This results in the following accessor functions :%module mymodule ... struct Foo { char *name; ... }
char *Foo_name_get(Foo *obj) { return Foo->name; } char *Foo_name_set(Foo *obj, char *c) { if (obj->name) free(obj->name); obj->name = (char *) malloc(strlen(c)+1); strcpy(obj->name,c); return obj->name; } This seems to work most of the time, but occasionally it's not always what you want. Typemaps can be used to change this behavior if necessary. Array membersArrays may appear as the members of structures, but they will be read-only. SWIG will write an accessor function that returns the pointer to the first element of the array, but will not write a function to change the array itself. This restriction is due to the fact that C won't let us change the "value" of an array. When this situation is detected, SWIG generates a warning message such as the following :
To eliminate the warning message, typemaps can be used, but this is discussed in a later chapter (and best reserved for experienced users). Otherwise, if you get this warning, it may be harmless.interface.i : Line 116. Warning. Array member will be read-only C constructors and destructorsWhile not part of the C language, it is usually useful to have some mechanism for creating and destroying an object. You can, of course, do this yourself by making an appropriate call to malloc(), but SWIG can make such functions for you automatically if you use C++ syntax like this :
When used with C code, SWIG will create two additional functions like this :%module mymodule ... struct Vector { Vector(); // Tell SWIG to create a C constructor ~Vector(); // Tell SWIG to create a C destructor double x,y,z; }
While C knows nothing about constructors and destructors, SWIG does---and it can automatically create some for you if you want. This only applies to C code--handling of C++ is handled differently.Vector *new_Vector() { return (Vector *) malloc(sizeof(Vector)); } void delete_Vector(Vector *v) { free(v); }
As an alternative to explicitly defining constructors and destructors, SWIG can also automatically generate them using either a command line option or a pragma. For example :
orswig -make_default example.i
This works with both C and C++.%module foo ... %pragma make_default // Make default constructors ... declarations ... %pragma no_default // Disable default constructors Adding member functions to C structuresMany scripting languages provide a mechanism for creating classes and supporting object oriented programming. From a C standpoint, object oriented programming really just boils down to the process of attaching functions to structures. These functions typically operate on the structure (or object) in some way or another. While there is a natural mapping of C++ to such a scheme, there is no direct mechanism for utilizing it with C code. However, SWIG provides a special %addmethods directive that makes it possible to attach methods to C structures for purposes of building an object oriented scripting language interface. Suppose you have a C header file with the following declaration :
You can make a Vector look alot like a class by doing the following in an interface file :/* file : vector.h */ ... typedef struct { double x,y,z; } Vector;
Now, when used with shadow classes in Python, you can do things like this :// file : vector.i %module mymodule %{ #include "vector.h" %} %include vector.h // Just grab original C header file %addmethods Vector { // Attach these functions to struct Vector Vector(double x, double y, double z) { Vector *v; v = (Vector *v) malloc(sizeof(Vector)); v->x = x; v->y = y; v->z = z; return v; } ~Vector() { free(self); } double magnitude() { return sqrt(self->x*self->x+self->y*self->y+self->z*self->z); } void print() { printf("Vector [%g, %g, %g]\n", self->x,self->y,self->z); } };
>>> v = Vector(3,4,0) # Create a new vector >>> print v.magnitude() # Print magnitude 5.0 >>> v.print() # Print it out [ 3, 4, 0 ] >>> del v # Destroy it The %addmethods directive can also be used in the definition of the Vector structure. For example:
// file : vector.i %module mymodule %{ #include "vector.h" %} typedef struct { double x,y,z; %addmethods { Vector(double x, double y, double z) { ... } ~Vector() { ... } ... } } Vector; Finally, %addmethods can be used to access externally written functions provided they follow the naming convention used in this example :
So why bother with all of this %addmethods business? In short, you can use it to make some pretty cool `object oriented' scripting language interfaces to C programs without having to rewrite anything in C++./* File : vector.c */ /* Vector methods */ #include "vector.h" Vector *new_Vector(double x, double y, double z) { Vector *v; v = (Vector *) malloc(sizeof(Vector)); v->x = x; v->y = y; v->z = z; return v; } void delete_Vector(Vector *v) { free(v); } double Vector_magnitude(Vector *v) { return sqrt(v->x*v->x+v->y*v->y+v->z*v->z); } // File : vector.i // Interface file %module mymodule %{ #include "vector.h" %} typedef struct { double x,y,z; %addmethods { double magnitude(); // This will call Vector_magnitude ... } } Vector; Nested structuresOccasionally, a C program will involve structures like this :
When SWIG encounters this, it performs a structure splitting operation that transforms the declaration into the equivalent of the following:typedef struct Object { int objtype; union { int ivalue; double dvalue; char *strvalue; void *ptrvalue; } intRep; } Object;
SWIG will create an Object_intRep structure for use inside the interface file. Accessor functions will be created for both structures. In this case, functions like this would be created :typedef union { int ivalue; double dvalue; char *strvalue; void *ptrvalue; } Object_intRep; typedef struct Object { int objType; Object_intRep intRep; } Object;
Is it hairy? You bet. Does it work? Well, surprisingly yes. When used with Python and Perl5 shadow classes, it's even possible to access the nested members just like you expect :Object_intRep *Object_intRep_get(Object *o) { return (Object_intRep *) &o->intRep; } int Object_intRep_ivalue_get(Object_intRep *o) { return o->ivalue; } int Object_intRep_ivalue_set(Object_intRep *o, int value) { return (o->ivalue = value); } double Object_intRep_dvalue_get(Object_intRep *o) { return o->dvalue; } ... etc ...
# Perl5 script for accessing nested member $o = CreateObject(); # Create an object somehow $o->{intRep}->{ivalue} = 7 # Change value of o.intRep.ivalue If you've got a bunch of nested structure declarations, it is certainly advisable to check them out after running SWIG. However, there is a good chance that they will work. If not, you can always remove the nested structure declaration and write your own set of accessor functions. Other things to note about structuresSWIG doesn't care if the definition of a structure exactly matches that used in the underlying C code (except in the case of nested structures). For this reason, there are no problems omitting problematic members or simply omitting the structure definition altogether. If you are happy simply passing pointers around, this can be done without ever giving SWIG a structure definition.
It is also important to note that most language modules may choose to build a more advanced interface. You may never use the low-level interface described here, although most of SWIG's language modules use it in some way or another. C++ supportSWIG's support for C++ is an extension of the support for C functions, variables, and structures. However, SWIG only supports a subset of the C++ language. It has never been my goal to write a full C++ compiler or to turn scripting languages into some sort of weird pseudo C++ interpreter (considering how hard it is to write a C++ compiler, I'm not sure this would even be feasible anyways).
This section describes SWIG's low-level access to C++ declarations. In many instances, this low-level interface may be hidden by shadow classes or an alternative calling mechanism (this is usually language dependent and is described in detail in later chapters). Supported C++ featuresSWIG supports the following C++ features :
The following C++ features are not currently supported :
Since SWIG's C++ support is a "work in progress", many of these limitations may be lifted in future releases. In particular, function overloading and nested classes, may be supported in the future. Operator overloading and templates are unlikely to be supported anytime in the near future, but I'm not going to rule out the possibility in later releases. C++ exampleThe following code shows a SWIG interface file for a simple C++ class.
%module list %{ #include "list.h" %} // Very simple C++ example for linked list class List { public: List(); ~List(); int search(char *value); void insert(char *); void remove(char *); char *get(int n); int length; static void print(List *l); }; When compiling C++ code, it is critical that SWIG be called with the `-c++' option. This changes the way a number of critical features are handled with respect to differences between C and C++. It also enables the detection of C++ keywords. Without the -c++ flag, SWIG will either issue a warning or a large number of syntax errors if it encounters any C++ code in an interface file. Constructors and destructorsC++ constructors and destructors are translated into accessor functions like the following :
If the original C++ class does not have any constructors or destructors, putting constructors and destructors in the SWIG interface file will cause SWIG to generate wrappers for the default constructor and destructor of an object.List * new_List(void) { return new List; } void delete_List(List *l) { delete l; } Member functionsMember functions are translated into accessor functions like this :
Virtual member functions are treated in an identical manner since the C++ compiler takes care of this for us automatically.int List_search(List *obj, char *value) { return obj->search(value); } Static membersStatic member functions are called directly without making any additional C wrappers. For example, the static member function print(List *l) will simply be called as List::print(List *l) in the resulting wrapper code.Member dataMember data is handled in exactly the same manner as used for C structures. A pair of accessor functions will be created. For example :
A read-only member can be created using the %readonly and %readwrite directives. For example, we probably wouldn't want the user to change the length of a list so we could do the following to make the value available, but read-only.int List_length_get(List *obj) { return obj->length; } int List_length_set(List *obj, int value) { obj->length = value; return value; }
class List { public: ... %readonly int length; %readwrite ... }; ProtectionSWIG can only wrap class members that are declared public. Anything specified in a private or protected section will simply be ignored. To simplify your interface file, you may want to consider eliminating all private and protected declarations (if you've copied a C++ header file for example).
By default, members of a class definition are assumed to be private until you explicitly give a `public:' declaration (This is the same convention used by C++). Enums and constantsEnumerations and constants placed in a class definition are mapped into constants with the classname as a prefix. For example :
Generates the following set of constants in the target scripting language :class Swig { public: enum {ALE, LAGER, PORTER, STOUT}; };
Members declared as const are wrapped in a similar manner.Swig_ALE = Swig::ALE Swig_LAGER = Swig::LAGER Swig_PORTER = Swig::PORTER Swig_STOUT = Swig::STOUT ReferencesC++ references are supported, but SWIG will treat them as pointers. For example, a declaration like this :
class Foo { public: double bar(double &a); } will be accessed using a function like this :
Functions returning a reference will be mapped into functions returning pointers.double Foo_bar(Foo *obj, double *a) { obj->bar(*a); } InheritanceSWIG supports basic C++ public inheritance of classes and allows both single and multiple inheritance. The SWIG type-checker knows about the relationship between base and derived classes and will allow pointers to any object of a derived class to be used in functions of a base class. The type-checker properly casts pointer values and is safe to use with multiple inheritance.SWIG does not support private or protected inheritance (it will be parsed, but ignored).
The following example shows how SWIG handles inheritance. For clarity, the full C++ code has been omitted.
// shapes.i %module shapes %{ #include "shapes.h" %} class Shape { public: virtual double area() = 0; virtual double perimeter() = 0; void set_location(double x, double y); }; class Circle : public Shape { public: Circle(double radius); ~Circle(); double area(); double perimeter(); }; class Square : public Shape { public: Square(double size); ~Square(); double area(); double perimeter(); } When wrapped into Perl5, we can now perform the following operations :
In our example, we have created Circle and Square objects. We can call member functions on each object by making calls to Circle_area, Square_area, and so on. However, we can can accomplish the same thing by simply using the Shape_area function on either object.beazley@slack% perl5.003 use shapes; $circle = shapes::new_Circle(7); $square = shapes::new_Square(10); print shapes::Circle_area($circle),"\n"; # Notice use of base class below print shapes::Shape_area($circle),"\n"; print shapes::Shape_area($square),"\n"; shapes::Shape_set_location($square,2,-3); print shapes::Shape_perimeter($square),"\n"; <ctrl-d> 153.93804004599999757 153.93804004599999757 100.00000000000000000 40.00000000000000000 TemplatesSWIG does not support template definitions--that is, it does not support anything that would be declared in C++ using the `template' keyword. If a template definition is found, SWIG will issue a warning message and attempt to ignore the contents of the entire declaration. For example, a template class such as the following would be ignored by SWIG :
However, SWIG can support instantiations of a template and types involving templates. For example, the following interface file would be legal :// File : list.h #define MAXITEMS 100 template<class T> class List { // Entire class is ignored by SWIG private: T *data; int nitems; public: List() { data = new T [MAXITEMS]; nitems = 0; } ~List() { delete [] data; }; void append(T obj) { if (nitems < MAXITEMS) { data[nitems++] = obj; } } int length() { return nitems; } T get(int n) { return data[n]; } };
The type "List<double>" becomes the datatype for the function parameter. In, Python it might appear like this :// SWIG interface involving a template %module example %{ #include "list.h" // Get Template definition %} // Now a function involving templates extern void PrintData(List<double> &l);
To create specific objects, you may need to supply helper functions such as the following :>>> print cl _80a2df8_List<double>_p >>>
%inline %{ // Helper function to create a List<double> List<double> *new_DoubleList() { return new List<double>; } %} Specific templates can also be wrapped in a clever way using typedef. For example, the following would also work :
In this case, SWIG thinks that there is a class "DoubleList" with the methods supplied. It generates the appropriate code and everything works like you would expect (of course, in reality there is no such class). When the SWIG module is compiled, all of the methods get supplied by the original template class. A key thing to keep in mind when working with templates is that SWIG can only handle particular instantiations of a template (such as a list of double). More general support is not yet provided (but may be added someday).%module example %{ #include "list.h" typedef List<double> DoubleList; %} class DoubleList { public: DoubleList(); ~DoubleList(); void append(double); int length(); double get(int n); }; RenamingC++ member functions and data can be renamed with the %name directive. The %name directive only replaces the member function name. For example :
This will create the functions List_find, List_delete, and a function named new_ListSize for the overloaded constructor.class List { public: List(); %name(ListSize) List(int maxsize); ~List(); int search(char *value); %name(find) void insert(char *); %name(delete) void remove(char *); char *get(int n); int length; static void print(List *l); };
The %name directive can be applied to all members including constructors, destructors, static functions, data members, and enumeration values.
The class name prefix can be changed by specifying
%name(newname) class List { ... } Adding new methodsNew methods can be added to a class using the %addmethods directive. This directive is primarily used in conjunction with shadow classes to add additional functionality to an existing class. For example :
%module vector %{ #include "vector.h" %} class Vector { public: double x,y,z; Vector(); ~Vector(); ... bunch of C++ methods ... %addmethods { char *__str__() { static char temp[256]; sprintf(temp,"[ %g, %g, %g ]", v->x,v->y,v->z); return &temp[0]; } } }; This code adds a __str__ method to our class for producing a string representation of the object. In Python, such a method would allow us to print the value of an object using the print command.
The %addmethods directive follows all of the same conventions as its use with C structures.>>> >>> v = Vector(); >>> v.x = 3 >>> v.y = 4 >>> v.z = 0 >>> print(v) [ 3.0, 4.0, 0.0 ] >>> Partial class definitionsSince SWIG is still somewhat limited in its support of C++, it may be necessary to only use partial class information in an interface file. This should not present a problem as SWIG does not need the exact C++ specification. As a general rule, you should strip all classes of operator overloading, friends, and other declarations before giving them to SWIG (although SWIG will generate only warnings for most of these things).
As a rule of thumb, running SWIG on raw C++ header or source files is currently discouraged. Given the complexity of C++ parsing and limitations in SWIG's parser it will still take some time for SWIG's parser to evolve to a point of being able to safely handle most raw C++ files. SWIG, C++, and the Legislation of MoralityAs languages go, C++ is quite possibly one of the most immense and complicated languages ever devised. It is certainly a far cry from the somewhat minimalistic nature of C. Many parts of C++ are designed to build large programs that are "safe" and "reliable." However, as a result, it is possible for developers to overload operators, implement smart pointers, and do all sorts of other insane things (like expression templates). As far as SWIG is concerned, the primary goal is attaching to such systems and providing a scripting language interface. There are many features of C++ that I would not have the slightest idea how to support in SWIG (most kinds of templates for example). There are other C++ idioms that may be unsafe to use with SWIG. For example, if one implements "smart" pointers, how would they actually interact with the pointer mechanism used by SWIG?
Needless to say, handling all of the possible cases is probably impossible. SWIG is certainly not guaranteed to work with every conceivable type of C++ program (especially those that use C++ in a maximal manner). Nor is SWIG claiming to build C++ interfaces in a completely "safe" manner. The bottom line is that effective use of C++ with SWIG requires that you know what you're doing and that you have a certain level of "moral flexibility" when it comes to the issue of building a useful scripting language interface. The future of C++ and SWIGSWIG's support of C++ is best described as an ongoing project. It will probably remain evolutionary in nature for the foreseeable future. In the short term, work is already underway for supporting nested classes and function overloading. As always, these developments will take time. Feedback and contributions are always welcome.Objective-COne of SWIG's most recent additions is support for Objective-C parsing. This is currently an experimental feature that may be improved in future releases.
Objective-C support is built using the same approach as used for C++ parsing. Objective-C interface definitions are converted into a collection of ANSI C accessor functions. These accessor functions are then wrapped by SWIG and turned into an interface.
To enable Objective-C parsing, SWIG should be given the -objc option (this option may be used in conjunction with the -c++ option if using Objective-C++). It may also be helpful to use the -o option to give the output file the .m suffix needed by many Objective-C compilers. For example :
Objective-C interfaces should also include the file `objc.i' as this contains important definitions that are common to most Objective-C programs.% swig -objc -o example_wrap.m example.i Objective-C ExampleThe following code shows a SWIG interface file for a simple Objective-C class :
%module list %{ #import "list.h" %} %include objc.i // Very simple list class @interface List : Object { int nitems; // Number of items in the list int maxitems; // Maximum number of items id *items; // Array holding the items } //------------------------- List methods -------------------------- // Create a new list + new; // Destroy the list - free; // Copy a list - copy; // Append a new item to the list - (void) append: (id) item; // Insert an item in the list - (void) insert: (id) item : (int) pos; // Delete an item from the list - remove: (int) pos; // Get an item from the list - get: (int) i; // Find an item in the list and return its index - (int) index: obj; // Get length of the list - (int) len; // Print out a list (Class method) + (void) print: (List *) l; @end Constructors and destructorsBy default, SWIG assumes that the methods "new" and "free" correspond to constructors and destructors. These functions are translated into the following accessor functions :
If the original Objective-C class does not have any constructors or destructors, putting them in the interface file will cause SWIG to generate wrappers for a default constructor and destructor (assumed to be defined in the object's base-class).List *new_List(void) { return (List *) [List new]; } void delete_List(List *l) { [l free]; }
If your Objective-C program uses a different naming scheme for constructors and destructors, you can tell SWIG about it using the following directive :
%pragma objc_new = "create" // Change constructor to `create' %pragma objc_delete = "destroy" // Change destructor to `destroy' Instance methodsInstance methods are converted into accessor functions like this :
void List_append(List *l, id item) { [l append : item]; } Class methodsClass methods are translated into the following access function :
void List_print(List *l) { [List print : l]; } Member dataMember data is handled in the same manner as for C++ with accessor functions being produced for getting and setting the value. By default, all data members of an Objective-C object are private unless explicitly declared @public.ProtectionSWIG can only wrap data members that are declared @public. Other protection levels are ignored.The use of idThe datatype `id' assumes the same role in SWIG as it does with Objective-C. A function operating on an `id' will accept any Object type (works kind of like void *). All methods with no explicit return value are also assumed to return an `id'.InheritanceEssentially all Objective-C classes will inherit from a baseclass Object. If undefined, SWIG will generate a warning, but other function properly. A missing baseclass has no effect on the wrapper code or the operation of the resulting module. Really, the only side effect of a missing base class is that you will not be able to execute base-class methods from the scripting interface. Objective-C does not support multiple inheritance.Referring to other classesThe @class declaration can be used to refer to other classes. SWIG uses this in certain instances to make sure wrapper code is generated correctly.CategoriesCategories provide a mechanism for adding new methods to existing Objective-C classes. SWIG correctly parses categories and attaches the methods to the wrappers created for the original class. For example :
%module example %{ #import "foo.h" %} // Sample use of a category in an interface @interface Foo (CategoryName) // Method declarations -bar : (id) i; @end Implementations and ProtocolsSWIG currently ignores all declarations found inside an @implementation or @protocol section. Support for this may be added in future releases.
Although SWIG ignores protocols, protocol type-specifiers may be used. For example, these are legal declarations :
SWIG will carry the protocol lists through the code generation process so the resulting wrapper code compiles without warnings.%module example %interface Foo : Object <proto1, proto2> { } // Methods - Bar : (id <proto1,proto2>) i; @end RenamingObjective-C members can be renamed using the %name() directive as in :
@interface List : Object { @public %name(size) int length; // Rename length to size } + new; - free; %name(add) -(void) append: (id) item; // Rename append to add @end Adding new methodsNew methods can be added to a class using the %addmethods directive. This is primarily used with shadow classes to add additional functionality to a class. For example :
@interface List : Object { } ... bunch of Objective-C methods ... %addmethods { - (void) output { ... code to output a list ... } } @end %addmethods works in exactly the same manner as it does for C and C++ (except that Objective-C syntax is allowed). Consult those sections for more details. Other issuesObjective-C is dynamically typed while SWIG tends to enforce a type-checking model on all of its pointer values. This mismatch could create operational problems with Objective-C code in the form of SWIG type errors. One solution to this (although perhaps not a good one) is to use the SWIG pointer library in conjunction with Objective-C. The pointer library provides simple functions for casting pointer types and manipulating values.
Certain aspects of Objective-C are not currently supported (protocols for instance). These limitations may be lifted in future releases. Conditional compilationSWIG does not run the C preprocessor, but it does support conditional compilation of interface files in a manner similar to the C preprocessor. This can be done by placed #ifdef, #ifndef, #if, #else, #elif, and #endif directives in your interface file. These directives can be safely nested. This allows one to conditionally compile out troublesome C/C++ code if necessary. For example, the following file can serve as both a C header file and a SWIG interface file :
#ifdef SWIG %module mymodule %{ #include "header.h" %} %include wish.i #endif ... normal C declarations here ... Similarly, conditional compilation can be used to customize an interface. The following interface file can be used to build a Perl5 module that works with either static or dynamic linking :
However, it is not safe to use conditional compilation in the middle of a declaration. For example :%module mymodule %{ #include "header.h" %} ... Declarations ... #ifdef STATIC %include perlmain.i // Include code for static linking #endif
This fails because the SWIG parser is not equipped to handle conditional compilation directives in an arbitrary location (like the C preprocessor). For files that make heavy use of the C preprocessor like this, it may be better to run the header file through the C preprocessor and use the output as the input to SWIG.double foo( #ifdef ANSI_ARGS double a, double b #endif ); Defining symbolsTo define symbols, you can use the -D option as in :
Symbols can also be defined using #define with no arguments. For example :swig -perl5 -static -DSTATIC interface.i
%module mymodule #define STATIC ... etc ... For the purposes of conditional compilation, one should not assign values to symbols. If this is done, SWIG interprets the #define as providing the definition of a scripting language constant. The #if directiveThe #if directive can only be used in the following context :
#if defined(SYMBOL) ... #elif !defined(OTHERSYMBOL) ... #endif The C preprocessor version supports any constant integral expression as an argument to #if, but SWIG does not yet contain an expression evaluator so this is not currently supported. As a result, declarations such as the following don't yet work :
#if (defined(foo) || defined(bar)) ... #endif Predefined SymbolsOne or more of the following symbols will be defined by SWIG when it is processing an interface file :
Interface files can look at these symbols as necessary to change the way in which an interface is generated or to mix SWIG directives with C code. These symbols are also defined within the C code generated by SWIG (except for the symbol `SWIG' which is only defined within the SWIG compiler).SWIG Always defined when SWIG is processing a file SWIGTCL Defined when using Tcl SWIGTCL8 Defined when using Tcl8.0 SWIGPERL Defined when using Perl SWIGPERL4 Defined when using Perl4 SWIGPERL5 Defined when using Perl5 SWIGPYTHON Defined when using Python SWIGGUILE Defined when using Guile SWIGWIN Defined when running SWIG under Windows SWIGMAC Defined when running SWIG on the Macintosh Code InsertionSometimes it is necessary to insert special code into the resulting wrapper file generated by SWIG. For example, you may want to include additional C code to perform initialization or other operations. There are four ways to insert code, but it's useful to know how the output of SWIG is structured first.The output of SWIGSWIG creates a single C source file containing wrapper functions, initialization code, and support code. The structure of this file is as follows :
![]()
The headers portion typically contains header files, supporting code, helper functions, and forward declarations. If you look at it, you'll usually find a hideous mess since this also contains the SWIG run-time pointer type-checker and internal functions used by the wrapper functions. The "wrapper" portion of the output contains all of the wrapper functions. Finally, the initialization function is a single C function that is created to initialize your module when it is loaded. Code blocksA code block is enclosed by a %{, %} and is used to insert code into the header portion of the resulting wrapper file. Everything in the block is copied verbatim into the output file and will appear before any generated wrapper functions. Most SWIG input files have at least one code block that is normally used to include header files and supporting C code. Additional code blocks may be placed anywhere in a SWIG file as needed.
%module mymodule %{ #include "my_header.h" %} ... Declare functions here %{ ... Include Tcl_AppInit() function here ... %} Code blocks are also typically used to write "helper" functions. These are functions that are used specifically for the purpose of building an interface and are generally not visible to the normal C program. For example :
%{ /* Create a new vector */ static Vector *new_Vector() { return (Vector *) malloc(sizeof(Vector)); } %} // Now wrap it Vector *new_Vector(); Inlined code blocksBecause the process of writing helper functions is fairly common, there is a special inlined form of code block that is used as follows :
The %inline directive inserts all of the code that follows verbatim into the header portion of an interface file. The code is then fed into the SWIG parser and turned into an interface. Thus, the above example creates a new command new_Vector using only one declaration. Since the code inside an %inline %{ ... %} block is given to both the C compiler and SWIG, it is illegal to include any SWIG directives inside the %{ ... %} block.%inline %{ /* Create a new vector */ Vector *new_Vector() { return (Vector *) malloc(sizeof(Vector)); } %} Initialization blocksCode may also be inserted using an initialization block, as shown below :
%init %{ init_variables(); %} This code is inserted directly into SWIG's initialization function. You can use it to perform additional initialization and operations. Since this code is inserted directly into another function, it should not declare functions or include header files. Primarily this can be used to add callouts to widgets and other packages that might also need to be initialized when your extension is loaded. Wrapper code blocksCode may be inserted in the wrapper code section of an output file using the %wrapper directive as shown :
This directive, for almost all practical purposes, is identical to just using a %{,%} block, but may be required for more sophisticated applications. It is mainly only used for advanced features in the SWIG library. As a general rule, you should avoid using this directive unless you absolutely know what you are doing.%wrapper %{ ... a bunch of code ... %} A general interface building strategyThis section describes the general approach for building interface with SWIG. The specifics related to a particular scripting language are found in later chapters.Preparing a C program for SWIGSWIG doesn't require modifications to your C code, but if you feed it a collection of raw C header files or source code, the results might not be what you expect---in fact, they might be awful. Here's a series of steps you can follow to make an interface for a C program :
While this may sound complicated, the process turns out to be relatively easy in practice--for example, making an interface to the entire OpenGL library only takes about 5-10 minutes.
In the process of building an interface, you are encouraged to use SWIG to find problematic declarations and specifications. SWIG will report syntax errors and other problems along with the associated file and line number. The SWIG interface fileThe preferred method of using SWIG is to generate separate interface file. Suppose you have the following C header file :
A typical SWIG interface file for this header file would look like the following :/* File : header.h */ #include <stdio.h> #include <math.h> extern int foo(double); extern double bar(int, int); extern void dump(FILE *f);
Of course, in this case, our header file is pretty simple so we could have made an interface file like this as well:/* File : interface.i */ %module mymodule %{ #include "header.h" %} extern int foo(double); extern double bar(int, int); extern void dump(FILE *f);
/* File : interface.i */ %module mymodule %include header.h Naturally, your mileage may vary. Why use separate interface files?While SWIG can parse many header files, it is more common to write a special .i file defining the interface to a package. There are several reasons for doing this :
Getting the right header filesSometimes, it is necessary to use certain header files in order for the code generated by SWIG to compile properly. You can have SWIG include certain header files by using a %{,%} block as follows :
%module graphics %{ #include <GL/gl.h> #include <GL/glu.h> %} // Put rest of declarations here ... What to do with main()If your program defines a main() function, you may need to get rid of it or rename it in order to use a scripting language. Most scripting languages define their own main() procedure that must be called instead. main() also makes no sense when working with dynamic loading. There are a few approaches to solving the main() conflict :
Getting rid of main() may cause potential initialization problems of a program. To handle this problem, you may consider writing a special function called program_init() that initializes your program upon startup. This function could then be called either from the scripting language as the first operation, or when the SWIG generated module is loaded.
As a general note, many C programs only use the main() function to parse command line options and to set parameters. However, by using a scripting language, you are probably trying to create a program that is more interactive. In many cases, the old main() program can be completely replaced by a Perl, Python, or Tcl script. Working with the C preprocessorIf you have a header file that makes heavy use of macros and C preprocessor directives, it may be useful to run it through the C preprocessor first. This can usually be done by running the C compiler with the -E option. The output will be completely hideous, but macros and other preprocessor directives should now be expanded as needed. If you want to wrap a C preprocessor macro with SWIG, this can be done by giving a function declaration with the same name and usage as the macro. When writing the macro as a function declaration, you are providing SWIG with type-information--without that, SWIG would be unable to produce any sort of wrapper code.How to cope with C++Given the complexity of C++, it will almost always be necessary to build a special interface file containing suitably edited C++ declarations. If you are working with a system involving 400 header files, this process will not be trivial. Perhaps the best word of advice is to think hard about what you want this interface to be. Also, is it absolutely critical to wrap every single function in a C++ program? SWIG's support of C++ will improve with time, but I'll be the first to admit that SWIG works much better with pure ANSI C code when it comes to large packages.How to avoid creating the interface from hellSWIG makes it pretty easy to build a big interface really fast. In fact, if you apply it to a large enough package, you'll find yourself with a rather large chunk of code being produced in the resulting wrapper file. To give you an idea, wrapping a 1000 line C header file with a large number of structure declarations may result in a wrapper file containing 20,000-30,000 lines of code. I can only imagine what wrapping a huge C++ class hierarchy would generate. Here's a few rules of thumb for making smaller interfaces :
Writing a nice interface to a package requires work. Just because you use SWIG it doesn't mean that you're going to end up with a good interface. SWIG is primarily designed to eliminate the tedious task of writing wrapper functions. It does not eliminate the need for proper planning and design when it comes to building a useful application. In short, a little forethought can go a long way.
Of course,if you're primarily interested in just slapping something together for the purpose of debugging, rapid application development, and prototyping, SWIG will gladly do it for you (in fact, I use SWIG alot for this when developing other C/C++ applications).
SWIG 1.1 - Last Modified : Mon Aug 4 10:46:53 1997 |