swig_cpp_python /

Filename Size Date modified Message
mod
src
swig
39 B
410 B
5.4 KB
15.9 KB
982 B

Python and C++ via SWIG

This project gives some example of how python and C++ can be interfaced using SWIG. The idea here is to allow one to write simple classes and functions in C++, and then to have SWIG automatically provide wrappers based on simple naming conventions. NumPy arrays are wrapped with armadillo_ vectors and matrices (sharing the memory) so that they can be modified and used safely.

Usage

# Develop your C++ code. # If needed, create a wrapper C++ header for this code using the argument naming

conventions described below to specify their interfaces. This is the code in src/*.hpp here.
# Create a SWIG wrapper that defines the module you want to contain these
functions. This wrapper will typically name the module, include some type conversions and then include the appropriate header files. This is the code in swig/*.i here.
# Edit the Makefile so that it properly generates the wrappers. They go to
_generated/*_wrap.cpp and _generated/py/*.py here.
# Edit setup.py to tell python how to build these modules. I.e. add the
appropriate wrapper files to the sources for the extension.

# Include any python support code in the module (mod here). # Make and build the code with:

 make
 python setup.py build

The results will go to ``build/lib*/``.  You can ``cd`` to this directory to
try importing and running your modules, or you can ``python setup.py install``
to install the compiled modules on your system.

Note: you may need to add the directory with the armadillo_ shared libraries
to your ``LD_LIBRARY_PATH`` in order for python to find them.  This is
`not ideal`_, but I do not know of a better solution.  (One option is to link
this into a common place, and wrap the python executable in a local
environment that sets ``LD_LIBRARY_PATH``.)

The Build Process

The build process consists of two steps:

# Generating the *_wrap.cpp files using swig # Compiling these and installing the python modules.

In principle, these could both be done with setup.py, but this requires some hacking (see the open tickets listed at the end). Thus, the recommended way is to use a tool like make to perform the first step, and then let setup.py do the final building, and we take this approach here. The Makefile here is kept simple to demonstrate usage: it does not properly track dependencies etc.

Modules

The raw files here consist of:

src/*.hpp:
C++ source files defining the classes and functions.
swig/*.i:
SWIG interface file defining the modules. Ideally these will just define the typemaps required so that the interface can be deduced automatically, but this is a little incomplete right now.
swig/numpy.i, swig/pyfragments.swg:
SWIG interface files defining NumPy typemaps and associated fragments. These come from the numpy doc directory. (They hope it will be eventually included with SWIG.)
swig/arma.i:
SWIG interface that defines typemaps for armadillo_ matrices and vectors. By providing types like mat_OUT, we can specify input and output arguments directly in the source file, eschewing the need for detailed specifications in the module *.i file.
mod:
Python package with pure python sources that will form the base package. This should also have mod/__init__.py defined which might want to from swig import *.

The Makefile is responsible for calling swig and generating:

_generated/*_wrap.cpp: _generated/py/*.py: _generated/py/__init__.py:

The python setup.py build_ext process will then compile these files:

_generated/py/_*.so:
Compiled extension module.

Finally, the python setup.py build process (which will call build_ext first if needed) will install everything into the build directory under something like:

build/lib.macosx-10.5-i386-2.6/mod
build/lib.macosx-10.5-i386-2.6/mod/__init__.py
build/lib.macosx-10.5-i386-2.6/mod/swig/__init__.py
build/lib.macosx-10.5-i386-2.6/mod/swig/*.py
build/lib.macosx-10.5-i386-2.6/mod/swig/_*.so

In order to get everything in there properly I needed to do the following in setup.py:

  • Name the extension mod.swig._*. This makes sure that it gets put in the correct place. Note the convention for included an underscore before the module name.
  • Include packages = ["mod", "mod.swig"]: This includes both the pure python stuff in mod as well as the generated stuff.
  • Include package_dir = {"mod.swig": "_generated/py"]: This tells distutils that the generated package _generated/py should be remapped to mod.swig. Note that this requires _generated/py to be a package, which is why make had to generate the _generated/py/__init__.py files.

Notes

The SWIG support built into distutils is not ideal as pointed out by these tickets (open as of 23 May 2012):

Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for ProjectModifiedEvent.java.
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.