I am trying to access a C function with the following prototype from python using swig:
int cosetCoding(int writtenDataIn, int newData, const int memoryCells, int *cellFailure, int failedCell);
Swig creates the .so with no problems and I can import it into python, but when I try to access it with the following:
cosetCoding.cosetCoding(10,11,8,[0,0,0,0,0,0,0,0],0)
I get the following traceback:
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: in method 'cosetCoding', argument 4 of type 'int *'
The pointer is supposed to be an int array with size defined by memoryCells
We use the SWIG %apply directive to apply the typemap for one-dimensional input arrays of type double to the actual prototype used by rms . Using numpy. i effectively, therefore, requires knowing what typemaps are available and what they do.
To build Python extension modules, SWIG uses a layered approach in which parts of the extension module are defined in C and other parts are defined in Python. The C layer contains low-level wrappers whereas Python code is used to define high-level features.
The Simplified Wrapper and Interface Generator (SWIG) is an open-source software tool used to connect computer programs or libraries written in C or C++ with scripting languages such as Lua, Perl, PHP, Python, R, Ruby, Tcl, and other languages like C#, Java, JavaScript, Go, D, OCaml, Octave, Scilab and Scheme.
SWIG is a software development tool that simplifies the task of interfacing different languages to C and C++ programs. In a nutshell, SWIG is a compiler that takes C/C++ declarations and creates the wrappers needed to access those declarations from other languages including Perl, Python, Tcl, Ruby, Guile, and Java.
Use ctypes if you can. It is simpler. However, since you asked for SWIG, what you need is a typemap describing how to handle the int*. SWIG doesn't know how many integers may be pointed to. Below is hacked from an example in the SWIG documentation on multi-argument typemaps:
%typemap(in) (const int memoryCells, int *cellFailure) {
int i;
if (!PyList_Check($input)) {
PyErr_SetString(PyExc_ValueError, "Expecting a list");
return NULL;
}
$1 = PyList_Size($input);
$2 = (int *) malloc(($1)*sizeof(int));
for (i = 0; i < $1; i++) {
PyObject *s = PyList_GetItem($input,i);
if (!PyInt_Check(s)) {
free($2);
PyErr_SetString(PyExc_ValueError, "List items must be integers");
return NULL;
}
$2[i] = PyInt_AsLong(s);
}
}
%typemap(freearg) (const int memoryCells, int *cellFailure) {
if ($2) free($2);
}
Note that with this definition, when called from Python leave out the memoryCells
parameter and just pass an array such as [1,2,3,4]
for cellFailure
. The typemap will generate the memoryCells
parameter.
P.S. I can post a fully working example (for Windows) if you want it.
Mark is right, you'll need a typemaps. However, there's no need to code the typemap by hand if you use numpy.i
(http://docs.scipy.org/doc/numpy/reference/swig.interface-file.html), which already defines the necessary typemaps to turn C into NumPy arrays and vice versa.
In your case (assuming cellFailure
is an input array) you'll want to use
%apply (int DIM1, int* IN_ARRAY1) {(int memoryCells, int *cellFailure)}
Note (as Mark already pointed out) that this conveniently fuses these 2 parameters in C to a single python array parameter, no need to pass the array length separately. Your call will look like:
from numpy import asarray
cosetCoding.cosetCoding(10,11,asarray([0,0,0,0,0,0,0,0]),0)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With