【工作總結】通過SWIG實現 python 和 c++ 互相通訊
1. 應用場景和需求:
> . 通過c++程式碼對python擴充套件,實現先在python中呼叫c++ 函式完成工作;
>. c++ 資料上推至python適用py 對資料進行分析處理;
2. 工具:
> . swig for windows- , python2.7.3, vs2013下載地址不一一理出,谷歌一下就能找到了;
3. 開始工作:
1. c++介面的實現,這個和一般寫法差不多,標頭檔案宣告,cxx檔案實現,根據各人程式碼風格而定
//rtsp_client.h class CallBack { public: CallBack(){} virtual ~CallBack(){} virtual void run(float val1, float val2) { printf("(%f, %f)\n", val1, val2); } }; // -- bool api_init(); bool api_exit(); char* api_sendDESCRIBE(char const* url, CallBack* deamonCallback = NULL ); char* api_sendGETPARAMETER(char const* url, int handle = 0); char* api_sendSETUP(char const* url, double angle = 0.0, CallBack* dataCallback = NULL ); char* api_sendPLAY(char const* url, double abs_start = 0.0f, double abs_end = -1.0f, float scale = 1.0F, int flag1 = 0, int flag2 = 0); char* api_sendPAUSE(char const* url); char* api_sendTEARDOWN(char const* url); //tear down all session char* api_shutdownStream(char const* url); //tear down a subsession transportation
實現檔案即對標頭檔案中的函式進行具體該執行什麼給一個明確的過程。以上注意,在api_sendDESCRIBE() 函式中有引數 CallBack* 這個引數就是用來實現回撥的功能。在python中會從 CallBack 類繼承子類並對 run 函式進行覆蓋,通過多型形式呼叫執行python中的函式。
2. 實現 swig 特定的指令碼 ProjectName.i ,這個檔案裡面需要對函式,類等做一些說明,還有一些其他的命令,沒有深究,可以根據需要查詢和研究swig 自帶的python 的examples => callback 部分,下面列出我的指令碼 rtsp_client.i:
// based on ./include/libLive555Client.h and ./source/libLive555Client.cpp // generite a python module %module(directors="1") RTSPClient_0430 %{ #include "libLive555Client.h" %} %include "std_string.i" %feature("director") CallBack; %include ".//include//libLive555Client.h" extern bool api_init(); extern bool api_exit(); extern char* api_sendDESCRIBE(char const* url, CallBack* deamonCallback = NULL ); extern char* api_sendGETPARAMETER(char const* url, int handle = 0); extern char* api_sendSETUP(char const* url, double angle = 0.0, CallBack* dataCallback = NULL ); extern char* api_sendPLAY(char const* url, double abs_start = 0.0f, double abs_end = -1.0f, float scale = 1.0F, int flag1 = 0, int flag2 = 0); extern char* api_sendPAUSE(char const* url); extern char* api_sendTEARDOWN(char const* url); //tear down all session extern char* api_shutdownStream(char const* url); //tear down a subsession transportation
3. 把swig解壓目錄下的swig.exe所在目錄新增到系統的環境變數path中,可以方便的適用swig命令。這一步完成之後進入cmd控制檯切換目錄到 rtsp_client.i 所在的目錄,執行 swig 命令生成 xxx_wrap.cxx 或者 xxx_wrap.c , 命令如下
swig -c++ -python -threads rtsp_client.i
說明一下, -c++ 命令是用來支援 c++的,如果沒有會生成 xxx_wrap.c 的檔案,這個根據需要來定,但是也需要非常注意,誤設可能會帶來編譯時候出錯; -python 選項的命令應該是生成 python 版本的包裝器;
-threads 這個引數 想特別的說明一下,坑了我們好久的時間。由於c++模組涉及到多執行緒的操作,所以需要這個選項,在python中由於多執行緒的GIL導致類無法高效,合理的使用python的多執行緒,所以python有些頻繁操作的功能用多執行緒來說是不合適的,因為他們公用一個全域性直譯器鎖GIL(Global Iterpreter Lock ), 頻繁的請求會造成低效,所以Python有一個multiprocessing
包來完成填補這一缺陷,這也是Python的一個詬病。我們c++中的多執行緒對GIL這個東西是沒有做同步的,所以很容易出現問題,如果自己寫同步請求鎖那好麻煩。所以適用swig 的 -threads 這以選項填補了這個問題。
TIP1:關於vs2013 的使用,因為我除錯適用 vs2013 debug 除錯來對 dll 進行除錯,我下載的 python27_d.dll 一直有問題,所以到至了出很多問題,後來的結局辦法是: 在vs 的 debug 模式下,使用 python 的 release 版本的 庫進行除錯,因為不需要除錯 python的東西,需要的是除錯我的程式碼。這個問題解決
TIP2:關於python在 debug 模式下 包含 Python.h 有一個漏洞,會造成stl 的連結錯誤,這個錯誤在網上查了一下是這個解決的:
--- a/Wrapping/Python/vtkPython.h
+++ b/Wrapping/Python/vtkPython.h
@@ -53,6 +53,25 @@
# include <Python.h>
#else
# ifdef _DEBUG
+// Include these low level headers before undefing _DEBUG. Otherwise when doing
+// a debug build against a release build of python the compiler will end up
+// including these low level headers without DEBUG enabled, causing it to try
+// and link release versions of this low level C api.
+# include <basetsd.h>
+# include <assert.h>
+# include <ctype.h>
+# include <errno.h>
+# include <io.h>
+# include <math.h>
+# include <sal.h>
+# include <stdarg.h>
+# include <stddef.h>
+# include <stdio.h>
+# include <stdlib.h>
+# include <string.h>
+# include <sys/stat.h>
+# include <time.h>
+# include <wchar.h>
# undef _DEBUG
# if defined(_MSC_VER) && _MSC_VER >= 1400
# define _CRT_NOFORCE_MANIFEST 1
在debug 模式下除錯,把 以上標頭檔案手動的在包含 python.h 之前手動的加了進去。此問題解決,我也是雲裡霧裡;
TIP3: 關於vs的一個功能的使用,除錯 動態連結庫: 大概方法如下:
在工程屬性,除錯,選擇本地偵錯程式, 選擇命令,和引數。其實這個和 執行命令 python.exe test_player應該是一樣的,但是路徑要確保沒錯。之後設好了之後
F5執行就會執行 啟動 命令引數這個檔案, 之後在程式中加入斷點,呼叫動態連結庫的時候就會跳至斷點了。
TIP4: 關於python程式的打包,可以適用 pyinstaller 這個工具進行打包生成 .exe ,打包方式可以打包成一個單一的 exe ,體積略大。或者是一個exe 和一些依賴庫,對於適用vs開發的程式需要帶上對應版本的 vs 的執行時庫,我的vs2013 用 msvcr120.dll, msvcp120.dll, 也可以在編譯的時候選用靜態連結把所呼叫的東西直接編譯到生成檔案裡,這種情況好像有缺陷,這些情況都是可選的,設定在專案的屬性-> c++ -> 程式碼生成 -> 執行時庫 -> MT / MD , 這兩個選項的行作用可以查一下。對於64 位的系統,在C盤windows -> systemWOW, 好像有這麼一個資料夾,裡面是對 32 位程式相容的一些庫,在64 位系統下可以用win32程式,也可以用64程式,是因為64位系統對win32程式的執行也提供支援,重新拷貝了一份,所以安裝系統的時候會發現,64位系統比32位系統大很多,C盤就是這麼被耗用了的。
-- 暫時到這裡 --