如何为静态库编译SWIG Python封装?

2 投票
1 回答
5696 浏览
提问于 2025-04-16 09:28

这是个新手问题。我正在学习如何使用SWIG为一个C++库创建Python接口。这个库是一个第三方的专有库,我得到的只有一个头文件(foo.h)和一个静态库文件(libfoo.a)。

为了简化问题,我做了一个示例,我觉得这个示例有类似的问题。反正错误信息是一样的。

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

作为参考,这里是foo.c。我手头只有真实第三方库的头文件和库文件。

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

我通过输入 g++ -c foo.cxx && ar rcs libfoo.a foo.o 来创建这个库。

我的SWIG接口文件如下:

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

我通过输入

swig -python -c++ foo.i

来生成foo_wrap.cxx。

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

编译是成功的,但当我运行Python并输入 import foo 时,我遇到了未定义符号的错误。

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

这是怎么回事呢?问题似乎出在链接步骤,它找不到构造函数TC::TC的定义。

注意:如果我把链接步骤改成

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

那么一切就正常了。但是对于我真实的问题,这样做可行吗?因为我没有原始的源代码。能不能从.a文件中提取出.o文件?我想这可能可以手动完成,但难道没有什么自动化的方法吗?

1 个回答

8

我不太确定这是否适用于你,但一般来说,目标文件和静态库的顺序是很重要的。这个顺序决定了它们的初始化顺序。

你需要把最通用的对象文件和/或静态库放在最后面,而依赖关系最复杂的对象文件和库则应该放在前面。

举个例子,假设目标文件 A.o 提供了一个函数 A(),而目标文件 B.o 使用了这个函数 A()。你需要这样写:ld -o libmy.so B.o A.o(把最通用的文件 A.o 放在最后)。

你也可以用 objdump -x _foo.so 来检查某个符号是否存在于文件中。

正确的调用方式是:g++ -shared -L. -lpython2.6 -Wl,-soname,_foo.so foo_wrap.o -lfoo -o _foo.so

不要对 -lpython2.6 感到困惑,它是一个在运行时链接的动态库。

撰写回答