利用swig實現python呼叫C/C++的方法

Mr_John_Liang發表於2015-04-10
 
利用swig實現python呼叫C/C++的方法

 Python是一門語法簡單而且清晰的指令碼語言,不過執行效率比較低。簡單的說就是開發相對C/C++容易,但是執行效率不如C/C++,甚至有人稱之為執行效率最低的魚眼。如果可以將最重要的而且變化一般不大的運算邏輯用 C/C++實現,其他用python書寫,那就最好不過了。據說python底層就是用C實現的,因此這一想法也是可行的。目前來說,python呼叫C/C++有以下幾種方法:

1)  利用python提供的API呼叫C。主要方法是在c++檔案中藉助Python提供的標頭檔案python.h,對C/Cpp函式進行封裝。然後將它編譯為一個動態連結庫(一個Module)。最後在Python檔案中將這個module 載入進去,就可以呼叫了。具體例子請見http://blog.csdn.net/marising/article/details/2845339

2)  利用boost工具進行封裝。相對1)來說更為方便,但是和1)一樣都需要對原C程式碼進行破壞。具體例子請見http://blog.csdn.net/marising/article/details/2917827

3)  利用ctypes。ctypes是Python標準庫提供的呼叫動態連結庫的模組,相對1)2)來說不需要對原始碼進行破壞,只需要對相應的c++資料型別進行python的轉換。但是據說對C/C++的支援不一定完整.

4)  利用Swig工具。Swig和boost一樣是一個對C進行封裝的工具,但是和boost不一樣,它不需要對原始碼進行破壞,只需要新增一個介面檔案對需要封裝的函式和類進行描述,swig會自動對c程式碼封裝成一個能被呼叫的module供Python呼叫。

        下面具體介紹一下Swig的使用方法。剛才說了,swig和boost不一樣,它不用對原始碼進行破壞,只需要在外面多寫一個介面檔案。假設有如下的cpp檔案需要封裝:

#include <time.h>
 double My_variable = 3.0;
 
 int fact(int n) {
     if (n <= 1) return 1;
     else return n*fact(n-1);
 }
 
 int my_mod(int x, int y) {
     return (x%y);
 }
     
 char *get_time()
 {
     time_t ltime;
     time(<ime);
     return ctime(<ime);
 }

       那麼我們需要寫如下介面檔案(example.i):

 %module example
 %{
 /* Put header files here or function declarations like below */
#define SWIG_FILE_WITH_INIT
 extern double My_variable;
 extern int fact(int n);
 extern int my_mod(int x, int y);
 extern char *get_time();
 %}
 
 extern double My_variable;
 extern int fact(int n);
 extern int my_mod(int x, int y);
 extern char *get_time();


      這是Python tutorial中的一個例子。下面將具體介紹一下example.i這個檔案。

      %module 後面的名字是被封裝的模組名稱。封裝口,python通過這個名稱載入程式。

     %{  %}之間所新增的內容,一般包含此檔案需要的一些函式宣告和標頭檔案。

      最後一部分,宣告瞭要封裝的函式和變數。

      比較建議的寫法是,把要封裝的函式宣告部分寫成標頭檔案,假如為example.h,這樣介面檔案就非常簡單了:

 %module example
 %{
 /* Put header files here or function declarations like below */
#define SWIG_FILE_WITH_INIT
#include"example.h"
 %}
 
%include"example.h"

     為了編譯出一個封裝的動態庫,依次執行:

 $ swig -python -c++ example.i
會生成 .cxx   .py檔案
 $ g++ -c -fPIC example_wrap.cxx -I/usr/local/include/python2.6
會生成 兩個.o 檔案
 $ g++ -shared example_wrap.o -o _example.so
------如果生成的_example.so依賴其他的.SO,編譯時需新增  -L..... -lxxx,例如

g++ -L../generateFingerPrint/ -lgenerateFingerPrintdll64 -L/usr/local/lib -lpython2.7 -shared sp_fingerprint_swig_wrap.o sp_fingerprint_swig.o -o _FingerPrintLocal.so

       第一步的過程會生成example_wrap.cxx的檔案。因為現在是cpp檔案,所以編譯出來是個.cxx檔案和一個example_wrap.py。如果是c的檔案,編譯後會出現一個.c的檔案。這個檔案相當於將原cpp檔案進行了封裝,wrap了一層。後面兩步就是標準的生成動態連結庫的步驟了。這樣得到的動態連結庫就可以直接被python import了。

 >>> import example
 >>> example.fact(5)
 120
 >>> example.my_mod(7,3)
 1
 >>> example.get_time()
 'Tue Dec 11 23:01:07 2012'
 >>>

相關文章