I'm trying to wrap some third-party code from a library in my Python application. Essentially, the function I would like to call takes a struct as input that houses (among other things) pointers to double arrays. A simplified example would be:
myfunc.h:
typedef struct mystruct_t {
int n;
double *x;
} mystruct_t;
double myfunc(mystruct_t* data);
myfunc.c:
#include "myfunc.h"
double myfunc(mystruct_t* data) {
double result = 0.;
for(int i = 0; i < data->n; i++) {
result += data->x[i];
}
return result;
}
Makefile:
CC = gcc
CFLAGS = -g -Wall -fPIC -lm -std=gnu99
all: libmyfunc.so
m.PHONY : clean
libmyfunc.so: myfunc.o
gcc -shared -Wl,-soname,$@ -o $@ $^
%.o: %.c
$(CC) -c $(CFLAGS) $<
clean:
rm -vf libmyfunc.so *.o
I would like to wrap myfunc using NumPy, ctypes.Structure and numpy.ctypeslib so that I can pass NumPy arrays to myfunc as attributes of mystruct_t. So far I've been trying the following:
myfunc.py:
#!/usr/bin/env python
import numpy as np
import numpy.ctypeslib as npct
import ctypes
import os
array_1d_double = npct.ndpointer(dtype=np.double, ndim=1, flags='C_CONTIGUOUS')
class MyStruct(ctypes.Structure):
_fields_ = [
('n', ctypes.c_int16),
('x', array_1d_double)
]
libmyfunc = npct.load_library('libmyfunc', os.path.dirname(__file__))
libmyfunc.myfunc.restype = ctypes.c_double
libmyfunc.myfunc.argtypes = [
ctypes.POINTER(MyStruct)
]
x = np.array([1.0, 2.0, 3.0, 4.0])
mystruct = MyStruct()
mystruct.n = len(x)
mystruct.x = x
res = libmyfunc.myfunc(mystruct)
However, this fails with the following error message:
$ python myfunc.py
Traceback (most recent call last):
File "./myfunc.py", line 26, in <module>
mystruct.x = x
TypeError: cannot be converted to pointer
How do I define my function signatures correctly so that type conversion can happen? Or do I need to convert x somehow before assigning it to mystruct.x?
Unfortunately I cannot change the signature of the method I would like to call and I would like to not have to write wrapper C code unless it is absolutely necessary. The other questions and resources that I've found on this only deal with either ctypes.Structures or numpy.ctypeslib, but can you make them work together?
I've uploaded my reduced example as a gist so you can use it as a starting point.
Many thanks in advance!