一、Python调用C动态链接库
Python调用C库比较简单,不经过任何封装打包成so,再使用python的ctypes调用即可。
(1)C语言文件:pycall.c
(2)gcc编译生成动态库libpycall.so:gcc -o libpycall.so -shared -fPIC pycall.c。使用g++编译生成C动态库的代码中的函数或者方法时,需要使用extern "C"来进行编译。
(3)Python调用动态库的文件:pycall.py
补充说明:
stdcall调用约定:两种加载方式
cdecl调用约定:也有两种加载方式
(4)运行结果:
二、Python调用C++(类)动态链接库
需要extern "C"来辅助,也就是说还是只能调用C函数,不能直接调用方法,但是能解析C++方法。不是用extern “C”,构建后的动态链接库没有这些函数的符号表。
(1)C++类文件:pycallclass.cpp
(2)g++编译生成动态库libpycall.so:g++ -o libpycallclass.so -shared -fPIC pycallclass.cpp。
(3)Python调用动态库的文件:pycallclass.py
(4)运行结果:
三、Python调用C/C++可执行程序
1)C/C++程序:main.cpp
(2)编译成二进制可执行文件:g++ -o testmain main.cpp。
(3)Python调用程序:main.py
(4)运行结果:
四、扩展Python(C++为Python编写扩展模块)
所有能被整合或导入到其它python脚本的代码,都可以被称为扩展。可以用Python来写扩展,也可以用C和C++之类的编译型的语言来写扩展。Python在设计之初就考虑到要让模块的导入机制足够抽象。抽象到让使用模块的代码无法了解到模块的具体实现细节。Python的可扩展性具有的优点:方便为语言增加新功能、具有可定制性、代码可以实现复用等。
为 Python 创建扩展需要三个主要的步骤:创建应用程序代码、利用样板来包装代码和编译与测试。
(1)创建应用程序代码和样板代码
接口的代码被称为“样板”代码,它是应用程序代码与Python解释器之间进行交互所必不可少的一部分。样板主要分为4步:a、包含Python的头文件;b、为每个模块的每一个函数增加一个型如PyObject* Module_func()的包装函数;c、为每个模块增加一个型如PyMethodDef ModuleMethods[]的数组;d、增加模块初始化函数PyMODINIT_FUNC。
Python.h头文件在大多数类Unix系统中会在/usr/local/include/python2.x或/usr/include/python2.x目录中,系统一般都会知道文件安装的路径。
增加包装函数,所在模块名为Extest,那么创建一个包装函数叫Extest_fac(),在Python脚本中使用是先import Extest,然后调用Extest.fac(),当Extest.fac()被调用时,包装函数Extest_fac()会被调用,包装函数接受一个 Python的整数参数,把它转为C的整数,然后调用C的fac()函数,得到一个整型的返回值,最后把这个返回值转为Python的整型数做为整个函数调用的结果返回回去。其他两个包装函数Extest_doppel()和Extest_test()类似。
从Python到C的转换用PyArg_Parse系列函数,int PyArg_ParseTuple():把Python传过来的参数转为C;int PyArg_ParseTupleAndKeywords()与PyArg_ParseTuple()作用相同,但是同时解析关键字参数;它们的用法跟C的sscanf函数很像,都接受一个字符串流,并根据一个指定的格式字符串进行解析,把结果放入到相应的指针所指的变量中去,它们的返回值为1表示解析成功,返回值为0表示失败。从C到Python的转换函数是PyObject Py_BuildValue():把C的数据转为Python的一个对象或一组对象,然后返回之;Py_BuildValue的用法跟sprintf很像,把所有的参数按格式字符串所指定的格式转换成一个Python的对象。
C与Python之间数据转换的转换代码:
为每个模块增加一个型如PyMethodDef ModuleMethods[]的数组,以便于Python解释器能够导入并调用它们,每一个数组都包含了函数在Python中的名字,相应的包装函数的名字以及一个METH_VARARGS常量,METH_VARARGS表示参数以tuple形式传入。 若需要使用PyArg_ParseTupleAndKeywords()函数来分析命名参数的话,还需要让这个标志常量与METH_KEYWORDS常量进行逻辑与运算常量 。数组最后用两个NULL来表示函数信息列表的结束。
所有工作的最后一部分就是模块的初始化函数,以便于解释器能正确的调用模块中的函数。
(2)编译
-fPIC:生成位置无关目标代码,适用于动态连接;
-L path:表示在path目录中搜索库文件,如-L.表示在当前目录;
-I path:表示在path目录中搜索头文件;
-o file:制定输出文件为file;
-shared:生成一个共享库文件;
把生成的so放到import能找到的目录(一般放在C:\Python34\DLLs\中)。
备注如果是window下,需要把dll重命名t2.pyd.
运行Python解释器,测试如下
五、Boost::python编写C++扩展模块
5.1 编译boost::python库
5.1.1 下载源码
到boost官网下载boost源码,解压到想放到的位置,例如: E:\Learning\Boost\boost_1_69_0
5.1.2 编译boost的lib库
如何系统中只有一个VS,并且Python已加入环境变量,可以切换到boost源码路径下,简单执行以下命令进行编译:
可参考:Boost Getting Started on Windows , Installing Boost.Python on your System
其默认会在boost的stage文件夹下生成静态lib文件。
若需指定参数编译可运行以下命令,查看其帮助文档:
可参考:vs2017编译boost库 ,解决无法打开文件“libboost_filesystem-vc140-mt-1_58.lib” 问题,C++和Python的混合编程-Boost::python的编译和配置
5.2 VS项目配置
- VS2015建立名为Boost_Python_Sample的Win32的dll工程
- VS2015也可建立一个Win32 Console Applicantion,然后在VS->Project->Properties::Genneral::Configuration Type里改成dll
- 工程设置(Project->Properties->VC++ Directories)
- Include Diretorise加上Boost根目录
- Include Diretorise加上Python的include目录
- Library Diretoties加上boost编译出来的lib目录
- Library Diretoties加上Python的libs目录
可参考:BOOST的AUTO link机制以及配置,Boost库解密——自动链接库(auto_link),C++和Python的混合编程-Boost::python的编译和配置
5.3 源码
(1)因为使用的是静态编译的boost::python库,所以在include头文件之前要加上BOOST_PYTHON_STATIC_LIB,因为在boost::python库的config.hpp中规定,如没定义BOOST_PYTHON_STATIC_LIB ,则采用动态编译的库
(2)示例代码
可参考:C++和Python的混合编程-Boost::python的编译和配置,Boost Exposing Classes,Boost.Python C++导出基本用法
(3)Python_Test_Sample为导出的模块dll,可直接将输出dll文件改成bp.pyd(和BOOST_PYTHON_MODULE(bp)中的bp保持一致),可将pyd文件拷贝到python的库目录下(python —>lib —>site-packages),或者命令行直接进入pyd所在的目录。
(4)执行Python
新建bp.py,然后执行它,或者命令行执行:
参考
1、Python与C/C++的混合调用 2、Python调用C++程序的几种方法
3、Python调用windows下DLL详解 - ctypes库的使用
4、python3 C++扩展
6、Windows下为Python编译C扩展模块
7、Boost Getting Started on Windows
8、Installing Boost.Python on your System
10、Boost.Python C++导出基本用法
11、C++和Python的混合编程-Boost::python的编译和配置
12、Boost::Python的安装与调用教程
13、boost github
14、官网Boost.Python
15、vs2017编译boost库 ,解决无法打开文件“libboost_filesystem-vc140-mt-1_58.lib” 问题
16、BOOST的AUTO link机制以及配置
17、Boost库解密——自动链接库(auto_link)
18、C++ Boost库的编译及使用