SIP - A Tool for Generating Python Bindings for C and C++ Libraries

Reference Guide

Contact: info@riverbankcomputing.com
Version: 4.7.9
Copyright: Copyright (c) 2008 Riverbank Computing Limited

Contents

1   Introduction

This is the reference guide for SIP 4.7.9. SIP is a tool for automatically generating Python bindings for C and C++ libraries. SIP was originally developed in 1998 for PyQt - the Python bindings for the Qt GUI toolkit - but is suitable for generating bindings for any C or C++ library.

This version of SIP generates bindings for Python v2.3 or later.

There are many other similar tools available. One of the original such tools is SWIG and, in fact, SIP is so called because it started out as a small SWIG. Unlike SWIG, SIP is specifically designed for bringing together Python and C/C++ and goes to great lengths to make the integration as tight as possible.

The homepage for SIP is http://www.riverbankcomputing.com/software/sip/. Here you will always find the latest stable version, current development snapshots, and the latest version of this documentation.

1.1   License

SIP is licensed under the same terms as Python itself. SIP places no restrictions on the license you may apply to the bindings you create.

1.2   Features

SIP, and the bindings it produces, have the following features.

  • bindings are fast to load and minimise memory consumption especially when only a small sub-set of a large library is being used
  • automatic conversion between standard Python and C/C++ data types
  • overloading of functions and methods with different argument signatures
  • access to a C++ class's protected methods
  • the ability to define a Python class that is a sub-class of a C++ class, including abstract C++ classes
  • Python sub-classes can implement the __dtor__(self) method which will be called from the C++ class's virtual destructor
  • support for ordinary C++ functions, class methods, static class methods, virtual class methods and abstract class methods
  • the ability to re-implement C++ virtual and abstract methods in Python
  • support for global and class variables
  • support for global and class operators
  • support for C++ namespaces
  • support for C++ templates
  • support for C++ exceptions and wrapping them as Python exceptions
  • the automatic generation of complementary rich comparison slots
  • support for deprecation warnings
  • the ability to define mappings between C++ classes and similar Python data types that are automatically invoked
  • the ability to automatically exploit any available run time type information to ensure that the class of a Python instance object matches the class of the corresponding C++ instance
  • full support of the Python global interpreter lock, including the ability to specify that a C++ function of method may block, therefore allowing the lock to be released and other Python threads to run
  • support for consolidated modules where the generated wrapper code for a number of related modules may be included in a single, possibly private, module
  • support for the concept of ownership of a C++ instance (i.e. what part of the code is responsible for calling the instance's destructor) and how the ownership may change during the execution of an application
  • the ability to generate bindings for a C++ class library that itself is built on another C++ class library which also has had bindings generated so that the different bindings integrate and share code properly
  • a sophisticated versioning system that allows the full lifetime of a C++ class library, including any platform specific or optional features, to be described in a single set of specification files
  • the ability to include documentation in the specification files which can be extracted and subsequently processed by external tools
  • the ability to include copyright notices and licensing information in the specification files that is automatically included in all generated source code
  • a build system, written in Python, that you can extend to configure, compile and install your own bindings without worrying about platform specific issues
  • support for building your extensions using distutils
  • SIP, and the bindings it produces, runs under UNIX, Linux, Windows and MacOS/X

1.3   SIP Components

SIP comprises a number of different components.

  • The SIP code generator (sip or sip.exe). This processes .sip specification files and generates C or C++ bindings. It is covered in detail in Using SIP.
  • The SIP header file (sip.h). This contains definitions and data structures needed by the generated C and C++ code.
  • The SIP module (sip.so or sip.pyd). This is a Python extension module that is imported automatically by SIP generated bindings and provides them with some common utility functions. See also Using the SIP Module in Applications.
  • The SIP build system (sipconfig.py). This is a pure Python module that is created when SIP is configured and encapsulates all the necessary information about your system including relevant directory names, compiler and linker flags, and version numbers. It also includes several Python classes and functions which help you write configuration scripts for your own bindings. It is covered in detail in The SIP Build System.
  • The SIP distutils extension (sipdistutils.py). This is a distutils extension that can be used to build your extension modules using distutils and is an alternative to writing configuration scripts with the SIP build system. This can be as simple as adding your .sip files to the list of files needed to build the extension module. It is covered in detail in Building Your Extension with distutils.

1.4   Qt Support

SIP has specific support for the creation of bindings based on Trolltech's Qt toolkit.

The SIP code generator understands the signal/slot type safe callback mechanism that Qt uses to connect objects together. This allows applications to define new Python signals, and allows any Python callable object to be used as a slot.

SIP itself does not require Qt to be installed.

2   Potential Incompatibilities with Earlier Versions

2.1   SIP v4.7.8

This version allows a Python int object to be passed whenever an enum is expected. This can mean that two signatures that were different with prior versions are now the same as far as Python is concerned. The Constrained annotation can now be applied to an enum argument to revert to the earlier behaviour.

2.2   SIP v4.7.3

Prior to this version SIP did not automatically generate missing complementary comparison operators. Typically this was worked around by adding them explicitly to the .sip files, even though they weren't implemented in C++ and relied on the C++ compiler calling the complementary operator that was implemented.

A necessary change to the code generator meant that this not longer worked and so SIP was changed to automatically generate any missing complementary operators. If you have added such operators explicitly then you should remove them or make them dependent on the particular version of SIP.

2.3   SIP v4.4

3   Installing SIP

3.1   Downloading SIP

You can get the latest release of the SIP source code from http://www.riverbankcomputing.com/software/sip/download.

SIP is also included with all of the major Linux distributions. However, it may be a version or two out of date.

3.2   Configuring SIP

After unpacking the source package (either a .tar.gz or a .zip file depending on your platform) you should then check for any README files that relate to your platform.

Next you need to configure SIP by executing the configure.py script. For example:

python configure.py

This assumes that the Python interpreter is on your path. Something like the following may be appropriate on Windows:

c:\python26\python configure.py

If you have multiple versions of Python installed then make sure you use the interpreter for which you wish SIP to generate bindings for.

The full set of command line options is:

-h Display a help message.
-a Export all symbols in any SIP generated module and the SIP module itself. This was the default behaviour of SIP prior to v4.2. Normally only a module's inititialisation function is exported. This option is deprecated as the ModuleMakefile class of The SIP Build System allows this to be specified on a per module basis.
-b dir The SIP code generator will be installed in the directory dir.
-d dir The SIP module will be installed in the directory dir.
-e dir The SIP header file will be installed in the directory dir.
-k The SIP module will be built as a static library. This is useful when building the SIP module as a Python builtin (see Builtin Modules and Custom Interpreters).
-n The SIP code generator and module will be built as universal binaries under MacOS/X.
-p plat Explicitly specify the platform/compiler to be used by the build system, otherwise a platform specific default will be used. The -h option will display all the supported platform/compilers and the default.
-s sdk If the -n option was given then this specifies the name of the SDK directory. If a path is not given then it is assumed to be a sub-directory of /Developer/SDKs.
-u The SIP module will be built with debugging symbols.
-v dir By default .sip files will be installed in the directory dir.

The configure.py script takes many other options that allows the build system to be finely tuned. These are of the form name=value or name+=value. The -h option will display each supported name, although not all are applicable to all platforms.

The name=value form means that value will replace the existing value of name.

The name+=value form means that value will be appended to the existing value of name.

For example, the following will disable support for C++ exceptions (and so reduce the size of module binaries) when used with GCC:

python configure.py CXXFLAGS+=-fno-exceptions

A pure Python module called sipconfig.py is generated by configure.py. This defines each name and its corresponding value. Looking at it will give you a good idea of how the build system uses the different options. It is covered in detail in The SIP Build System.

3.2.1   Configuring SIP Using MinGW

SIP, and the modules it generates, can be built with MinGW, the Windows port of GCC. You must use the -p command line option to specify the correct platform. For example:

c:\python26\python configure.py -p win32-g++

3.2.2   Configuring SIP Using the Borland C++ Compiler

SIP, and the modules it generates, can be built with the free Borland C++ compiler. You must use the -p command line option to specify the correct platform. For example:

c:\python26\python configure.py -p win32-borland

You must also make sure you have a Borland-compatible version of the Python library. If you are using the standard Python distribution (built using the Microsoft compiler) then you must convert the format of the Python library. For example:

coff2omf python26.lib python26_bcpp.lib

3.3   Building SIP

The next step is to build SIP by running your platform's make command. For example:

make

The final step is to install SIP by running the following command:

make install

(Depending on your system you may require root or administrator privileges.)

This will install the various SIP components.

4   Using SIP

Bindings are generated by the SIP code generator from a number of specification files, typically with a .sip extension. Specification files look very similar to C and C++ header files, but often with additional information (in the form of a directive or an annotation) and code so that the bindings generated can be finely tuned.

4.1   A Simple C++ Example

We start with a simple example. Let's say you have a (fictional) C++ library that implements a single class called Word. The class has one constructor that takes a \0 terminated character string as its single argument. The class has one method called reverse() which takes no arguments and returns a \0 terminated character string. The interface to the class is defined in a header file called word.h which might look something like this:

// Define the interface to the word library.

class Word {
    const char *the_word;

public:
    Word(const char *w);

    char *reverse() const;
};

The corresponding SIP specification file would then look something like this:

// Define the SIP wrapper to the word library.

%Module word 0

class Word {

%TypeHeaderCode
#include <word.h>
%End

public:
    Word(const char *w);

    char *reverse() const;
};

Obviously a SIP specification file looks very much like a C++ (or C) header file, but SIP does not include a full C++ parser. Let's look at the differences between the two files.

  • The %Module directive has been added [1]. This is used to name the Python module that is being created and to give it a generation number. In this example these are word and 0 respectively. The generation number is effectively the version number of the module.
  • The %TypeHeaderCode directive has been added. The text between this and the following %End directive is included literally in the code that SIP generates. Normally it is used, as in this case, to #include the corresponding C++ (or C) header file [2].
  • The declaration of the private variable this_word has been removed. SIP does not support access to either private or protected instance variables.

If we want to we can now generate the C++ code in the current directory by running the following command:

sip -c . word.sip

However, that still leaves us with the task of compiling the generated code and linking it against all the necessary libraries. It's much easier to use the SIP build system to do the whole thing.

Using the SIP build system is simply a matter of writing a small Python script. In this simple example we will assume that the word library we are wrapping and it's header file are installed in standard system locations and will be found by the compiler and linker without having to specify any additional flags. In a more realistic example your Python script may take command line options, or search a set of directories to deal with different configurations and installations.

This is the simplest script (conventionally called configure.py):

import os
import sipconfig

# The name of the SIP build file generated by SIP and used by the build
# system.
build_file = "word.sbf"

# Get the SIP configuration information.
config = sipconfig.Configuration()

# Run SIP to generate the code.
os.system(" ".join([config.sip_bin, "-c", ".", "-b", build_file, "word.sip"]))

# Create the Makefile.
makefile = sipconfig.SIPModuleMakefile(config, build_file)

# Add the library we are wrapping.  The name doesn't include any platform
# specific prefixes or extensions (e.g. the "lib" prefix on UNIX, or the
# ".dll" extension on Windows).
makefile.extra_libs = ["word"]

# Generate the Makefile itself.
makefile.generate()

Hopefully this script is self-documenting. The key parts are the Configuration and SIPModuleMakefile classes. The build system contains other Makefile classes, for example to build programs or to call other Makefiles in sub-directories.

After running the script (using the Python interpreter the extension module is being created for) the generated C++ code and Makefile will be in the current directory.

To compile and install the extension module, just run the following commands [3]:

make
make install

That's all there is to it.

See Building Your Extension with distutils for an example of how to build this example using distutils.

[1]All SIP directives start with a % as the first non-whitespace character of a line.
[2]SIP includes many code directives like this. They differ in where the supplied code is placed by SIP in the generated code.
[3]On Windows you might run nmake or mingw32-make instead.

4.2   A Simple C Example

Let's now look at a very similar example of wrapping a fictional C library:

/* Define the interface to the word library. */

struct Word {
    const char *the_word;
};

struct Word *create_word(const char *w);
char *reverse(struct Word *word);

The corresponding SIP specification file would then look something like this:

/* Define the SIP wrapper to the word library. */

%CModule word 0

struct Word {

%TypeHeaderCode
#include <word.h>
%End

    const char *the_word;
};

struct Word *create_word(const char *w) /Factory/;
char *reverse(struct Word *word);

Again, let's look at the differences between the two files.

  • The %CModule directive has been added. This has the same syntax as the %Module directive used in the previous example but tells SIP that the library being wrapped is implemented in C rather than C++.
  • The %TypeHeaderCode directive has been added.
  • The Factory annotation has been added to the create_word() function. This tells SIP that a newly created structure is being returned and it is owned by Python.

The configure.py build system script described in the previous example can be used for this example without change.

4.3   A More Complex C++ Example

In this last example we will wrap a fictional C++ library that contains a class that is derived from a Qt class. This will demonstrate how SIP allows a class hierarchy to be split across multiple Python extension modules, and will introduce SIP's versioning system.

The library contains a single C++ class called Hello which is derived from Qt's QLabel class. It behaves just like QLabel except that the text in the label is hard coded to be Hello World. To make the example more interesting we'll also say that the library only supports Qt v4.2 and later, and also includes a function called setDefault() that is not implemented in the Windows version of the library.

The hello.h header file looks something like this:

// Define the interface to the hello library.

#include <qlabel.h>
#include <qwidget.h>
#include <qstring.h>

class Hello : public QLabel {
    // This is needed by the Qt Meta-Object Compiler.
    Q_OBJECT

public:
    Hello(QWidget *parent, const char *name = 0, WFlags f = 0);

private:
    // Prevent instances from being copied.
    Hello(const Hello &);
    Hello &operator=(const Hello &);
};

#if !defined(Q_OS_WIN)
void setDefault(const QString &def);
#endif

The corresponding SIP specification file would then look something like this:

// Define the SIP wrapper to the hello library.

%Module hello 0

%Import QtCore/QtCoremod.sip

%If (Qt_4_2_0 -)

class Hello : QLabel {

%TypeHeaderCode
#include <hello.h>
%End

public:
    Hello(QWidget *parent /TransferThis/, const char *name = 0, WFlags f = 0);

private:
    Hello(const Hello &);
};

%If (!WS_WIN)
void setDefault(const QString &def);
%End

%End

Again we look at the differences, but we'll skip those that we've looked at in previous examples.

  • The %Import directive has been added to specify that we are extending the class hierarchy defined in the file QtCore/QtCoremod.sip. This file is part of PyQt. The build system will take care of finding the file's exact location.
  • The %If directive has been added to specify that everything [4] up to the matching %End directive only applies to Qt v4.2 and later. Qt_4_2_0 is a tag defined in QtCoremod.sip [5] using the %Timeline directive. %Timeline is used to define a tag for each version of a library's API you are wrapping allowing you to maintain all the different versions in a single SIP specification. The build system provides support to configure.py scripts for working out the correct tags to use according to which version of the library is actually installed.
  • The public keyword used in defining the super-classes has been removed. This is not supported by SIP.
  • The TransferThis annotation has been added to the first argument of the constructor. It specifies that if the argument is not 0 (i.e. the Hello instance being constructed has a parent) then ownership of the instance is transferred from Python to C++. It is needed because Qt maintains objects (i.e. instances derived from the QObject class) in a hierachy. When an object is destroyed all of its children are also automatically destroyed. It is important, therefore, that the Python garbage collector doesn't also try and destroy them. This is covered in more detail in Ownership of Objects. SIP provides many other annotations that can be applied to arguments, functions and classes. Multiple annotations are separated by commas. Annotations may have values.
  • The = operator has been removed. This operator is not supported by SIP.
  • The %If directive has been added to specify that everything up to the matching %End directive does not apply to Windows. WS_WIN is another tag defined by PyQt, this time using the %Platforms directive. Tags defined by the %Platforms directive are mutually exclusive, i.e. only one may be valid at a time [6].

One question you might have at this point is why bother to define the private copy constructor when it can never be called from Python? The answer is to prevent the automatic generation of a public copy constructor.

We now look at the configure.py script. This is a little different to the script in the previous examples for two related reasons.

Firstly, PyQt includes a pure Python module called pyqtconfig that extends the SIP build system for modules, like our example, that build on top of PyQt. It deals with the details of which version of Qt is being used (i.e. it determines what the correct tags are) and where it is installed. This is called a module's configuration module.

Secondly, we generate a configuration module (called helloconfig) for our own hello module. There is no need to do this, but if there is a chance that somebody else might want to extend your C++ library then it would make life easier for them.

Now we have two scripts. First the configure.py script:

import os
import sipconfig
import pyqtconfig

# The name of the SIP build file generated by SIP and used by the build
# system.
build_file = "hello.sbf"

# Get the PyQt configuration information.
config = pyqtconfig.Configuration()

# Get the extra SIP flags needed by the imported qt module.  Note that
# this normally only includes those flags (-x and -t) that relate to SIP's
# versioning system.
qt_sip_flags = config.pyqt_qt_sip_flags

# Run SIP to generate the code.  Note that we tell SIP where to find the qt
# module's specification files using the -I flag.
os.system(" ".join([config.sip_bin, "-c", ".", "-b", build_file, "-I", config.pyqt_sip_dir, qt_sip_flags, "hello.sip"]))

# We are going to install the SIP specification file for this module and
# its configuration module.
installs = []

installs.append(["hello.sip", os.path.join(config.default_sip_dir, "hello")])

installs.append(["helloconfig.py", config.default_mod_dir])

# Create the Makefile.  The QtModuleMakefile class provided by the
# pyqtconfig module takes care of all the extra preprocessor, compiler and
# linker flags needed by the Qt library.
makefile = pyqtconfig.QtModuleMakefile(
    configuration=config,
    build_file=build_file,
    installs=installs
)

# Add the library we are wrapping.  The name doesn't include any platform
# specific prefixes or extensions (e.g. the "lib" prefix on UNIX, or the
# ".dll" extension on Windows).
makefile.extra_libs = ["hello"]

# Generate the Makefile itself.
makefile.generate()

# Now we create the configuration module.  This is done by merging a Python
# dictionary (whose values are normally determined dynamically) with a
# (static) template.
content = {
    # Publish where the SIP specifications for this module will be
    # installed.
    "hello_sip_dir":    config.default_sip_dir,

    # Publish the set of SIP flags needed by this module.  As these are the
    # same flags needed by the qt module we could leave it out, but this
    # allows us to change the flags at a later date without breaking
    # scripts that import the configuration module.
    "hello_sip_flags":  qt_sip_flags
}

# This creates the helloconfig.py module from the helloconfig.py.in
# template and the dictionary.
sipconfig.create_config_module("helloconfig.py", "helloconfig.py.in", content)

Next we have the helloconfig.py.in template script:

import pyqtconfig

# These are installation specific values created when Hello was configured.
# The following line will be replaced when this template is used to create
# the final configuration module.
# @SIP_CONFIGURATION@

class Configuration(pyqtconfig.Configuration):
    """The class that represents Hello configuration values.
    """
    def __init__(self, sub_cfg=None):
        """Initialise an instance of the class.

        sub_cfg is the list of sub-class configurations.  It should be None
        when called normally.
        """
        # This is all standard code to be copied verbatim except for the
        # name of the module containing the super-class.
        if sub_cfg:
            cfg = sub_cfg
        else:
            cfg = []

        cfg.append(_pkg_config)

        pyqtconfig.Configuration.__init__(self, cfg)

class HelloModuleMakefile(pyqtconfig.QtModuleMakefile):
    """The Makefile class for modules that %Import hello.
    """
    def finalise(self):
        """Finalise the macros.
        """
        # Make sure our C++ library is linked.
        self.extra_libs.append("hello")

        # Let the super-class do what it needs to.
        pyqtconfig.QtModuleMakefile.finalise(self)

Again, we hope that the scripts are self documenting.

[4]Some parts of a SIP specification aren't subject to version control.
[5]Actually in versions.sip. PyQt uses the %Include directive to split the SIP specification for Qt across a large number of separate .sip files.
[6]Tags can also be defined by the %Feature directive. These tags are not mutually exclusive, i.e. any number may be valid at a time.

4.4   Ownership of Objects

When a C++ instance is wrapped a corresponding Python object is created. The Python object behaves as you would expect in regard to garbage collection - it is garbage collected when its reference count reaches zero. What then happens to the corresponding C++ instance? The obvious answer might be that the instance's destructor is called. However the library API may say that when the instance is passed to a particular function, the library takes ownership of the instance, i.e. responsibility for calling the instance's destructor is transferred from the SIP generated module to the library.

Ownership of an instance may also be associated with another instance. The implication being that the owned instance will automatically be destroyed if the owning instance is destroyed. SIP keeps track of these relationships to ensure that Python's cyclic garbage collector can detect and break any reference cycles between the owning and owned instances. The association is implemented as the owning instance taking a reference to the owned instance.

The TransferThis, Transfer and TransferBack annotations are used to specify where, and it what direction, transfers of ownership happen. It is very important that these are specified correctly to avoid crashes (where both Python and C++ call the destructor) and memory leaks (where neither Python and C++ call the destructor).

This applies equally to C structures where the structure is returned to the heap using the free() function.

See also sipTransferTo(), sipTransferBack() and sipTransferBreak().

4.5   Support for Python's Buffer Interface

SIP supports Python's buffer interface in that whenever C/C++ requires a char or char * type then any Python type that supports the buffer interface (including ordinary Python strings) can be used.

If a buffer is made up of a number of segments then all but the first will be ignored.

4.6   Support for Wide Characters

SIP v4.6 introduced support for wide characters (i.e. the wchar_t type). Python's C API includes support for converting between unicode objects and wide character strings and arrays. When converting from a unicode object to wide characters SIP creates the string or array on the heap (using memory allocated using sipMalloc()). This then raises the problem of how this memory is subsequently freed.

The following describes how SIP handles this memory in the different situations where this is an issue.

  • When a wide string or array is passed to a function or method then the memory is freed (using sipFree()) after than function or method returns.
  • When a wide string or array is returned from a virtual method then SIP does not free the memory until the next time the method is called.
  • When an assignment is made to a wide string or array instance variable then SIP does not first free the instance's current string or array.

4.7   The Python Global Interpreter Lock

Python's Global Interpretor Lock (GIL) must be acquired before calls can be made to the Python API. It should also be released when a potentially blocking call to C/C++ library is made in order to allow other Python threads to be executed. In addition, some C/C++ libraries may implement their own locking strategies that conflict with the GIL causing application deadlocks. SIP provides ways of specifying when the GIL is released and acquired to ensure that locking problems can be avoided.

SIP always ensures that the GIL is acquired before making calls to the Python API. By default SIP does not release the GIL when making calls to the C/C++ library being wrapped. The ReleaseGIL annotation can be used to override this behaviour when required.

If SIP is given the -g command line option then the default behaviour is changed and SIP releases the GIL every time is makes calls to the C/C++ library being wrapped. The HoldGIL annotation can be used to override this behaviour when required.

5   The SIP Command Line

The syntax of the SIP command line is:

sip [options] [specification]

specification is the name of the specification file for the module. If it is omitted then stdin is used.

The full set of command line options is:

-h Display a help message.
-V Display the SIP version number.
-a file The name of the QScintilla API file to generate. This file contains a description of the module API in a form that the QScintilla editor component can use for auto-completion and call tips. (The file may also be used by the SciTE editor but must be sorted first.) By default the file is not generated.
-b file The name of the build file to generate. This file contains the information about the module needed by the SIP build system to generate a platform and compiler specific Makefile for the module. By default the file is not generated.
-c dir The name of the directory (which must exist) into which all of the generated C or C++ code is placed. By default no code is generated.
-d file The name of the documentation file to generate. Documentation is included in specification files using the %Doc and %ExportedDoc directives. By default the file is not generated.
-e Support for C++ exceptions is enabled. This causes all calls to C++ code to be enclosed in try/catch blocks and C++ exceptions to be converted to Python exceptions. By default exception support is disabled.
-g The Python GIL is released before making any calls to the C/C++ library being wrapped and reacquired afterwards. See The Python Global Interpreter Lock and the ReleaseGIL and HoldGIL annotations.
-I dir The directory is added to the list of directories searched when looking for a specification file given in an %Include or %Import directive. This option may be given any number of times.
-j number The generated code is split into the given number of files. This make it easier to use the parallel build facility of most modern implementations of make. By default 1 file is generated for each C structure or C++ class.
-p module The name of the %ConsolidatedModule which will contain the wrapper code for this component module.
-r Debugging statements that trace the execution of the bindings are automatically generated. By default the statements are not generated.
-s suffix The suffix to use for generated C or C++ source files. By default .c is used for C and .cpp for C++.
-t tag The SIP version tag (declared using a %Timeline directive) or the SIP platform tag (declared using the %Platforms directive) to generate code for. This option may be given any number of times so long as the tags do not conflict.
-w The display of warning messages is enabled. By default warning messages are disabled.
-x feature The feature (declared using the %Feature directive) is disabled.
-z file The name of a file containing more command line options.

6   SIP Specification Files

A SIP specification consists of some C/C++ type and function declarations and some directives. The declarations may contain annotations which provide SIP with additional information that cannot be expressed in C/C++. SIP does not include a full C/C++ parser.

It is important to understand that a SIP specification describes the Python API, i.e. the API available to the Python programmer when they import the generated module. It does not have to accurately represent the underlying C/C++ library. There is nothing wrong with omitting functions that make little sense in a Python context, or adding functions implemented with handwritten code that have no C/C++ equivalent. It is even possible (and sometimes necessary) to specify a different super-class hierarchy for a C++ class. All that matters is that the generated code compiles properly.

In most cases the Python API matches the C/C++ API. In some cases handwritten code (see %MethodCode) is used to map from one to the other without SIP having to know the details itself. However, there are a few cases where SIP generates a thin wrapper around a C++ method or constructor (see Generated Derived Classes) and needs to know the exact C++ signature. To deal with these cases SIP allows two signatures to be specified. For example:

class Klass
{
public:
    // The Python signature is a tuple, but the underlying C++ signature
    // is a 2 element array.
    Klass(SIP_PYTUPLE) [(int *)];
%MethodCode
        int iarr[2];

        if (PyArg_ParseTuple(a0, "ii", &iarr[0], &iarr[1]))
        {
            // Note that we use the SIP generated derived class
            // constructor.
            Py_BEGIN_ALLOW_THREADS
            sipCpp = new sipKlass(iarr);
            Py_END_ALLOW_THREADS
        }
%End
};

6.1   Syntax Definition

The following is a semi-formal description of the syntax of a specification file.

specification ::= {module-statement}

module-statement ::= [module-directive | statement]

module-directive ::= [%CModule | %CompositeModule |
        %ConsolidatedModule | %Copying | %Doc | %ExportedDoc |
        %ExportedHeaderCode | %Feature | %Import | %Include |
        %License | %MappedType | mapped-type-template |
        %Module | %ModuleCode | %ModuleHeaderCode |
        %OptionalInclude | %Platforms | %PreInitialisationCode |
        %PostInitialisationCode | sip-option-list | %Timeline |
        %UnitCode]

sip-option-list :: %SIPOptions ( option-list )

option-list ::= option [, option-list]

statement :: [class-statement | function | variable]

class-statement :: [%If | class | class-template | enum |
        namespace | opaque-class | operator | struct | typedef |
        exception]

class ::= class name [: super-classes] [class-annotations]
        { {class-line} };

super-classes ::= name [, super-classes]

class-line ::= [class-statement | %BIGetReadBufferCode |
        %BIGetWriteBufferCode | %BIGetSegCountCode |
        %BIGetCharBufferCode | %ConvertToSubClassCode |
        %ConvertToTypeCode | %GCClearCode | %GCTraverseCode |
        %PickleCode | %TypeCode | %TypeHeaderCode |
        constructor | destructor | method | static-method |
        virtual-method | special-method | operator |
        virtual-operator | class-variable | public: |
        public slots: | protected: | protected slots: |
        private: | private slots: | signals:]

constructor ::= [explicit] name ( [argument-list] )
        [exceptions] [function-annotations]
        [c++-constructor-signature] ; [%MethodCode]

c++-constructor-signature ::= [( [argument-list] )]

destructor ::= [virtual] ~ name () [exceptions] [= 0]
        [function-annotations] ; [%MethodCode]
        [%VirtualCatcherCode]

method ::= type name ( [argument-list] ) [const]
        [exceptions] [= 0] [function-annotations] [c++-signature]
        ; [%MethodCode]

c++-signature ::= [ type ( [argument-list] )]

static-method ::= static function

virtual-method ::= virtual type name ( [argument-list] )
        [const] [exceptions] [= 0] [function-annotations]
        [c++-signature] ; [%MethodCode] [%VirtualCatcherCode]

special-method ::= type special-method-name
        ( [argument-list] ) [function-annotations] ;
        [%MethodCode]

special-method-name ::= [ __abs__ | __add__ | __and__ |
        __call__ | __cmp__ | __contains__ | __delitem__ |
        __div__ | __eq__ | __float__ | __ge__ |
        __getitem__ | __gt__ | __hash__ | __iadd__ |
        __iand__ | __idiv__ | __ilshift__ | __imod__ |
        __imul__ | __int__ | __invert__ | __ior__ |
        __irshift__ | __isub__ | __ixor__ | __le__ |
        __len__ | __long__ | __lshift__ | __lt__ |
        __mod__ | __mul__ | __ne__ | __neg__ |
        __nonzero__ | __or__ | __pos__ | __repr__ |
        __rshift__ | __setitem__ | __str__ | __sub__ |
        __xor__]

operator ::= operator-type
        ( [argument-list] ) [const] [exceptions]
        [function-annotations] ; [%MethodCode]

virtual-operator ::= virtual operator-type
        ( [argument-list] ) [const] [exceptions] [= 0]
        [function-annotations] ; [%MethodCode]
        [%VirtualCatcherCode]

operatator-type ::= [ operator-function | operator-cast ]

operator-function ::= type operator operator-name

operator-cast ::= operator type

operator-name ::= [+ | - | * | / | % | & |
        | | ^ | << | >> | += | -= | *= |
        /= | %= | &= | |= | ^= | <<= | >>= |
        ~ | () | [] | < | <= | == | != |
        > | >>=]

class-variable ::= [static] variable

class-template :: = template < type-list > class

mapped-type-template :: = template < type-list >
        %MappedType

enum ::= enum [name] [enum-annotations] { {enum-line} };

enum-line ::= [%If | name [enum-annotations] ,

function ::= type name ( [argument-list] ) [exceptions]
        [function-annotations] ; [%MethodCode]

namespace ::= namespace name { {namespace-line} };

namespace-line ::= [%TypeHeaderCode | statement]

opaque-class ::= class scoped-name ;

struct ::= struct name { {class-line} };

typedef ::= typedef [typed-name | function-pointer]
        typedef-annotations ;

variable::= typed-name [variable-annotations] ; [%AccessCode]
        [%GetCode] [%SetCode]

exception ::= %Exception exception-name [exception-base] {
        [%TypeHeaderCode] %RaiseCode };`

exception-name ::= scoped-name

exception-base ::= ( [exception-name | python-exception] )

python-exception ::= [SIP_Exception | SIP_StopIteration |
        SIP_StandardError | SIP_ArithmeticError |
        SIP_LookupError | SIP_AssertionError |
        SIP_AttributeError | SIP_EOFError |
        SIP_FloatingPointError | SIP_EnvironmentError |
        SIP_IOError | SIP_OSError | SIP_ImportError |
        SIP_IndexError | SIP_KeyError | SIP_KeyboardInterrupt |
        SIP_MemoryError | SIP_NameError | SIP_OverflowError |
        SIP_RuntimeError | SIP_NotImplementedError |
        SIP_SyntaxError | SIP_IndentationError | SIP_TabError |
        SIP_ReferenceError | SIP_SystemError | SIP_SystemExit |
        SIP_TypeError | SIP_UnboundLocalError |
        SIP_UnicodeError | SIP_UnicodeEncodeError |
        SIP_UnicodeDecodeError | SIP_UnicodeTranslateError |
        SIP_ValueError | SIP_ZeroDivisionError |
        SIP_WindowsError | SIP_VMSError]

exceptions ::= throw ( [exception-list] )

exception-list ::= scoped-name [, exception-list]

argument-list ::= argument [, argument-list] [, ...]

argument ::= [type [name] [argument-annotations]
        [default-value] | SIP_ANYSLOT [default-value] | SIP_QOBJECT |
        SIP_RXOBJ_CON | SIP_RXOBJ_DIS | SIP_SIGNAL [default-value] |
        SIP_SLOT [default-value] | SIP_SLOT_CON | SIP_SLOT_DIS]

default-value ::= = expression

expression ::= [value | value binary-operator expression]

value ::= [unary-operator] simple-value

simple-value ::= [scoped-name | function-call | real-value |
        integer-value | boolean-value | string-value |
        character-value]

typed-name::= type name

function-pointer::= type (* name )( [type-list] )

type-list ::= type [, type-list]

function-call ::= scoped-name ( [value-list] )

value-list ::= value [, value-list]

real-value ::= a floating point number

integer-value ::= a number

boolean-value ::= [true | false]

string-value ::= " {character} "

character-value ::= ` character `

unary-operator ::= [! | ~ | - | +]

binary-operator ::= [- | + | * | / | & | |]

argument-annotations ::= see Argument Annotations

class-annotations ::= see Class Annotations

enum-annotations ::= see Enum Annotations

function-annotations ::= see Function Annotations

typedef-annotations ::= see Typedef Annotations

variable-annotations ::= see Variable Annotations

type ::= [const] base-type {*} [&]

type-list ::= type [, type-list]

base-type ::= [scoped-name | template | struct scoped-name |
        short | unsigned short | int | unsigned |
        unsigned int | long | unsigned long | float |
        double | bool | char | signed char |
        unsigned char | void | wchar_t | SIP_PYCALLABLE |
        SIP_PYDICT | SIP_PYLIST | SIP_PYOBJECT | SIP_PYSLICE |
        SIP_PYTUPLE | SIP_PYTYPE]

scoped-name ::= name [:: scoped-name]

template ::= scoped-name < type-list >

name ::= _A-Za-z {_A-Za-z0-9}

Here is a short list of differences between C++ and the subset supported by SIP that might trip you up.

  • SIP does not support the use of [] in types. Use pointers instead.
  • A global operator can only be defined if its first argument is a class or a named enum that has been wrapped in the same module.
  • Variables declared outside of a class are effectively read-only.
  • A class's list of super-classes doesn't not include any access specifier (e.g. public).

6.2   Variable Numbers of Arguments

SIP supports the use of ... as the last part of a function signature. Any remaining arguments are collected as a Python tuple.

6.3   Additional SIP Types

SIP supports a number of additional data types that can be used in Python signatures.

6.3.1   SIP_ANYSLOT

This is both a const char * and a PyObject * that is used as the type of the member instead of const char * in functions that implement the connection or disconnection of an explicitly generated signal to a slot. Handwritten code must be provided to interpret the conversion correctly.

6.3.2   SIP_PYCALLABLE

This is a PyObject * that is a Python callable object.

6.3.3   SIP_PYDICT

This is a PyObject * that is a Python dictionary object.

6.3.4   SIP_PYLIST

This is a PyObject * that is a Python list object.

6.3.5   SIP_PYOBJECT

This is a PyObject * of any Python type.

6.3.6   SIP_PYSLICE

This is a PyObject * that is a Python slice object.

6.3.7   SIP_PYTUPLE

This is a PyObject * that is a Python tuple object.

6.3.8   SIP_PYTYPE

This is a PyObject * that is a Python type object.

6.3.9   SIP_QOBJECT

This is a QObject * that is a C++ instance of a class derived from Qt's QObject class.

6.3.10   SIP_RXOBJ_CON

This is a QObject * that is a C++ instance of a class derived from Qt's QObject class. It is used as the type of the receiver instead of const QObject * in functions that implement a connection to a slot.

6.3.11   SIP_RXOBJ_DIS

This is a QObject * that is a C++ instance of a class derived from Qt's QObject class. It is used as the type of the receiver instead of const QObject * in functions that implement a disconnection from a slot.

6.3.12   SIP_SIGNAL

This is a const char * that is used as the type of the signal instead of const char * in functions that implement the connection or disconnection of an explicitly generated signal to a slot.

6.3.13   SIP_SLOT

This is a const char * that is used as the type of the member instead of const char * in functions that implement the connection or disconnection of an explicitly generated signal to a slot.

6.3.14   SIP_SLOT_CON

This is a const char * that is used as the type of the member instead of const char * in functions that implement the connection of an internally generated signal to a slot. The type includes a comma separated list of types that is the C++ signature of of the signal.

To take an example, QAccel::connectItem() connects an internally generated signal to a slot. The signal is emitted when the keyboard accelerator is activated and it has a single integer argument that is the ID of the accelerator. The C++ signature is:

bool connectItem(int id, const QObject *receiver, const char *member);

The corresponding SIP specification is:

bool connectItem(int, SIP_RXOBJ_CON, SIP_SLOT_CON(int));

6.3.15   SIP_SLOT_DIS

This is a const char * that is used as the type of the member instead of const char * in functions that implement the disconnection of an internally generated signal to a slot. The type includes a comma separated list of types that is the C++ signature of of the signal.

7   SIP Directives

In this section we describe each of the directives that can be used in specification files. All directives begin with % as the first non-whitespace character in a line.

Some directives have arguments or contain blocks of code or documentation. In the following descriptions these are shown in italics. Optional arguments are enclosed in [brackets].

Some directives are used to specify handwritten code. Handwritten code must not define names that start with the prefix sip.

7.1   %AccessCode

%AccessCode
    code
%End

This directive is used immediately after the declaration of an instance of a wrapped class or structure, or a pointer to such an instance. You use it to provide handwritten code that overrides the default behaviour.

For example:

class Klass;

Klass *klassInstance;
%AccessCode
    // In this contrived example the C++ library we are wrapping defines
    // klassInstance as Klass ** (which SIP doesn't support) so we
    // explicitly dereference it.
    if (klassInstance && *klassInstance)
        return *klassInstance;

    // This will get converted to None.
    return 0;
%End

7.2   %BIGetCharBufferCode

%BIGetCharBufferCode
    code
%End

This directive (along with %BIGetReadBufferCode, %BIGetSegCountCode and %BIGetWriteBufferCode) is used to specify code that implements Python's buffer interface. See the section Buffer Object Structures for the details.

The following variables are made available to the handwritten code:

type *sipCpp
This is a pointer to the structure or class instance. Its type is a pointer to the structure or class.
void **sipPtrPtr
This is the pointer used to return the address of the character buffer.
SIP_SSIZE_T sipRes
The handwritten code should set this to the length of the character buffer or -1 if there was an error.
SIP_SSIZE_T sipSegment
This is the number of the segment of the character buffer.
PyObject *sipSelf
This is the Python object that wraps the the structure or class instance, i.e. self.

7.3   %BIGetReadBufferCode

%BIGetReadBufferCode
    code
%End

This directive (along with %BIGetCharBufferCode, %BIGetSegCountCode and %BIGetWriteBufferCode) is used to specify code that implements Python's buffer interface.

The following variables are made available to the handwritten code:

type *sipCpp
This is a pointer to the structure or class instance. Its type is a pointer to the structure or class.
void **sipPtrPtr
This is the pointer used to return the address of the read buffer.
SIP_SSIZE_T sipRes
The handwritten code should set this to the length of the read buffer or -1 if there was an error.
SIP_SSIZE_T sipSegment
This is the number of the segment of the read buffer.
PyObject *sipSelf
This is the Python object that wraps the the structure or class instance, i.e. self.

7.4   %BIGetSegCountCode

%BIGetSegCountCode
    code
%End

This directive (along with %BIGetCharBufferCode, %BIGetReadBufferCode and %BIGetWriteBufferCode) is used to specify code that implements Python's buffer interface.

The following variables are made available to the handwritten code:

type *sipCpp
This is a pointer to the structure or class instance. Its type is a pointer to the structure or class.
SIP_SSIZE_T *sipLenPtr
This is the pointer used to return the total length in bytes of all segments of the buffer.
SIP_SSIZE_T sipRes
The handwritten code should set this to the number of segments that make up the buffer.
PyObject *sipSelf
This is the Python object that wraps the the structure or class instance, i.e. self.

7.5   %BIGetWriteBufferCode

%BIGetWriteBufferCode