Estoy usando la API C de numpy para escribir algunas funciones para el cálculo de matrices. Hoy quería mover algunas partes de mis funciones en un archivo .c separado y usar un encabezado para declararlas. Ahora tengo un problema extraño que tiene que ver con la función import_array
de numpy. Intenté simplificar el problema tanto como sea posible. En primer lugar está el programa de trabajo:Numpy C API: Vincular varios archivos de objetos
mytest.c
#include "mytest.h"
PyObject* my_sub_function() {
npy_intp dims[2] = {2, 2};
double data[] = {0.1, 0.2, 0.3, 0.4};
PyArrayObject* matrix = (PyArrayObject*)PyArray_SimpleNew(2, dims, NPY_FLOAT64);
memcpy(PyArray_DATA(matrix), data, sizeof(double) * dims[0] * dims[1]);
return (PyObject*)matrix;
}
static PyObject* my_test_function(PyObject* self, PyObject* args) {
return my_sub_function();
}
static PyMethodDef methods[] = {
{"my_test_function", my_test_function, METH_VARARGS, ""},
{0, 0, 0, 0}
};
static struct PyModuleDef module = {
PyModuleDef_HEAD_INIT, "mytest", 0, -1, methods
};
PyMODINIT_FUNC PyInit_mytest() {
import_array();
return PyModule_Create(&module);
}
mytest.h
#ifndef mytest_h
#define mytest_h
#include <Python.h>
#include <numpy/arrayobject.h>
#include <numpy/npy_common.h>
PyObject* my_sub_function();
#endif
Makefile
all: mytest.o sub.o
gcc -shared -Wl,-soname,mytest.so -o mytest.so mytest.o
mytest.o: sub.o
gcc -fPIC -c mytest.c `pkg-config --cflags python3`
clean:
rm -rf *.so
rm -rf *.o
Todo funciona como se esperaba. Puedo llamar make
y luego cargar el módulo y llamar a la función:
test.py
import mytest
print(mytest.my_test_function())
Si me retire import_array
de la función init habría una violación de segmento, que es el comportamiento que ha sido reportado en muchas listas de correo y foros.
Ahora sólo desea eliminar toda la función de my_sub_function
mytest.c y moverlo en un archivo llamado sub.c:
#include "mytest.h"
PyObject* my_sub_function() {
npy_intp dims[2] = {2, 2};
double data[] = {0.1, 0.2, 0.3, 0.4};
PyArrayObject* matrix = (PyArrayObject*)PyArray_SimpleNew(2, dims, NPY_FLOAT64);
memcpy(PyArray_DATA(matrix), data, sizeof(double) * dims[0] * dims[1]);
return (PyObject*)matrix;
}
El nuevo Makefile es:
all: mytest.o sub.o
gcc -shared -Wl,-soname,mytest.so -o mytest.so mytest.o sub.o
mytest.o:
gcc -fPIC -c mytest.c `pkg-config --cflags python3`
sub.o:
gcc -fPIC -c sub.c `pkg-config --cflags python3`
clean:
rm -rf *.so
rm -rf *.o
Si intento cargar el módulo y llamar a la función ahora, la llamada a la función me da una segfault. Puedo resolver el problema si llamo al import_array
en la parte superior de my_sub_function
, pero no creo que esta sea la forma en que se debe usar esa función.
Así que me gustaría saber por qué sucede esto y cuál es la forma "limpia" de dividir un módulo numpy en varios archivos fuente.