在深入研究 NumPy 标头后,我想我找到了解决方案:
in numpy/__multiarray_api.h
,有一节讨论内部 API 缓冲区应该在哪里。为了简洁起见,以下是相关片段:
#if defined(PY_ARRAY_UNIQUE_SYMBOL)
#define PyArray_API PY_ARRAY_UNIQUE_SYMBOL
#endif
#if defined(NO_IMPORT) || defined(NO_IMPORT_ARRAY)
extern void **PyArray_API;
#else
#if defined(PY_ARRAY_UNIQUE_SYMBOL)
void **PyArray_API;
#else
static void **PyArray_API=NULL;
#endif
#endif
看起来这是为了允许多个模块定义自己的内部 API 缓冲区,其中每个模块必须调用自己的import_array
define.
让多个翻译单元使用相同内部 API 缓冲区的一致方法是在每个模块中定义PY_ARRAY_UNIQUE_SYMBOL
某个库的唯一名称,然后每个翻译单元除了定义 import_array 包装器的包装器之外定义NO_IMPORT
or NO_IMPORT_ARRAY
。顺便说一句,ufunc 功能也有类似的宏:PY_UFUNC_UNIQUE_SYMBOL
, and NO_IMPORT
/NO_IMPORT_UFUNC
.
修改后的工作示例:
header1.hpp
#ifndef HEADER1_HPP
#define HEADER1_HPP
#ifndef MYLIBRARY_USE_IMPORT
#define NO_IMPORT
#endif
#define PY_ARRAY_UNIQUE_SYMBOL MYLIBRARY_ARRAY_API
#define PY_UFUNC_UNIQUE_SYMBOL MYLIBRARY_UFUNC_API
#include <Python.h>
#include <numpy/npy_3kcompat.h>
#include <numpy/arrayobject.h>
void initialize();
#endif
文件1.cpp
#define MYLIBRARY_USE_IMPORT
#include "header1.hpp"
void* wrap_import_array()
{
import_array();
return (void*) 1;
}
void initialize()
{
wrap_import_array();
}
文件2.cpp
#include "header1.hpp"
#include <iostream>
int main()
{
Py_Initialize();
initialize();
npy_intp dims[] = {5};
std::cout << "creating descr" << std::endl;
PyArray_Descr* dtype = PyArray_DescrFromType(NPY_FLOAT64);
std::cout << "zeros" << std::endl;
PyArray_Zeros(1, dims, dtype, 0);
std::cout << "cleanup" << std::endl;
return 0;
}
我不知道这个黑客有什么陷阱,或者是否有更好的替代方案,但这似乎至少编译和运行没有任何段错误。