14 Working with Modules

When first working with SWIG, users commonly start by creating a single module. That is, you might define a single SWIG interface that wraps some set of C code. You then compile all of the generated wrapper code into a module and use it. For large applications, however, this approach is problematic---the size of the generated wrapper code can be rather large. Moreover, it is probably easier to manage the scripting interface when it is broken up into smaller pieces.

This chapter describes the problem of using SWIG in programs where you want to create a collection of modules.

14.1 The SWIG runtime code

All SWIG-generated wrapper modules include a set of functions commonly known as the "SWIG runtime." These functions are primarily related to the runtime type system which checks pointer types and performs other tasks such as proper casting of pointer values in C++.

By default, the runtime functions are private to each SWIG-generated module. That is, the runtime functions are declared with "static" linkage and are visible only to the wrapper functions defined in that module. If two completely different SWIG modules are loaded, this presents no problem---each module uses its own private runtime code. The only problem with this approach is that when more than one SWIG module is used in the same application, those modules often need to share type information. This is especially true for C++ programs where SWIG must collect and share information about inheritance relationships that cross module boundaries.

To solve the problem of sharing information across modules, the SWIG runtime functions need to be exposed in a way that allows data to be shared between modules. The next section describes how to do that.

14.2 Compiling Multiple SWIG modules

Suppose that you have three SWIG interface files A.i, B.i, and C.i and suppose that these modules interact with each other. To make this work, there are two approaches you can take:

Option 1: Designate one module to provide the runtime code

With this option, one of the modules is designated as providing the runtime environment. This is done with the -runtime option like this:

% swig -runtime -c++ -python A.i
The other modules are then compiled without runtime support. This is done by supplying the -noruntime option like this:
% swig -noruntime -c++ -python B.i
% swig -noruntime -c++ -python C.i
To use the modules, you compile and link everything as before, but you need to make sure that module A is loaded before all of the other modules are used---otherwise you will unresolved symbols.

Now, the bad news: This approach may or may not work depending on the platform you are using, what target language you are using, and the way that shared libraries work on the system. On many systems, the symbols contained in dynamically loaded modules are private. Therefore, even though module A provides the runtime code, the other modules won't be able to find it. You'll know if this is the case if you try to load the other modules and you get errors about unresolved SWIG_* functions.

Option 2: Build a runtime library

The second way to work with multiple modules is to create a special runtime library module. To do this, you first build a runtime library like this:

% swig -runtime -python swigrun.i
% # Build a shared library --- this is different on every machine! (shown for Linux)
% gcc -fpic swigrun_wrap.c -o swigrun_wrap.o
% gcc -shared swigrun_wrap.o -o libswigrunpy.so
Now, you compile all of the normal SWIG modules using the -noruntime option:
% swig -noruntime -c++ -python A.i
% swig -noruntime -c++ -python B.i
% swig -noruntime -c++ -python C.i
Finally, when linking the dynamically loadable modules, you need to link again the special runtime library above. For example (Linux) :
% g++ -shared A_wrap.o -L. -lswigrunpy -o _A.so
% g++ -shared B_wrap.o -L. -lswigrunpy -o _B.so
% g++ -shared C_wrap.o -L. -lswigrunpy -o _C.so
Again, all of the details will vary depending on what compiler you use, the platform, target language, and so forth. The key point is that the runtime needs to be contained in a shared/dynamic library and you need to link all of the modules against that library.

When you use the modules created using this technique, the runtime code will be automatically loaded when the modules are imported. Moreover, since all of the modules are linked against the same runtime library, they will share that code.

14.3 A word of caution about static libraries

When working with multiple SWIG modules, you should take care not to use static libraries. For example, if you have a static library libfoo.a and you link a collection of SWIG modules with that library, each module will get its own private copy of the library code inserted into it. This is very often NOT what you want and it can lead to unexpected or bizarre program behavior. When working with dynamically loadable modules, you should try to work exclusively with shared libaries.

14.4 References

Due to the complexity of working with shared libraries and multiple modules, it might be a good idea to consult an outside reference. John Levine's "Linkers and Loaders" is highly recommended.


SWIG 1.3 - Last Modified : November 22, 2003