8

numpyのCAPIを使用して、行列計算用の関数をいくつか記述しています。今日は、関数の一部を別の.cファイルに移動し、ヘッダーを使用してそれらを宣言したいと思いました。import_array今、私はnumpyの機能に関係する奇妙な問題を抱えています。私は問題をできるだけ単純化しようとしました。最初に作業プログラムがあります:

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())

init関数から削除import_arrayすると、セグメンテーション違反が発生します。これは、多くのメーリングリストやフォーラムで報告されている動作です。

ここで、 mytest.cmy_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モジュールをいくつかのソースファイルに分割する「クリーンな」方法は何であるかを知りたいです。

4

1 に答える 1

9

デフォルトでは、import_arrayルーチンはNumPyCAPIを単一のファイル内でのみ使用可能にします。これは、静的グローバル変数に格納されている関数ポインターのテーブルを介して機能するためです(つまり、エクスポートされず、同じファイル内でのみ表示されます)。

ドキュメントに記載されているように、いくつかのプリプロセッサ定義を使用してこの動作を変更できます。

  1. 拡張機能のすべてのファイルで、PY_ARRAY_UNIQUE_SYMBOL他の拡張機能と競合する可能性が低い一意の変数に定義します。拡張機能のモジュール名を変数名に含めることをお勧めします。

  2. 呼び出すファイルを除くすべてのファイルでimport_array、シンボルを定義しますNO_IMPORT_ARRAY

これらのシンボルを有効にするには、含める前にこれらのシンボルを定義する必要がありますarrayobject.h

于 2012-09-04T08:35:35.447 に答える