2012-09-03 26 views
8

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

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 

一切按预期工作。我可以打电话make然后加载模块和调用该函数:

test.py

import mytest 
print(mytest.my_test_function()) 

如果我会从初始化函数删除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_arraymy_sub_function的顶部,我可以解决问题,但我不认为这是应该使用此功能的方式。

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

回答

8

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

由于mentioned in the documentation,你可以用一些预处理器定义改变这种行为:

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

  2. 在除了一个地方你叫import_array每一个文件,你包括arrayobject.h,以便它们生效之前定义符号NO_IMPORT_ARRAY

这些符号需要定义。