summaryrefslogtreecommitdiffstats
path: root/doc/html/_sources/using.txt
diff options
context:
space:
mode:
authorTimothy Pearson <kb9vqf@pearsoncomputing.net>2011-11-22 02:59:34 -0600
committerTimothy Pearson <kb9vqf@pearsoncomputing.net>2011-11-22 02:59:34 -0600
commit6c4cc3653e8dd7668295f3e659b7eb4dc571b67c (patch)
treea559fd71fc982e35a4f984d85a5c9d92b764ae8c /doc/html/_sources/using.txt
downloadsip4-tqt-6c4cc3653e8dd7668295f3e659b7eb4dc571b67c.tar.gz
sip4-tqt-6c4cc3653e8dd7668295f3e659b7eb4dc571b67c.zip
Initial import of SIP4 for Qt3
Diffstat (limited to 'doc/html/_sources/using.txt')
-rw-r--r--doc/html/_sources/using.txt662
1 files changed, 662 insertions, 0 deletions
diff --git a/doc/html/_sources/using.txt b/doc/html/_sources/using.txt
new file mode 100644
index 0000000..ff121ce
--- /dev/null
+++ b/doc/html/_sources/using.txt
@@ -0,0 +1,662 @@
+.. _ref-using:
+
+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.
+
+
+.. _ref-simple-c++-example:
+
+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 :directive:`%Module` directive has been added [#]_. 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 :directive:`%TypeHeaderCode` directive has been added. The text
+ between this and the following :directive:`%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 [#]_.
+
+ - 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
+:ref:`SIP build system <ref-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 [#]_::
+
+ make
+ make install
+
+That's all there is to it.
+
+See :ref:`ref-distutils` for an example of how to build this example using
+distutils.
+
+.. [#] All SIP directives start with a ``%`` as the first non-whitespace
+ character of a line.
+.. [#] SIP includes many code directives like this. They differ in where the
+ supplied code is placed by SIP in the generated code.
+.. [#] On Windows you might run ``nmake`` or ``mingw32-make`` instead.
+
+
+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 :directive:`%CModule` directive has been added. This has the same
+ syntax as the :directive:`%Module` directive used in the previous example
+ but tells SIP that the library being wrapped is implemented in C rather
+ than C++.
+
+ - The :directive:`%TypeHeaderCode` directive has been added.
+
+ - The :fanno:`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.
+
+
+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 = 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 QtGui/QtGuimod.sip
+
+ %If (Qt_4_2_0 -)
+
+ class Hello : QLabel {
+
+ %TypeHeaderCode
+ #include <hello.h>
+ %End
+
+ public:
+ Hello(QWidget *parent /TransferThis/ = 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 :directive:`%Import` directive has been added to specify that we are
+ extending the class hierarchy defined in the file ``QtGui/QtGuimod.sip``.
+ This file is part of PyQt. The build system will take care of finding
+ the file's exact location.
+
+ - The :directive:`%If` directive has been added to specify that everything
+ [#]_ up to the matching :directive:`%End` directive only applies to Qt
+ v4.2 and later. ``Qt_4_2_0`` is a *tag* defined in ``QtCoremod.sip``
+ [#]_ using the :directive:`%Timeline` directive. :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 :aanno:`TransferThis` annotation has been added to the constructor's
+ argument. 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 :ref:`ref-object-ownership`. 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 :directive:`%If` directive has been added to specify that everything
+ up to the matching :directive:`%End` directive does not apply to Windows.
+ ``WS_WIN`` is another tag defined by PyQt, this time using the
+ :directive:`%Platforms` directive. Tags defined by the
+ :directive:`%Platforms` directive are mutually exclusive, i.e. only one
+ may be valid at a time [#]_.
+
+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
+ from PyQt4 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 PyQt modules. Note that
+ # this normally only includes those flags (-x and -t) that relate to SIP's
+ # versioning system.
+ pyqt_sip_flags = config.pyqt_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, pyqt_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 QtGuiModuleMakefile class provided by the
+ # pyqtconfig module takes care of all the extra preprocessor, compiler and
+ # linker flags needed by the Qt library.
+ makefile = pyqtconfig.QtGuiModuleMakefile(
+ 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": pyqt_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::
+
+ from PyQt4 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.QtGuiModuleMakefile):
+ """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.QtGuiModuleMakefile.finalise(self)
+
+Again, we hope that the scripts are self documenting.
+
+.. [#] Some parts of a SIP specification aren't subject to version control.
+.. [#] Actually in ``versions.sip``. PyQt uses the :directive:`%Include`
+ directive to split the SIP specification for Qt across a large number of
+ separate ``.sip`` files.
+.. [#] Tags can also be defined by the :directive:`%Feature` directive. These
+ tags are not mutually exclusive, i.e. any number may be valid at a time.
+
+
+.. _ref-object-ownership:
+
+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 :cfunc:`sipTransferTo()`, :cfunc:`sipTransferBack()` and
+:cfunc:`sipTransferBreak()`.
+
+
+.. _ref-types-metatypes:
+
+Types and Meta-types
+--------------------
+
+Every Python object (with the exception of the :class:`object` object itself)
+has a meta-type and at least one super-type. By default an object's meta-type
+is the meta-type of its first super-type.
+
+SIP implements two super-types, :class:`sip.simplewrapper` and
+:class:`sip.wrapper`, and a meta-type, :class:`sip.wrappertype`.
+
+:class:`sip.simplewrapper` is the super-type of :class:`sip.wrapper`. The
+super-type of :class:`sip.simplewrapper` is :class:`object`.
+
+:class:`sip.wrappertype` is the meta-type of both :class:`sip.simplewrapper`
+and :class:`sip.wrapper`. The super-type of :class:`sip.wrappertype` is
+:class:`type`.
+
+:class:`sip.wrapper` supports the concept of object ownership described in
+:ref:`ref-object-ownership` and, by default, is the super-type of all the types
+that SIP generates.
+
+:class:`sip.simplewrapper` does not support the concept of object ownership but
+SIP generated types that are sub-classed from it have Python objects that take
+less memory.
+
+SIP allows a class's meta-type and super-type to be explicitly specified using
+the :canno:`Metatype` and :canno:`Supertype` class annotations.
+
+SIP also allows the default meta-type and super-type to be changed for a module
+using the :directive:`%DefaultMetatype` and :directive:`%DefaultSupertype`
+directives. Unlike the default super-type, the default meta-type is inherited
+by importing modules.
+
+If you want to use your own meta-type or super-type then they must be
+sub-classed from one of the SIP provided types. Your types must be registered
+using :cfunc:`sipRegisterPyType()`. This is normally done in code specified
+using the :directive:`%InitialisationCode` directive.
+
+As an example, PyQt4 uses :directive:`%DefaultMetatype` to specify a new
+meta-type that handles the interaction with Qt's own meta-type system. It also
+uses :directive:`%DefaultSupertype` to specify that the smaller
+:class:`sip.simplewrapper` super-type is normally used. Finally it uses
+:canno:`Supertype` as an annotation of the ``QObject`` class to override the
+default and use :class:`sip.wrapper` as the super-type so that the parent/child
+relationships of ``QObject`` instances are properly maintained.
+
+
+.. _ref-lazy-type-attributes:
+
+Lazy Type Attributes
+--------------------
+
+Instead of populating a wrapped type's dictionary with its attributes (or
+descriptors for those attributes) SIP only creates objects for those attributes
+when they are actually needed. This is done to reduce the memory footprint and
+start up time when used to wrap large libraries with hundreds of classes and
+tens of thousands of attributes.
+
+SIP allows you to extend the handling of lazy attributes to your own attribute
+types by allowing you to register an attribute getter handler (using
+:cfunc:`sipRegisterAttributeGetter()`). This will be called just before a
+type's dictionary is accessed for the first time.
+
+
+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.
+
+
+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 :cfunc:`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 :cfunc:`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.
+
+
+.. _ref-gil:
+
+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 :fanno:`ReleaseGIL` annotation can be used to
+override this behaviour when required.
+
+If SIP is given the :option:`-g <sip -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 :fanno:`HoldGIL` annotation can be used to
+override this behaviour when required.
+
+
+.. _ref-incompat-apis:
+
+Managing Incompatible APIs
+--------------------------
+
+.. versionadded:: 4.9
+
+Sometimes it is necessary to change the way something is wrapped in a way that
+introduces an incompatibility. For example a new feature of Python may
+suggest that something may be wrapped in a different way to exploit that
+feature.
+
+SIP's :directive:`%Feature` directive could be used to provide two different
+implementations. However this would mean that the choice between the two
+implementations would have to be made when building the generated module
+potentially causing all sorts of deployment problems. It may also require
+applications to work out which implementation was available and to change
+their behaviour accordingly.
+
+Instead SIP provides limited support for providing multiple implementations
+(of classes, mapped types and functions) that can be selected by an
+application at run-time. It is then up to the application developer how they
+want to manage the migration from the old API to the new, incompatible API.
+
+This support is implemented in three parts.
+
+Firstly the :directive:`%API` directive is used to define the name of an API
+and its default version number. The default version number is the one used if
+an application doesn't explicitly set the version number to use.
+
+Secondly the :canno:`API class <API>`, :manno:`mapped type <API>` or
+:fanno:`function <API>` annotation is applied accordingly to specify the API
+and range of version numbers that a particular class, mapped type or function
+implementation should be enabled for.
+
+Finally the application calls :func:`sip.setapi` to specify the version number
+of the API that should be enabled. This call must be made before any module
+that has multiple implementations is imported for the first time.
+
+Note this mechanism is not intended as a way or providing equally valid
+alternative APIs. For example::
+
+ %API MyAPI 1
+
+ class Foo
+ {
+ public:
+ void bar();
+ };
+
+ class Baz : Foo
+ {
+ public:
+ void bar() /API=MyAPI:2-/;
+ };
+
+If the following Python code is executed then an exception will be raised::
+
+ b = Baz()
+ b.bar()
+
+This is because when version 1 of the *MyAPI* API (the default) is enabled
+there is no *Baz.bar()* implementation and *Foo.bar()* will not be called
+instead as might be expected.