静态库和动态库
1、什么是库文件
库文件就是计算机上的一种文件,也相当于一种代码仓库,可以供他人直接使用的变量、函数以及类。库是一类特殊的程序,编写库的程序与编写一般程序的差别不大,但是库不可单独运行。库文件主要功能是代码保密以及方便部署。
库文件可区分为静态库以及动态库,其中:静态库是在程序的链接阶段被复制在程序中;动态库则是在链接阶段不会复制在程序中,而是在运行时由系统动态加载到内存中供程序调用。
2、静态库
2.1库文件命名规则
Linux : libxxx.a
--lib : 固定前缀
--xxx : 库文件名
--.a : 固定后缀
windows : libxxx.lib
2.2静态库制作
1、 gcc获取.o文件 : gcc -c main.c ,编译 main.c 文件,并生成目标文件 main.o
--gcc: GNU Compiler Collection 的缩写,是一个开源的编译器套件,用于编译和链接程序。
-- -c : 是 gcc 的选项之一,表示进行编译但不进行链接。它告诉编译器只生成目标文件,而不生成可执行文件。
--main.c: 是需要编译的源文件名,这里假设 main.c 是你的源代码文件。
2、 将 .o 文件打包制作成库 : ar rcs libxxx.a xxx.o xxx.o
--ar: 是一个用于创建、修改和提取静态库文件(Archive 文件)的工具。
--rcs: 是 ar 命令的选项参数,具体含义如下:
r: 将文件插入到归档文件中。如果文件已经存在于归档文件中,则先删除原文件再插入。
c: 创建归档文件。如果归档文件不存在,则创建一个新的归档文件。
s: 更新归档文件的索引信息。这个选项通常用于更新归档文件的索引,以确保归档文件中包含每个对象文件的索引信息,这样可以加快链接过程。
--libxxx.a : 创建的静态库名
--xxx.o : 需要插入到静态库中的目标文件
3、动态库
3.1命名规则
Linux : libxxx.so
--lib : 固定前缀
--xxx : 动态库的名字
--.so : 固定后缀
windows : libxxx.dll
3.2动态库制作
1、gcc 得到 .o 文件,得到和位置无关的代码 : gcc -c –fpic/-fPIC a.c b.c
-- -fpic 或 -fPIC: 这两个选项是用来告诉编译器生成位置无关代码。
2、gcc 得到动态库 : gcc -shared a.o b.o -o libxxx.so
-- -shared: 是 gcc 的选项之一,表示生成一个共享库(shared library)。共享库也被称为动态链接库(Dynamic Link Library,DLL),它包含可在运行时加载到内存中并被程序动态链接的代码和数据。
--a.o b.o: 是要链接的目标文件列表,通常是使用 -fpic 或 -fPIC 选项编译得到的位置无关代码的目标文件。
-- -o libxxx.so: 指定生成的动态库文件的名称为 libxxx.so
4、工作原理
- 静态库 : GCC在进行链接时,将静态库中的代码打包至可执行程序中
- 动态库 : GCC在进行链接时,动态库中的代码不会打包至可执行程序中
- 可执行程序在启动之后,动态库将动态加载至内存,可通过 ldd 命令检查动态库依赖关系
- 定位动态库文件方法:
- 1.先搜索 elf 文件的 DT_RPATH 段
- 2.搜索环境变量 LD_LIBRARY_PATH , 设置 LD_LIBRARY_PATH 环境变量来指定动态链接器的搜索路径 : export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/home/nowcoder/Linux/lesson03/04_lib/library/lib 。 这样设置后,动态链接器在运行时会优先搜索 /home/nowcoder/Linux/lesson03/04_lib/library/lib 目录中的共享库。
- 3.使用 ldconfig 更新共享库缓存 , ldconfig 命令用于更新动态链接器的运行时连接配置,它会重建 /etc/ld.so.cache 文件,其中包含了动态链接库的缓存信息。如果你安装了新的共享库或者修改了共享库路径,可能需要运行sudo ldconfig 命令来更新系统的共享库缓存,以确保新的共享库可以被正确加载。
- 4.系统默认搜索路径 :Linux系统在链接共享库时会搜索一组默认的路径,这些路径通常包括: /lib/,/usr/lib 目录。
- 5.指定额外的共享库路径 : 如果共享库不在默认的搜索路径下,可以使用 -L 选项来指定额外的搜索路径。
gcc myprogram.o -o myprogram -L/path/to/custom/lib -lmath
-- myprogram.o: 是编译生成的目标文件。
-- -o myprogram: 指定输出文件为 myprogram。
-- -L/path/to/custom/lib: 指定额外的库文件搜索路径,这里假设 /path/to/custom/lib 是 libmath 库所在的路径。
-- -lmath: 指定要链接的库为 libmath。gcc 将会在指定的路径和系统默认路径下查libmath.so 或 libmath.a 文件,并将其链接到最终的可执行文件 myprogram 中。
这样,你就可以成功编译并链接一个依赖于 libmath 数学库的程序 myprogram。
5、两者区别
静态库
优点
- 静态库打包到应用程序中加载速度快
- 因为静态库在编译时完全嵌入到可执行文件中,所以发布程序时无需提供静态库,移植方便
缺点
- 消耗系统资源 : 静态库会将所有代码和数据都复制到可执行文件中,这意味着如果多个程序使用了同一个静态库,每个程序都会包含一份完整的库副本。这会导致可执行文件体积变大,尤其是当静态库较大时,会占用大量磁盘空间。
- 浪费内存、内存使用效率低 : 当多个程序同时运行且使用同一个静态库时,操作系统需要为每个程序分配该静态库的内存空间。相比之下,共享库可以在内存中只加载一份,并由多个程序共享,节省内存使用。
- 更新、部署、发布麻烦 : 如果静态库更新了,所有依赖它的程序都需要重新编译以使用更新后的版本。这可能会增加维护成本,尤其是在需要频繁更新或修复 bug 的情况下。
动态库
优点
- 可以实现进程间资源共享 :动态库可以被多个应用程序共享使用,因为它们在内存中只需加载一次,不同的应用程序可以共享同一个动态库的实例,从而节省内存。
- 动态加载:动态库在程序运行时才会被加载,而不是编译时静态链接到可执行文件中。这使得程序可以根据需要动态加载和卸载库,从而实现更灵活的组件化和模块化设计。
- 更新管理:更新动态库比更新静态库更为方便,因为只需替换库文件即可,无需重新编译整个程序。这可以减少更新对程序其他部分的影响,并简化版本管理。
缺点
- 加载速度比静态库慢:相对于静态库,动态库在运行时需要进行加载和链接操作,这可能会导致一些额外的运行时性能开销。
- 发布程序时需要提供依赖的动态库 : 使用动态库需要确保目标环境中有正确的库版本,并在部署时处理好依赖关系和库路径设置,以确保程序正常运行。