首言
本文主要通过举例来说明在 Linux 中如何创建静态库和动态库,以及使用它们
一、用gcc生成.a静态库和.so动态库
1.静态库和动态库
(1)静态库
静态库在程序编译时会被连接到目标代码中,程序运行时将不再需要该静态库
(2)动态库
动态库在程 序编译时并不会被连接到目标代码中,而是在程序运行是才被载入
2.静态库与动态库的区别
(1)链接方式:静态库在编译时链接,动态库在运行时链接。
(2)文件大小:静态库较大,包含了所有的函数代码;动态库较小,在运行时再加载需要的代码。
(3)依赖性:静态库不依赖运行库,可以独立运行;动态库依赖运行库。
(4)安全性:静态库相对安全,不容易被篡改;动态库可能被篡改。
(5)部署:发布应用时需要带上静态库;只需发布动态库,应用本身不需要带库。
总的来说,静态库更独立,安全性好一些;动态库体积小,更灵活,但依赖性强,安全性差。一般来说,系统底层的通用库采用静态库,而应用程序的非关键库采用动态库。
二、创建静态库和动态库
1.创建前的准备
在创建静态库和动态库之前,需要准备三个源程序,分别是公用函数的.h和.c文件,以及一个主程序的.c文件,本文的例子是一个hello的公用函数。
(1)创立作业目录
此做法主要是为了能够保存此次用到的各种文件,代码如下:
#mkdir test1
#cd test1
(2)创建hello.h
#ifndef hello_h
#define hello_h
void hello(const char *name);
#endif
hello.h是我们建立的函数的头文件,里面应该包括函数的声明
(3)创建hello.c
#include<stdio.h>
void hello (const char *name)
{
printf("hello %s!\n",name);
}
该源程序需要包括我们函数具体所执行的内容,同时需要引入头文件
(4)创建main.c
#include"hello.h"
int main()
{
hello("everyone");
return 0;
}
主程序里面应该包含我们要用的函数的头文件,也就是我们创立的hello.h
2.将hello.c文件生成.o目标文件文件
无论静态库,还是动态库,都是由.o 文件,这也是为什么选哟生成这里会用到gcc命令
基本语法 gcc [option] [filename],下表为不同选择的语法作用
-c | 将输入的.c源文件生成.o的目标源文件 |
-o | 可以指定编译后输出的可执行文件的名称 |
-E | 编译并产生汇编文件 |
-S | 对.c源文件进行预处理 |
3.由.o 文件创建静态库
静态库创建规范:lib+静态库名+.a
运用的命令:-ar
语法:ar[-dmpqrtx][cfosSuvV][a<成员文件>][b<成员文件>][i<成员文件>][备存文件][成员文件]
含义:例如我们可以用ar -rv libtest.a hello.o hello1.o来生成一个库,库名字是test,链接时可以用-ltest链接。该库中存放了两个模块hello.o和hello1.o。
ar命令的参数如下:
参数 | 意义 |
---|---|
-r | 将objfile文件插入静态库尾或者替换静态库中同名文件 |
-x | 从静态库文件中抽取文件objfile |
-t | 打印静态库的成员文件列表 |
-d | 从静态库中删除文件objfile |
-s | 重置静态库文件索引 |
-v | 显示详细信息 |
-c | 创建静态库文件 |
本文创建的是名字为myhello的静态库,同时用ls命令查看创建结果,如下:
4.在程序中使用静态库
(1)生成目标程序hello
这里的目标程序也就是可执行文件,在本文也就是将main.c和libmhyhello.a编译后的可执行文件的名称取名为hello
这里有三种方法,如下:
法一:
法二:
法三:先生成main.o目标文件,再生成可执行文件
(2)验证
删除静态库文件试试公用函数 hello 是否真的连接到目标文件
5.由.o文件创建动态库文件
动态库创建规范:lib+动态库名+.so
6.在程序中使用动态库
这里使用到的命令与静态库一样,本文直接采用静态库中的第一个命令,结果如下:
由结果可以看出,出错了,原因是找不到这个动态库文件,这是因为程序在运行时, 会在/usr/lib 和/lib 等目录中查找需要的动态库文件。若找到,则载入动态库,否则将提示类似上述错误而终止程序运行。因此,我们需要将建立的动态库libmyhello.so复制到目录/usr/lib中,如下:
注意:因为这里涉及到地址更换,所以应该先获取权限,再将libmyhello.so复制到目录/usr/lib中。
由上图我们可以看出当成功将文件复制到/usr/lib后程序就可以正常运行了。
三、对比
由以上过程我们可以得出,那么接下来我们将继续探索当静态库和动态库同名时,gcc命令会优先使用哪个库文件。
1.准备工作
我们需要先删除除最开始准备的.c和.h以外的所有文件。
2.创建静态库和动态库
3.运行gcc
由上图可视,出现错误,并且这个错误与动态库出现的一致,因此可以得出结论:当静态库和动态库同名时,gcc会优先使用动态库。
四、实际演示
创建两个函数x2x、x2y,和一个主函数
1.静态库
将3个函数分别写成单独的3个 .c文件,并用gcc分别编译为3个.o 目标文件;将x2x、x2y目标文件用 ar工具生成1个 .a 静态库文件, 然后用 gcc将 main函数的目标文件与此静态库文件进行链接,生成最终的可执行程序,记录文件的大小。
最终结果如下:
2.动态库
将x2x、x2y目标文件用 ar工具生成1个 .so 动态库文件, 然后用 gcc将 main函数的目标文件与此动态库文件进行链接,生成最终的可执行程序,记录文件的大小
五、总结
1.静态库
- 静态库是将目标文件(.o文件)打包成一个单独的库文件(.a文件)的方式。
- 在静态库中,目标文件的代码被完全复制到调用程序中,与调用程序链接在一起。
- 静态库在编译时会被链接到可执行文件中,因此在运行时不需要额外的库文件。
- 优点是简单易用,不需要依赖额外的库文件。
- 缺点是每个调用程序拥有一份自己的代码副本,会占用更多的磁盘空间和内存。
2.动态库
- 动态库是将目标文件编译成具有共享特性的库文件(.so文件)
- 在动态库中,目标文件的代码在运行时被动态加载到内存中,并与调用程序共享。
- 动态库可以在多个程序之间共享,减少了代码的冗余,节省了空间。
- 在运行时,调用程序需要动态链接器在系统中找到并加载动态库。
- 优点是节省了磁盘空间,可以在多个程序之间共享。
- 缺点是在运行时需要依赖相应的动态库文件。
生成静态库将目标文件的代码完全复制到调用程序中,不需要依赖额外的库文件,但会占用更多的磁盘空间和内存。生成动态库允许多个程序共享库文件,减少了冗余代码,但需要在运行时依赖相应的动态库文件。选择静态库还是动态库取决于具体需求和应用场景。
六、参考
(1)https://blog.csdn.net/chen1415886044/article/details/104395351