SWIG:Python调用C++
配置SWIG
下载SWIG
Download SWIGwww.swig.org/download.html
官网下载最新版本。解压到某个文件夹。比如笔者放在了:
D:\PROGRAM\IDE\swigwin-4.0.2
【记住这个地址!下面要用】
PATH配置
Windows快捷搜索“环境变量”,打开此窗口:
然后点击“环境变量”
选择“path”,再点编辑,添加上文提到的路径
“用户变量”和“系统变量”中,分别如上图选择“Path”,再点击各板块的“编辑”,添加swig的路径(添加两次!)如下两图:
第一处
第二处
一路“确定”即配置完成。
打开cmd(怎么打开?windows快捷搜索),输入
swig -version
检查是否成功。
C++变Python
笔者将使用“mod”作为模块名,使用时把以下所有“mod”换调自己起的名字即可。
以下文件放在同一目录下,比如笔者是:
D:\PROGRAM\C++程序\test\swig测试
编写C++源文件
新建h文件,只声明;新建cpp文件,定义h中声明的(一刀切,名字最好都叫mod)
头文件只有声明(既有声明又有定义的头文件文末说)
与h配套的cpp
把C++功能打包成接口
新建mod.i文件,内容如下:
%module mod
%{
#include "mod.h"
%}
int fun(int x,int y);
int fun2(int x,int y);
a.%module后面的名字是被封装的模块名称,Python通过这个名称加载程序。
b.%{…%}之间所添加的内容,一般包含此文件需要的一些函数声明和头文件。
c.最后一部分,声明了要封装的函数和变量。如果要导入h中所有内容,这一部分可以写成:
%include "mod.h"
在放这三个文件的文件夹界面,点击地址
点击地址,输入cmd,打开该文件夹下的cmd
改为“cmd”,然后回车(目的是让cmd指向这个目录),就打开了命令提示符,输入
swig -c++ -python mod.i
【注意,如果原来是C语言,这里不是这样写。在文末的参考资料里可以找到相关写法】
回车,新增两个文件:
新增的两个文件
把接口打包成模块
新建setup.py文件,内容如下:
from distutils.core import setup, Extension
mod_module = Extension('_mod',
sources=['mod_wrap.cxx', 'mod.cpp'],
)
setup (name = 'mod',
version = '0.1',
author = "beshar",
description = """Simple swig example from docs""",
ext_modules = [mod_module],
py_modules = ["mod"],
)
再次打开该目录下的cmd,输入:
python setup.py build_ext --inplace
cmd里面会显示编译过程,完成之后又会生成几个文件。
测试与使用
现在python中就可以使用C++函数了。在该目录下新建test.py使用一下转换的成果吧!
测试脚本test.py
运行结果
成功!
经测试,只要这三个文件在同一目录下即可。运行test.py时会生成“__pycache__”文件夹
有用的三个文件,其他可以删了
补充
因为不懂原理,以下都是才疏学浅的笔者一个个试出来的……
1.可以用%include偷懒(比如定义了一个类但是懒得敲)
节选自参考资料中的知乎回答
2.如果声明定义全在头文件(即只有.h没有.cpp),那setup.py中的sources就不需要写mod.cpp。如果有很多cpp,在sources里面添加即可。但是cxx文件一定要有
3.如果有h配有cpp,且h中定义了全局变量,会编译不过去,因为会重复定义(h被include了多次)。要把变量定义在cpp中,h中用extern。【这是C++语法问题了……但是初学者如我常常会犯】
4.如果正确定义了全局变量(就叫con吧),打包时也用%include全囊括了,但在py里,C++中定义的全局变量不能用mod.con访问。得用函数访问,就像private里面的变量。所以SWIG只能把C++函数、类做成接口,变量不行。但是全局变量只是不能直接访问,它还是在发挥作用的。
5.函数A调用函数B,“mod.i”中可以只声明函数A(接口只做A的)。因为经过了编译,B也在发挥作用,但是你没有使用它的接口。(上文变量同理)
6.C++函数返回值为地址,py收到的真的就是地址。
7.函数要指针参数(比如int*、int&),就算py里传id(),也没用。但是如果C++要字符串char*,py中传字符串是可以的。
8.函数返回值使用char*,返回字符串。
9.用了template需要在.i文件中具体化(其实就是失去了模板的意义),以下例子在SWIG and Python的“31.3.13 C++ templates”一节
%module example
%{
#include "pair.h"
%}
template<class T1, class T2>
struct pair {
typedef T1 first_type;
typedef T2 second_type;
T1 first;
T2 second;
pair();
pair(const T1&, const T2&);
~pair();
};
%template(pairii) pair<int,int>;
/*
py中:
>>> import example
>>> p = example.pairii(3,4)
*/
参考资料
https://blog.csdn.net/qq_42004289/article/details/90634739
https://www.cnblogs.com/santion/p/8612068.html
https://blog.csdn.net/zhanhuai1/article/details/7236262