swig实现Python和C的互联

Python实在是一种让人上瘾的编程语言,简洁的语法+丰富的扩展包,几乎可以用Python做任何事情,尤其是与高效的编译语言C互联以后,解决了脚本语言运行速度慢的问题,可以用来做一些计算密集型的工作,比如CFD。

为什么是swig?

Python底层就是C语言,有原生的C语言接口,用来传递变量,但是完全手写中间层对于我这样的业余Coder实在太痛苦了,这不是一件很有意思的工作。事实上,即使在Python的官方文档里也推荐用第三方的接口工具处理。

Third party tools like Cython, cffi, SWIG and Numba offer both simpler and more sophisticated approaches to creating C and C++ extensions for Python.

除了以上的第三方工具外,还有 sip,Boost.python,pyrex等好用的工具,在这篇文章里初步介绍了C扩展Python的各种方法。 之前用过Boost.python,使用后的感觉是,真大啊!Boost是一个非常强大的C++库,也提供Boost.python这样专业的接口工具,非常适合重度C++用户,然而我并不是,其实我都算不上是一个C++用户,我的日常工作是PythonFortran,但是Fortran真的有很多不好的语法,相比之下我更愿意用C来连接Python。 然后对swig一见倾心的原因真实基于纯C语言的良好支持,事实上我不希望把C++的类扩展到Python,而是调用C的函数,在Python层面构造类,也有可能根本不需要面向对象的

怎么安装swig?

1.Mac OS 强烈建议用brew来装

1
brew install swig

一条命令搞定,妈妈再也不用担心你的依赖问题了。 2.Windows 博主暂时脱离windows开发环境一会儿,建议参考官方文档 3.Linux 大名鼎鼎的apt-get install

怎么使用swig?

我参考了官方文档里的一个示例程序,最终的目的是生成一个动态链接库和一个供调用的py文件。 假设我们有一个叫做example.c的文件需要转化成python可以直接调用的模块:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
/* File: example.c */
#include "example.h"
int fact(int n) {
if (n < 0){
/* This should probably return an error, but this is simpler */
return 0; }
else if (n == 0) {
return 1;
}
else {
/* testing for overflow would be a good idea here */
return n * fact(n-1);
}
}

相应的我们要有一个example.h头文件来声明这个函数:

1
2
/*File: example.h*/
int fact(int n);

然后最重要的是,需要一个example.i来配置swig

1
2
3
4
5
6
7
8
9
/* File: example.i */
%module example
%{
#define SWIG_FILE_WITH_INIT
#include "example.h"
%}
int fact(int n);

简单解释一下这个配置文件,#define SWIG_FILE_WITH_INIT宏指令规定这个C文件将会被编译成Python模块,#include "example.h"给处理需要包含的文件,最后一句声明了这个函数,就是这么简单嘛。 有了这三个文件之后,我们需要先编译一个Python模块,在终端运行:

1
swig -python example.i

如果编译的是C++文件,需要加上-C++选项:

1
swig -c++ -python example.i

运行完这个命令后,在工作目录里会出现example_wrap.cexample.cxx以及一个example.py的Python文件,但是现在这个模块还不能直接调用,因为还缺少动态链接库,如果强行调用会出现一下错误:

1
ImportError: No module named '_example'

接下来需要编译出一个shared object file,在Linux平台里是so文件,在windows下是Dll文件,有两种方法完成这个步骤,官方文档中推荐使用distutils,即Python的setup.py生成模块:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
"""
setup.py file for SWIG example
"""
from distutils.core import setup, Extension
example_module = Extension('_example',
sources=['example_wrap.c', 'example.c'],
)
setup(name = 'example',
version = '0.1',
author = "SWIG Docs",
description = """Simple swig example from docs""",
ext_modules = [example_module],
py_modules = ["example"],
)

然后在终端里输入:

1
python setup.py build_ext --inplace

build_ext告诉Python需要编译的是扩展模块,--inplace会确保编译生成的文件放在当前目录中。 运行完这个命令后,会在工作目录出现一个so文件,这时example.py文件可以直接被Python调用: