如何实现 CC++ 与 Python 的通信

Python015

如何实现 CC++ 与 Python 的通信,第1张

这个事情做过好多遍,摸索的过程基本这样的:

1. 通过stdout通信...土到爆,但上手极快,简单粗暴;

2. 调用原始的python.h 接口,编写可以被python import 的so,支持python调用c++接口,c++接口调用python同样的方式;

3. 使用boost-python 完成2中的功能,接口简单很多,本质上没有不同;

这里遇到的主要几个问题在于:

1. 数据的序列化反序列化,因为有时c++和python之间通信的不是基本类型,可能是用户自定义类型;

2. 多线程的问题,c++多线程调python接口时,需要注意GIL的使用,貌似因为python解释器不是线程安全的;

3.

对象传递,大多数情况下,如果只是静态接口调用,都比较简单,考虑一种情况:c++中的对象的一个函数调用python一个接口,这个python接口中

又需要反过来调用这个对象中的另一个接口,这里就需要考虑怎么把对象相互传递,我这里是把对象指针地址传递到python中,在python中调用一个

c++的静态接口,带上地址和其他需要的参数,在这个c++的静态接口中,把地址转换成指针在调用..

用C/C++对脚本语言的功能扩展是非常常见的事情,Python也不例外。除了SWIG,市面上还有若干用于Python扩展的工具包,比较知名的还有Boost.Python、SIP等,此外,Cython由于可以直接集成C/C++代码,并方便的生成Python模块,故也可以完成扩展Python的任务。答主在这里选用SWIG的一个重要原因是,它不仅可以用于Python,也可以用于其他语言。如今SWIG已经支持C/C++的好基友Java,主流脚本语言Python、Perl、Ruby、PHP、JavaScript、tcl、Lua,还有Go、C#,以及R。SWIG是基于配置的,也就是说,原则上一套配置改变不同的编译方法就能适用各种语言(当然,这是理想情况了……)SWIG的安装方便,有Windows的预编译包,解压即用,绿色健康。主流Linux通常集成swig的包,也可以下载源代码自己编译,SWIG非常小巧,通常安装不会出什么问题。用SWIG扩展Python,你需要有一个待扩展的C/C++库。这个库有可能是你自己写的,也有可能是某个项目提供的。这里举一个不浮夸的例子:希望在Python中用到SSE4指令集的CRC32指令。首先打开指令集的文档可以看到有6个函数。分析6个函数的原型,其参数和返回值都是简单的整数。于是书写SWIG的配置文件(为了简化起见,未包含2个64位函数):/*File:mymodule.i*/%modulemymodule%{#include"nmmintrin.h"%}int_mm_popcnt_u32(unsignedintv)unsignedint_mm_crc32_u8(unsignedintcrc,unsignedcharv)unsignedint_mm_crc32_u16(unsignedintcrc,unsignedshortv)unsignedint_mm_crc32_u32(unsignedintcrc,unsignedintv)接下来使用SWIG将这个配置文件编译为所谓PythonModuleWrapperswig-pythonmymodule.i得到一个mymodule_wrap.c和一个mymodule.py。把它编译为Python扩展:Windows:cl/LDmymodule_wrap.c/o_mymodule.pyd-IC:\Python27\includeC:\Python27\libs\python27.libLinux:gcc-fPIC-sharedmymodule_wrap.c-o_mymodule.so-I/usr/include/python2.7/-lpython2.7注意输出文件名前面要加一个下划线。现在可以立即在Python下使用这个module了:>>>importmymodule>>>mymodule._mm_popcnt_u32(10)2回顾这个配置文件分为3个部分:定义module名称mymodule,通常,module名称要和文件名保持一致。%{%}包裹的部分是C语言的代码,这段代码会原封不动的复制到mymodule_wrap.c欲导出的函数签名列表。直接从头文件里复制过来即可。还记得本文第2节的那个great_function吗?有了SWIG,事情就会变得如此简单:/*great_module.i*/%modulegreat_module%{intgreat_function(inta){returna+1}%}intgreat_function(inta)换句话说,SWIG自动完成了诸如Python类型转换、module初始化、导出代码表生成的诸多工作。对于C++,SWIG也可以应对。例如以下代码有C++类的定义://great_class.h#ifndefGREAT_CLASS#defineGREAT_CLASSclassGreat{private:intspublic:voidsetWall(int_s){s=_s}intgetWall(){returns}}#endif//GREAT_CLASS对应的SWIG配置文件/*great_class.i*/%modulegreat_class%{#include"great_class.h"%}%include"great_class.h"这里不再重新敲一遍class的定义了,直接使用SWIG的%include指令SWIG编译时要加-c++这个选项,生成的扩展名为cxxswig-c++-pythongreat_class.iWindows下编译:cl/LDgreat_class_wrap.cxx/o_great_class.pyd-IC:\Python27\includeC:\Python27\libs\python27.libLinux,使用C++的编译器g++-fPIC-sharedgreat_class_wrap.cxx-o_great_class.so-I/usr/include/python2.7/-lpython2.7在Python交互模式下测试:>>>importgreat_class>>>c=great_class.Great()>>>c.setWall(5)>>>c.getWall()5也就是说C++的class会直接映射到PythonclassSWIG非常强大,对于Python接口而言,简单类型,甚至指针,都无需人工干涉即可自动转换,而复杂类型,尤其是自定义类型,SWIG提供了typemap供转换。而一旦使用了typemap,配置文件将不再在各个语言当中通用。参考资料:SWIG的官方文档,质量比较高。SWIGUsersManual有个对应的中文版官网,很多年没有更新了。写在最后:由于CPython自身的结构设计合理,使得Python的C/C++扩展非常容易。如果打算快速完成任务,Cython(C/C++调用Python)和SWIG(Python调用C/C++)是很不错的选择。但是,一旦涉及到比较复杂的转换任务,无论是继续使用Cython还是SWIG,仍然需要学习Python源代码。本文使用的开发环境:Python2.7.10Cython0.22SWIG3.0.6Windows10x64RTMCentOS7.1AMD64MacOSX10.10.4文中所述原理与具体环境适用性强。文章所述代码均用于演示,缺乏必备的异常检查