【工作总结】通过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 
 #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 
+# include 
+# include 
+# include 
+# include 
+# include 
+# include 
+# include 
+# include 
+# include 
+# include 
+# include 
+# include 
+# include 
+# include 
 #  undef _DEBUG
 #  if defined(_MSC_VER) && _MSC_VER >= 1400
 #    define _CRT_NOFORCE_MANIFEST 1

在debug 模式下调试,把 以上头文件手动的在包含 python.h 之前手动的加了进去。此问题解决,我也是云里雾里;

TIP3: 关于vs的一个功能的使用,调试 动态链接库: 大概方法如下:

【工作总结】通过SWIG实现 python 和 c++ 互相通信_第1张图片

在工程属性,调试,选择本地调试器, 选择命令,和参数。其实这个和 执行命令 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盘就是这么被耗用了的。


-- 暂时到这里 --


你可能感兴趣的:(C++)