Skip to content

Regenerating The Bindings

James Grogan edited this page Nov 1, 2016 · 2 revisions

PyChaste is a mix of manual and automatically generated bindings. This page gives some background on Python wrapping and details how to wrap your own functionality or regenerate existing bindings.

Notes on Python Wrapping (Linux Only)

Background:

Boost Python Boost Python and SWIG are the two most common tools from generating Python wrappers from C++. I have used Boost Python as it plays nicely with templates, namespaces, Boost shared pointers, Boost Ublas and Boost Units, all of which are used heavily in Chaste or user projects of interest. A downside of Boost Python is that, unlike SWIG, it is a 'manual' rather than automatic generator: on its own you need to generate wrapper code for every class and method.

There are some external automatic generators for Boost Python. I have gone with PyPlusPlus as it has been around for a while and has been used in several large projects. The original package is no longer maintained, so it is necessary to use a [fork] (https://bitbucket.org/ompl/ompl/src/tip/doc/markdown/installPyPlusPlus.md?fileviewer=file-view-default).

Prerequisites:

There are five requirements for wrapping beyond the normal Chaste dependencies (two for manual wrapping, extra three for automatic). The first are the Python development headers and shared library. If using Linux you probably already have these on your system. To check, look in /usr/include/<python version> or try locate pyconfig.h. If not, doing sudo apt-get install python-dev will grab them. The shared library is of the form libpythonx.x.so. If you are using Python virtual environment (you will know if you are) you may need to explicitly tell it to build a shared library when building Python. The version of the Python library and headers (e.g. 2.7) needs to be the same as that used by whatever Python interpreter you are trying to run the final wrapped code in. In theory the mentioned build tools support Python 3, but I have not tried to use it.

The second requirement is Boost Python. Again, you may already have it (locate libboost-python). If not, and you are following the Chaste Install guide (InstallGuides/InstallGuide), you just need the following small change:

./bootstrap.sh --prefix=$CHASTE_LIBS --with-libraries=system,filesystem,serialization

with:

./bootstrap.sh --prefix=$CHASTE_LIBS --with-libraries=system,filesystem,serialization,python

The remaining requirements are for automatic wrapping. They are [CastXML] (https://github.com/CastXML/CastXML CastXML) which has a linux binary, pygccxml and pyplusplus. The latter two can be installed with pip.

pip install pygccxml==1.7.2 https://bitbucket.org/ompl/pyplusplus/get/1.6.tar.gz

There is a version of CastXML that comes with Ubuntu 14 and 16. This should not be used as it cannot parse the Chaste source and will crash with a segfault.

Integrating with CMake:

Using the Chaste CMake build system it is possible to have fine-grained control over how user-projects are built, including adding extra dependencies and targets. The PyChaste user project has examples of using CMake to generate both manual and automatic Python wrappers. The CMakeLists.txt file for the PyChaste project shows that the Python wrapper generation code is included in a separate file WrapPython.cmake. This latter file has the following steps:

  1. Try to automatically find the Boost Python and Python libraries.
  2. Try to find CASTXML (only needed for automatic wrapping).
  3. Add includes from Chaste and any non-wrapper code used in the PyChaste project.
  4. Collect any files (modules) for automatic wrapping in the list PYCHASTE_PYTHON_AUTO_MODULES, and corresponding locations where the wrapped module should go in the Python package in PYCHASTE_PYTHON_MODULE_LOCATIONS.
  5. Collect all files (modules) for manual and automatic wrapping in the list PYCHASTE_PYTHON_MODULES.
  6. Copy any pure Python files from the source to build location
  7. Loop through all modules for automatic wrapping and add targets which will use a Python script generate_bindings.py to automatically generate Boost Python wrapper code. All individual targets are added to project_PyChaste_Python_Bindings so the code will be generated when the user does make project_PyChaste_Python_Bindings.
  8. Loop through all modules (which will now have either manually written or automatic wrapper code) and make a shared library target for module_name.so. This shared library is what is actually imported into Python by doing import module_name.
  9. Add all shared library targets to the single target project_PyChaste_Python so the user can just run make project_PyChaste_Python to build all the wrappers.

Examples of manually generated wrappers are in dynamic/hello_manual.cpp and dynamic/preload.cpp. The automatic generator script dynamic/generate_bindings.py goes through the following steps:

  1. Create a !PyPlusPlus wrapper build builder and pass it the configuration for CASTXML, locations of the module header files (dynamic/wrapper_headers/<module_name>_headers.hpp) and locations of any needed include files (e.g. boost, vtk, petsc).
  2. Use module specific scripts dynamic/wrapper_generators/generate_<module_name>.py to say which classes should be wrapped, give templated classes Python-ish names, exclude methods with unsupported return types etc. etc.
  3. Build the wrapper code, ending up in dynamic/module_name.cpp.

Clone this wiki locally