构建Python C扩展时与共享C库的未解决外部符号

0 投票
2 回答
886 浏览
提问于 2025-04-18 13:42

我正在尝试使用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 的源代码,我可能会继续链接这个额外的共享库。

撰写回答