Question

This is a noob question. I'm trying to learn how to use SWIG to make a python interface for a C++ library. The library is a proprietary 3rd party library; it comes to me in the form of a header file (foo.h) and a static archive (libfoo.a).

To simplify matters, I've cooked up an example which I think has the same pathology. Same error messages anyways.

/* foo.hpp */
class TC {
    public:
       TC();
       int i;
    private:
};

For reference, here's foo.c. I only have the header and archive files for the real 3rd party library.

/*foo.cxx */
#include "foo.hpp"
TC::TC() {
    i = 0;
}

I made this library by typing g++ -c foo.cxx && ar rcs libfoo.a foo.o

My SWIG interface file is as follows:

/* foo.i */ 
%module foo
%{
#include "foo.hpp"
%}
%include "foo.hpp"

I generate foo_wrap.cxx by typing

swig -python -c++ foo.i

and then compile.

g++ -c -fPIC -I/usr/include/python2.6 foo_wrap.cxx 
g++ -shared -L. -lfoo -lpython2.6 -Wl,-soname,_foo.so foo_wrap.o -o _foo.so

The compilation succeeds, but when I run Python and import foo, I get an undefined symbol error.

>>> import foo
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
  File "foo.py", line 25, in <module>
    _foo = swig_import_helper() 
  File "foo.py", line 21, in swig_import_helper
    _mod = imp.load_module('_foo', fp, pathname, description)
ImportError: ./_foo.so: undefined symbol: _ZN2TCC1Ev

What's going on here? The problem seems to be that the linking step isn't finding the definition of the constructor TC::TC.

Note: If I alter the linking step to

g++ -shared -L. -lfoo -lpython2.6 -Wl,-soname,_foo.so foo_wrap.o -o _foo.so

then everything works. But is this an option for my real problem, where I don't have the raw source code? Can one extract a .o from a .a? Presumably one can do this by hand, but shouldn't there be some automated way of doing it?

Was it helpful?

Solution

I'm not really sure if it's the case for you but in general the order of object files and static libraries matters. The order defines the order of initialisation.

You have to put the most general objects and/or static archives as last parameters. The objects/archives with the most dependencies have to be placed at the beginning.

An example. The object file A.o offer the fucntion A(). The object B.o uses the function A(). You have to write ld -o libmy.so B.o A.o (the most general file A.o as last parameter).

You can also check with objdump -x _foo.so if the symbol exists in the file.

The right call would be: g++ -shared -L. -lpython2.6 -Wl,-soname,_foo.so foo_wrap.o -lfoo -o _foo.so

Do not be confused with -lpython2.6, it's a dynamic library linked at runtime.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top