FAQ

William S Fulton edited this page Jan 3, 2017 · 1 revision

Frequently Asked Questions

Installation

Q: When I run SWIG, it complains that it can't find swig.swg. How do I fix this?

In order to generate code, SWIG relies on a library of files known as the SWIG Library. This error message is being caused ecause SWIG is either not installed correctly or is misconfigured so that it can't locate its library files.

  • Make you sure always do a 'make install' before running SWIG.
  • Make sure you have write permission on the directory where SWIG will be installed (perhaps the installation failed and you didn't notice).
  • If you tried to install SWIG in your own directory, you might have used a shell escape character such as ~ when specifying the installation directory. Don't do this---use a full pathname instead.

If you have no idea where SWIG is looking for its files, try typing this to display the location:

$ swig -swiglib
/r0/beazley/Projects/lib/swig1.3
$

As a temporary fix, you can set the SWIG_LIB environment ariable. However, it's probably better to just recompile SWIG with the right setting.

Q: How do I install SWIG in a directory other than /usr/local/...?

To install SWIG in a different location, use the --prefix option to configure. For example:

$ ./configure --prefix=/home/yourname/packages
$ make
$ make install

Note: when specifying your home directory, do not use characters that only have meaning in the Unix shell. For example, a common installation mistake is to type:

$ ./configure --prefix=~        # ERROR!

On many machines, this doesn't work because the ~ character is left unexpanded. This in turn, causes a bad pathname to be used for SWIG's configuration. When you try to use SWIG later, you will then get a lot of file-not-found errors and it won't work (see the previous question).

Q: I run make -k check, but some of the tests fail. What is going on?

SWIG is a work in progress. Some of the tests are designed to exercise obscure parsing features and hard code generation problems. If only a few of the tests fail, it's probably nothing to worry about (it's likely a bug that we're working on). If a lot of the tests fail, then something more serious may be wrong.

Some of the obscure test cases will also fail due to the limitations of the compiler you are using. Generally the test suite works with the latest version of gcc.

Common Usage Problems

Q: I tried to wrap a structure or a class and am getting tons of "variable undeclared" errors. What's going on?

A common problem is forgetting to include header files or definitions. For example, if you write an interface file like this:

%module foo

typedef struct {
  double x,y;
} Vector;

and try to compile the resulting wrapper code, you might get tons of compiler errors like this:

./defines2_wrap.c: In function `_wrap_Vector_x_set':
./defines2_wrap.c:1708: `Vector' undeclared (first use in this function)
./defines2_wrap.c:1708: (Each undeclared identifier is reported only once
./defines2_wrap.c:1708: for each function it appears in.)
./defines2_wrap.c:1708: `_arg0' undeclared (first use in this function)
./defines2_wrap.c:1709: parse error before `double'
./defines2_wrap.c:1712: `_argo0' undeclared (first use in this function)
./defines2_wrap.c:1712: `_arg1' undeclared (first use in this function)
./defines2_wrap.c:1715: `_result' undeclared (first use in this function)
...

To fix this, you need to make sure you include the proper header files in your interface. For example:

%module foo
%{
  /* Include header with definition of Vector */
  #include "someheader.h"
%}

typedef struct {
  double x,y;
} Vector;

Keep in mind that SWIG only transforms declarations into wrapper code. Putting the definition of a structure or class in the interface file does not actually create a declaration in the output.

Also, note that structures used only in the context of a SWIG interface can also be wrapped using %inline like this:

%inline %{
  typedef struct {
    double x,y;
  } Vector;
%}

Shared Libraries

In order to compile SWIG generated code into an extension module, you usually have to create a shared library. This page contains information about doing this on different platforms. Note: the SWIG developers only have access to a limited number of machines. If you have information for platforms not listed below, please edit this page!

There are example makefiles which might have been configured correctly for your system when you installed SWIG. Find an example under the Examples directory and run make. If the environment variable SWIG_LIB isn't set, you will first need to set it to SWIG's Lib directory.

Q: How do I create shared libraries for Linux?

For C:

$ cc -fpic -c $(SRCS)
$ ld -shared $(OBJS) -o module.so

For C++:

$ c++ -fpic -c $(SRCS)
$ c++ -shared $(OBJS) -o module.so

If you are using GCC 4.x under Ubuntu and using python 2.6 try the following

$ swig -python module.i
$ gcc -fpic -I/usr/include/python2.6 -c module_wrap.c
$ gcc -shared module_wrap.o -o module.so

Q: How do I create shared libraries for Solaris?

If using gcc, you will need to do this:

For C:

$ gcc -c $(SRCS)
$ ld -G $(OBJS) -o module.so

For C++:

$ g++ -c $(SRCS)
$ g++ -Wl,-G $(OBJS) -o module.so

If you are using the Sun Workshop C/C++ compilers. It's usually just this:

For C:

$ cc -c $(SRCS)
$ ld -G $(OBJS) -o module.so

For C++:

$ CC -c $(SRCS)
$ CC -G $(OBJS) -L/opt/SUNWspro/lib -lCrun -o module.so

You may need to add "-lCstd" before "-lCrun" if you use the C++ standard library.

Q: How do I create shared libraries for Irix?

With mipspro compilers, you can do:

cc -n32 -DPIC  -c foo.c
cc -n32 -shared foo.o -o libfoo.so

For C++:

CC -n32 -ptused -DPIC -c foo.cxx
CC -n32 -shared foo.o -o libfoo.so

Note: in order for extension modules to work, they need to be compiled with the same linking options as the target language. For example, if you have compiled Python using -n32, then extension modules should use -n32. It is generally not possible to mix linking formats in the same application. For example, a module compiled with -o32 can't be dynamically loaded into an -n32 application.

Q: How do I create shared libraries for HPUX?

HP-UX supports dynamically loadable libraries (shared libraries). Shared libraries end with the suffix .sl. On Itanium systems, they end with the suffix .so.

Shared libraries created on a platform using a particular PA-RISC version are not usable on platforms using an earlier PA-RISC version by default. However, this backwards compatibility may be enabled using the same +DAportable compiler flag (with the same PA-RISC 1.0 caveat mentioned above).

Shared libraries created on an Itanium platform cannot be loaded on a PA-RISC platform. Shared libraries created on a PA-RISC platform can only be loaded on an Itanium platform if it is a PA-RISC executable that is attempting to load the PA-RISC library. A PA-RISC shared library cannot be loaded into an Itanium executable nor vice-versa.

To create a shared library, the following steps must be performed:

  1. Compile source modules with +z or +Z flag to create a .o module which contains Position-Independent Code (PIC). The linker will tell you in the next step if +Z was needed.
  2. Link the shared library using the -b flag. If the code calls any functions in other system libraries (e.g., libm), it must be included on this line.

If these dependent libraries are not listed at shared library creation time, you will get fatal ``Unresolved symbol'' errors at run time when the library is loaded.

You may create a shared library that refers to another library, which may be either an archive library or a shared library. If this second library is a shared library, this is called a dependent library. The dependent library's name is recorded in the main shared library, but it is not linked into the shared library. Instead, it is loaded when the main shared library is loaded. This can cause problems if you build an extension on one system and move it to another system where the libraries may not be located in the same place as on the first system.

If the referred library is an archive library, then it is treated as a simple collection of .o modules (all of which must contain PIC). These modules are then linked into the shared library.

Q: How do I create shared libraries for AIX?

How to link a SWIG program on AIX for PERL

ksh commands used:

$ perlcore=/usr/opt/perl5/lib/5.6.0/aix/CORE
$ swig -perl5 util_lib.i
$ gcc -O3 -I${perlcore} -c <any>.c ... <anyother>.c util_lib_<any>.c
$ ld -o util_lib.so -bhalt:4 -G -bI:${perlcore}/perl.exp -bE:util_lib.exp -bnoentry -lc fontmetr.o <any>.o util_lib_<any>.o -lc_r

This assumes that you have a SWIG interface file (util_lib.i) that looks something like:

%module util_lib
%{
  #include "<any>_struct.h"
%}
%include <any>_proto.h

and declarations (in proto.h) like:

<any>_proto.h::
#ifndef __<any>_proto_DEFINED_qqzz
#define __<any>_proto_DEFINED_qqzz
extern int my_entry_1(int, int, int);
extern int my_entry_2(void);
extern struct <any> *my_entry_3(void);
... etc. ...
#endif

and a util_lib.exp file (whatever that is) like:

#!
boot_util_lib
my_entry_1
my_entry_2
...
my_entry_n

Q: How do I create a DLL for Windows?

Also see the Cygwin and Mingw/Msys FAQ questions below. Please note that there are instructions in the SWIG documentation for many languages. See the individual language documentation files, for example Perl5.html. Also check out http://www.swig.org/Doc3.0/Windows.html for further info.

With Microsoft Visual C++ 6.0:

Create a new Win32 DLL project:

File -> New -> Project tab: Select Win32 dynamic-link library and specify a name.

In Tool -> Options -> Directories it is handy to add include file directory for your script languages include files and to add library file directory for your script languages library files.

In project settings -> C/C++ -> Preprocessor definitions: add __WIN32__.

Then just add your source and header files to the project and build.

You may also want to insert your interface file and specify how Visual C++ shall compile it In Project settings -> Custom build.

Enter "SWIG" in the description field.
Enter "swig -<script language> <other options> -o $(ProjDir)\$(InputName)_wrap.c $(InputPath)" in the "Build command(s)" field
Enter "$(ProjDir)\$(InputName)_wrap.c" in the "Output files(s)" field.

With Microsoft Visual C++ 7.0 (Version 2002):

To create a new Win32 DLL project:

File -> New -> Project tab: Select Managed C++ Class Library and specify a name.

Otherwise the process is the same as that of Microsoft Visual C++ 6.0 above.

With Microsoft Visual C++ 2005 Express[1]:

First install and configure the Microsoft Platform SDK[2]. Once the Platform SDK is configured, create a new DLL Project:

New Project -> Win32 Console Application.
Enter a project name and click OK.
Select DLL radio-button and click Finish.

Otherwise the process is the same as that of Microsoft Visual C++ 6.0 above.

Q: How do I create DLLs using Cygwin?

When creating DLLs in Windows there cannot be any unresolved symbols. Thus all the libraries you need to link against must be specified using the -l command line option. Most of the SWIG target languages will need linking against the language library. In general use:

For C,

$ gcc -c $SRCS
$ gcc -shared $OBJS $LIBPATH $LIBS -o module.dll

For C++

$ g++ -c $SRCS
$ g++ -shared $OBJS $LIBPATH $LIBS -o module.dll

where,

$SRCS: C/C++ sources
$OBJS: compiled .o files
$LIBPATH: Path to language library, e.g. -L/usr/lib/python2.2/config. Use the path to the .a file in preference to the .dll file.
$LIBS: Language library, e.g. -lpython2.2

Q: How do I create DLLs using Mingw?

This is from my makefile. I'm attempting to build smimeutil.dll.

# i wanna use the perl56.dll -- google for impdef.exe if you need it
# i use redir if there's too many errors -- google for it if you need it

perl56.dll: ; copy \perl\bin\perl56.dll .

perl56.def: perl56.dll; \dc\bin\impdef perl56.dll >perl56.def

libperl56.a: perl56.def; dlltool --dllname perl56.dll --def perl56.def --kill-at --output-lib libperl56.a

smimeutil.dll: smimeutil_wrap.o libperl56.a libsmime.a ; dllwrap --export-all --output-def smimeutil.def -o smimeutil.dll smimeutil_wrap.o libsmime.a libperl56.a ..\lib\libcrypto.a ..\lib\libgdi32.a ..\lib\libwsock32.a

With the Minimal System (msys) and Mingw for Tcl:

download: msys_mingwx.zip from the tcl project containing gcc and a minimal system (sh.exe, make ...): http://sourceforge.net/projects/tcl/ download the tcltk-sources from the same url and make tcltk-binaries

with the binary SWIG for windows do the following:

> /d/SWIG-1.3.17/swig.exe -tcl example.i
> gcc -c example_wrap.c -I/local/include
# /local/include contains tcl.h, /local/lib libtcl84.a
> gcc -shared example_wrap.o -L/local/lib/ -ltcl84 -o example.dll

Q: Can I use a single libZZZ.so file for multiple language support?

I generate zzz_perl.cc and zzz_perl.tcl and generate libzzz.so I would like to use this combined shared library with different (say Tcl and Perl) shells. When I tried, the combined one worked with Perl, but failed for Tcl ("undefined reference to PM_* functions").

In general, it is not possible to make a single extension module that works with more than one language. This is because the SWIG generated wrapper code will contain unresolved references to API functions contained in all of the other languages. The only way that these would be resolved is if you somehow link the universe together (Perl, Tcl, Python, and SWIG code all at once).

You might (and this is a big might) be able to make it work if you added empty stub functions with the same name as required API functions (ex. PM_*) to the SWIG generated wrappers. If the dynamic linker is smart, it will bind to the real implementation of the functions when loaded into a specific target language whereas functions for other languages will just bind to the stubs (which won't be used anyways).

Q: How do I create shared libraries for Mac OS X?

The following code works for compiling the tutorial Python example on recent versions of Mac OS X (e.g., 10.6, Snow Leopard):

swig -python example.i
cc -c `python-config --cflags` example.c example_wrap.c
cc -bundle `python-config --ldflags` example.o example_wrap.o -o _example.so

(Both -bundle and -dynamiclib work in this context, but loadable modules built for one specific program are more properly bundles than dylibs.)

And here's a quick session showing the interface in action.

Python 2.6.1 (r261:67515, Feb 11 2010, 00:51:29)
[GCC 4.2.1 (Apple Inc. build 5646)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> import example
>>> example.fact(4)
24
>>> example.get_time()
'Mon Jul  5 13:10:37 2010\n'
>>> example.cvar.My_variable
3.0
>>> example.cvar.My_variable = example.cvar.My_variable + 1
>>> example.cvar.My_variable
4.0

Likewise, for perl, the relevant commands are

swig -perl5 example.i
cc -c example.c example_wrap.c `perl -MExtUtils?::Embed -e ccopts`
cc -bundle -o example.bundle example.o example_wrap.o `perl -MExtUtils?::Embed -e ldopts`

and the example session is:

perl
 use example;
 print $example::My_variable,"\n";
 print example::fact(5),"\n";
 print example::get_time(),"\n";
[CTRL-D]
3
120
Mon Jul  5 13:33:28 2010

For Java, the necessary incantation is

cc -c example.c example_wrap.c -I`javaconfig Headers`
cc -framework JavaVM? -bundle example.o example_wrap.o -o libexample.jnilib

and running it, we get

javac main.java
java main
3.0
120
Mon Jul  5 14:13:11 2010

Q: How do I build the tutorial example for Java on Linux?

If you use and adapt the tutorial example, you might get an UnsatisfiedLinkError. The most likely reason is the you didn't change example.so into libexample.so.

The following commands worked on my Suse 9.0 Linux system:

% swig -java example.i
% gcc -fpic -c example.c example_wrap.c -I/usr/java/j2sdk1.4.2/include -I/usr/java/j2sdk1.4.2/include/linux
% gcc -shared example.o example_wrap.o -o libexample.so
% javac main.java
% java main

Chances are that you get an error message:

% java main
  Exception in thread "main" java.lang.UnsatisfiedLinkError: no example in java.library.path
  at java.lang.ClassLoader.loadLibrary(ClassLoader.java:1517)
  at java.lang.Runtime.loadLibrary0(Runtime.java:788)
  at java.lang.System.loadLibrary(System.java:834)
  at main.main(main.java:3)

A simple solution is to adjust the environment variable LD_LIBRARY_PATH as suggested in http://www.swig.org/Doc3.0/SWIGDocumentation.html#dynamic_linking_problems . This could be done like this

% LD_LIBRARY_PATH=$LD_LIBRARY_PATH:PUT_YOUR_PATH_HERE java main

Q: How do I build the tutorial example for Perl5 on Linux?

If you use and adapt the tutorial example, you might get errors like

... CORE/proto.h:199: error: parse error before "off64_t"
... CORE/proto.h:201: error: parse error before "Perl_do_sysseek"

For me, it worked only with the option -c++, although the example is pure C:

% swig -c++ -perl example.i
% g++ -c example.c
% g++ -c example_wrap.cxx -I/usr/lib/perl5/5.8.1/i586-linux-thread-multi/CORE
% g++ -shared example.o example_wrap.o -o example.so
% perl
    use example;
    print $example::My_variable,"\n";
    print example::get_time(),"\n";
    <CTRL-D>
3
Sat Apr  3 15:26:23 2004

C++ Issues

Q: When I build a C++ extension, it won't load due to unresolved symbols. Why?

This is almost always caused by improper linking of the shared library. When building a C++ extension, it is fairly common to link using the C++ compiler. For example:

$ c++ -shared $(OBJS) -o module.so

Note: the compiler options vary on each machine so you will have to read the man pages for the compiler and linker.

On some machines, you may also need to link with special libraries. For example, the Sun compiler on Solaris often requires something like this:

$ CC -G $(OBJS) -L/opt/SUNWspro/lib -lCrun -o module.so

If you are using g++ on a Linux box, you may need to link in the stdc++ library. If you are using automake, you can use or modify the flags for the linker:

my_swigged_library_la_LDFLAGS = -lstdc++

In general, you can use the commonly available nm program to look at a library's symbol table, or even through all of /usr/lib:

myhost:/usr/lib$ nm --print-file-name * | grep "_unresolved_symbol_name"

and then simply make sure that library can be found by the linker. Bottom line: you may have to experiment with a simple example to get things to work. Once you get one example to work, simply write down the compiler options and use them for your other projects.

Q: When my code derives from std::exception, is there a way to tell SWIG to not wrap std::exception (essentially messing everything up then)?

No.

Have you tried using %ignore to simply ignore std::exception? Please clarify with an example. -Dave.

Q: When a method refers to an undeclared class, SWIG doesn't seem to produce correct wrappers. Why?

Consider this wrapped code:

class Foo {
public:
  ...
  Bar *some_method();
  ...
};

class Bar {
public:
  ...
};

When producing wrappers, code is generated in the same order as declarations appear in the interface file. Because of this, Bar *some_method() is wrapped before SWIG knows anything about the definition of Bar *. In certain cases, this will break shadow classes and produce "incorrect" code.

To fix the problem, all you need to do is tell SWIG that Bar is a class. Use a forward declaration like this:

class Bar;

class Foo {
public:

  Bar *some_method();
};

Note: this is exactly the same technique that you need to use in C++ in order for the code to compile correctly.

Q: I use std::cout to output debug information. It works fine under *nix/macOS systems but not under ActivePython IDE and IDLE, Why?

GUI may not have a standard output as terminals have. sys.stdout is the preferred way to output to python workspace. However, you can let cout use a streambuf that output to python sys.stdout in the following way:

create a streambuf object that write to sys.stdout using PySys WriteStdout function.
use this streambuf in cout.

Source Code: (Use at your own risk)

// for PySys_WriteStdout
#include "Python.h"
// for streambuf stuff
#include <streambuf>

/// a streambuf that print to python sys.stdout
class PythonCoutBuf: public std::streambuf
{
  public:
    PythonCoutBuf(){}

  protected:

    int overflow(int c)
    {
      // write out current buffer
      if( pbase() != pptr() )
      {
        // the end of buf might not be \0 -- make it be
        // This can be dangerous, you can strncpy to a buffer.
        char_type * endPtr  = pptr();
        char_type   endChar = * endPtr;
        *endPtr = '\0';
        // output to python sys.stdout
        PySys_WriteStdout("%s",pbase());
        // put original end character back, whatever it is.
        *endPtr = endChar;
        // I do not really know what this is doing.
        setp(pbase(), epptr());
      }
      // then how to deal with this overflowed c?
      if( c != EOF )
      {
        // unbuffered, write out this character, do not put into buffer
        if ( pbase() == epptr() )
          PySys_WriteStdout("%c", c);
        else
          sputc(c);
      }
      return 0;
    }
};

/// create an object
PythonCoutBuf g_pythonCout;

/// then in init function, change streambuf of cout
cout.rdbuf( &g_pythonCout );

Q: Why do I get a message about undefined ios_base?

You need to compile with '-fPIC'.

Q: How can I downcast objects returned from Factory methods?

This problem occurs with functions that instantiate objects whose type is derived from a common base, but the return type is the base type. Attempting to downcast these objects in the target language causes type exceptions.

The problem most commonly occurs in code that uses "Factory" patterns.

One possibility is to use the %factory typedef defined in Lib/typemaps/factory.swg.

Here are some examples that exploit introspective abilities of the target language:

This code could definitely be more efficient and more general, so please feel free to improve on it.

The following code is intended for factory code that follows the pattern described below. It has the advantage of enabling changes made to the C++ factory dispatch code to propagate to each target language automatically.

Classes are derived from a common base. The factory creation method is defined in the base class, and each derived class can be identified by a publicly-accessible ID (usually an integer or string).

The ID defined for each derived class can be returned via both a static variable, enum or function, and a virtual function defined in the base.

The SWIG code takes advantage of the target language's introspective abilities to create the correct wrapped type, given the object ID.

Example:

class Base
{
public:
    static Base* create(int id)
    {
        switch (id)
        {
            case Derived1::OBJECT_ID: return new Derived1;
            case Derived2::OBJECT_ID: return new Derived2;
        }

        virtual int objectID() = 0;
    }
};

class Derived1 : public Base
{
public:
    enum
    {
        OBJECT_ID = 10
    }

    virtual int objectID() { return OBJECT_ID; }
};

class Derived2 : public Base
{
public:
    enum
    {
        OBJECT_ID = 20
    }

    virtual int objectID() { return OBJECT_ID; }
};

Python example

%pythoncode %{
    // SWIGFactoryHelper is used to build a map from object IDs to class names.
    class SWIGFactoryHelper:
        def __init__(self, this_mod):
            self._id_to_class_name = {}

            for val in this_mod.__dict__.values():
                if isinstance(val, type):
                    if hasattr(val, 'OBJECT_ID'):
                        self._id_to_class_name[val.OBJECT_ID] = val.__name__

        def id_to_class_name(self):
          return self._id_to_class_name

    _swig_factory_helper = None

    def swig_factory_helper(module):
        global _swig_factory_helper

        if _swig_factory_helper == None:
            _swig_factory_helper = SWIGFactoryHelper(module)

        return _swig_factory_helper
%}

%wrapper %{
  std::map<int, swig_type_info*> _objectIDToSWIGInfo;

  swig_type_info* objectIDToSWIGInfo(int objectID)
  {
    if (_objectIDToSWIGInfo.empty())
    {
      // Make use of python's introspection features to get mappings from object ids to swig_type_info objects.

      // Get SWIG python module.
      // SWIG_name returns "_module_name" which is the native module, but the python module is required, so
      // +1 to skip the underscore.
      std::string python_module_name = SWIG_name + 1;

      PyObject* module = PyImport_ImportModule(python_module_name.c_str());
      if (!module)
        return 0;

      // Get factory helper from module
      PyObject* swig_factory_helper = PyObject_CallMethod(module, "swig_factory_helper", "O", module);
      if (!swig_factory_helper)
        return 0;

      Py_DecRef(module);

      // Get class name mappings from python.
      PyObject* py_id_to_class_name = PyObject_CallMethod(swig_factory_helper, "id_to_class_name", 0);
      if (!py_id_to_class_name)
        return 0;

      int pos = 0;
      PyObject* key = 0;
      PyObject* value = 0;
      while (PyDict_Next(py_id_to_class_name, &pos, &key, &value))
      {
        int object_id = PyInt_AsLong(key);

        // The SWIG type query expects pointer types.
        std::string class_name = "_p_";
        class_name += PyString_AsString(value);

        swig_type_info* info = SWIG_TypeQuery(class_name.c_str());

        _objectIDToSWIGInfo[object_id] = info;
      }

      Py_DecRef(py_id_to_class_name);
      Py_DecRef(swig_factory_helper);
    }

    return _objectIDToSWIGInfo[objectID];
  }
%}

%typemap(out) Base* Base::create {
  swig_type_info* info = objectIDToSWIGInfo($1->objectID());

  if (!info)
    SWIG_exception_fail(SWIG_RuntimeError, "Fatal error: objectIDToSWIGInfo returned null.");

  $result = SWIG_NewPointerObj(SWIG_as_voidptr($1), info, SWIG_POINTER_OWN);
};

C# Example

%pragma(csharp) imclasscode=%{
  public static class SWIGFactoryHelper
  {
    private static System.Collections.Generic.Dictionary<int, Type> _factoryTypes = null;

    private static System.Collections.Generic.Dictionary<int, Type> FactoryTypes
    {
      get
      {
        if (_factoryTypes== null)
        {
          _factoryTypes = new System.Collections.Generic.Dictionary<int, Type>();

          System.Reflection.Assembly assembly = System.Reflection.Assembly.GetExecutingAssembly();

          Type[] types = assembly.GetTypes();

          foreach (Type i in types)
          {
            if (i.IsSubclassOf(typeof(Base)))
            {
              System.Reflection.FieldInfo objectIDField = i.GetField("OBJECT_ID", System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Static);
              if (objectIDField == null)
                continue;

              int classID = (int)objectIDField.GetValue(null);
              _factoryTypes.Add(classID, i);
            }
          }
        }

        return _factoryTypes;
      }
    }

    static public Base ConstructFromSWIG(IntPtr swigCPtr)
    {
      // Extract the object ID from the class object that was created in C++.
      // Is there a way to do this that avoids the object construction?
      Base idInspectorTemp = new Base(swigCPtr, false);
      int newObjectID = idInspectorTemp.objectID();
      idInspectorTemp.Dispose();

      Type newClassType;
      if (!FactoryTypes.TryGetValue(newObjectID, out newClassType))
        throw new SystemException("ConstructFromSWIG could not find a class type for ID '" + newObjectID.ToString() + "'");

      Object[] args = {swigCPtr, true};

      return (Base)newClassType.InvokeMember(null, System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.CreateInstance, null, null, args);
    }
  }
%}

%typemap(csout, excode=SWIGEXCODE) Base* Base::create
{
  IntPtr cPtr = $imcall;

  $excode;

  return ctsdkPINVOKE.SWIGFactoryHelper.ConstructFromSWIG(cPtr);
}

Autotools Integration

Q: What is the best way to configure the Autotools to build C/C++ wrappers?

The following documentation describes configuration of an Autotools-controlled build environment for the construction of a Python-loadable shared library called foo.

First, all SWIG interface files should be declared as being part of the distribution--but not build targets--using the EXTRA_DIST variable, as follows:

EXTRA_DIST = foo.i

If your package is also distributing executable script files that use this library, those script files should be named in the bin_SCRIPTS variable:

bin_SCRIPTS = foo.py

Should your package also contain script files that are used by the executable script but are not executable themselves, name them with the pkgdata_DATA variable:

pkgdata_DATA = bar.py

Your shared library is named for libtool compilation using the lib_LTLIBRARIES variable. Its dependencies are defined like this:

lib_LTLIBRARIES = libFooPython.la
libFooPython_la_SOURCES = foo_wrap_python.cpp
foo_wrap_python.cpp: foo.i
    swig -python -c++ -o $@ $<

Note that a truly configurable build environment will not directly specify the swig executable in your Makefile.am. It is a safer and more generalized solution to check for the existance of the swig binary, verify its version, and set an automake variable in an m4 configuration file. In addition, build-specific parameters can be configured for the entire build in the same file. These variables can then be referenced in Makefile.am like this:

lib_LTLIBRARIES = libFooPython.la
libFooPython_la_SOURCES = foo_wrap_python.cpp
foo_wrap_python.cpp: foo.i
    $(SWIG) -python $(SWIG_ARGS) -o $@ $<

This Example's Python Specifics

For this particular example, two more steps are required before your shared library can be used. First, since Python requires that loadable shared libraries be of the format foomodule.so, you must add a softlink in your installation directory to the created shared library using this required name. An install hook will do this for you:

install-exec-hook:
    ln -fs ${prefix}/lib/libFooPython.so.0.0.0 ${prefix}/lib/foomodule.so

Instead of ln -s above, one can also use add AC_PROG_LN_S into one's configure.ac or configure.in and then use in Makefile.am:

install-exec-hook:
    -rm ${prefix}/lib/libFooPython.so.0.0.0
    $(LN_S) ${prefix}/lib/libFooPython.so.0.0.0 ${prefix}/lib/foomodule.so

Lastly, Python must know where it can find the shared library you've created as well as the non-executable Python scripts that your executable scripts use. This is done with the PYTHONPATH variable. Assuming you have named your Autotools package as foo, you would set your PYTHONPATH environmental variable as follows:

export PYTHONPATH=installdir/lib:installdir/share/foo

Using SWIG's configure.in script

Building extension modules for most languages involves a rather complex set of rules involving flags to linkers and compilers. The SWIG distribution works very hard to pick options that work on most common machines. Thus, if you're adverse to using libtool, the SWIG configure.in script itself might be a resource for configuring makefiles related to your project.

Multiple Languages

Q: How to generate multiple language files with one SWIG file

Use the language defines, e.g. SWIGPYTHON for python.

Example:

/* common code */

int foo_method(foo arg);

#ifdef SWIGPYTHON
/* Python specific code */
%typemap foo {
}
#endif

#ifdef SWIGPERL
/* Perl specific code */
%typemap foo {
}
#endif

Q: The interface file from one language overwrites the interface files from other languages

Use the option -o to specify a output directory.

Example:

swig -python -outdir py -o py/interface_wrap.c interface.i

swig -perl -outdir pl -o pl/interface_wrap.c interface.i

Types

Q: When wrapping types such as __int32, SWIG wants to create a pointer __int32 *. How do I prevent this?

By default SWIG turns all unknown datatypes into pointers in order to convert call-by-value into call-by-reference. Normally, this is used with classes and structures. For example,

double dot_product(Vector a, Vector b);

gets wrapped as:

double wrap_dot_product(Vector a, Vector *b) { return dot_product(a,*b); }

This transformation occurs for any datatype that isn't recognized as a primitive type (which is why __int32 is turning into a pointer). However, you can usually eliminate the problem by using a typedef declaration. For example:

typedef int __int32;

A common confusion among new users is that they have to write a typemap to handle new types. This is never necessary with anything related to the primitive datatypes---simply supply a typedef instead.

Q: How do I interact with functions that require double pointers such as Foo **?

Suppose you have a function such as the following:

void bar(Foo **f);

If this function is using the argument f to return a newly allocated object (i.e., a constructor), the easiest way to handle this may be to write a helper function like this:

%inline %{
Foo *my_bar() {
    Foo *f;
    bar(&f);
    return f;
%}

Then, just use my_bar() in your interface. If you want to keep the same name, use %rename.

%rename my_bar bar;
%inline %{
Foo *my_bar() {
...
}
%}

If the argument f is an array of pointers, you may want to write some helper functions to create, populate, and manage the arrays. See http://www.swig.org/Doc3.0/Library.html#Library_nn5 for some examples.

Q: How do I interact with functions that require double void pointers - void **?

Some libraries use an opaque (void) pointer to pass around internal information.

Here I present a complete example. A typedef is used for clarity, but the same idea works directly with void pointers. Eg

int Create_Opaque(void **OUTPUT)

opaque.h the library interface definition.

typedef void *opaque_t;

/* Return pointer to opaque data structure */
int Create_Opaque( const int value, opaque_t *OUTPUT );

/* Store value in opaque data.  If opaque pointer is NULL
(python:None), initialise and return one */
int Update_Opaque( const int value, opaque_t *INOUT);

/* Use the data in the opaque data structure. */
int Use_Opaque( const int value, opaque_t IN);

/* return a null pointer */
int Null_Opaque(opaque_t *OUTPUT);

opaque.i the SWIG definition file

%module opaque
%{
#include "opaque.h"
%}

%include "typemaps.i"

/* Used for functions that output a new opaque pointer */
%typemap(in,numinputs=0) opaque_t *OUTPUT (opaque_t retval)
{
 /* OUTPUT in */
    retval = NULL;
    $1 = &retval;
}

/* used for functions that take in an opaque pointer (or NULL)
and return a (possibly) different pointer */
%typemap(argout) opaque_t *OUTPUT, opaque_t *INOUT
{
 /* OUTPUT argout */
  %append_output(SWIG_NewPointerObj(SWIG_as_voidptr(retval$argnum), $1_descriptor, 0));
}

%typemap(in) opaque_t *INOUT (opaque_t retval)
{
   /* INOUT in */
   SWIG_ConvertPtr(obj1,SWIG_as_voidptrptr(&retval), 0, 0);
    $1 = &retval;
}

/* No need for special IN typemap, it works anyway */

%include "opaque.h"

opaque.c the library implementation In this toy example the functions print stuff about what they are up to. The opaque data is just a stored integer.

#include <stdio.h>
#include "opaque.h"

static int private_data;
typedef int* private_t;

int Create_Opaque( const int value, opaque_t *OUTPUT )
{
  private_data = value;
  *OUTPUT = &private_data;
  printf("Private data address %p\n", &private_data);
  printf("Create value=%d, OUTPUT=%p, *OUTPUT=%p\n", value, OUTPUT, *OUTPUT);

  return 1;
}

int Update_Opaque( const int value, opaque_t *INOUT)
{
  if (*INOUT == 0) {
    printf("Update create new handle\n");
    *INOUT = &private_data;
  }

  opaque_t p = *INOUT;

  *(int*)p = value;

  printf("Update value=%d, INOUT=%p, *INOUT=%p\n", value, INOUT,*INOUT);

  return 3;
}

int Null_Opaque(opaque_t *OUTPUT)
{
  *OUTPUT = NULL;
  return 0;
}

int Use_Opaque( const int value, opaque_t IN)
{
  /* convert opaque to private pointer */
  private_t p = IN;
  if (p == NULL) {
    printf("Null handle\n");
    return 0;
  }

  printf("Use private_data=%d, value=%d, IN=%p\n", *p,value,IN);

  return *p * 10 + value;
}

setup.py

Use for instance "setup.py build", "setup.py install --home ~" to build and install this locally.

#!/usr/bin/env python
import distutils
from distutils.core import setup, Extension

setup(name = "OPAQUE",
    version = "1.0",
    ext_modules = [
        Extension(
            "_opaque", sources = ["opaque.i", "opaque.c"],
            swig_opts=['-modern'],
        )
    ],
)

Finally test_opaque.py. Demonstrate the wrapper working.

#!/usr/bin/env python
from opaque import *

e,h = Create_Opaque(1)
print e,h

e = Use_Opaque(9, h)
print 'Expect 19',e

e,h = Update_Opaque(2, h)
print e,h

e = Use_Opaque(7, h)
print 'Expect 27',e

e,h = Update_Opaque(4, None)
print e,h

e = Use_Opaque(5, h)
print 'Expect 45',e

e,h = Null_Opaque()
e = Use_Opaque(7, h)
print 'Expect 0, warning about null',e

e,h = Update_Opaque(6, None)
print e,h

e = Use_Opaque(3, h)
print 'Expect 63',e

Typemaps

Q: Is there some kind of paper or document that describes what typemaps are all about?

Probably the most concise description of SWIG typemaps can be found in the paper "Automated scientific software scripting with SWIG" that was published in Future Generation Computer Systems, Volume 19, Issue 5 (July, 2003). This article can be purchased from http://www.sciencedirect.com (search for "SWIG" and you'll find it). A pre-publication draft is available from the author at http://www.dabeaz.com/papers/fgcs/beazley_fgcs.pdf

Q: I wrote a typemap, but it doesn't seem to get applied. What's going on?

SWIG applies typemaps in the order in which they are defined in the interface file. This means that typemaps only take effect for declarations that follow the typemap definition. A common problem is defining something like this:

void foo(Sometype *f);
...
%typemap(in) Sometype * {
...
}

In this case, the typemap has no effect on the wrapping of foo. A more subtle variation of the above problem is caused by the following:

%include "somefile.h"
%typemap(in) Sometype * { ... }

A subtle twist related to the application of typemaps has to do with the behavior of %extend. The %extend directive is used to attach new declarations to a class or structure definition. When this is done, these declarations are added to the class as if they appeared as part of the class declaration itself. This can effect the application of a typemap as shown in this example:

class Someclass {
...
}

%typemap(in) Sometype * { ... }
%extend Someclass {
  void bar(Sometype *) { ... }
  ...
}

In this case, the typemap has no effect on bar whatsoever. This is because this code is really the same as this:

class Someclass {
...
%extend {
  void bar(Sometype *) { ... }
  ...
}
}

%typemap(in) Sometype * { ... }

Notice how the typemap appears after the added methods. This problem seems to arise more frequently when including header files. For example:

%include "somefile.h"

%typemap(in) Sometype * { ... }
%extend Someclass {
  void bar(Sometype *) { ... }
  ...
}

To fix this, move the typemap before the %include statement.

Exceptions

Q: Where is basic information about handling and generating exceptions documented?

See: http://www.swig.org/Doc3.0/SWIGPlus.html#SWIGPlus_exception_specifications

Q: How do I raise an exception based on the return value of a function and return a parameter (and ONLY the parameter)?

Let's use as an example a C declaration like this, and use Python as our target language:

int getVal(int* returnedValue);

The returned int is actually an error code (let's say that 0 is "ok" and anything else is bad), and the result of the function is returned in the "returnedValue". Let's break it down into 3 steps; raise the exception, remove the return value, and add the parameter in.

To raise the exception use code like this:

%exception {
  $action
  if (result!=0) {
    PyErr_SetObject(PyExc_Exception,PyInt_FromLong(result));
    goto fail;
  }
 }

To understand this code better, take a look at the generated code to see it in context since it uses variables and jump targets defined outside of itself.

To remove the return value, use an "out" typemap to override the return code handling to nothing, like this:

%typemap(out) int {};

To add the parameter in, use the SWIG predefined OUTPUT typemaps, by just redeclaring the function:

%include "typemaps.i"
int getVal(int* OUTPUT);

Finally remove the overrides:

%exception;
%typemap(out) int;