什么是库文件?
库文件是事先编译好的方法的合集。比如:我们提前写好一些数据公式的实现,将其打包成库文件,以后使用只需要库文件就可以,不需要重新编写。
库文件分两种:静态库和动态库(也叫共享库)
Windows系统静态库扩展名为:.lib 动态库扩展名为.dll;
Linux系统下静态库的扩展名为.a 动态库的扩展名为.so;
一、静态库(也称作归档文件):
简单来说就是一组“准备好使用”状态的目标文件。当程序需要使用库函数中的某个函数时,程序就要包含该函数的头文件。(这时,想起了libevent库,使用时要引用头文件#include"event.h",编译链接时再命令后加 -levent,编译器和链接器负责将程序代码和库函数结合在一起以组成一个单独的可执行文件。)
程序在链接的过程中,链接器从库文件中取得所需代码,复制到生成的可执行文件中。因此,静态库是在程序员的链接阶段被复制到程序当中,和程序的执行没有任何关系。
如何创建静态库?
例如有两个源文件main1.c main2.c
(1)gcc -c a.c b.c (得到main1.o main2.o)
(2)ar crv libxxx.a main1.o main2.o (ar命令(archive即建立归档文件) 将目标文件归档)
xxxlibxxx.a 即为我们创建的静态库。
二、动态库:
在链接阶段并没有加载到程序当中,而程序在运行时被系统动态加载到内存中供程序使用。(程序本身不包含)
如何创建?
例如:有源文件 main.c
(1)gcc -fPIC -shared -o libxx.so main.c
(相当于gcc -c -fPIC main.c
gcc -shared -o libxx.so main.o
)
**libxx.so即是生成的共享库
两个参数的意义:
-shared :指定创建的为共享文件
-FPIC :代码位置无关
关于地址无关代码:可示例分析:nm -main.o (nm命令查看.o文件的符号)
动态链接下,一个程序被分成了一个可执行部分和若干个共享库(lib.so),也将这部分成为 模块。
命令ldd :查看可执行文件中用到那些共享库
看到熟悉的libevent库、json库、mysql库、openssl库......
三、二者在底层实现上的区别:(这里写的是我的理解,参考《程序员自我修养》)
1.链接时(链接器完成):
静态链接时分两步:空间与地址分配、符号解析与重定位。
链接时重定位;链接器在空间与地址分配后可以确定所有符号的虚拟地址了,然后链接器根据每个符号的地址对需要重定位的指令进行地位修改;
动态链接时分三步:启动动态链接器本身(它本身也是一个共享对象)、装载所有需要的共享对象、重定位的初始化。
动态链接时的重定位为:装载时重定位,即在链接时,对所有的符号的绝对地址不做重定位,而把这一步操作推迟 到装载时完成。一旦模块装载地址确定,即目标地址确定,那么操作系统就会对程序中所有的绝对地址进行重定位。
1.运行时的区别:(程序最终要到物理内存上运行)
静态链接的程序最终只有一个可执行文件;
动态链接设计运行时的链接和多个文件的装载,所以需要系统的支持。
四、二者在功能上的区别
1.静态库的可执行文件中包含了库文件的一份完整的拷贝,因此,当它被多次使用时就会有多份没用的拷贝在内存中,所以比较占内存;(当你运行许多应用程序,这些应用程序都使用了来自同一个函数库的函数时,那么这台运行多个程序的计算机的内存中就会有这个函数的多份副本,而且程序文件自身中也会有多份同样的副本。不仅占用内存也占磁盘);
2.还有一个缺点就是 模块更新困难(对程序的更新、部署、发布带来困难,比如一个公司发布一个程序,这个程序需要第三方厂商的一个lib.o库,之后这个厂商更新的lib.o库,那么这个公司需要再次将新版本的库和原来程序的.o文件重新链接,再发布给用户;即一旦产品有任何模块更新,整个程序需要重新链接、发布)
-----------------
1.动态库系统只需要载入一次动态库,不同的程序可以得到内存当中的动态库的副本,因此节省很多内存,节省磁盘。
2.减少物理页面的换进换出,增加CPU缓存的命中率,因为不同程序间的数据和指令访问都集中在同一个共享模块上。
3.程序升级方便。用户只需要下载一个升级包,不需要安装整个更新后的程序。
4.可拓展性增强:因为程序在运行时可以动态的加载各个模块,以此为特点就可以制作--插件(plug—in)
5.增加程序的兼容性。
动态库也有一些缺点:
程序更新后,新模块和旧模块中间接口不兼容,导致原来的程序不能运行。
(本文参考【程序员的自我修养】第4章 第7章 ,详细讲解静态链接和动态链接;参考【Linux程序设计】第一章第二节第4小结)
--------------------------(一些废话)----------------
自己写的这篇,感觉思路不够清晰,可以参考https://blog.csdn.net/sssssuuuuu666/article/details/78788369,个人认为写的比我强很多,图文搭配,版型也好。
写这篇博客后,发现最近学习的一些误区,把CSDN上的博客当主力去分析,而很多帖子其实讲的只是我不知道的一个点或者两个点,内容其实很浅,而我仅仅不知道一个点所以很浅的内容让我觉得很收益。但这样的学习,并不是很有效。
发现我在学习的深度上,还走的不够深,很多东西都是知道大概,知其然而不知其所以然。所以,应该系统性的看书去学习。
就像那本《程序员的自我修养》,还没学Linux时,我硬着头皮看了前6章,很多东西理解的很不到位;现在学完了Linux的课程,今天为了写博客,再去翻那本书,感受确实不一样,很多东西的理解,很多书上的内容,确实会产生共鸣。