Fork me on GitHub

Python and Co.

written on March 15, 2009

Last night, I started playing a little bit with embedding python + exposing classes via Boost::Python, because I wanna integrate this kind of functionalities in my 3D engine.

Since my system is fully modular, and each sub-system lives in its own shared object ( or dynamic linking library under win32 ), it turned out quite easy to make those python modules as well.

(I use Gists @ GistHub to post the source code instead of having it in the post itself, since it's easier to manage over time)

Here is some boilerplate code for a sample sub-subsystem header and implementation:

It is clearly visibile that it is a singleton class, hence the getInstance static method. I've also chosen to use the "py" prefix for the actual module name.

Now this can be compiled to a nice shared object or dynamic linking library and used right away.

g++ LeraSystem.cpp -shared -o pyLeraSystem.so -I/usr/include/python2.6 -lboost_python

I provide compile commands for Linux + GCC only, since it is my primary development platform, but this is very similar under Windows, there you one would get two files like pyLeraSystem.dll + pyLeraSystem.lib .

Again some boilerplate code and the expected output produced by it here ( cmd -- python pyLeraTest.py ):

Produced Output:

hello world
Instance check ...
<pyLeraSystem.leraSystem object at 0xb7cb7534>
<pyLeraSystem.leraSystem object at 0xb7cb7534>
<pyLeraSystem.leraSystem object at 0xb7cb7534>
hello world

Yayy! With this the singleton thingy was working, but wasn't the end of the journey :) Why? The answer is quite simple, I had to embed the python interpreter in order to take full advantage of this.

I already had my sub-system as an shared object (even before exposing anything to python), so I just had to link it to interpreter stub to make the full magic happen between C++ & Python working with truly the same instance of a sub-system.

A hack needs to be done here by doing an symbolic link from pyLeraSystem.so to libLeraSystem.so which can be achieved with the following command (assuming that the files are in the current working directory):

ln -s pyLeraSystem.so libLeraSystem.so

( this is not necessary under Windows, because there the .lib file is used to link against an dynamic linking library )

... to compile the embedded python interpreter ...

g++ LeraPythonEmbed.cpp -I/usr/include/python2.6 -L. -lpython2.6 -lm -lLeraSystem -o leraTestEmbed

To make it run one more hack is necessary, and that is adjusting the LD_LIBRARY_PATH to include the current working directory with a command like:

export LD_LIBRARY_PATH=.:$LD_LIBRARY_PATH

( this is again not necessary under Windows )

Also the python script needs to be adjusted a little:

Now running ./leraTestEmbed produces the following output:

this message was set from C++ and printed by Python
this message was set from Python and printed by C++

With this I reached my final goal, python and c++ fully interacting, using the same singleton sub-system class at runtime.

The approach of using modules instead of exposing classes, etc. directly from the embed interpreter adds a great deal of flexibility, and makes exposing existing plugins to python using Boost::Python piece of cake.

In the real life scenario ( my 3d engine and framework ) the actual sub-subsystems are not linked against the stub, they are dynamically loaded, and instantiated once in their full lifetime, but this is pretty much the same story.

Uffff, 548 words at the moment of typing this ... duhhh, I really need to get a life :))