-
Notifications
You must be signed in to change notification settings - Fork 2
Regenerating The Bindings
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.
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).
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,serializationwith:
./bootstrap.sh --prefix=$CHASTE_LIBS --with-libraries=system,filesystem,serialization,pythonThe 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.gzThere 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.
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:
- Try to automatically find the Boost Python and Python libraries.
- Try to find CASTXML (only needed for automatic wrapping).
- Add includes from Chaste and any non-wrapper code used in the PyChaste project.
- 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 inPYCHASTE_PYTHON_MODULE_LOCATIONS. - Collect all files (modules) for manual and automatic wrapping in the list
PYCHASTE_PYTHON_MODULES. - Copy any pure Python files from the source to build location
- Loop through all modules for automatic wrapping and add targets which will use a Python script
generate_bindings.pyto automatically generate Boost Python wrapper code. All individual targets are added toproject_PyChaste_Python_Bindingsso the code will be generated when the user doesmake project_PyChaste_Python_Bindings. - 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 doingimport module_name. - Add all shared library targets to the single target
project_PyChaste_Pythonso the user can just runmake project_PyChaste_Pythonto 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:
- Create a !PyPlusPlus wrapper build
builderand 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). - Use module specific scripts
dynamic/wrapper_generators/generate_<module_name>.pyto say which classes should be wrapped, give templated classes Python-ish names, exclude methods with unsupported return types etc. etc. - Build the wrapper code, ending up in
dynamic/module_name.cpp.