关于动态库与静态库
-
本质上来说库是一种可执行代码的二进制形式,可以被操作系统载入内存执行。库有两种:静态库(.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 -> 依赖 A , A又依赖于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
- 关于我们: