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

blo*_*gsh 8 c python api gcc numpy

我正在使用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);
}
Run Code Online (Sandbox Code Playgroud)

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
Run Code Online (Sandbox Code Playgroud)

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
Run Code Online (Sandbox Code Playgroud)

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

test.py

import mytest
print(mytest.my_test_function())
Run Code Online (Sandbox Code Playgroud)

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

现在我只想my_sub_functionmytest.c中删除整个函数并将其移动到一个名为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;
}
Run Code Online (Sandbox Code Playgroud)

新的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
Run Code Online (Sandbox Code Playgroud)

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

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

Jam*_*dge 9

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

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

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

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

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