一、基本认识
1.什么是库?
在编译C或C++时,在使用一些函数时,我们都需要先声明头文件,头文件中一般存放着这些函数的声明,而具体的实现方法,一般就被放在库中,库文件在编译链接的阶段会被链接到可执行程序中,本质是实现方法的二进制文件打包成的库文件
2.动态库和静态库的区别
我们使用的各种c库封装好的函数时,在编译生成可执行程序时一定要有对应的实现方法,这些实现方法在编译到链接的阶段,编译器需要通过头文件中的声明去找到具体的实现方法,也就是需要库,动态库和静态库的区别就是,静态库在此时会将具体的实现方法代码直接拷贝链接到可执行程序中,一旦生成可执行程序,可执行程序的执行不依赖静态库,而动态库在链接阶段只是将该动态库的地址等各种信息记录到可执行程序中,只有当程序执行时,才会真正的去将具体实现的方法加载到内存中,并且通过地址等各种信息去找到具体实现方法,因此,动态链接生成的可执行程序是依赖库的。
动态库可以在多个程序间共享,所以动态链接使得可执行文件更小,节省了磁盘空间。操作系统采用虚 拟内存机制允许物理内存中的一份动态库被要用到该库的所有进程共用,节省了内存和磁盘空间。通常我们使用的都是动态链接
3.为什么要有库?
库实际就是各种函数的具体实现方法,在实际开发中,会存在大量的重复功能的需求,为了节省开发的成本,提高效率,我们可以将常用的各种功能打包成库,提供给别人使用,也可以下载别人已经实现好的库,提高开发效率
二、动静态库的制作
1.前提知识
1.1 库的命名
动态库和静态库都会以lib为前缀
动态库的后缀为:.so
静态库的后缀为:.a
库的实际名字是去掉前缀和去掉后缀的
1.2 云服务器中默认只有动态库
一般的云服务器都只会存在动态库,静态库需要自己安装下载
1.3 库文件的本质
接下来会用一个例子去体现如何打包制作库,以及如何使用库,实际就是将我们具体的实现方法的文件进行编译到二进制文件阶段,然后将所有的二进制文件进行打包成一个库文件,这个过程就是制作库的过程
1.4 前提准备
接下来,我们简单的用一个例子去演示库文件的打包和使用,我们自己实现一个加法和减法的功能,并且将这两个功能分别用放在不同的文件,声明放在不同头文件中(为了演示多个文件如何打包成库),因此先简单做以上的准备
2.静态库的打包
2.1 先将实现方法文件编译到二进制文件
2.2 将二进制文件打包制作静态库
3.动态库的打包
3.1 形成二进制文件
同样用gcc编译形成二进制文件,但与静态库有所不同,需要添加一个命令行参数 -fPIC(与位置无关码),至于为什么,在后面关于动态库的理解中会有解释
3.2 制作动态库
与静态库不同,直接使用gcc指令即可制作动态库,需要添加命令行参数-shared
三、动静态库的使用
1.前提知识
1.1 gcc在编译时对头文件和库文件的搜索策略
2. 静态库的使用
在使用gcc编译时,若是需要使用第三方库,根据gcc的搜索策略,我们需要指定头文件和库文件所在路径,或者将文件所在路径配置到环境变量或者系统默认目录中
示例:
首先,假设我们将第三方库和头文件下载到了当前工程main文件的目录下,分别放在了include和lib目录下
需要指定路径去编译
实际在下载第三方库时,系统通常会默认下载到系统默认路径下,在Linux下,对任意软件而言,安装和卸载的本质就是拷贝到系统特定的路径下
注意,即便是已经将库和头文件都配置到系统默认路径下了,在使用gcc或g++编译时,依然要指定库的具体名称
3.动态库的使用
3.1 前提知识
和使用静态库时一样,我们也需要告诉gcc编译器头文件和库文件的路径,但是,不同的是,因为静态库的链接方式是直接将库内的代码直接拷贝到编译生成的可执行程序中,而动态链接则是需要在可执行程序被运行时,通过进程由OS去找到库的内容,因此还需要让OS找到库的位置
3.2 系统路径
OS会到系统默认路径去找,我们要如何知道或者配置当前的系统路径?系统默认查找路径可以在环境变量中配置和查看
查看系统路径:
3.3 使用动态库示例
示例一:采用修改环境变量的方式,让系统能够找到和链接到动态库(临时方案)
示例二:在系统默认搜索路径下建立软链接指向库所在路径
示例三:配置系统文件
四、动态库的理解
在系统层面加载链接一个动态库具体是如何的呢?
首先一个程序在被编译时,采用动态链接编译通过后,生成的可执行程序中,里面包含着关于这个动态库的各种信息
该可执行程序被执行时,OS会创建一个进程,有对应的task_struct、虚拟地址空间、页表,该可执行程序的代码被加载到物理内存后,通过页表映射到虚拟地址的代码区,而当代码执行到需要动态链接库的实现方法的部分时,OS才会根据可执行程序中关于动态库的地址路径找到动态库,将该动态库加载到物理内存中,再建立页表映射关系,动态库的内容会被放到虚拟地址的共享区部分(堆栈中间的那部分空间),然后系统根据需要的方法实现的偏移量信息,找到具体的实现方法
当有其他进程也要用到该库中的方法时,只需要页表建立映射关系,并且记录各个实现方法的偏移量,在虚拟空间分配好虚拟地址后,通过偏移量去找到具体实现方法即可,这也是fPIC(与位置无关码)的作用
五、细节补充
1.在动态库和静态库同时存在时,OS会默认采用动态链接,若是要指定静态链接,需要加上命令行参数-static
2.云服务器一般只提供动态库,若是需要C和C++的静态库,可以使用yum进行安装
yum install -y glibc-static
yum install -y libstdc++-static
3. 与位置无关码的作用是在生成动态库时,动态库中的不同方法实现的位置信息都采用偏移量的方式去记录
总结
本篇整理总结了关于动静态库的制作和使用,已经动态链接在系统层面上该如何看待,之后在一些项目开发时,会经常使用到第三方库,因此其中的指令和如何使用非常重要