爱测未来开发-手把手教你利用C++为Python写扩展

关于动态库与静态库

  • 本质上来说库是一种可执行代码的二进制形式,可以被操作系统载入内存执行。库有两种:静态库(.a、.lib)和动态库(.so、.dll)。



程序编译的过程

src源代码 (.cpp,.c)-> 预编译 -> 编译 -> 汇编 -> 链接 

链接-> 可执行程序 .exe/.bin

从链接 到可执行程序之间 有两种方式,一种叫静态链接,另一种叫动态链接

对于静态链接:

  • 静态库对函数库的链接是放在编译时期完成的。

  • 程序在运行时与函数库再无瓜葛,移植方便。

  • 浪费空间和资源,因为所有相关的目标文件与牵涉到的函数库被链接合成一个可执行文件。


而对于动态链接

  • 空间浪费是静态库的一个问题。

  • 静态库在更新上,如果一个依赖更新,全部需要重新编译

  • 动态库在程序编译时并不会被连接到目标代码中,而是在程序运行是才被载入。不同的应用程序如果调用相同的库,那么在内存里只需要有一份该共享库的实例,规避了空间浪费问题。动态库在程序运行是才被载入,也解决了静态库对程序的更新、部署和发布页会带来麻烦。用户只需要更新动态库即可,增量更新。


动态库特征

  • 动态库把对一些库函数的链接载入推迟到程序运行的时期。

  • 可以实现进程之间的资源共享。(因此动态库也称为共享库)

  • 将一些程序升级变得简单。

  • 甚至可以真正做到链接载入完全由程序员在程序代码中控制(显示调用)。

Windows动态库和Linux动态库区别

Window与Linux执行文件格式不同,在创建动态库的时候有一些差异。

  • 在Windows系统下的执行文件格式是PE格式,动态库需要一个DllMain函数做出初始化的入口,通常在导出函数的声明时需要有_declspec(dllexport)关键字。

  • Linux下gcc编译的执行文件默认是ELF格式,不需要初始化入口,亦不需要函数做特别的声明,编写比较方便。 与创建静态库不同的是,不需要打包工具(ar、lib.exe),直接使用编译器即可创建动态库。

言归正传说Python扩展

我们本次采用给python扩展dll也就是动态库的方式来实现python调用c++

准备

  • python2.7.10 win32环境 c:/python27

  • vs2010

  • boost 1_62_0最新src代码

但是我们还是要先说下boost,因为今天python扩展主教就是 boost.python

编译boost

  • 首先解压boost, 使用vc 2010 command 进入boost源码,执行bootsrap.bat生成b2.exe等工具链

  • 使用命令:bjam stage --with-python --toolset=msvc-10.0 --build-type=complete --stagedir="D:\boost_1_62_0\bin\vc10" link=shared runtime-link=shared threading=multi debug release编译出带python的boost lib库

  • 得到lib库为boost_python-vc100-mt-1_62.dll,boost_python-vc100-mt-1_62.lib两个

  • vc设置 include 和link目录为boost以及python等


编译遇到的问题

link, runtime-link 组合分析

假设一个库A依赖于库B,我们自己的程序client依赖于库A,即:
client -> 依赖 AA又依赖于B ,A和B就是run-time link
而我们自己程序 client 和 A 就是link
  • link=static runtime-link=static

    这时候client通过A.a(A.lib)静态包含A;A通过B.a (B.lib)静态包含B;不关 .so .dll的事

  • link=static runtime-link=shared client通过A.a (A.lib)静态包含A; 在运行时,client要动态调用B.so (B.dll)

  • link=shared runtime-link=shared client会包含A.a (A.lib); A会包含 B.a (B.lib); 但都只保存动态库的真正实现的stub,运行时通过stub去动态加载 A.so(A.dll), B.so (B.dll) 中的实现

  • link=shared runtime-link 这种貌似不存在

boost库名称特点

1)以“lib”开头的是“link=static”版本(静态链接库版本,没有dll),而直接以“boost”开头的是“link=shared”版本(动态链接库版本,包含lib和dll)。

(2)所有的库都含有"boost"前缀。

(3)紧随其后的是boost库名称(比如date_time库)。

(4)然后是编译器的版本,与库名称之间以"-"而不是下划线"_"分隔(比如 -vc100)。

(5)有“mt”的为“threading=multi”版本,没有的则是“threading=single”版本。

(6)有“s”的为“runtime-link=static”版本,没有的则是“runtime-link=shared”版本。

(7)有“gd”的为debug版本,没有的则是release版本。

(8)所有的库都含有boost库的版本号结尾(比如1_62,其中的"."以下划线"_"代替)

所以我们来Helloworld吧

  • 官方示例

#include <boost/python.hpp>
char
const* greet()
{
return
"hello, world"; } BOOST_PYTHON_MODULE(export){
using namespace boost::python def("greet",greet); }
  • 我们编译的是32位的,因此要link 32位python(一般装python没有debug版本故要选择 release编译) lib库,include添加c:/python27/include 等配置我就不说了

  • 项目属性configproperies -> general -> targent_extension 填写.pyd


配置正确后 编译后在注意是 RELEASE版本输出目录找到export.pyd

拷贝boost_python-vc100-mt-1_62.dll 到此目录 我们命令行执行python并且cd到此目录验证我们的 pyd扩展

Python 2.7.12 (v2.7.12:d33e0cf91556, Jun 27 2016, 15:19:22) [MSC v.1500 32 bit (Intel)] on win32Type"help", "copyright", "credits" or "license" for more information.
>>> import export
>>> export.greet()
'hello, world'
>>> print export.greet() hello, world
>>
>

Done

  • 整个流程已经走通, 对python的一些具体扩展方式 参见官方doc

    http://www.boost.org/doc/libs/1_62_0/libs/python/doc/html/tutorial/index.html#tutorial.quickstart

  • 关于我们:

    公众号:itest_forever


    CSDN:http://blog.csdn.net/itest_2016

    QQ群:274166295(爱测未来2群)、610934609(爱测未来3群)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值