cppython brings C++ classes to Python world using cython
- Automatically generate C++ wrapper classes and cython files
- Support pure virtual method
- C++ virtual method could be override in Python sub class
In order to export a non-pod C++ class Foo to python:
- Export forward name
Fooin*.pxdfile - Create a C++ proxy class inheriting from
Foo. It also links with a python object - Override virtual methods in proxy class to make them overrideable in python
- Export proxy class and its methods in *.pxd file
- Wrap Foo proxy class in *.pyx file as a normal Cython class
- Implement proxy call API for each of virtual methods
The steps are tedious and boring. cppython helps you automation the whole process
Given a header file header_file.hpp which contains all symbols need to export to python module foo,
cppython will generate following files:
head_file.pxd: export C++ symbol to cythonfoo.pyx: the main file for foo module, it will generate foo.h and foo.c through cython to build foo modulefoo.pxi: the public API used for proxy call, will be include byfoo.pyxfoo_cppython.hpp: the proxy classes' definationfoo_cppython.cpp: the proxy classes' implementationfoo_cppython.pxd: export C++ proxy class to cythonsetup.py: setup file for build python extension
- write a header file which include all the symbols you would like to export, including
- classes
- POD structs
- free functions
- const int
- enums
- marco constants
- run command
python cppython.py -t header-file-for-export.hpp -s <C++ source files> -m path/to/module_name - after that you could find generated
module_namefiles underpath/to. you could review and modify manually - run command
cd path/to && python setup.pyto actually build the python extension module using cython - For detail command line argument list, run
python cppython.py -h
- wrap static method as static class method in python, right now it is exported as python instance method
- better support for C++ reference
- better support for C array (using view?)
- forward declaration support
- boost.python support
- support customize C++ entities name
- add include path support
- support more than one constructor,right now it only export the first constructor
- ubuntu 64 and Mac are supported out of the box
mock,enum34andcythonneed to be installed first- run
./test.sh
if C extension spawn threads, you must call PyEval_InitThreads at least once in the main thread.
What it does is init GIL and aquire it. So that python itself could be thread safe running any python code.
In child thread any time you want to manipulate Python objects, make sure to call pair PyGILState_Ensure(), PyGILState_Release() to get GIL and release it. There API is safe to call recursively.
If you would like to call some non-Python/c blocking code (like Join()), you could use PyEval_SaveThread() PyEval_RestoreThread() pair to release GIL and re get it
In general situations, the C library needs to call PyEval_InitThreads() to gain GIL before spawning any thread that invokes python callbacks. And the callbacks need to be surrounded with PyGILState_Ensure() and PyGILState_Release() to ensure safe execution.
However, if the C library is running within the context of, say, a python C extension, then there are special cases where it is safe to omit GIL manipulation at all if the sub thread execuation is enclosed by the main thread.
export C/C++ all marked as nogil to tell cython that they are safe to call with nogil
There are 3 ways to mark nogil, they are identical
cdef extern from "export.hpp" nogil:nogil for all entity insideexport.hppcdef cppclass SomeClass(BaseClass) nogil:nogil for all class membersvoid some_member_function(const char * arg) nogil except +nogil for a single member
When calling, it could be invoke without gil explicitly:
- with nogil:
- self._this.register_front(address)
Notice that without with nogil:, the function still called with GIL wheather or not it has been marked as nogil
if you call non nogil quanlifier member inside with nogil: scope, cython will report error message
Calling gil-requiring function not allowed without gil
When called with nogil:, the generated code will have PyEval_SaveThread() PyEval_RestoreThread() pair enclosed the call.