不過,本篇的重點在於介紹如果讓Python呼叫C/C++ level的function,有機會的話,再介紹一下GIL好了。目前其實有很多Tool提供這樣的功能,包括SWIG、Boost.Python、Robin…等等,這邊就介紹一下SWIG的用法。
先簡單說明一下SWIG是怎麼辦到的
1. 將我們C/C++ level的code包在一個"Sample" DLL project裡
2. 寫一份interface的Sample.i檔給SWIG.exe parse後產生出一個Sample_wrap.c與Sample.py檔
3. 我們再將Sample_wrap.c加進DLL project裡,一起compile成_Sample.pyd
4. 在Python code中import Sample 就能呼叫Sample裡的API了
所以,其實SWIG做的事情只是parse Sample.i檔,產生wrapper檔:Sample_wrap.c,DLL project連著這個wrapper檔一起compile的話,就可以讓Python層呼叫執行了。
1. 下載SWIG
目前最新的SWIG已經2.0.10版了,下載後,解壓縮,我們在compile project時,只需要其中的swig.exe檔
2. 設定VC的Include, Library, Execute path
為了在C/C++ code裡撰寫CPython,必須指定Python的Include, Library path
而指定Execute path是為了在Project property使用swig時,不需要輸入絕對路徑
假如電腦裡安裝的是Python 2.7
在Window裡的預設路行就是C:\Python27
在Tool | Options | Projects and Solutions | VC++ Directories裡新增
Sample.cpp
右鍵選擇 Sample.i 的Property,設置Custom Build Step
Example : c, output file為Sample_wrap.c
Example : c++, output file為Sample_wrap.cxx, 記得加上-c++
Sample.i範例
Linker | Output File
$(OutDir)\_$(ProjectName).pyd
讓最後的檔案輸出成_Sample.pyd
點選Project Property,修改
C/C++ | Preprocessor | Preprocessor Definitions
新增 __WIN32__
以上都完成後,就可以開始Compile了
Example :
而指定Execute path是為了在Project property使用swig時,不需要輸入絕對路徑
假如電腦裡安裝的是Python 2.7
在Window裡的預設路行就是C:\Python27
在Tool | Options | Projects and Solutions | VC++ Directories裡新增
- Include files : C:\Python27\include
- Library files : C:\Python27\libs
- Executable files : C:\swigwin-2.0.10\ (第一步中解壓縮的路徑)
3. 建立C/C++ DLL Project
我以VC2008(其他版本也可以),建立一個Win32的C/C++的DLL Project
若不選擇"Empty Project"也沒關係,記得要將 Project Property | C/C++ | Precompiled Headers | Create/Use Precompiled Header 切換成 "Not Using Precompiled Headers"
4. 撰寫C/C++的API - Sample.h, Sample.cpp
Sample.h#include "Python.h" int AddOne(int n); int Sqrt(int n); PyObject* SqrtInPyObj(PyObject* obj);
Sample.cpp
#include "Sample.h" int AddOne(int n) { return n+1; } int Sqrt(int n) { return n*n; } PyObject* SqrtInPyObj(PyObject* obj) { int n = PyInt_AsLong(obj); return Py_BuildValue("i", n*n); }
5. 設置interface檔 - Sample.i
由於SWIG需要此interface檔來產生wrapper的cxx檔,因此需撰寫一個 Sample.i 檔加到Project裡,這樣才能在Compile後即時update最新的pyd檔右鍵選擇 Sample.i 的Property,設置Custom Build Step
Example : c, output file為Sample_wrap.c
- Command Line
- swig.exe -python -o $(ProjectDir)\$(InputName)_wrap.c "$(InputPath)"
- Outputs
- $(InputName)_wrap.c
Example : c++, output file為Sample_wrap.cxx, 記得加上-c++
- Command Line
- swig.exe -c++ -python -o $(ProjectDir)\$(InputName)_wrap.cxx "$(InputPath)"
- Outputs
- $(InputName)_wrap.cxx
%module Sample %{ #include "Sample.h" %} %include "Sample.h"
interface檔尚有許多的功能,有興趣的人可以再深入研究 - SWIG 2.0 Python Document
這邊就不多做著墨了
這邊就不多做著墨了
6. 加入Sample_wrap.cxx or Sample_wrap.c至Project中
在做完以上的步驟後,可以先compile一次,就會透過 Sample.i 的Custom Build Step產生Sample_wrap.cxx檔,再將此當加入Project中一起Compile7. Compile
點選Project Property,修改Linker | Output File
$(OutDir)\_$(ProjectName).pyd
讓最後的檔案輸出成_Sample.pyd
點選Project Property,修改
C/C++ | Preprocessor | Preprocessor Definitions
新增 __WIN32__
以上都完成後,就可以開始Compile了
8. Import Python module
將Compile過後的Sample.py與_Sample.pyd複製到你的Python script旁,執行應該就可以看到結果了!Example :
import Sample print Sample.AddOne(1) # >>> 2 print Sample.Sqrt(2) # >>> 4 print Sample.Sqrt(3) # >>> 9 print Sample.SqrtInPyObj(2) # >>> 4 print Sample.SqrtInPyObj(3) # >>> 9
沒有留言:
張貼留言