1. Windows下安装Swig
详情参考 https://blog.csdn.net/aganliang/article/details/91129379
2. 新建test.cpp文件
#include "test.h"
int addReturnInt(int a, int b)
{
return a + b;
}
void addPointerDouble(double& a, double& b, double& res)
{
res = a + b;
}
新建test.h文件
#ifndef TEST_H
#define TEST_H
int addReturnInt(int a, int b);
#ifdef SWIG
%apply double& INPUT{ double& a }
%apply double& INPUT{ double& b }
%apply double& INOUT{ double& res }
#endif
void addPointerDouble(double & a, double & b, double & res);
#endif
新建test.i文件
%module TestSwig
%{
#include "test.h"
%}
%include "test.h"
将这三个新建的文件放入一个文件夹中
3. 打开cmd命令行 cd进刚刚创建的文件夹内
执行swig命令
swig -c++ -python test.i
执行完毕后,会在当前目录下生成一个名为test_wrap.cxx的文件以及TestSwig.py文件
4. 打开VS,新建一个C++空项目(控制台)
在菜单栏(正上方)设置为release x86, 将cxx文件,h文件,cpp文件添加进项目中
5. python环境配置:
- 配置改为Release x86
- 配置属性->常规->Windows SDK版本修改为【10.0.18362.0】或【最新安装版本】
- 配置属性->常规->配置类型修改为【动态库(.dll)】
- 配置属性->高级->目标文件扩展名修改为【.pyd】
- 配置属性->C/C++->常规->附加包含目录->添加【D:\anconda\envs\py36\include】
- 配置属性->VC++目录->库目录->添加【D:\anconda\envs\py36\libs】(即为python36.lib所在路径)
- 配置属性->连接器->输入->附加依赖项->添加【python36.lib】
6. VS编译项目,点击生成选项,会在配置的输出目录中生成TestSwig.pyd文件。生成完毕之后将此文件重命名为_TestSwig.pyd(原因:与刚刚swig生成的py文件重名了,不利于调用)
7. 将pyd文件与生成的py文件放在同一个目录下
执行测试代码:
import TestSwig
a = 1
b = 2
res = TestSwig.addReturnInt(a, b)
print('原生C++ int 返回:', type(res), res)
print('-------------------------')
a1 = 1.0
a2 = 2.0
res = 0.0
# 这里的res是通过swig编译脚本里的INOUT关键字返回
res = TestSwig.addPointerDouble(a1, a2, res) 的
print('原生C++ double 引用返回:', type(res), res)
执行结果:
原生C++ int 返回: <class 'int'> 3
-------------------------
原生C++ double 引用返回: <class 'float'> 3.0
至此,python就可以调用c++封装的函数了
总结:
test.h中的swig宏是解决python类型中没有double类型返回的关键
#ifdef SWIG
%apply double& INPUT{ double& a }
%apply double& INPUT{ double& b }
%apply double& INOUT{ double& res }
#endif
其中:% 与apply不能分离(这个巨坑,别问我怎么知道的)
参数与函数保持一致,如果函数入参为int这种非引用、指针类型的,可以不写入SWIG宏内
INPUT代表输入输出,编译后的python得出结果需要返回(因为python没有显式的使用指针)
OUTOUT代表输出,只能在python内return出结果
INPUT代表输入,只能通过python赋值给C++函数参数
更新:使用c++ class风格的swig封装
头文件test.h:
#ifndef TEST_H
#define TEST_H
class ClassTest
{
public:
ClassTest();
~ClassTest();
int addReturnIntCpp(int a, int b);
#ifdef SWIG
%apply double& INPUT{ double& a }
%apply double& INPUT{ double& b }
%apply double& INOUT{ double& res }
#endif
void addPointerDoubleCpp(double& a, double& b, double& res);
};
#endif
类文件test.cpp:
#include "test.h"
ClassTest::ClassTest(){}
ClassTest::~ClassTest() {}
int ClassTest::addReturnIntCpp(int a, int b)
{
return a + b;
}
void ClassTest::addPointerDoubleCpp(double& a, double& b, double& res)
{
res = a + b;
}
i文件同上,编译方式同上。