构建Python C扩展时与共享C库的未解决外部符号
我正在尝试使用SWIG将一个C语言库封装成Python库。我是在一个64位的Linux系统(Gentoo)上,使用的是标准的系统工具链。这个库(SUNDIALS)已经安装在我的系统上,相关的共享库放在/usr/local/lib
目录下。
我的接口文件很简单(刚开始的时候)
%module nvecserial
%{
#include "sundials/sundials_config.h"
#include "sundials/sundials_types.h"
#include "sundials/sundials_nvector.h"
#include "nvector/nvector_serial.h"
%}
%include "sundials/sundials_config.h"
%include "sundials/sundials_types.h"
%include "sundials/sundials_nvector.h"
%include "nvector/nvector_serial.h"
根据上面的接口文件,我运行了
$ swig -python -I/usr/local/include nvecserial.i
$ gcc -O2 -fPIC -I/usr/include/python2.7 -c nvecserial_wrap.c
$ gcc -shared /usr/local/lib/libsundials_nvecserial.so nvecserial_wrap.o -o _nvecserial.so
$ python -c "import nvecserial"
Traceback (most recent call last):
File "<string>", line 1, in <module>
File "nvecserial.py", line 28, in <module>
_nvecserial = swig_import_helper()
File "nvecserial.py", line 24, in swig_import_helper
_mod = imp.load_module('_nvecserial', fp, pathname, description)
ImportError: ./_nvecserial.so: undefined symbol: N_VLinearSum
稍微查了一下,确认了一些事情,结果显示
$ objdump -t /usr/local/lib/libsundials_nvecserial.so |grep Linear
0000000000001cf0 g F .text 00000000000002e4 N_VLinearSum_Serial
$ objdump -t _nvecserial.so |grep Linear
00000000000097e0 l F .text 0000000000000234 _wrap_N_VLinearSum
000000000000cd10 l F .text 0000000000000234 _wrap_N_VLinearSum_Serial
0000000000000000 *UND* 0000000000000000 N_VLinearSum
0000000000000000 F *UND* 0000000000000000 N_VLinearSum_Serial
据我了解,N_VLinearSum是N_VLinearSum_Serial的一个封装(还有一个并行的实现,所以可以推测,nvecparallel中的N_VLinearSum会封装N_VLinearSum_Parallel)。不过我现在不太明白接下来该怎么做。是我的接口定义有问题,还是我的编译有问题呢?
2 个回答
0
不要这样做:
gcc -shared /usr/local/lib/libsundials_nvecserial.so nvecserial_wrap.o -o _nvecserial.so
试试这样:
gcc -shared -L/usr/local/lib nvecserial_wrap.o -o _nvecserial.so -lsundials_nvecserial
“-l”这个选项应该放在最后,否则可能找不到库里的符号。这个在ld的手册里有解释。
1
我通过链接一个额外的库让它工作了。看起来 libsundials_nvecserial.so
以及类似的文件里没有 N_VLinearSum 这个符号。SUNDIALS 的构建过程把 sundials_nvector.h
里的函数和符号放到了不同的 .so 文件里,这有点让人摸不着头脑。
目前,我是通过以下方式让它工作的:
$ gcc -shared -L/usr/local/lib nvecserial_wrap.o -o _nvecserial.so\
-lsundials_nvecserial -lsundials_cvode
$ python -c "import nvecserial"
$
我会继续尝试从源代码分发中获取实际的 .o 文件,但考虑到最终打算使用 distutils 来分发这个封装模块,并且并不是每个人的系统上都有 SUNDIALS 的源代码,我可能会继续链接这个额外的共享库。