最近用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
没有评论:
发表评论