SWIG C++ ->python打包方法
1. swig安装
1.1. windows 环境下安装swig
Link: http://www.swig.org/download.html
- 直接下载swigwin
- 将下载后的swigwin.zip解压到本地任意目录
- 将解压后的目录打包,将swig.exe配置到PATH环境变量中
- 在cmd中测试输入swig,出现‘Must specify an input file. Use -help for available options.’表示安装成功
1.2. linux 环境下安装swig
Link: http://www.swig.org/download.html
LINK: https://sourceforge.net/projects/pcre/files/pcre/8.41/pcre-8.41.tar.gz/download
- 直接下载swig 4.0.1
- 然后下载PCRE
- 安装pcre
- 安装swig
- 如果出现swig:error while loading shared libraries:libpcre.so.异常
输入#ln -s /usr/local/lib/libpcre.so.1 /lib
- 修改环境变量 vim /etc/profile PATH=/usr/loacl/swig/bin:$PATH $source /etc/profile
- Swig 使用方法
LINK :http://www.swig.org/Doc3.0/Introduction.html#Introduction_nn10
LINK:https://segmentfault.com/a/1190000013219667
Ps: 基础的打包方法上面两篇写的都非常详细了,看完上面两个就可以完成基本的C++程序python接口封装了,下面我要介绍的部分是针对python 和C++数据交互的部分。
-
- 传出int
C++ 传出int有两种方法:
- 直接在函数返回值返回
- 参数返回(传出参数)
在实际的工作中,第二种使用更多,这是因为,我们的函数返回值可能要做更多的事情,比如说,使用bool类型作为返回值,这样的话,我们就可以知道函数的运行情况,甚至在一些项目中,我们需要使用RUNCODE(函数运行状态)作为返回值,以及时知道函数的使用情况。
第一种方法,在swig打包中是不需要做额外操作的,我介绍的是第二种方法:
在 XXX.i文件中,我们需要添加下面的代码段:
%include "typemaps.i"
%apply int *OUTPUT { int *num };
注意点: int* num ,num这个字段和你实际C++算法中的参数要一致。这样在打包好python中,该API就变成了两个返回值(tuple形式),第一个返回值是你函数原始的返回自己,第二个返回值就是你的传出函数。
EX: C++code :void getVcpBinNum(int* num);
Python API : num = test_b.getVcpBinNum()
其中getVcpBinNum函数的,参数部分就变成了返回值!,不需要再里面继续写参数。
-
- 传出short 一维数组
注意: 这里不仅仅表示的是short的一位数组,还有关于int 、 float 、double 、byte的一位数组。
在这个位置上,就是我们工作中最重要的一部,实现python C++数组交互,在很多时候python和C++交互上,一个是字符串(XML、JSON),一个是结构体二进制(struct、class)、一个就是数组。
一个熟练的C++程序员眼中,只要不是锯齿数组,一般情况下,不管是多少维的数组,都可以看作是一维数组,所以掌握一维数组就相当于掌握了全部的数组传入传出方法。
在swig的官方文档中,有关于carrays.i的使用方法,但是一旦使用了这个东西,就会陷入到一个大坑中,后面会有数不清的问题,因为carrays.i中使用 %array_class中生成的数组生成器,这个玩意生产的数组是没有边界检查的,结果就是你在python中使用数组生成器生成的数组,如果放在for 中去迭代直接可以跑到程序崩溃。
这里推荐另外一种方法,这个方法出现在了numpy的官方文档中(ps:对,swig的打包方法出现在numpy的官方文档中,真是日了狗!!!)
地址在:https://docs.scipy.org/doc/numpy/reference/swig.html
在这其中,详细讲解了各种维度的各种数组的传入传出方法。
这里我贴一个demo:
C++ API: short* getRefData(short*Data,int len,bool nc);
XXX.i :
%{
#define SWIG_FILE_WITH_INIT
#include "XXX.h"
%}
%include "numpy.i"
%init %{
import_array();
%}
%apply (short* ARGOUT_ARRAY1, int DIM1) {(short* Data, int len)};
%include "XXX.h"
这里面 ARGOUT_ARRAY1 代表传出的一维数组,DIM1代表一维数组长度,所以这里即使我的API中len是没有在运算中使用的,我还是需要加上,不然就需要在.i中再包一层 %inline
Python使用方法:
ref_data=np.arange(14*width*width,dtype='short')
ref_data= test_b.getRefPPiData(np.shape(ref_data)[0],True)[1]#这里只需要维度!!
-
- 传出char*数组
所谓的char*数组,其实就是广义上的字符串,这里没有讲std::string,是因为,在业务中,很多时候有C/C++混编的情况,如果一个业务机器只有C环境,那么它就不能使用string的相关操作,所以在设计接口的时候,一般都会设计成char* ,或者const char* 这种比较兼容性好的接口。
下面是我的一个demo:
C++ API: void getVcptType(char* vcp_type);
XX.i :
%include "cstring.i"
%cstring_bounded_output(char *vcp_type, 32);
Python API:
vcp_type = test_b.getVcptType()
Char* 的传出使用的就是swig自带的一个cstring 配置文件。