Numpy C API:链接多个目标文件

我正在使用numpy的C API来编写一些用于矩阵计算的函数。 今天我想将我的函数的某些部分移动到一个单独的.c文件中,并使用标头来声明它们。 现在我有一个与numpy的import_array函数有关的奇怪问题。 我试图尽可能地简化问题。 起初有工作计划:

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  #include  #include  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 

一切都按预期工作。 我可以调用make然后加载模块并调用函数:

test.py

 import mytest print(mytest.my_test_function()) 

如果我从init函数中删除import_array ,则会出现段错误,这是在许多邮件列表和论坛中报告的行为。

现在我只想从mytest.c中删除整个函数my_sub_function并将其移动到一个名为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; } 

新的Makefile是:

 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 

如果我尝试加载模块并立即调用该函数,则函数调用会给我一个段错误。 如果我将import_array调用到my_sub_function的顶部,我可以解决问题,但我不认为这是应该使用该函数的方式。

所以我想知道为什么会发生这种情况以及将numpy模块拆分成几个源文件的“干净”方法是什么。

默认情况下, import_array例程仅使NumPy C API在单个文件中可用。 这是因为它通过存储在静态全局变量中的函数指针表来工作(即不导出,只在同一文件中可见)。

如文档中所述 ,您可以使用一些预处理器定义来更改此行为:

  1. 在扩展的所有文件中,将PY_ARRAY_UNIQUE_SYMBOL定义为不可能与其他扩展冲突的唯一变量。 在变量名中包含扩展名的模块名称是个好主意。

  2. 在除调用import_array文件之外的每个文件中,定义符号NO_IMPORT_ARRAY

在包含arrayobject.h之前,需要定义这些符号才能使它们生效。