SWIG简介
SWIG是Simplified Wrapper and Interface Generator的简称,它是一个能将C和C++的程序与其他各种高级语言诸如Perl,Python,Ruby和Tcl进行连结的开发工具。
目前支持的语言:
- C# – Mono
- C# – MS.NET
- D
- Go language
- Guile
- Java
- Javascript – Node.js
- Javascript – V8
- Javascript – WebKit
- Lua
- MzScheme/Racket
- OCaml
- Octave
- Perl
- PHP
- Python
- R
- Ruby
- Scilab
- Tcl/Tk
SWIG与Python
利用SWIG,Python可以现实以下功能:
- 用Python调用C/C++库
- 用Python继承C++类,并在Python中使用该继承类
理解脚本语言如何和C/C++交互,首先简单说一下Python的标准实现CPython,Python标准的解析器实现是由C编写的,基础功能模块也都是C编写的,然后将其编译成了Python解析器和相关so, 所以对于CPython来说,其本身解析过程最终都是通过执行底层C代码来进行实现的。官方标准CPython提供了对应的API允许对Python进行扩展,CPython扩展需要在C/C++代码中嵌入很多<Python.h>中的API,为了能够调用C/C++的函数,需要声明如何调用函数,参数的类型转换等等,很麻烦。
SWIG的目的就是要为C/C++ API提供脚本语言的接口,SWIG所有做的就是解决脚本语言和C/C++交互的问题,SWIG所做的事情其实就是两件事:
- 根据要调用的C API生成Wrapper函数,作为胶水来让脚本解析器和底层C函数进行交互。
- 为生成的Wrapper函数生成脚本语言的调用接口。
完成了对C/C++函数脚本语言接口的生成,通过直接使用脚本语言的接口,调用对应的Wrapper函数,Wrapper函数将脚本语言传入的参数,转换成C的参数,然后调用对应的C的接口,执行完后,Wrapper函数会将C返回的结果,转换成脚本语言的数据类型返回给脚本上层。
SWIG的安装
Windows
安装SWIG非常的简单,仅需要到官方下载后配置环境变量即可。
Linux
wget http://prdownloads.sourceforge.net/swig/swig-4.0.1.tar.gz tar -zxvf swig-4.0.1.tar.gz cd swig-4.0.1 ./configure make sudo make install
安装完后需要添加路径到.bashrc以便于在任何目录下都可以操作swig的命令。
nano ~/.bashrc # 添加以下两行到bashrc中 SWIG_PATH=/usr/local/share/swig/4.0.1 PATH=$PATH:$SWIG_PATH source ~/.bashrc
使用swig -version
确认版本型号即为安装完成。
swig: error while loading shared libraries: libpcre.so.1: cannot open shared object file: No such file or directory
问题主要是swig使用时,找不到libpcre.so.1文件,我们在系统中查找以下它的位置:
sudo find / -name libpcre.so.1
查询后发现这个文件都在anaconda的子环境文件夹中:
/home/qw/anaconda3/lib/libpcre.so.1 /home/qw/anaconda3/pkgs/pcre-8.43-he6710b0_0/lib/libpcre.so.1
解决方案:创建软链接
sudo ln -s /home/qw/anaconda3/lib/libpcre.so.1 /usr/lib/libpcre.so.1
C语言示例
编写代码文件
1、编写C语言头文件example.h
int fact(int n);
2、 编写C语言源码example.c
#include "example.h" int fact(int n) { if (n < 0) { return 0; } if (n == 0) { return 1; } else { return n * fact(n-1); } }
3、 编写接口文件example.i
%module example %{ #define SWIG_FILE_WITH_INIT #include "example.h" %} int fact(int n);
- %module后面的名字是被封装的模块名称,Python通过这个名称加载程序。
- %{…%}之间所添加的内容,一般包含此文件需要的一些函数声明和头文件。
- 最后一部分,声明了要封装的函数和变量。
使用命令行调用 Swig 方法产生 Python 模块
swig -python example.i
执行后会生成2个新的文件:example_wrap.c,example.py
利用 distutils 生成动态库
新建 setup.py,内容如下:
from distutils.core import setup, Extension example_module = Extension('_example', sources=['example_wrap.c', 'example.cpp'], ) setup(name='example', version='0.1', author="SWIG Docs", description="""Simple swig example from docs""", ext_modules=[example_module], py_modules=["example"], )
编译生成库文件:
python setup.py build_ext –inplace
如果是Linux,执行完成后会在目录下生成类似 _example.cpython-37m-x86_64-linux-gnu.so 的文件
测试.so 文件能否顺利被python调用。在example目录下创建一个test.py文件。文件内容为
import example print(example.fact(4))
其后执行python ./test.py看能正常的输出。
如果是Windows,则会在目录下生成类似 _example.cp37-win_amd64.pyd文件。调用方法稍有区别:
import _example print(_example.fact(4))
参考链接:
example.i 中的”int fact(int n)”在行尾缺少了分号,造成swig报语法错误。
谢谢指正,应该是复制的时候遗漏了