PyCXX -- Python C++ Extensions Support

Installation using distutils

Windows Installation and Demo

  1. Fetch http://prdownloads.sourceforge.net/cxx/pycxx_5_3_1.tar.gz
  2. Expand the archive into a directory of your choosing C:\ for example. Note: WinZip can expand .tar.gz files.
  3. Install the PyCXX files:
    1. C:> cd \pycxx_5_3_1
    2. C:\pycxx_5_3_1> python setup.py install
  4. Install the PyCXX Demo:
    1. C:> cd \PYCXX_5_3_1\Demo
    2. C:\PYCXX_5_3_1\Demo> python setup.py install
  5. Run the demo:
    1. C:> python
    2. >>> import CXX.example
    3. >>> CXX.example.test()
    4. >>> r = CXX.example.range( 11, 100, 13 )
    5. >>> for i in r: print i
    6. ...

Unix Installation and Demo

Note: distutils is not available for Python 1.5.2

  1. Fetch http://prdownloads.sourceforge.net/cxx/PyCXX-V5.3.0.tar.gz
  2. Login as root. root access is typically needed on Unix systems to install the PyCXX files into the Python directories.
  3. Expand the archive into a directory of your choosing ~\ for example.
  4. Install the PyCXX files:
    1. # cd ~\PYCXX_5_3_1
    2. # python setup.py install
  5. Install the PyCXX Demo:
    1. # cd ~\PYCXX_5_3_1\Demo
    2. # python setup.py install
  6. Run the demo:
    1. ~ python
    2. >>> import CXX.example
    3. >>> CXX.example.test()
    4. >>> r = CXX.example.range( 11, 100, 13 )
    5. >>> for i in r: print i
    6. ...

Installation using Project and Makefile

If you cannot or do not wish to use the distutils methods to work with PyCXX a set of Makefiles and Project files are provided.

