C++动态库和静态库的特点及编译使用

1 库的概念?

库是写好的现有的,成熟的,可以复用的代码。现实中每个程序都要依赖很多基础的底层库。

2 动态库与静态库的概念?

先回顾一下编译过程:

2.1 静态库

在链接阶段,链接器会将汇编生成的目标文件.o与引用到的静态库中的目标模块一起链接打包到可执行文件中,对应的链接方式称为静态链接。试想一下,静态库与汇编生成的目标文件(.o文件)一起链接为可执行文件,那么静态库必定跟.o文件格式相似。

其实一个静态库可以简单看成是一组目标模块(.o/.obj文件)的归档集合,即很多目标文件经过压缩打包后形成的一个文件,链接可执行程序时只取其中用到的目标模块。静态库特点总结:

1、静态库对函数库的链接是放在编译时期完成的。
2、程序在运行时与函数库再无瓜葛,移植方便。
3、浪费空间和资源,因为所有相关的目标文件与牵涉到的函数库被链接合成一个可执行文件。

除了上面提到的浪费空间和资源的弊端,使用静态库还有另一个问题:对程序的更新、部署和发布页会带来麻烦。如果静态库libtest.a更新了,所有使用它的应用程序都需要重新编译、发布给用户。

 

2.2 动态库

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

3 动态库的创建和使用

 

我们编写了一个string类型接口的测试程序,工程中包含mystring.cpp mystring.h mystring_test.cpp三个源文件,以及工程的makefile文件

3.1 创建libstring.so动态库

"g++ -shared mystring.cpp mystring.h -o libstring.so"编译生成动态库,但是报了如下错误:

 

 

 

 

 

 

"g++ mystring.cpp mystring.h -fPIC -shared -o libstring.so"成功编译生成动态库:

【注:PIC参数告诉编译器产生与位置无关代码(Position-Independent Code),则产生的代码中,没有绝对地址,全部使用相对地址,故而代码可以被加载器加载到内存的任意位置,都可以正确的执行。这正是共享库所要求的,共享库被加载时,在内存的位置不是固定的。共享对象可能会被不同的进程加载到不同的位置上,如果共享对象中的指令使用了绝对地址、外部模块地址,那么在共享对象被加载时就必须根据相关模块的加载位置对这个地址做调整,也就是修改这些地址,让它在对应进程中能正确访问,而被修改到的段就不能实现多进程共享一份物理内存,它们在每个进程中都必须有一份物理内存的拷贝。fPIC指令就是为了让使用到同一个共享对象的多个进程能尽可能多的共享物理内存,它背后把那些涉及到绝对地址、外部模块地址访问的地方都抽离出来,保证代码段的内容可以多进程相同,实现共享。

3.2 在测试程序中使用动态库

工程的makefile如下:

【注:-L参数指定动态库路径,-l参数动态链接】

用"ldd mystring"查看这个可执行文件的动态链接情况,发现libstring.so这个动态库找不到,是因为链接时链接器(dynamic linker)找到了动态库libstring.so,但动态加载器(dynamic loader, 一般是/lib/ld-linux.so.2)却没找到。

在运行可执行mystring可执行文件时就报错了:

linux为我们提供了两种解决方法:

1.可以把当前动态库路径加入/etc/ld.so.conf中然后运行ldconfig,或者以当前路径为参数运行ldconfig(要有root权限才行)。

2.把当前路径加入环境变量LD_LIBRARY_PATH中

我们这里使用export命令直接将当前路径导入环境变 量LD_LIBRARY_PATH,然后运行程序,运行成功

4 静态库的创建和使用

4.1 创建静态库

先编译生成目标文件,如下图,其中的mystring.o是目标文件

 

 

 

 

将目标文件归档创建成静态库(libmystring.a)

4.2 使用静态库

修改工程makefile:

与动态链接编译命令相比较,静态链接编译命令只是多了"-static"参数,Linux默认链接动态库,加了static参数就会链接静态库。"-static"参数告诉编译器驱动程序,链接器应该构建一个完全链接的可执行目标文件,它可以加载到内存并运行,在加载时无须更进一步的链接。"-L."告诉链接器在当前目录下查找libmystring.a。

注:关于库的一般准则是将它们放在命令行的结尾:

  1. 如果各个库的成员是相互独立的(没有引用其它库定义的成员符号),那么这些库可以以任意顺序放在命令行的结尾。
  2. 如果库不是相互独立的,那么必须对它们排序,使得对于每个被存档文件的成员外部引用的符号s,在命令行中至少有一个s的定义是在对s的引用之后的。比如foo.c调用libx.a和libz.a中的函数,而libx.a和libz.a又调用liby.a中函数,那么,命令行中libx.a和libz.a必须在liby.a前面:
gcc foo.c libx.a libz.a liby.a

5 对比

看一下使用动态库链接的方式和静态链接的方式生成的程序有什么差别:

动态链接方式:

静态链接方式:

 

 

 

 

很明显,动态链接方式生成的可执行文件比静态链接方式生成的可执行文件将占用更少的内存。

 

 

 

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值