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檔案同上,編譯方式同上。