用swig对c/cpp代码进行python包装

声明: 本文非原创, 基本转载自这篇文章, 略有修改.

swig (simplified wrapper and interface generator) 可以把c/cpp代码包装成python/ruby等接口. 本文主要记录如何用swig包装c/cpp为python模块的相关资料.

c/cpp 包装为 python 的几种方法:

Python C Api

python解释器提供的一组 c api, 详见官网. 可以用c/cpp实现python module, 也可以将python解释器作为一个脚本引擎嵌入c/cpp代码中, 为c/cpp程序提供解释python脚本的能力. python c api 是其他工具的基础, 可以认为其他工具方法都是基于 python c api 的封装. 官方 python c api 可以理解为底层, 强大的同时意味着比较繁琐, 容易出错, 如果不是相当的高手, 还是较少采用这种方法.

ctypes

ctypes是python标准库提供的调用动态链接库的模块, 使用该模块可以直接在python代码里加载动态链接库, 调用其中的函数. ctypes的优势是使用简单, 不用编写或修改c/cpp代码. 目前还不了解ctypes对c/cpp的支持是否完整.

boost.python

boost提供的cpp的模板库, 用来支持python和cpp的无缝互操作. 相对swig来说, 这个库的优势是功能通过cpp api 完成, 不用学习新的语法 ( swig 就需要再学习swig的用法). boost.python的问题是: 1) 由外部依赖; 2) 文档不友好, tutorial都很难跑通.

swig

swig 完整支持ANSI C, 支持除嵌套类外的所有cpp特性. swig是一个接口编译器, 旨在为c/cpp方便的提供脚本语言接口. google 也使用swig.

swig 概览

swig 接口描述文档

swig本质是个代码生成器, 为c/cpp程序生成到其他语言的包装代码(wrapper code), 这些包装代码里会礼用各语言提供的 c api, 将c/cpp程序中的内容暴露给相应的语言. 为了生成这些代码, swig需要一个接口描述文件, 描述将什么样的接口暴露给其他语言.

swig的接口描述文件可以包含以下内容:

  1. ANSI C 函数原型声明
  2. ANSI C 变量声明
  3. swig 指示器(directive)相关内容

swig可以直接接受.h头文件作为接口描述文件, 在有了接口描述文件后, 就可以礼用swig命令生成包装代码了. 然后将包装代码编译链接成可被其他语言调用的库.

swig可以实现以下功能:

  1. 用python调用c/cpp库
  2. 用python继承cpp类, 并在python中使用该继承类
  3. cpp使用python扩展(通过文档描述应该可以支持, 未验证)

本文中使用swig 1.3.40版本.

swig 官方文档说明

swig官方文档有两大部分, 一部分是其基础文档, 另一部分是针对各语言的文档. 建议直接看具体语言对应的文档, 遇到问题再查找基础文档.

  1. 基础文档

swig的基本使用, 对c/cpp的支持, swig库及其扩展库

  1. 各语言文档

例如python, ruby等.

swig 包含内容

swig主要包含以下几部分:

  1. 代码生成器(swig)

代码生成器根据接口说明文件, 生成对应的包装代码

swig将常用的内容放到库里, 比如对数组, 指针, 字符串, STL的支持, 可以在接口文件中直接引用库里的内容, 方便接口文件的编写.

  1. 简单示例

example.h

1
2
3
4
5
6
7
8
#include <iostream>

using namespace std;

class Example{
public:
void say_hello();
};

example.cpp

1
2
3
4
5
#include "example.h"

void Example::say_hello(){
cout << "Hello" << endl;
}

example.i

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
%module example
%{
#include "example.h"
%}
%include "example.h"
setup.py
#! /usr/bin/env python

"""
setup.py file for SWIG C\+\+/Python example
"""
from distutils.core import setup, Extension

example_module = Extension('_example',
sources=['example.cpp', 'example_wrap.cxx',],
)

setup (
name='example',
version='0.0.1',
author='someone',
description="""Simple swig C\+\+/Python example""",
ext_modules=[example_module],
py_modules=["example"],
)

运行下面的命令:

1
2
swig -c\+\+ -python example.i
python setup.py build_ext --inplace

如果编译通过的话, 可以在python中测试:

1
2
3
>>> import example
>>> example.Example().say_hello()
hello

以上是用distutils构建了 example module, 也可以通过编译器直接构建, 如下:

1
gcc -fPIC -I/usr/include/python2.5/ -lstdc\+\+ -shared -o _example.os example_wrap.cxx example.cpp

注意, -fPIC 和 -lstdc++ 都是必需的, _example.os 前面的下划线(‘_‘)也是必需的.