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

https://www.zhihu.com/question/2300

转自:https://zhuanlan.zhihu.com/p/462193340

posted @ 2022-10-27 09:55  MasonLee  阅读(142)  评论(0编辑  收藏  举报