我将 rnnlib 编译为共享库。它是一个 C++ 库。我想从 python 中调用它。我的选择落在了 cython 上。所以我创建了一个c++函数
void libCall(int argc, char* argv[])
实际上与 rnnlib 的主函数相同,但重命名为使其更易于调用。 rnnlib 库在里面 /usr/lib
rnn.pyx
# distutils: language = c++
cdef extern from "libcall.hpp":
void libCall(int argc, char* argv[])
cpdef call():
print 'hallo welt'
setuprnn.py
from distutils.core import setup
from Cython.Build import cythonize
from distutils.extension import Extension
import os
os.environ["CC"] = "gcc"
os.environ["CXX"] = "g++"
os.environ["CFLAGS"]="-I./src/"
setup(ext_modules = cythonize(
"rnn.pyx",
libraries=["rnnlib","netcdf_c++","netcdf","m","stdc++"],
language="c++",
))
附加test.cpp
#include <iostream>
#include "libcall.hpp"
using namespace std;
int main(int argc, char* argv[]) {
libCall(argc, argv);
}
使用
构建 test.cppg++ -Wall -I./src/ test.cpp -lrnnlib -lnetcdf_c++ -lnetcdf -lm -lstdc++ -o 测试 有效。
当我跑步
python setuprnn.py build_ext -i
时,我得到 rnn.so
和 rnn.cpp
。但是当我运行 python 并输入 import rnn
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ImportError: ./rnn.so: undefined symbol: _ZNK5NcVar3getEPcPKl
用 nm 产量检查
rnn.so
:
000000000003f140 W _ZNK5Mdrnn5printERSo
U _ZNK5NcDim4sizeEv
U _ZNK5NcVar3getEPcPKl
这很奇怪,因为这似乎是缺少的符号。
我无法复制你的问题。这是我创建的脚本,用于创建文件、构建扩展并在 python 中运行代码:
#!/bin/sh -e
echo "Cleaning up /tmp"
rm -f /tmp/rnn.pyx /tmp/rnn.so /tmp/setuprnn.py /tmp/libcall.hpp /tmp/rnn.cpp /tmp/rnn.so
rm -rf /tmp/build/
echo "Creating /tmp/rnn.pyx"
cat > /tmp/rnn.pyx << EOF
# distutils: language = c++
cdef extern from "libcall.hpp":
void libCall(int argc, char* argv[])
cpdef call():
print 'hallo welt'
EOF
echo "Creating /tmp/setuprnn.py"
cat > /tmp/setuprnn.py << EOF
from distutils.core import setup
from Cython.Build import cythonize
from distutils.extension import Extension
import os
os.environ["CC"] = "gcc"
os.environ["CXX"] = "g++"
os.environ["CFLAGS"]="-I./src/"
setup(ext_modules = cythonize(
"rnn.pyx", # our Cython source
libraries=["rnnlib","netcdf_c++","netcdf","m","stdc++"], # additional source file(s)
language="c++", # generate C++ code
))
EOF
echo "Creating /tmp/libcall.hpp"
touch /tmp/libcall.hpp
echo "Building rnn.so extension"
python setuprnn.py build_ext -i
python -c "import rnn; print('-' * 30); print('Imported rnn'); print(dir(rnn))"
这是我得到的结果:
Cleaning up /tmp
Creating /tmp/rnn.pyx
Creating /tmp/setuprnn.py
Creating /tmp/libcall.hpp
Building rnn.so extension
Compiling rnn.pyx because it changed.
Cythonizing rnn.pyx
running build_ext
building 'rnn' extension
creating build
creating build/temp.linux-x86_64-2.7
gcc -fno-strict-aliasing -DNDEBUG -g -fwrapv -O2 -Wall -Wstrict-prototypes -I./src/ -fPIC -I/usr/include/python2.7 -c rnn.cpp -o build/temp.linux-x86_64-2.7/rnn.o
cc1plus: warning: command line option ‘-Wstrict-prototypes’ is valid for C/ObjC but not for C++ [enabled by default]
g++ -pthread -shared -Wl,-O1 -Wl,-Bsymbolic-functions -Wl,-Bsymbolic-functions -Wl,-z,relro -fno-strict-aliasing -DNDEBUG -g -fwrapv -O2 -Wall -Wstrict-prototypes -D_FORTIFY_SOURCE=2 -g -fstack-protector --param=ssp-buffer-size=4 -Wformat -Werror=format-security -I./src/ build/temp.linux-x86_64-2.7/rnn.o -o /tmp/rnn.so
------------------------------
Imported rnn
['__builtins__', '__doc__', '__file__', '__name__', '__package__', '__test__', 'call']
我觉得不错。当然,我没有正确实现您的所有代码,并且我编写的任何内容都无法引入 netcdf 或您引用的其他库。也许您可以更新您的描述,以便其他人可以测试一下?
抱歉没有早点发帖,我现在真的很忙。 所以是的,总的来说休布朗你是对的。它应该有效。问题是我的库的依赖关系。 Cython 没有捕获它。
上面的 python 脚本(setuprnn.py)除了执行以下命令之外什么也不做:
cython ...
gcc ...
g++ ... -lrnnlib -lnetcdf -lstdc++ -o rnn.so
这会产生如上所述的问题。解决方案就是创建一个用于创建库的 shell 脚本:
#!/bin/sh
cython ...
gcc ...
g++ ... -o rnn.so -lnetcdf_c++ -lnetcdf -lm -lstdc++ -lrnnlib
我希望这可以帮助后代不要浪费太多时间:)