文章结构
静态库的制作
静态库的特点
1.命名方式
静态库的命名统一为:lib
+ 静态库名
+ .a
2. 静态库的优点
- 寻址方便、速度快
- 静态库中会被用到的模块会被一次性打包到可执行程序中
- 发布的可执行程序可直接使用不需要再依赖于静态库
3. 静态库的缺点
- 静态库的代码在编译过程中会被载入可执行目标程序中,因此体积较大。
- 如果静态函数库改变了,那么之前发布的程序必须重新编译。
4. 使用场景
- 在核心程序上使用,保证速度,可忽视空间,主流应用于80、90年代,现在很少用
制作过程
1. 创建存储文件夹:
先创建三个文件夹:head、lib、src
作用:
head:用于存放静态库头文件
lib:用于存放静态库
src:用于存放源文件
2. 编写源代码:
编写源代码并将编写的源代码文件放入src文件夹里面,如编写sub.c,其它源文件除了运算符不一样其余全部相同
#include "calc.h"
int div(int a, int b)
{
if(b == 0)
printf("The divisor cannot be zero\n");
return a / b;
}
3. 编写头文件
将静态库用到的函数或变量声明写进头文件中,并且存放进head文件夹里面
4. 生成二进制的.o文件
将源文件(.c文件)通过汇编器生成对应的二进制的 .o文件,命令:gcc *.c -Ihead -c (不用加 -o 参数默认会生成对应的 .o文件)
5. 打包成静态库文件
这里打包需要用到一个工具ar
命令:ar rcs libCalc.a *.o (*.o 也可以单独分开来写)
成功后将其移动到lib
文件加内
注: 到这里静态库就制作完成啦!!!
静态库使用
先编写主文件main.c 然后通过通过gcc参数指定要使用的静态库
方法一:
命令格式:gcc + 源文件 + 静态库文件(路径+全名) + 头文件路径 + -o + 输出可执行文件
如:gcc main.c ./day02/makelib/lib/libCalc.a -I ./day02/makelib/head/ -o calc
方法二:
命令格式:gcc + 源文件 + 头文件路径 + -L 静态库文件的路径 + -l 静态库名(不是全名, -l是小写L) + -o + 输出可执行文件
如:gcc main.c -I ./day02/makelib/head/ -L ./day02/makelib/lib/ -l Calc -o calc
注:推荐使用这种方法,因为后面的动态库指定只能用这用写法。
nm命令
nm命令可用来查看静态库和可执行文件里面的内容
动态库(共享库)的制作
动态库的特点
1.命名方式
动态库的命名统一为:lib
+ 动态库名
+ .so
2. 动态库的优点
- 节省内存,动态库是目标程序运行时才载入内存,在编译过程中只是简单的引用,因此代码体积较小。
- 易于更新,如果需要更新的话只需要使用新库覆盖旧库就可以了(但要保证新库和旧库名称一致、接口一致)。
3. 动态库的缺点
- 动态库因为是动态绑定,所以没有打包到应用程序当中,较静态库速度慢。
- 发布程序的时候需要将动态库提供给用户。
4. 使用场景
- 对速度要求不是很强烈的地方都应使用动态库,目前被广泛使用。
制作过程
1. 准备源文件
首先还是和制作静态库的步骤一样,写好源文件、头文件并放在对应的文件夹内(与制作静态库步骤1-3一致)。
2. 生成“与位置无关”的 .O 目标文件
命令:gcc -fPIC 源文件 -I 头文件路劲 -c
3. 生成动态库
命令:gcc 输入文件 -shared -I 头文件路劲 -o 动态库文件名
生成之后将其移动到lib文件夹里面
注: 到这里动态库就制作完成啦!!!
动态库的使用
使用方式还是和静态库一样
命令格式:gcc + 源文件 + 静态库文件(路径+全名) + 头文件路径 + -o + 输出可执行文件
还有一种写法和静态库也是一样的这里就不写了!
动态库链接失效问题
ldd命令
作用:查看依赖的共享库
命令:ldd + 可执行文件
1. 问题引入 - 动态库加载失效
我们知道在这里动态库是放在lib文件夹下面的,思考一下如果我们把动态库libCalc.so从lib文件里面移走会发生什么??
动手尝试下
发现运行报错,提示加载动态库失败。
同时查看依赖的动态库,没有发现对应的动态库文件。
而我们同样移除之前的静态库然后执行用静态库打包成的可执行程序,结果如下:
这是因为动态库是在程序运行的时候加载,而静态库则在程序发布的时候就已经加载到了程序当中,因此程序就不再需要依赖静态库。
所以对于动态库而言,指定动态库路径可以使得程序在其它目录也能够运行,这里介绍四种指定方法。
2. 动态库指定 - 四种方法
方式一: 指定动态库所在的路径,也就是上面的lib目录,当生成可执行程序的时候使用指定动态链接库的绝对路径,这样可执行程序就能在任何目录下执行了
方式二: 将动态库所在目录导入到环境变量里面
- 将动态库直接导入到系统的
/lib
目录里面,/lib
目录属于系统的库目录,是一个可执行程序最先查找动态库的目录,这样无论可执行文件在哪个目录同样也能执行。 - 导入到
LD_LIBRARY_PATH
环境变量里面,该变量的值就是动态库所在的路径,变量的值可以设置多个,但是此方法当终端退出了就无效了,所以一般用于临时测试。
用法:export LD_LIBRARY_PATH=动态库绝对路径
注意:gcc编译时需要将目录和名称分开指定gcc main.c -Ihead -L lib -l Calc -o calc
,也就是使用静态/动态库使用里面介绍的第二种方法。
方法三: 将方法二中的环境变量加入家目录下的.bashrc
配置文件中
方法四: 修改/etc/ld.so.conf
配置文件 (推荐使用该方法)
先将动态库所在的绝对路径加入到/etc/ld.so.conf
配置文件
查看并更新
命令:ldconfig [-v] (-v是显示详细信息)
执行成功: