Home | Download/Install | Documentation | Packages | Screenshots | News | Forum/Mailing-lists | Contact | GForge

How to integrate C++ code in Python

Introduction

Existing libraries can be interfaced with the Python language without rewriting all the code. There are different tools to achieve this task for different langage. However, in this document, we will only deals with C++ code wrapping via the Boost.Python library.

Layout

In order to have homogeneous packages, we advice to respect a particular package layout.

 src/
  cpp/      : contains cpp library source files
  include/  : contains cpp library header
  wrapper/  : contains wrapper code
  my_package/ : contains python module

For more information, read the How to create an open alea package document.

Wrapping

We recommend to use Boost.Python to create C++ to Python wrappers.

Boost.Python wrappers are C++ code to expose C++ classes and functions in python.

Please read the Boost.Python tutorial to learn how to write Boost.Python wrappers.

How to install Boost.Python ?

On Linux

Use the standard installation procedure of your distribution (apt-get, urpmi, yum…). Most linux distributions include a boost binary package.

On Windows

You can download the sources on the boost web site and compile them.

However, an installer for MinGw, Visual Studio 7.1 and 8. is distributed on the OpenAlea website : Boost.Python for windows.

File organisation

Boost.Python uses extensively C++ template. They can lead to compilation problems. Moreover, templates use a huge amount of memory. To avoid this kind of problems, we advice to separate wrapper code in different files.

A wrapped Python module is usually declared with the macro BOOST_PYTHON_MODULE. ex:

// Define python module sceneobject
// Note : Python module and generated dll/so file must have the SAME NAME
BOOST_PYTHON_MODULE(sceneobject)
{
  //scene_object class wrapper
  class_<scene_objectWrap, boost::noncopyable>("sceneobject", "Abstract base class for scene object" )
    .def("display", &scene_object::display, "Display the object name")
    .def("get_name", pure_virtual(&scene_object::get_name), "Return the object name");
 
  //leaf class wrapper
  class_<leaf, bases<scene_object> >("leaf", "Leaf object" );
}

Instead of declaring all the class inside the same block, we declare each class wrappers class_< > in a separate function placed in an external file. This allow to have separate compilation process for each file. The previous example is divided as follow : sceneobject_wrap.cpp, class_scene_object.h, class_scene_object.cpp, class_leaf.h and class_leaf.cpp:

// sceneobject_wrap.cpp
 
#include "class_scene_object.h"
#include "class_leaf.h"
 
// Define python module sceneobject
BOOST_PYTHON_MODULE(sceneobject)
{
   class_scene_object();
   class_leaf();
}
// class_scene_object.h
#ifndef __CLASS_SCENE_OBJECT__
#define __CLASS_SCENE_OBJECT__
 
void class_scene_object();
 
#endif
// class_scene_object.cpp
 
void class_scene_object()
{
    class_<scene_objectWrap, boost::noncopyable>("sceneobject", "Abstract base class for scene object" )
      .def("display", &scene_object::display, "Display the object name")
      .def("get_name", pure_virtual(&scene_object::get_name), "Return the object name");
}
// class_leaf.h
#ifndef __CLASS_LEAF__
#define __CLASS_LEAF__
 
void class_leaf();
 
#endif
// class_leaf.cpp
 
void class_leaf()
{
  class_<leaf, bases<scene_object> >("leaf", "Leaf object" );
}

Compilation

Boost.Python tutorial recommend to use BJam tool for the compilation.

Instead, we recommend to use scons, for a better integration in Python. Scons is a portable tool to compile modules on Linux and Windows plateforms, and manage dependencies between files and libraries.

We developed the tool SConsX which extends scons base functionnalities in order to facilitate build process with specific tools like Boost.Python.

#The SConsX code to create a scons environment which support Boost.Python compilation
from openalea.sconsx import config, environ
 
ALEAConfig= config.ALEAConfig
ALEAEnvironment= config.ALEAEnvironment
 
 
options = Options( 'options.py', ARGUMENTS )
 
wrapper_conf = ALEAConfig(name,['boost_python', 'alea'])
 
wrapper_env = ALEAEnvironment( wrapper_conf, 'options.py', ARGUMENTS )

Install the wrapped packages

Once C++ code has been wrapped to Python, wrapped package must be considered as a Python package which link with dynamic C++ libraries. The installation procedure is then supported by the Python distutils module.

We have also developed a extension Deploy in order to install external libraries on the system within Python framework.

Memory management

Interfacing C++ code with Python can be a little confusing concerning the memory management, and particulary the dynamic object lifetime. Indeed, object ownership can be difficult to implement correctly because an object can be created either by C++ code or by Python code.

To tackle this problem, we recommend to use smart pointers.

Boost Smart pointer definition :

Smart pointers are objects which store pointers to dynamically allocated (heap) objects. They behave much like built-in C++ pointers except that they automatically delete the object pointed to at the appropriate time. Smart pointers are particularly useful in the face of exceptions as they ensure proper destruction of dynamically allocated objects. They can also be used to keep track of dynamically allocated objects shared by multiple owners.

You can find an implementation and the usage of smart pointers (formely RefCountObject and RefCountPtr in the starter package.

 
documentation/package/how_to_integrate_cpp_code_in_python.txt · Last modified: 2009/01/14 16:29 by user   Back to top
INRIA   INRA     CIRAD     AGROPOLIS
INRIA GForge RSS feed Valid XHTML 1.0 Valid CSS Driven by DokuWiki