SWIG简介
SWIG是Simplified Wrapper and Interface Generator的简称,它是一个能将C和C++的程序与其他各种高级语言诸如Perl,Python,Ruby和Tcl进行连结的开发工具。目前支持的语言:
- C# – Mono
- C# – MS .NET
- Go language
- Guile
- Java
- Javascript – Node.js
- Javascript – V8
- Javascript – WebKit
- Lua
- MzScheme/Racket
- OCaml
- Octave
- Perl
- PHP
- Python
- 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返回的结果,转换成脚本语言的数据类型返回给脚本上层。
![2da06ceccbdf37a354b47d6e3f3ac7dd.png](https://img-blog.csdnimg.cn/img_convert/2da06ceccbdf37a354b47d6e3f3ac7dd.png)
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"],
)
编译生成库文件:
![9a54a68e65e874415747ed23a6b7159e.png](https://img-blog.csdnimg.cn/img_convert/9a54a68e65e874415747ed23a6b7159e.png)
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))