1 最常用的编译方式: 动态编译
最常用的莫过于上一章SWIG入门1里所讲的方法了
$ swig -python example.i $ gcc -O2 -fPIC -c example.c $ gcc -O2 -fPIC -c example_wrap.c -I/usr/include/python2.6 $ gcc -shared example.o example_wrap.o -o _example.so
这里的动态编译指的是将源代码(example.c) 和 封装接口的代码(example_wrap.c)编译到一个动态库(_example.so)中。在PYTHON中你就可以利用example.py的接口直接调用_example.so中的代码。
-I/usr/include/python2.6
这个参数自然取决于你的python的安装位置了。有的系统也可能在/usr/local/include/python2.6等等目录下。
2 少见的编译方式: 静态编译
静态编译的原理,因为python是通过解释器运行的,所以你可以把你写的模块直接编译到python解释器的可执行程序里。这种方法在以前比较流行,原因是以前的一些机器对于动态库的支持不够好,迫于无奈的采用这种方法。现在这种状况已经得到完全改善了,所以最好不要采用这种方法。不过作为一篇介绍swig的用法的文字,还是会简要介绍一下。
与动态编译有一点不同的是,你需要在.i脚本中增加一行:%include "embed.i" 。 否则在编译的时候会提示你找不到main函数。embed.i这个文件提供了重新编译python的一切东西。
然后你的.i文件会变成这样。
//file foo.i %module foo %{ extern int bar(); %} %include "embed.i" extern int bar();
foo.c文件是这样:
//file foo.c #include <stdio.h> int bar() { printf("hello it is bar\n"); return 0; }
Makefile文件是这样:
#Makefile CFLAG= -g -Werror -O3 all: mypython foo.py foo_wrap.c: foo.i swig -python foo.i clean: rm -f mypython foo_wrap.c foo.py mypython: foo_wrap.c gcc foo.c foo_wrap.c \ -Xlinker -export-dynamic \ -DHAVE_CONFIG_H -I/usr/include/python2.6 \ -I/usr/lib/python2.6/config \ -L/usr/lib/python2.6/config -lpython2.6 -lm -ldl \ -o mypython
然后你就可以通过你自己编译的mypython这个bin文件来调用foo模块了。
costa@pepsi:~/test/swig/second$ ./mypython Python 2.6.6 (r266:84292, Dec 27 2010, 00:18:12) [GCC 4.4.5] on linux2 Type "help", "copyright", "credits" or "license" for more information. >>> import foo >>> foo.bar() hello it is bar 0 >>>
需要注意的几个问题:
a. 这种方式在性能上并不会有太大提升
b. embed.i这个文件已经deprecated很多年没有维护了。不过,经过我的验证在python2.6上是可以工作正常。
总之,不到万不得已是不要采用静态编译的。
3 C++的编译
swig现在也可以支持C++的代码的调用。方法也非常简单,与C无异。
//file: foo.h class Foo{ private: int bar1; public: Foo(int bar); ~Foo(); int bar(); };
//file: foo.cpp #include "foo.h" #include <iostream> using namespace std; Foo::Foo(int bar):bar1(bar) { } Foo::~Foo() { cout<<"descrutive Foo"<<endl; } int Foo::bar() { cout<<"this is "<<bar1<<endl; return 0; }
//file: foo.i %module foo %{ #include "foo.h" %} %include "foo.h"
#file: Makefile CFLAGS= -g -Werror -O3 INC_PYTHON= -I /usr/include/python2.6 all: _foo.so foo.o: foo.cpp foo.h g++ ${CFLAGS} -c foo.cpp foo_wrap.cxx foo.py: foo.i foo.h swig -python -c++ foo.i foo_wrap.o: foo_wrap.cxx g++ ${CFLAGS} -c $^ ${INC_PYTHON} -o $@ _foo.so: foo.o foo_wrap.o g++ ${CFLAGS} -shared -fPIC -o $@ $^ clean: rm -f foo.o foo_wrap.o foo_wrap.cxx foo.py foo.pyc _foo.so
注意到调用swig的时候要多加一个-c++这个参数。
最后就可以使用python的Foo类了。
Python 2.6.6 (r266:84292, Dec 27 2010, 00:02:40) [GCC 4.4.5] on linux2 Type "help", "copyright", "credits" or "license" for more information. >>> import foo >>> fo=foo.Foo() Traceback (most recent call last): File "<stdin>", line 1, in <module> File "foo.py", line 76, in __init__ this = _foo.new_Foo(*args) TypeError: new_Foo() takes exactly 1 argument (0 given) >>> fo=foo.Foo(1) >>> fo.bar() this is 1 0
4 使用swig常出现的一些错误。
>>> import example Traceback (most recent call last): File "<stdin>", line 1, in ? File "example.py", line 2, in ? import _example ImportError: No module named _example
这种错误的原因是动态库的命名不正确。正确的命名是_example.so。
>>> import example Traceback (most recent call last): File "<stdin>", line 1, in ? ImportError: dynamic module does not define init function (init_example) >>>
出现这样错误有两种可能的原因。第一种原因和上面一样,动态库的命名不正确。第二种原因是.i文件中的%module指令指定的模块名称不正确。
Traceback (most recent call last): File "example.py", line 3, in ? import example ImportError: ./_example.so: undefined symbol: fact
假如出现这种错误,首先你要检查的就是你是否真的把源文件和wrap文件都编译到你的动态库里面去了。假如都编译进去了,那你就要去查一查是不是你在.i中声明的某些函数在你的源文件里面没有真正实现它。这种情况在你使用了include头文件的情况下比较常见,你也可以用%ignore语句去忽略某些声明但没有被实现的函数。
$ gcc -shared example.o example_wrap.o -L/home/beazley/projects/lib -lfoo -o _example.so >>> import example Traceback (most recent call last): File "<stdin>", line 1, in ? ImportError: libfoo.so: cannot open shared object file: No such file or directory >>>
这种错误也很明显是加载器程序找不到libfoo.so了。解决这样问题的办法,无非就是在/etc/ld.so.conf中增加上链接库的地址,然后用ldconfig。 或者是将链接库的地址加入到LD_LIBRARY_PATH中。
或者是用这样的方式指定动态库的路径来编译你的动态库:
$ gcc -shared example.o example_wrap.o -L/home/beazley/projects/lib -lfoo \ -Xlinker -rpath /home/beazley/projects/lib \ -o _example.so
costa@pepsi:~/test/swig/cplusplus$ python Python 2.6.6 (r266:84292, Dec 27 2010, 00:02:40) [GCC 4.4.5] on linux2 Type "help", "copyright", "credits" or "license" for more information. >>> import foo >>> fo=foo.Foo() Traceback (most recent call last): File "<stdin>", line 1, in <module> AttributeError: 'module' object has no attribute 'Foo'
出现这种错误的原因是foo模块里根本都没有Foo这个东西。一般是.i出现问题。
比如以下这种
//file: foo.i %module foo %{ #include "foo.h" %} #include "foo.h"
这里第二个#include "foo.h" 这种用法是有问题的。在这里应该使用%include。
总之,编译swig的封装程序是很容易的一件事情。当然,最好用动态编译的方式。在万不得已的情况下,再考虑静态编译。
你可以在此处下载本文的例子:https://dl.dropbox.com/u/35106490/swig2.tgz