newbie-question: extending python with c++

Siegfried Gonzi siegfried.gonzi at kfunigraz.ac.at
Tue Apr 16 05:10:01 EDT 2002


Fernando Pérez wrote:

> Could you share that mini-howto here with the rest of us? I'm sure that more
> than one would find it useful.


I think it is not inappropiate to post here the instruction (thought I
got it due to private mail; but there is no private junk in it and hence
I believe the original author does not mind: author: Luigi Ballabio; I
augmented Luigi's B. stuff with the pointer stuff and some other
explanations).

The example is not really related to C++ but it demonstrates the recipe
well.

In the SWIG manual there is an example demonstration, which is as
follows:

A) The C code:

/* File : example.c */
/* A global variable */
double Foo = 3.0;

/* Compute the greatest common divisor of positive integers */
int gcd(int x, int y) {
  int g;
  g = y;
  while (x > 0) {
    g = x;
    x = y % x;
    y = g;
  }
  return g;
}

Save the above code to a file called "example.c".

B) You want to make an includable Python function of the above C code:
Construct an Python setup file:

from distutils.core import setup, Extension

setup(name         = "Example",
       description  = "Example Python extension",
       py_modules   = [],
       ext_modules  = [Extension("example",
                                
["C:/Wissenschaft/SWIG-1.3.11/ex/example_wrap.c",
				  "C:/Wissenschaft/SWIG-1.3.11/ex/example.c"],
                                 libraries = [],
                                 define_macros = [],
                                 include_dirs =
[C:/Wissenschaft/SWIG-1.3.11/ex/],
                                 library_dirs = [],
                                 extra_compile_args = [],
                                 extra_link_args = [])
                      ]
      )

This file called "setup.py" and should reside in the same folder as
example.c! Look carefully to the above scheme:

a) C:/Wissenschaft/SWIG-1.3.11/ex/ is my directory where example.c and
setup.py resides; yours can differ!

b) The stuff (right after "example") tells you where to find
"example_wrap.c" (which, see below, swig will create) and "example.c".
If lets say your example.c includes some header files, e.g.
"myMathHeader.h" then you would possibly include the C function here:
"MyMathHeader.c".

C) The SWIG specific stuff: Create first an file called "example.i",
where you specify your functions which you want to become visible (this
are then the functions which you can use in your Python environment):

/*File: example.i*/

%module example  
extern int gcd(int x, int y);
extern double Foo;


[example.i should reside in the directory where you store example.c and
setup.py]

D) Setup Microsoft Visual C++ (I am not sure how it works with other
compilers):
 
Your MVC++ installation created a file named vcvars32.bat which 
sets up the environment for using MVC++ from the command line. Run it 
before the next step, or add its contents to your autoexec.bat so 
that you can forget it ever after.

If you do not find vcvars32.bat easily: let Windows search for you and
change to that directoy (in your DOS command line window) and follow
point D), and type: vcvars32.bat


E) I have not set a gloabl variable for the SWIG and Python environment,
so I have always to change the directory in order to follow the next
steps (remember: C:/Wissenschaft/SWIG-1.311/ex/ is just my directory;
yours can differ): 

 1.1 swig -python C:/Wissenschaft/SWIG-1.3.11/ex/example.i
     [step 1.1 creates example_wrap.c] 
 1.2 I have to change to the Python directory:
 1.3 python C:/Wissenschaft/SWIG-1.3.11/ex/setup.py build
 If everything is okay you can move on:
 1.4 python C:/Wissenschaft/SWIG-1.3.11/ex/setup.py install
     [step 1.4 will put a file in the directory
/Python/Lib/site-packages

Now you can fire up your Python environment and include the functions:

from example import*
s = gcd(3,4)



Then I used the above scheme to create my  Mie calculation Python
function; I encounterd some problems:

a) I had to pass pointers to my C function, e.g.  c-function(float a,
float* p, float* d,...)

where p is an array pointer and d is just a pointer to a float; they all
become updated

b) In SWIG you realize this by including "-lpointer" :
		swig -python -lpointer example.i

This will make that you then can use some pointer-functions in your
Python environment after importing example.py.
 
c) If you want to use this c-function in Python, you would have to
create an array:

from c-function import*

p = ptrcreate("float",0,10)

creates an vector with 10 floating point (C floating points) values
initialzed to 0.

BUG: creating an arary with only 1 dimension results on my machine to
unforseeable idle crashes; I think there is maybe a SWIG bug. For
example I had to pass 4 differetn floating point pointers (float*
a,float* b,float* c,float* d). I did this as:

a = ptrcreate("float",0,1) and so on

This does not really work. I rewrote the C function and passed an array
which becomes updated with the 4 values: ptrcreate("float",0,4). I think
creating an array with dimension 1 is buggy (but you would have to play
around yourself in order to figure it out).


Your C function delivers you the pointer back and you can convert it to
a Python object (see also the SWIG manual):

def build_list(p,nitems):
	l = []
        for i in range(0,nitems):
        	l.append( ptrvalue(p,i) )
        return l

list_a = build_list(p,10)

and it is wise to dispose then the pointer in Python:  ptrfree(p)  

You can then work on with list_a.

I got the advise from the developers to use the dirty pointer stuff only
for quick hacks. Otherwise: you should invest time and try to use
typemap (see the SWIG documentation), which is much more elegant and
safe.


Thank you Mr. Gonzi for improving the world,
S. Gonzi



More information about the Python-list mailing list