Cython:使用distutils编译C++
Cython: using distutils to compile C++
我正在尝试包装一些 C++ 神经网络代码,因此我有:
numpy -> double* -> armadillo
无论如何,我得到了典型的:
ImportError: dynamic module does not define init function
很明显是我的distutils配置有问题。这是我的项目的 MEW,以防有人发现错误:
setup.py
#!/usr/bin/env python build_ext --inplace
# -*- coding: utf-8 -*-
# to run:
# python setup.py build_ext --inplace
from distutils.core import setup, Extension
from Cython.Build import cythonize
setup(
name='My Test',
ext_modules = cythonize(Extension(
"test",
sources=["nnet_wrap.pyx", "nnet.cpp"],
libraries = ['armadillo'],
language="c++",
)))
nnet_wrap.pyx
import numpy as np
cimport numpy as np
cdef extern from "nnet.h":
void nnet_fit(int D, int N, double* X, double* Y)
class WrapNN:
def nnet_fit(self, np.ndarray[np.double_t, ndim=2] X):
X = np.ascontiguousarray(X)
cdef np.ndarray[np.double_t, ndim=1] y = np.zeros((len(X),), dtype=np.double)
nnet_fit(X.shape[1], X.shape[0], &X[0,0], &y[0])
return y
nnet.h
void nnet_fit(int D, int N, double* X, double* Y);
nnet.cpp
#include <armadillo>
using namespace arma;
void nnet_fit(int D, int N, double* X, double* Y)
{
mat _X(X, N, D, false);
// do work
vec _Y; // results
for(int i = 0; i < N; i++)
Y[i] = _Y[i];
}
我知道这有点老套。无论如何,它编译得很好并生成了一个 test.so
文件,但是导入失败:
$ python setup.py build_ext --inplace
$ python
>>> import test
ImportError: dynamic module does not define init function (inittest)
编辑: 根据要求提供更多信息:
$ readelf -Ws test.so | grep init
118: 0000000000003168 0 FUNC GLOBAL DEFAULT 9 _init
123: 000000000000ab90 160 FUNC WEAK DEFAULT 11 _ZN4arma3MatIdE9init_coldEv
126: 0000000000009ae0 4211 FUNC GLOBAL DEFAULT 11 initnnet_wrap
42: 00000000000036e0 79 FUNC LOCAL DEFAULT 11 _ZL30__Pyx_CyFunction_init_defaultsP22__pyx_CyFunctionObject
202: 000000000020f3e0 1 OBJECT LOCAL DEFAULT 24 _ZStL8__ioinit
211: 000000000020dce0 0 OBJECT LOCAL DEFAULT 17 __frame_dummy_init_array_entry
306: 0000000000009ae0 4211 FUNC GLOBAL DEFAULT 11 initnnet_wrap
330: 000000000000ab90 160 FUNC WEAK DEFAULT 11 _ZN4arma3MatIdE9init_coldEv
344: 0000000000003168 0 FUNC GLOBAL DEFAULT 9 _init
顺便说一下,我的 Cython 版本是 Ubuntu 14.04 版本,可能有点过时了。我知道某些语法已从 distutils 更改。如果您认为这可能是个问题,请告诉我。
$ dpkg -s cython | grep Version
Version: 0.20.1+git90-g0e6e38e-1ubuntu2
正在构建的模块名为 nnet_wrap
,但输出文件名为 test.so
。您的 test.so
包含一个名为 initnnet_wrap
的符号(Python 错误地寻找 inittest
)这一事实证实了这一点。
在您的扩展定义中,将 'test'
替换为 'nnet_wrap'
,以便 Python 可以找到正确的符号。
ext_modules = cythonize(Extension(
"test",
# ^^^^
sources=["nnet_wrap.pyx", "nnet.cpp"],
# ^^^^^^^^^
libraries = ['armadillo'],
language="c++",
))
我正在尝试包装一些 C++ 神经网络代码,因此我有:
numpy -> double* -> armadillo
无论如何,我得到了典型的:
ImportError: dynamic module does not define init function
很明显是我的distutils配置有问题。这是我的项目的 MEW,以防有人发现错误:
setup.py
#!/usr/bin/env python build_ext --inplace
# -*- coding: utf-8 -*-
# to run:
# python setup.py build_ext --inplace
from distutils.core import setup, Extension
from Cython.Build import cythonize
setup(
name='My Test',
ext_modules = cythonize(Extension(
"test",
sources=["nnet_wrap.pyx", "nnet.cpp"],
libraries = ['armadillo'],
language="c++",
)))
nnet_wrap.pyx
import numpy as np
cimport numpy as np
cdef extern from "nnet.h":
void nnet_fit(int D, int N, double* X, double* Y)
class WrapNN:
def nnet_fit(self, np.ndarray[np.double_t, ndim=2] X):
X = np.ascontiguousarray(X)
cdef np.ndarray[np.double_t, ndim=1] y = np.zeros((len(X),), dtype=np.double)
nnet_fit(X.shape[1], X.shape[0], &X[0,0], &y[0])
return y
nnet.h
void nnet_fit(int D, int N, double* X, double* Y);
nnet.cpp
#include <armadillo>
using namespace arma;
void nnet_fit(int D, int N, double* X, double* Y)
{
mat _X(X, N, D, false);
// do work
vec _Y; // results
for(int i = 0; i < N; i++)
Y[i] = _Y[i];
}
我知道这有点老套。无论如何,它编译得很好并生成了一个 test.so
文件,但是导入失败:
$ python setup.py build_ext --inplace
$ python
>>> import test
ImportError: dynamic module does not define init function (inittest)
编辑: 根据要求提供更多信息:
$ readelf -Ws test.so | grep init
118: 0000000000003168 0 FUNC GLOBAL DEFAULT 9 _init
123: 000000000000ab90 160 FUNC WEAK DEFAULT 11 _ZN4arma3MatIdE9init_coldEv
126: 0000000000009ae0 4211 FUNC GLOBAL DEFAULT 11 initnnet_wrap
42: 00000000000036e0 79 FUNC LOCAL DEFAULT 11 _ZL30__Pyx_CyFunction_init_defaultsP22__pyx_CyFunctionObject
202: 000000000020f3e0 1 OBJECT LOCAL DEFAULT 24 _ZStL8__ioinit
211: 000000000020dce0 0 OBJECT LOCAL DEFAULT 17 __frame_dummy_init_array_entry
306: 0000000000009ae0 4211 FUNC GLOBAL DEFAULT 11 initnnet_wrap
330: 000000000000ab90 160 FUNC WEAK DEFAULT 11 _ZN4arma3MatIdE9init_coldEv
344: 0000000000003168 0 FUNC GLOBAL DEFAULT 9 _init
顺便说一下,我的 Cython 版本是 Ubuntu 14.04 版本,可能有点过时了。我知道某些语法已从 distutils 更改。如果您认为这可能是个问题,请告诉我。
$ dpkg -s cython | grep Version
Version: 0.20.1+git90-g0e6e38e-1ubuntu2
正在构建的模块名为 nnet_wrap
,但输出文件名为 test.so
。您的 test.so
包含一个名为 initnnet_wrap
的符号(Python 错误地寻找 inittest
)这一事实证实了这一点。
在您的扩展定义中,将 'test'
替换为 'nnet_wrap'
,以便 Python 可以找到正确的符号。
ext_modules = cythonize(Extension(
"test",
# ^^^^
sources=["nnet_wrap.pyx", "nnet.cpp"],
# ^^^^^^^^^
libraries = ['armadillo'],
language="c++",
))