SWIG是个帮助使用C或者C++编写的软件能与其它各种高级编程语言进行嵌入联接的开发工具。
SWIG能应用于各种不同类型的语言,包括常用脚本编译语言,例如Perl, PHP, Python, Tcl, Ruby 和 PHP。
SWIG普遍应用于创建高级语言解析或汇编程序环境、用户接口、作为一种用来测试C/C++或进行原型设计的工具。
工作中碰到了一个小问题:有一个加密/解密的程序原本是用C++语言写的,后来需要用Python来实现调用。简单粗暴的办法是照着C++代码重写一个Python版本的程序,但是很麻烦,还会带来以下问题:
- 时间成本,开发方面需要些代价
- 维护成本,需要自己维护,重复造轮子
- 代码冗余,多套代码,不易维护
后来经老手介绍,知道可以用SWIG来把C++的代码封装成Python库,供Python调用。
SWIG (Simplified Wrapper and Interface Generator) 是用来为C和C++程序构造脚本语言接口的软件开发工具。SWIG 实际上是一个编译器,获取C/C++的声明,用一个壳包起来,以便通过其他语言访问这些声明。因此,SWIG 最大的好处就是将脚本语言的开发效率和 C/C++ 的运行效率结合起来。
准备工作:
1.下载SWIG。https://sourceforge.net/projects/swig/
把SWIG添加到环境变量,这样你才能直接打开cmd直接用SWIG,不必cd来cd去。
1 原始文件
新建一个文件夹,里面放你的代码吧,不然生成的文件乱七八糟的。
新建这些文件,里面都是空的,直接改后缀名就行。
文件内容:
Zack.cpp (你要包装的C++代码)
/* File: Zack.c */
#include "Zack.h"
int fact(int n) {
if (n < 0) return 0;
if (n == 0) return 1;
else return n * fact(n-1);
}
Zack.h (你要导入的C++头文件)
int fact(int n);
2 编写.i接口文件
这两个是你要的C++的内容,用SWIG就需要告诉她怎么包装。这个文件就是Zack.i(随便什么名字,只要是.i结尾的就行),反正你SWIG命令的时候要指定这个文件。
/* File: Zack.i */
%module Zack
%{
#define SWIG_FILE_WITH_INIT
#include "Zack.h"
%}
int fact(int n);
.i接口文件中主要包含了三个部分:
%module
后面的名字是被封装的模块名称,Python通过这个名称加载程序。%{...%}
之间所添加的内容,一般包含此文件需要的一些函数声明和头文件。- 最后一部分,声明了要封装的函数和变量。
如果把要封装的函数声明部分写在了头文件里,最后一部分直接用%include
包含头文件名也行:
/* File: Zack.i */
%module Zack
%{
#define SWIG_FILE_WITH_INIT
#include "Zack.h"
%}
%include "Zack.h"
两种.i文件的效果是一样的,比较建议使用第二种方法,能够简化接口文件
3 封装代码
然后在当前目录进行包装,出现两个新文件,一个.cxx,一个.py,执行以下命令:
swig -c++ -python Zack.i
如果是c文件,可以直接执行“swig -python Zack.i”。
执行完毕后会生成Zack.py和Zack_wrap.cxx这两个文件,相当于将原cpp文件进行了封装,wrap了一层。
4 生成动态链接库
编写setup.py文件,用于自动化编译动态链接库:
from distutils.core import setup, Extension
#生成一个扩展模块(Zack_module )
Zack_module = Extension('_Zack',
sources=['Zack_wrap.cxx', #封装后的接口cxx文件
'Zack.cpp'], #以下为原始代码所依赖的文件,源代码从这里引入
)
setup (name = 'Zack', #打包后的名称
version = '0.1',
author = "SWIG Docs",
description = """Zack trial""",
ext_modules = [Zack_module], #与上面的扩展模块名称一致
py_modules = ["Zack"], #需要打包的模块列表
)
编写完成后执行以下命令进行编译:
python setup.py build
编译通过后在build/lib.*
开头的子目录下即可见到编译好的Python库文件:_Zack.cp37-win_amd64.pyd和Zack.py
至此,编译好的python模组就可以使用了,将_Zack.cp37-win_amd64.pyd和Zack.py复制到你的测试用路径下,编写test.py ,test.py文件中import Zack就可以了。
如果想将该模块安装到Python根目录,可以在刚刚的setup.py路径下用这个命令set up一下,把Zack这段模块安装到Python根目录中即可。(可以不需要执行python setup.py build,直接执行python setup.py install编译安装)
下面一大堆是输出的信息,不用管它。
测试一下,在随便一个py文件中import Zack就可以了。
5 编译中可能遇到的报错
在第4步执行python setup.py build编译时可能会遇到以下错误:
error: Unable to find vcvarsall.bat
这是由于python找不到微软自带的编译器导致,需要安装Microsoft Visual C++ compiler,或许你的电脑上已经安装过但仍然报错,这可能是由于你安装的跟python需要的版本不一致,去微软官网下载Visual Studio 2019 生成工具,
https://visualstudio.microsoft.com/zh-hant/visual-cpp-build-tools/
下载安装可能需要1个多 G ,安装后重启电脑重新编译即可。
另外,使用MinGW-w64编译c代码的兄弟,python3.4以上版本不在支持选择这个方式,所以我这里不在推荐。
参考: