动静态库
一、静态库(.a)
1.1 如何创建静态库?
- 编写源文件与头文件。注意:库的源文件没有main函数!
- 将所有的源文件编译生成目标文件。(如果只提供.h和.o给用户,用户也可以成功编译运行。但这样的做法太过麻烦,且容易出错。)
- 利用ar工具将所有的目标文件归档生成静态库。注意:静态库文件的前缀是lib后缀是.a!
提示:ar是gnu归档工具,用于归档生成静态库。rc选项表示replace and create。
- 打包发布静态库:为静态库创建目录,并将头文件和库文件分开存放。
- 自动化生成并发布静态库
1.2 如何使用静态库?
先将静态库拷贝给用户
方法一:
-
将头文件和库文件直接拷贝到系统的默认搜索路径下
-
gcc头文件的默认搜索路径:
/usr/include
-
gcc库文件的默认搜索路径:
/lib64
or/usr/lib64
-
-
gcc会自动链接C静态库(libc.a),第三方库需要带
-l
选项指定要链接的库。注意:这里的库名称是要去掉lib前缀和.a后缀的!
提示:我们将库拷贝到系统默认搜索路径下的操作,就叫做库的安装!
方法二:通过-I
和-L
选项指定头文件和库文件的所在路径,并用-l
指明要链接的库
二、动态库(.so)
2.1 如何创建动态库?
- 编写源文件与头文件。注意:库的源文件没有main函数!
- 将所有的源文件编译生成目标文件。注意:生成动态库的目标文件要加
-fPIC
选项,生成与位置无关的目标文件
注意:
- 所谓与位置无关,即动态库采用相对编址的方式:动态库并没有被合并到可执行程序中,编译和链接时分配的地址是相对地址(偏移量):在程序执行时由运行时链接器加载库。将库中数据加载到内存中后,每个使用了动态库的程序都要根据加载的起始位置计算内部函数以及变量的地址。
- 而静态库采用绝对编址的方式:静态库的代码是被合并到可执行程序中的,其变量和指令的地址在编译和链接时就已经确定,并且在程序执行时保持不变。
- 通过
gcc -shared
命令将所有的目标文件归档生成动态库。注意:动态库文件的前缀是lib后缀是.so!
- 打包发布动态库:为动态库创建目录,并将头文件和库文件分开存放。(此处包含静态库)
- 自动化生成并发布动态库(此处包含静态库)
2.2 如何使用动态库?
2.2.1 动态库的加载
-
静态库代码会同程序代码合并在一起,程序运行时被直接加载到进程地址空间的代码区。
-
动态库代码在调用时才会被加载到内存并通过页表建立与地址空间的映射关系。动态库代码会被加载到地址空间的共享区。
-
如果有多个进程同时调用了同一个动态库,只需要向内存加载一次。之后只要建立页表映射关系即可。因此,动态库也被成为共享库。
-
将动态库从磁盘加载到内存并建立与进程地址空间映射关系的工作,由操作系统链接器完成。
2.2.2 动态库的使用
先将动态库拷贝给用户
方法一:
- 安装库:将头文件和库文件直接拷贝到系统的默认搜索路径下
- 编译程序,带-l选项指定要链接的库
方法二:
-
通过
-I
和-L
选项指定头文件和库文件的所在路径,并用-l
指明要链接的库为什么动态链接后会报错:找不到动态库文件?就是因为动态链接器的运行时链接库缓存中没有对应动态库的路径。
-
向动态链接器缓存中添加动态库路径
-
可以将动态库拷贝到
/lib64
路径下,加载器默认会在该路径下进行搜索。 -
我们还可以在
/lib64
路径下创建动态库文件的软链接。 -
还可以在环境变量
LD_LIBRARY_PATH
中添加动态库的所在路径,加载器也会在环境变量中的路径下搜索动态库。
注意:修改环境变量,只是修改了bash缓冲区中的内容。只在本次登录中有效
-
还可以在bash的资源配置文件.bashrc中,添加登录时导入LD_LIBRARY_PATH环境变量的操作。
-
我们还可以通过在
/etc/ld.so.conf.d/
目录下添加配置文件的方法,永久性的添加动态库的搜索路径。提示:ldconfig是一个用于配置动态链接器运行时的命令。它用于更新动态链接器的运行时链接库缓存,以便在程序运行时能够正确地找到和加载动态库。
-
三、默认优先使用动态链接
此时的lib目录下既有动态库(.so)又有静态库(.a),编译链接的程序是动态链接还是静态链接?
- 如果目录下只有静态库:有动态库就动态链接,没有动态库也只能静态链接。(此时lib目录下没有libmylib.so)
- 如果目录下动静态库同时存在,gcc默认优先使用动态链接。
- 如果动静态库同时存在,非要使用静态库呢?-static选项:摒弃默认优先使用动态库的原则,所有库都直接使用静态链接方案。
三、为什么要有库?
-
站在使用者的角度:库的存在可以大大减少使用者的开发周期;同时使用高质量的库还可以提高软件本身的质量。
-
站在开发者的角度:可以使合作开发更加简单;同时也隐藏了源码,提高了代码安全性。
3.1 静态链接的优缺点
优点:
- 独立性:静态链接使得可执行文件成为一个独立的实体,不需要依赖外部的库文件。这意味着可执行文件可以在没有其他依赖项的情况下运行,更加方便和可移植。
- 简单部署:由于静态链接将所有依赖项都打包到可执行文件中,部署和分发可执行文件变得更加简单。只需将可执行文件复制到目标系统上,而不需要担心库文件的版本兼容性或缺失。
- 性能优化:静态链接可以在编译时进行优化,将库的代码和数据与主程序一起进行优化和整合。这可以提高程序的执行效率和性能,因为编译器可以进行更多的优化和内联操作。
缺点:
- 内存占用:静态链接会导致每个可执行文件都包含其所需的库和依赖项的副本,这会占用更多的内存空间。如果多个程序同时使用相同的库,每个程序都需要加载和占用相同的库的副本,造成内存浪费。
- 更新和维护:静态链接的可执行文件中包含了所有的库和依赖项,当库或依赖项发生更新时,需要重新编译和重新部署整个可执行文件。这增加了更新和维护的复杂性,尤其是在大型项目中或者涉及多个依赖项的情况下。
- 文件大小:由于静态链接将所有的库和依赖项都打包到可执行文件中,导致可执行文件的大小增加。这可能会增加程序的下载时间和存储空间的消耗。
3.2 动态链接的优缺点
优点:
- 节省内存:动态链接允许多个程序共享同一个库的实例,避免了每个程序都加载和占用相同库的副本,从而节省了内存空间。
- 减少页面交换:当使用动态链接时,操作系统只需要将库文件的代码和数据加载到内存中一次,然后多个程序可以共享这些库的实例。这减少了需要从磁盘加载和卸载库文件的次数,减少了页面交换的频率。
- 灵活更新:当库文件发生更新时,只需要更新库文件本身,而不需要重新编译和部署整个程序。这样可以简化更新和维护的过程,节省时间和资源。
- 减少程序体积:由于库文件是独立存在的,可执行文件只需要包含自身的代码和数据,因此可执行文件的体积相对较小。
缺点:
- 运行时依赖:动态链接需要依赖外部的库文件,如果库文件缺失或版本不兼容,程序可能无法正常运行。这增加了程序在不同环境中的部署和兼容性的挑战。
- 性能损失:动态链接需要在运行时加载和链接库文件,这会引入一定的性能开销。相比静态链接,动态链接的程序可能稍微慢一些。
- 部署复杂性:动态链接需要确保系统中存在正确的库文件,并设置正确的库路径。这可能需要额外的配置和管理工作,增加了部署的复杂性。
3.3 一些有趣的库
-
ncurses:字符界面库
ncurses库是一个用于创建基于终端的交互式应用程序的库。它提供了一套API,用于处理终端界面的输入和输出,以及控制终端的光标位置、颜色、窗口等。
使用ncurses库,您可以在终端中创建复杂的文本界面,包括窗口、菜单、按钮、文本框等。您可以使用函数来控制光标的位置,以及在终端上输出文本和图形。此外,ncurses库还提供了处理键盘和鼠标输入的功能,以及对终端的颜色和属性进行控制。
ncurses库的安装和使用请看这篇文章:【Linux拓展】ncurses库的安装和使用 {ncurses库的安装方法,ncurses库的使用手册,基于终端的贪吃蛇游戏}_芥末虾的博客-CSDN博客
-
Boost:C++准标准库
Boost是一个开源的、跨平台的C++库集合,提供了许多高质量、可移植且广泛使用的组件和工具,涵盖了从基本的数据结构和算法到高级的并发编程和网络编程等各个领域。
Boost库的特点包括:
-
高质量:Boost库的组件经过了严格的测试和评审,具有高质量和稳定性,广泛应用于工业和学术界。
-
可移植性:Boost库的组件可以在多个平台上运行,包括Windows、Linux、Mac等。
-
开源:Boost库是开源的,可以免费使用和修改。
Boost库提供了丰富的功能,包括但不限于以下几个方面:
-
智能指针:Boost库提供了多种智能指针,如shared_ptr、scoped_ptr等,用于管理动态分配的内存,避免内存泄漏和悬空指针等问题。
-
容器和算法:Boost库提供了许多扩展了标准库的容器和算法,如unordered_map、unordered_set、foreach等,方便开发者进行数据处理和算法实现。
-
并发编程:Boost库提供了多线程、原子操作、线程池等并发编程的工具和组件,简化了多线程编程的复杂性。
-
正则表达式:Boost库提供了强大的正则表达式库,支持正则表达式的匹配、替换、分割等操作。
-
文件系统:Boost库提供了对文件系统的操作接口,方便开发者进行文件和目录的创建、删除、遍历等操作。
-
网络编程:Boost库提供了网络编程的工具和组件,包括TCP/UDP套接字、异步IO、网络协议等,方便开发者进行网络应用的开发。
总之,Boost库是一个功能强大、广泛应用的C++库集合,可以提高开发效率,增加代码的可靠性和可移植性。
-