Cython构建导致未定义符号
我有一个C++程序,想把它转换成Cython。这个程序用到了一个特定的库,但不知道为什么,导致我无法成功导入模块。顺便说一下,C++程序本身是可以正常工作的。下面是我的setup.py:
ext_modules = [
Extension(
name="libnmfpy",
sources=["interface/nmf_lib.pyx"],
include_dirs = ["../src/", numpy.get_include()],
libraries=["nmf","mpi_cxx","mpi","m"],
library_dirs=["../build/Linux/bin.release","/usr/local/lib/","/usr/lib"],
language="c++",)
]
setup(
name = 'libnmfpy',
cmdclass = {'build_ext': build_ext},
ext_modules = ext_modules,
)
我得提一下,问题似乎出在libnmf这个库上。第一次构建libnmf的时候,这个脚本会出现这样的错误:
/usr/bin/ld: ../build/Linux/bin.release/libnmf.a(nmf.o): relocation R_X86_64_32 against `.rodata' can not be used when making a shared object; recompile with -fPIC
../build/Linux/bin.release/libnmf.a: could not read symbols: Bad value
collect2: error: ld returned 1 exit status
当我用-fPIC重新构建libnmf时,setup生成了一个libnmfpy.so文件,但当我在另一个脚本中导入这个文件时,又出现了之前提到的未定义符号错误:
Traceback (most recent call last):
File "test.py", line 1, in <module>
import libnmfpy
ImportError: $path/cython/libnmfpy.so: undefined symbol: _ZN4elem6lapack3SVDEiiPdiS1_
如果有帮助的话,我在搜索中发现了一些东西:
nm libnmfpy.so | grep _ZN4elem6lapack3SVDEiiPdiS1_
U _ZN4elem6lapack3SVDEiiPdiS1_
nm ../build/Linux/bin.release/libnmf.a | grep _ZN4elem6lapack3SVDEiiPdiS1_
U _ZN4elem6lapack3SVDEiiPdiS1_
这可能是导致错误的原因。我查看了我认为是libnmf构建所依赖的那个库:
nm $another_path/lib/libelemental.a | grep _ZN4elem6lapack3SVDEiiPdiS1_
0000000000005290 T _ZN4elem6lapack3SVDEiiPdiS1_
我对库和链接器还不太熟悉,所以任何帮助都非常感谢。谢谢!
补充:稍微查了一下,我意识到了一些事情。Mac OS X和Linux之间是否有我需要注意的区别?我工作的团队在最初编写这个程序时并没有报告过这样的构建错误。
2 个回答
1
我无法在我的环境中重现你的设置,也无法测试解决方案,因为我没有你的源代码。不过我觉得,当你用 fpic 重新编译 libnmf 时,它是以动态链接的方式重新编译的,而之前是静态链接的。
如果我猜得没错,你可以尝试以下两种方法:
- 再次编译 libnmf,使用
-fPIC
和-static
。 - 修改你的 setup.py 文件,在
libraries
列表中添加"elemental"
,这样链接器就会去获取这个库。
需要注意的是,方法 #1 通常被认为不太理想,但正如我所说,它可能本来就是这样编译的。而方法 #2 可能需要更多的工作,因为如果还有其他需要的库,你也得找到并添加它们。
2
你应该使用 nm -C
来解读你的符号。看起来你在混合使用静态库和共享库,这通常不是个好主意。此外,gcc的链接器是单遍链接器,这意味着库的顺序很重要。你需要按照依赖关系的反向顺序列出库。换句话说,如果a依赖于b,那么在链接器的参数中,b必须出现在a之前。