Originally published: May 27, 2005
Table of Contents
- Abstract
- Building Manually on the Command Line
- Adding SWIG to Autoconf
- Adding SWIG to Automake
- An Example Project
Abstract
In the article Python Extensions In C++ Using SWIG, I describe how to extend Python with C++ code. That article also contains instructions for building SWIG extension DLLs on Windows. This article contains instructions for using GNU Automake and Autoconf to build SWIG extensions as shared objects on GNU/Linux.
Building Manually on the Command Line
Without adding the SWIG steps to your makefiles, you can build a SWIG extension using these commands:
swig -c++ -python -o your_extension_wrap.cpp your_extension.i
gcc -fPIC -c your_extension_wrap.cpp -o your_extension_wrap.o -I/usr/include/python
g++ -shared your_extension_wrap.o <your-other-object-files> -o _your_extension.so
Note: It’s important to prefix the name of the shared object with an underscore, otherwise Python won’t be able to find it when import your_extension
is executed.
I also tried with ld
instead of g++
, but that resulted in the following error in Python:
>>> import _your_extension
Traceback (most recent call last):
File "<stdin>", line 1, in ?
ImportError: ./_your_extension.so: undefined symbol: __dso_handle
This occurs as soon as iostream
is included in the C++ source. Using g++
solves the problem.
Adding SWIG to Autoconf
You need additional Autoconf macros to enable SWIG support. I downloaded the file ac_pkg_swig.m4
from the Autoconf Macro Archive and placed it in the m4
subdirectory of my project tree:
project/
m4/
ac_pkg_swig.m4
pyext/
Makefile.am
swig.i
src/
Makefile.am
Makefile.am
configure.ac
When you place ac_pkg_swig.m4
in a subdirectory, you need to add this line to your project/Makefile.am
:
ACLOCAL_AMFLAGS = -I m4
You must also specify the option -I m4
whenever you invoke autoreconf
.
Now, add these lines to your configure.ac
:
AC_DISABLE_STATIC
AC_PROG_LIBTOOL
AM_PATH_PYTHON(2.3)
AC_PROG_SWIG(1.3.21)
SWIG_ENABLE_CXX
SWIG_PYTHON
Adding SWIG to Automake
In your Makefile.am
, you need to do the following:
- Run swig on your interface definition (.i) files
- Build a shared library from your C++ code and the generated SWIG wrapper
- Instruct <make install> to place the resulting files in the Python folder
To make this happen, add these lines to the file pyext/Makefile.am
:
Note: I assume that your .i files are stored in a subdirectory (pyext/
) that is a sibling of the directory that contains your C++ sources (src/
). If this is not the case, you will have to change the paths accordingly.
BUILT_SOURCES = $(srcdir)/swig_wrap.cpp
SWIG_SOURCES = swig.i <more .i files...>
pkgpython_PYTHON = your_extension.py
pkgpyexec_LTLIBRARIES = _your_extension.la
_your_extension_la_SOURCES = $(srcdir)/swig_wrap.cpp $(SWIG_SOURCES)
_your_extension_la_CPPFLAGS = $(SWIG_PYTHON_CPPFLAGS) -I$(top_srcdir)/src
_your_extension_la_LDFLAGS = -module
_your_extension_la_LIBADD = ../src/libproject.la
$(srcdir)/swig_wrap.cpp : $(SWIG_SOURCES)
$(SWIG) $(SWIG_PYTHON_OPT) -I$(top_srcdir)/src -o $@ $<
This code explained:
pkgpython
expands to something like/usr/local/lib/python2.4/site-packages/project
. This is where amake install
will install the SWIG-generated .py wrapper.pkgpyexec
is usually the same directory, but, according to the Autoconf manual, that’s where shared libraries should be installed.- Adding the option
-module
to theLDFLAGS
is important. Without it, Libtool requires all libraries to have a “lib” prefix. However, SWIG requires an underscore prefix. - The line
_your_extension_la_LIBADD = ../src/libproject.la
links the extension library to another shared library that is built from the C++ sources insrc/Makefile.am
. This is often useful when the C++ part of your project is not only used in the Python extension. A single shared library,libproject.la
in the example, can be used to link to your Python extension as well as to your C++ executables.If you don’t want to do this, you can just list your C++ sources in the line
_your_extension_la_SOURCES = ...
.
An Example Project
These are the relevant files from the mfGraph project:
mfgraph/
m4/
ac_pkg_swig.m4
pymfg/
Makefile.am
mfg_graph.i
...
swig.i
src/
Makefile.am
mfg_graph.cpp
mfg_graph.h
...
Makefile.am
autogen.sh
configure.ac
mfgraph/autogen.sh:
#!/bin/sh
autoreconf --force --install -I config -I m4
mfgraph/configure.ac:
dnl Process this file with autoconf to produce a configure script.
AC_INIT(mfGraph, 0.3, me@mail.com)
AC_CONFIG_AUX_DIR(config)
AC_CONFIG_SRCDIR(src/mfg_graph.cpp)
AM_INIT_AUTOMAKE
AC_DISABLE_STATIC
AC_PROG_LIBTOOL
AM_PATH_PYTHON(2.3)
AC_PROG_SWIG(1.3.21)
SWIG_ENABLE_CXX
SWIG_PYTHON
AC_OUTPUT(Makefile src/Makefile pymfg/Makefile)
mfgraph/Makefile.am:
ACLOCAL_AMFLAGS = -I m4
SUBDIRS = src pymfg
EXTRA_DIST = autogen.sh
mfgraph/pymfg/Makefile.am:
BUILT_SOURCES = $(srcdir)/swig_wrap.cpp
SWIG_SOURCES = swig.i mfg_graph.i <...>
pkgpython_PYTHON = pymfg.py
pkgpyexec_LTLIBRARIES = _pymfg.la
_pymfg_la_SOURCES = $(srcdir)/swig_wrap.cpp $(SWIG_SOURCES)
_pymfg_la_CPPFLAGS = $(SWIG_PYTHON_CPPFLAGS) -I$(top_srcdir)/src
_pymfg_la_LDFLAGS = -module
_pymfg_la_LIBADD = ../src/libmfgraph.la
$(srcdir)/swig_wrap.cpp : $(SWIG_SOURCES)
$(SWIG) $(SWIG_PYTHON_OPT) -I$(top_srcdir)/src -o $@ $<
mfgraph/src/Makefile.am:
lib_LTLIBRARIES = libmfgraph.la
libmfgraph_la_SOURCES = mfg_graph.cpp <...>
pkginclude_HEADERS = mfg_graph.h <...>