SWIG入门2 :如何编译

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

 

 

 

 

 

你可能感兴趣的:(python,swig)