我们编写的程序一般需要经过预处理,编译,汇编和链接这几个步骤才变成可执行的程序. 在实际的软件开发中,对于一些需要被许多模块反复使用的
公共代码,我们将它们编译为库文件. 在windows平台和linux平台下都大量存在着库. 本质上来说库是一种可执行的二进制形式,可以被操作系统载入
内存执行. 由于windows和linux的本质不同,因此二者库的二进制是不兼容的. 所以呢,今天我们着重来看看Linux下的库.
linux下的库有两种:静态库和共享库(动态库). 二者的不同点在于代码被载入的时刻不同:
静态库的代码在编译过程中已经被载入可执行程序,因此体积较大.
共享库的代码是在可执行程序运行时才载入内存的,在编译过程中仅简单的引用,因此代码体积较小.
我们的动态库和静态库都是链接的时候才会运行,回顾一下,将一个程序编译成可执行程序的步骤:
静态库在程序编译时会自动连接到目标代码中,程序运行时将不再需要该静态库. 不过呢,静态库在内存中存在多份拷贝会造成空间的浪费,例如
静态库占用1M内存,有2000个这样的程序,将占用近2GB的空间. 所以才会有动态库的出现. 静态库的特点有以下这几个部分:
1.静态库对函数库的链接是放在编译时期完成的.
2.程序在运行时与函数库再无瓜葛,移植方便.
3.浪费空间和资源,因为所有相关的目标文件与牵扯到的函数库被链接合成一个可执行文件.
4.是静态库对程序的更新,部署和发布页会带来麻烦.如果静态库liba.lib更新了,所以使用它的应用程序都需要重新编译,发布给用户.
接下来就是动态库啦,动态库就是静态库的一个升级版本,算是创新. 因为节约了空间. 动态库在程序编译时并不会被连接到目标代码中,而是程序
运行时才会被载入,因此在程序运行时还需要动态库的存在. 动态库就是一个对应的资源,所有要执行的程序来我这里拿,并不是我把我所有的拷贝
动态库的总结:
1.动态库把对一些库函数的链接载入推迟到程序运行的时期.
2.可以实现进程之间的资源共享 (动态库也叫共享库)
3.将一些程序升级变得简单
4.甚至可以真正做到链接载入完全由程序员在程序代码中控制(显示调用)
所以我们现在可以看到,静态库的优点是编译后的执行程序不需要外部的函数库支持,缺点是如果静态函数库改变了,那么你的程序就必须重新编译
;而动态库在多个应用程序都要使用同一个函数库的时候就非常合适啦,但是前提是程序的运行环境中必须提供相应的库.不管是静态库和动态库,都是
有*.o目标文件生产的.
//test.h
#ifndef _TEST_H__
#define _TEST_H__
int print();
#endif //_TEST_H__
//test.c
#include
int print()
{
printf("hello world\n");
return 1;
}
//main.c
#include"test.h"
int main()
{
print();
return 0;
}
gcc -fPIC -c test.c
gcc -shared -o libmytest.so test.o
这个时候就不能运行了,因为动态库把对一些库函数的链接载入推迟到程序运行的时期. 所以因为我删了动态库可执行程序报错了. 现在总结一下,这
种方式是动态库的常用的方式,我们程序在链接过程的时候链接到动态库,然后生产可执行文件. 在可执行文件执行时,将动态库内容加载到内存当中
所以程序启动起来之后,就跟动态库已经没什么关系了,其实这样是有一点隐患的,接下来我们来看看更好的方法.
首先我记着前几年的时候,那个时候我们热爱的一些网络游戏总是会有一些游戏更新,大部分都停服更新,然后给你发好多的更新包等你更新了以后就
可以进行愉快的玩游戏了,现在我突然想了一下,我们下载的难道不就是更换了静态库的可执行文件吗? 然后替换掉本地的可执行文件,最后就完成
了游戏的更新. 而现在很多的游戏有一个不停服更新,不知不觉的我们就更新完成了,究其原因还是因为使用了动态库替换了静态库. 我们程序中的大
型动态库都是利用动态链接器连接动态库,然后动态库映射到共享存储映射区,供进程使用. 所以我们如果能够让程序运行的时候寻找动态库,而不是
我们给他规定好路径,也就是说! 就算进程跑起来之后,他每一次需要数据的时候,他不去内存里面拿,他还是要去远程动态库中拿. 这样我们每次
更新的时候,只需要更改远程库的内容即可,动态库的动态加载方式就是这么的强大!
在main.c中增加头文件#include
我们目前为止只关心dlopen就可以啦.
第一个参数:指定共享库的名称,将会在下面位置查找指定的共享库.
第二个参数:指定打开共享库. -RTLD_NOW:将共享库的所有函数加载到内存 -RTLD_LAZY:会退后共享库中的函数的加载操作.
返回值:返回动态库的句柄.
对于以上几个函数我们需要对它们进行一定的了解,因为动态库的动态加载方式靠的都是他们这些函数,dlopen尤为重要。