-
Notifications
You must be signed in to change notification settings - Fork 1.3k
- Installation
- Common Usage Problems
- Shared Libraries
- C++ Issues
- Autotools Integration
- Multiple Languages
- Types
- Typemaps
- Exceptions
In order to generate code, SWIG relies on a library of files known as the SWIG Library. This error message is being caused because 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 variable. However, it's probably better to just recompile SWIG with the right setting.
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).
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.
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;
%}
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.
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
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.
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:
- 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.
- 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.
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
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.
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
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
The Windows and MinGW version of Python requires extension dlls to have the .pyd suffix. The DLL should also have an underscore prefix, so the output name would be _example.pyd when using %module example.
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).
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
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
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
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.
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 );You need to compile with '-fPIC'.
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);
}
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.
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
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
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.
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.
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',eProbably 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
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.
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;