简体   繁体   中英

Unresolved external symbols building a python C extension with swig against a shared C library

I'm trying to wrap a C library for python using SWIG. I'm on a linux 64-bit sytem (Gentoo) using the standard system toolchain. The library (SUNDIALS) is installed on my system with shared libraries in /usr/local/lib

My interface file is simple (to start with)

%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"

Given the interface file above, I run

$ 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

A little digging to double check things shows

$ 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

As far as I can tell, N_VLinearSum is a wrapper around N_VLinearSum_Serial (there's a parallel implementation too, so presumably, N_VLinearSum in nvecparallel would wrap N_VLinearSum_Parallel). Where I'm lost though is what to do next. Is this a problem with my interface definition, or a problem with my compilation?

We'll I've got it working by linking in an extra library. It seems libsundials_nvecserial.so and brethren don't contain the symbol N_VLinearSum. The SUNDIALS make process places functions and symbols from sundials_nvector.h into different .so files, somewhat counter intuitively.

For now, I got this working with

$ gcc -shared -L/usr/local/lib nvecserial_wrap.o -o _nvecserial.so\
-lsundials_nvecserial -lsundials_cvode
$ python -c "import nvecserial"
$

I'll continue playing around with actual .o files from the source distribution, but considering the intent to distribute the wrapped module eventually using distutils, and that not everyone will have access to the SUNDIALS source on their systems, I'll probably stick with linking in the extra shared library.

Instead of

gcc -shared /usr/local/lib/libsundials_nvecserial.so nvecserial_wrap.o -o _nvecserial.so

try

gcc -shared -L/usr/local/lib nvecserial_wrap.o -o _nvecserial.so -lsundials_nvecserial

The -l should be at end otherwise the lib may not be searched for symbols. This is explained in the ld man page.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM