最近用SWIG把TMUFE封装成Python module,发现SWIG还是非常强悍的,相比于boost-python,SWIG的入门更容易,而且由于可以直接把.so里的interface expose成Python方法,调用起来很方便。
先看个傻瓜教程:
SWIG 懒人方法
如上所见,并非总是需要写一个专门的接口文件。如果你有一个头文件,你可以直接在其中包含SWIG接口,如例:
%module example %{ /* Includes the header in the wrapper code */ #include "header.h" %} /* Parse the header file to generate wrappers */ %include "header.h"
只要照上面写个SWIG interface spec,然后:
建立Python模块
转换编码C成Python模块很简单,只需要按如下做即可(请见其他操作系统的SWIG共享库帮助手册):
unix % swig -python example.i unix % gcc -c example.c example_wrap.c \ -I/usr/local/include/python2.1 unix % ld -shared example.o example_wrap.o -o _example.so
不过傻瓜教程也就只适用于hello world的sample code了,真正在wrap TMUFE的时候还是遇到一些问题:
1. typedef
发现如果typedef两次,即使是primitive type,也会变成pointer to structure~~~
比如uint32_t在<stdint.h>里被
typedef unsigned int uint32_t;
,如果在interface里又被typedef一次
typedef uint32_t myuint32;
,那么在Python module里如果如果传递int给myuint32参数时,会提示:
>>> fn(3,4) Traceback (most recent call last): File "", line 1, in TypeError: Expected a pointer
解决方法就是在interface里把这个新类型重新typedef一次/或使用命令apply:
typedef unsigned int myuint32; typedef unsigned long long myuint64; etc... OR %apply unsigned int { myuint32 } %apply unsigned long long { myuint64 }
2. 函数指针/回调函数
如果你的C library里有些API需要接受function pointer/callbcack function,在Python里是调用不起来的,Python的方法无法被wrap成函数指针调用。
解决方法是在C里提供callback function的实现,并且让这些函数成为Python API,则可以把这些C函数传递给function pointer。
%module test %{ #include "a.h" int add(int x, int y) { return x + y; } %} %typedef int (*FUNC) (int, int); void fn(int, int, FUNC op); %callback("%s_cb") int add(int, int); %nocallback
这个例子实现了函数add,通过%callback把这个函数包装成add(…)和add_cb(…),在Python里可以调用:
from test import * fn(3, 4, add_cb) ==> 7 add(3,4) ==> 7
看起来SWIG灰常强大,现在还支持C#/Java等和C/C++的互调用,值得再花点时间研究一下~~~
SWIG currently generates wrapper code for eighteen different target languages:
- Allegro CL
- C#
- CFFI
- CLISP
- Chicken
- Guile
- Java
- Lua
- Modula-3
- Mzscheme
- OCAML
- Octave
- Perl
- PHP
- Python
- R
- Ruby
- Tcl
- UFFI
没有评论:
发表评论