Windows Installation and Demo

  1. Fetch http://prdownloads.sourceforge.net/cxx/pycxx_5_3_1.tar.gz
  2. Expand the archive into a directory of your choosing C:\ for example. WinZip can expand .tar.gz files.
  3. Build the example. Using Microsoft Visual C++ 6.0 load the workspace corresponsing to the version of Python you wish the work with.
  4. Run the example. (I'll assume you are testing Python 2.3)

Unix Installation and Demo

  1. Fetch http://prdownloads.sourceforge.net/cxx/PyCXX-V5.3.0.tar.gz
  2. Expand the archive into a directory of your choosing ~/ for example.
  3. Select to makefile for your system and python version.
  4. Build the example. Use GNU make
    $ make -f example-makefile example.so
  5. Run the example.
    $ make -f example-makefile test

Note: The Unix version of python 1.5.2 may need to be rebuilt so that C++ is support. If you get reports of undefined symbols like cout or cerr then its likely that python is not compiled and linked to support C and C++.

To create a makefile for another vendors Unix follow these steps:

  1. copy one of the example make files above.
  2. edit the variables to match your Python installation and C++ compile needs
  3. Proceed to build and test as above.

Note: most of the makefile rules to build PyCXX and its example are contained in example_common.mak.

Revision History

Version 5.3.1 (19-Jan-2005)

Support GCC4 and Microsoft .NET 2003 aka MSVC 7.1

Version 5.3 (21-Oct-2004)

String object now support python string and unicode string objects.

Fix most bugs reported on SourceForge

Version 5.2 (27-Nov-2003)

PyCXX supports Python version 2.3, 2.2, 2.1, 2.0 and 1.5.2 on Windows and Unix.

Fixed problems with keyword functions.

Improve Extension API to give access to names and docs

Support GCC 3.

Added support for custom Exceptions

Version 5.1 (2-Aug-2001)

I'm using the name PyCXX for this package, CXX is far to close to a compilers name.

PyCXX supports Python version 2.2, 2.1.1, 2.1, 2.0, 2.0.1 and 1.5.2 on Windows and Unix.

New in this release:

(July 9, 2000)

Renamed all header files to reflect the CXX include name space and that they are C++ header files.

OldNew
#include "CXX_Config.h"#include "CXX/Config.hxx"
#include "CXX_Exception.h"#include "CXX/Exception.hxx"
#include "CXX_Extensions.h"#include "CXX/Extensions.hxx"
#include "CXX_Objects.h"#include "CXX/Objects.hxx"

Version 5 (May 18, 2000)

This version adds Distutils support for installation and some code cleanup.

Version 4 (October 11, 1999)

This version contains a massive revision to the part of CXX that supports creating extension objects and extension modules. Barry Scott contributed these changes.

CXX has always consisted of two parts: the basic CXX_Objects.h and the more experimental CXX_Extensions.h. We will describe the changes to CXX_Objects first, and then the changes to CXX_Extensions.h.

Changes to CXX_Objects

1. Owned option eliminates need for FromAPI in most cases

Object's constructor from PyObject* and method set have a new (backward compatible) signature:

Object (PyObject* pyob, bool owned = false);
void set(PyObject* pyob, bool owned = false);

Users may call these with owned = true if they own the reference pyob already and want the Object instance to take over ownership.

A new inline function Object asObject(PyObject* pyob) returns Object(pyob, true); thus, one way to construct an object from a pointer returned by the Python API is to call asObject on it.

Previously a class FromAPI was provided to solve the problem of taking over an owned reference. FromAPI will be eliminated in the next release. It is no longer used by CXX itself or its demos. The new mechanism is much cleaner and more efficient.

Other classes in CXX have been given the same "owned" option on their constructors: Int, Float, Long, Complex, SeqBase<T>, Tuple, List, Dict, Module, Callable.

2. Namespace support in compiler assumed

Since EGCS / GCC now supports namespaces and the standard library, the need for CXX_config.h is almost gone. We have eliminated all the macros except for one obscure one dealing with iterator traits in the standard library.

Changes to CXX_Extensions

The changes to CXX_Extensions.h are not backward compatible. However, they simplify coding so much that we think it is worth the disruption.

1. Creating an extension module

To create an extension module, you inherit from class ExtensionModule templated on yourself: In the constructor, you make calls to register methods of this class with Python as extension module methods. In this example, two methods are added (this is a simplified form of the example in Demo/example.cxx):

class example_module : public ExtensionModule<example_module>
{
public:
    example_module()
	: ExtensionModule<example_module>( "example" )
	{
	add_varargs_method("sum", &example_module::ex_sum, "sum(arglist) = sum of arguments");
	add_varargs_method("test", &example_module::ex_test, "test(arglist) runs a test suite");

	initialize( "documentation for the example module" );
	}

    virtual ~example_module() {}

private:
    Object ex_sum (const Tuple &a) { ... }
    Object ex_test( const Tuple &a) { ... }
};

To initialize the extension, you just instantiate one static instance (static so it doesn't destroy itself!):

void initexample()
    {
    static example_module* example = new example_module;
    }

The methods can be written to take Tuples as arguments and return Objects. If exceptions occur they are trapped for you and a Python exception is generated. So, for example, the implementation of ex_sum might be:

Object ex_sum (const Tuple &a)
    {
        Float f(0.0);
        for( int i = 0; i < a.length(); i++ )
        { 
            Float g(a[i]);
            f = f + g;
        }
        return f;
    }

class ExtensionModule contains methods to return itself as a Module object, or to return its dictionary.

Creating extension objects

Creating extension objects is of course harder since you must specify how the object behaves and give it methods. This is shown in some detail in the example range.h and range.cxx, with the test routine rangetest.cxx, in directory Demo.

Here is a brief overview. You create a class that inherits from PythonExtension templated upon itself. You override various methods from PythonExtension to implement behaviors, such as getattr, sequence_item, etc. You can also add methods to the object that are usable from Python using a similar scheme as for module methods above.

One of the consequences of inheriting from PythonExtension is that you are inheriting from PyObject itself. So your class is-a PyObject and instances of it can be passed to the Python C API. Note: this example uses the namespace feature of CXX. The Py:: 's are not required if you use the namespace instead.

class range: public Py::PythonExtension<range> {
public:
    ... constructors, etc.

    ... methods
    // initializer, see below
    static void init_type();
    // override functions from PythonExtension
    virtual Py::Object repr();
    virtual Py::Object getattr( const char *name );

    virtual int sequence_length();
    virtual Py::Object sequence_item( int i );
    virtual Py::Object sequence_concat( const Py::Object &j );
    virtual Py::Object sequence_slice( int i, int j );

    // define python methods of this object
    Py::Object amethod (const Py::Tuple& args);
    Py::Object value (const Py::Tuple& args);
    Py::Object assign (const Py::Tuple& args); 
};

To initialize the type you provide a static method that you can call from some module's initializer. This method sets the name, doc string, and indicates which behaviors it supports. It then adds the methods.

void range::init_type()
{
    behaviors().name("range");
    behaviors().doc("range objects: start, stop, step");
    behaviors().supportRepr();
    behaviors().supportGetattr();
    behaviors().supportSequenceType();

    add_varargs_method("amethod", &range::amethod,
        "demonstrate how to document amethod");
    add_varargs_method("assign", &range::assign);
    add_varargs_method("value", &range::value);
}

Version 3 (June 18, 1999)

1. CXX compiles with EGCS snapshot 19990616. EGCS requires a standard library class random_access_iterator that is not yet available in some other compilers (such as Windows VC6). Therefore a new switch:

STANDARD_LIBRARY_HAS_ITERATOR_TRAITS

has been added to CXX_Config.h that you may need to toggle if you get an error on the two lines that mention random_access_iterator. The current definition is correct for VC6 and EGCS-19990616.

2. A new constructor was added to Module to allow construction from a string containing the module name. A test was added for this to the demo.

Version 2 (Dec. 28, 1998)

Fixed definition of extension type to match 1.5.2. This version will presumably not compile with older versions of Python. This can be fixed by using the previous version's definition. I did not take the time to find out what these new "flags" are for nor put in any methods to deal with them.

Version 1

This is an experimental set of files for supporting the creation of Python extensions in C++.

Documentation is in progress at http://xfiles.llnl.gov.

To use CXX you use the header files in Include, such as CXX_Objects.h or CXX_Extensions.h. You must include the sources in Src in your sources to supply parts of the CXX classes required.

A demo is included. The Setup file in this directory compiles this demo named "example". To try the demo, which is also a test routine, you import example and then execute:

example.test()

You can also play with the extension object whose constructor is named "range":

s = range(1, 100, 2)
print s[2]  # should print 5

Compilation with Microsoft Visual C++ 5.0 will succeed but only if you have Service Pack 3 installed. Compilation has been known to succeed on a Unix system using KCC by using:

setenv CCC "KCC -x"

before running makethis.py.

There is also a python.cxx file for making a stand-alone Python containing this example, as well as a similar file arraytest.cxx for testing Array.

Comments to barry@barrys-emacs.org, please.

Barry Scott