I am trying to reuse some old c code with SWIG and Python. Right now I am quite confused. The errors I get can be demonstrated on a small example:
bsp.h:
extern void add(int a[], int b[], int c[]);
bsp.c:
#include "bsp.h" void add(int a[], int b[], int c[]) { c[0] = a[0] + b[0]; c[1] = a[1] + b[1]; }
bsp.i
%module bsp %{ #include "bsp.h"; %} %include "bsp.h";
setup.py:
#!/usr/bin/env python from distutils.core import setup, Extension bsp_module = Extension('_bsp', sources = ['bsp_wrap.c', 'bsp.c'] ) setup(name = 'bsp', ext_modules = [bsp_module], py_modules = ["bsp"] )
The example Python file "pybsp.py":
import bsp a = [1, 1] b = [1, 1] c = [] bsp.add(a, b, c) print(c)
And I get the error:
Traceback (most recent call last): File "pybsp.py", line 31, in <module> bsp.add(a, b, c) TypeError: in method 'add', argument 1 of type 'int []'
Now, why I am confused is that the SWIG Documentation says: "C/C++ pointers are fully supported by SWIG. Furthermore, SWIG has no problem working with incomplete type information."
I also tried to add
%apply int * INPUT { int *a} %apply int * INPUT { int *b} %apply int * OUTPUT { int *c}
to my .i file, which was recommended in this context, without success. My guess is, that I have to create a pointer like object in Python to pass, but I don't know how that works and also hope, that there is a simpler way.
Thank you very much for your help!
P.S.: As you might guess, this is my first contact with SWIG, so, unfortunately, I was not able to deduce the solution from solutions of seemingly similar problems.
EDIT: I found out that for arrays with given dimensions, as above, NumPy seems to be a good option to avoid the wrapping by hand. Basic examples are given here. Accordingly I changed my function definition to
void add(int* a, int dim_a, int *b, int dim_b, int *c, int dim_c)
Now the wrapper seems to have a chance to convert the NumPy array into a C array.
i-File
%module bsp %{ #define SWIG_FILE_WITH_INIT #include "bsp.h" %} %include "numpy.i" %init %{ import_array(); %} %apply (int* IN_ARRAY1, int DIM1){(int* a, int dim_a), (int* b, int dim_b)} %apply (int* ARGOUT_ARRAY1, int DIM1){(int* c, int dim_c)} %include "bsp.h"
setup.py
#!/usr/bin/env python from distutils.core import setup, Extension import numpy try: numpy_include = numpy.get_include() except AttributeError: numpy_include = numpy.get_numpy_include() bsp_module = Extension('_bsp', sources=['bsp_wrap.c', 'bsp.c'], include_dirs=[numpy_include] ) setup(name='bsp', ext_modules=[bsp_module], py_modules=["_bsp"] )
And finally the python script, where I wanted to use int32 to avoid a type conversion Error (int64 -> int32) from NumPy
import bsp import numpy as np a = np.array([1, 1], dtype=np.int32) b = np.array([1, 1], dtype=np.int32) c = np.array([1, 1], dtype=np.int32) bsp.add(a, b, c) print(c)
Now I got rid of the previous Error, but I have a new one:
File "pybsp.py", line 10, in <module> bsp.add(a, b, c) TypeError: Int dimension expected. 'unknown type' given.
Any suggestions?