Home - Forums - Documentation - Gallery - Bugs
Line 143: Line 143:
For more information, read swig manuals, look at cs, cel, csextra, csexternal swig files. They cover a lot of curious situations and can help you to learn more.
For more information, read swig manuals, look at cs, cel, csextra, csexternal swig files. They cover a lot of curious situations and can help you to learn more.
 +
 +
back to [[PyCrystal]]

Revision as of 15:08, 9 October 2007

Contents

Motivation

CS has python wrappers, right, but what happens if you make your own plugins in an external source tree and want to have that accessible from python? This document tries to cover how you can achieve this and much more :)

Introduction

First, you must understand the basics:

  1. You will need to generate a wrapper python module that understands your code.
  2. We use swig for generating python modules.
  3. There is some SCF specific stuff you must be aware of for successfully working with your own python plugins and python.

Procedure

The basic procedure will be as follows:

  1. review what you have and what you want to do
  2. choose a name for your python module
  3. Create a swig .i file for your project.
  4. run swig on this file for creating the correct cpp file
  5. compile the module

Review what you have

You should have a set of header files from your project containing the information about interfaces or classes you want to wrap.

For this howto, we will use csextra repository as an example.

So.. under include/ we have a set of header files. Lets imagine only the csqt interface interests us, so basically we only want to cover that one.

Choose a name for your python module

You must choose a name for your future python module, in this case, we simply choose pycsextra, which seems informative and concise enough.

Creating a swig .i file for your project

Note this is not a full tutorial on working with swig, so only basics will be covered, for more info, refer to the swig manual.

As said in previous section, only csqt interests us in this case, so basic .i file would look as follows (note i removed some special stuff in the real csextra module we shouldnt need).

%module pycsextra
%import "bindings/cspace.i"

%{
#include "crystalspace.h"
#include "include/qtwin.h"
%}

INTERFACE_PRE(iQtWindow);
%include "qtwin.h"
INTERFACE_POST(iQtWindow);

Now, lets go through these lines (almost) one by one and explain them:

%module pycsextra

This is just a declaration about your package name, also informs swig this is the main .i file for a package.

%import "bindings/cspace.i"

This makes your package "know" (but not wrap) all the types and mappings in cs python wrappers. Its useful in case your package deals with cs stuff like csVector3, or in case you inheriting from cs classes.

%{
#include "crystalspace.h"
#include "include/qtwin.h"
%}

Here, the lines between the brackets with percent symbol, go directly into the output cpp code generated by swig. Note you really have to explicitly add in this list any necessary headers, as otherwise swig wont add them itself, and generated code wont compile.

INTERFACE_PRE(iQtWindow);
%include "qtwin.h"
INTERFACE_POST(iQtWindow);

This is the actual place where swig is informed about our own types. We can use %include for each .h file we need to wrap.

The INTERFACE_PRE and INTERFACE_POST directives, are there to add special scf wrapping stuff, so that you can query your interfaces from python. Also adds mappings to handle correctly csPtr, csRef and similar for your interface. Note you should only use these on interfaces actually inheriting from ibase.

Ok! This is it.

run swig on this file for creating the correct cpp file

If you have a jam based build system, you can simply copy the jam files from csextra for your own project, otherwise, you can run swig yourself with a command similar to this one:

swig -python -c++ -shadow -I/home/caedes/SVN/CS//include -I./include \
-I./include -outdir . -o /out/linuxx86/optimize/plugins/pycsextra/cs_csextra.cpp \
./include/bindings/pycsextra.i

Note 'cs_csextra.cpp' will be the generated code, 'pycsextra.i' is your input interface files, and the extra options for doing python wrappers, handling cpp and so on. If you are curious there is lots of interesting options for swig :)

compile the module

Again, if using jam compile system, adapting the files from pycsextra module should suffice. If using msvc, you can probably look somewhere how to compile the cpp and link it to python and crystalspace.


Using your python module

Should be simple, you just "import yourmodule". Then you can use your interfaces, for example for querying for a component loaded through registry, just use 'CS_QUERY_REGISTRY(object_reg_ptr,iMyInterface)'

Appendices

The plugins/pycsextra/csextramod.cpp file

You might have noticed in cs python modules there is one extra file exporting an special function, something like:

CS_IMPLEMENT_FOREIGN_DLL

extern "C" void SWIG_init_pycsextra();

extern "C" CS_EXPORT_SYM_DLL void init_pycsextra ()
{
  SWIG_init_pycsextra();
}

Interestingly enough, this is not really needed, but maybe you have to cope with it, i will explain the situation: the file is made to export an init_<modulename> function to the dll, this is already done by swig, but cs build system mangles this to look like SWIG_init_<modulename>. This is done like this so you can call the function yourself, but should not really be needed and hopefully will be removed soon. Meanwhile, be prepared to deal with this.

Declaring scfImplementation<>

Many times, constructs like this are used in cs classes:

class csPath : public scfImplementation1<csPath, iPath>

This is not a big problem to swig, but it wont wrap the template unless you explicitly declare it with a special directive. If you dont wrap it, the result is swig won't know about the inheritance here, so you loose the inherited functions or interface in the wrapper (so for example you wouldn't be able to use an csPath in the place where an iPath is required).

Dealing with this is simple enough, add the following to the swig file:

%template(scfPath) scfImplementation1<csPath,iPath >;

This basically tells swig what name to use for the templated class (only thing swig needs, really, and this is because the template notation is incompatible with most scripting languages).

Far and away

For more information, read swig manuals, look at cs, cel, csextra, csexternal swig files. They cover a lot of curious situations and can help you to learn more.

back to PyCrystal

| Article | Discussion | View source | History |