2011年11月6日星期日

用SWIG实现Python/C互调用

最近用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

没有评论:

发表评论

Test Ads
Hello World