本文共 3280 字,大约阅读时间需要 10 分钟。
熟悉Linux 下静态库.a 与.so 库文件的生成与使用——实例
程序环境:VMware® Workstation 15 Pro-15.0.0,Ubuntu16.04 LTS,gcc -5.4.0
摘要:我们通常把一些公用函数制作成函数库,供其它程序使用。函数库分为静态库和动态库两种。静态库在程序编译时会被连接到目标代码中,程序运行时将不再需要该静态库。动态库在程序编译时并不会被连接到目标代码中,而是在程序运行是才被载入,因此在程序运行时还需要动态库存在。
本文主要通过举例来说明在Linux 中如何创建静态库和动态库,以及使用它们。 关键字:Linux,静态库,动态库 相关知识:gcc,ar
知识拓展:
ar是Linux系统的一个备份压缩命令,用于创建、修改备存文件(archive),或从备存文件中提取成员文件。ar命令最常见的用法是将目标文件打包为静态链接库。
一、 静态库的生成与调用
1. 主要函数编译
该过程主要进行生成.h、.c、以及主函数(main.c)
①在熟悉的目录下建立一个test文件夹,放入此次实例程序mkdir test
进入该文件夹
cd test
②编译sub_1.h、sumfloat.c、subfloat.c、main1.c程序
用vim,nano或者gedit编写以下程序
sub_1.h代码如下:
#ifndef sub_1H //声明头文件#define sub_1H //宏定义#include//预处理#include //预处理float sumfloat(float,float); //声明sumfloat函数float subfloat(float,float); //声明subfloat函数#endif //结束
sumfloat.c代码如下:
#include"sub_1.h" //预处理float sumfloat(float a,float b) //sumfloat函数,浮点求和{ a+=b; return a;}
subfloat.c代码如下:
#include"sub_1.h" //预处理float subfloat(float a,float b) //subfloat函数,浮点相减{ a=a-b; return a;}
main1.c代码如下:
#include"sub_1.h" //预处理void main(){ float x,y; float a=12,b=13; //a=12,b=13 x=sumfloat(a,b); //x=a+b y=subfloat(a,b); //y=a-b printf("%f+%f=%f\n",a,b,x); //打印浮点相加的值 printf("%f-%f=%f\n",a,b,y); //打印浮点相减的值}
2. 生成主要函数.o文件
gcc -c sumfloat.c subfloat.c
知识拓展:
gcc 是 Gnu 的 c 编译器, gcc 在执行编译工作的时候,总共需要4步: 1、预处理,生成 .i 的文件[预处理器cpp] 2、将预处理后的文件转换成汇编语言, 生成文件 .s [编译器egcs] 3、有汇编变为目标代码(机器代码)生成 .o 的文件[汇编器as] 4、连接目标代码, 生成可执行程序 [链接器ld] 其中参数详解如下: -c:只编译,不链接成为可执行文件,生成.o文件 -o:链接生成可执行文件,默认生成a.out文件,但可以对生成的可执行文件进行命名
3. 生成静态库.a
ar crv libafile.a sumfloat.o subfloat.o
知识拓展:
ar命令可以用来创建修改库,也可以从库中提出单个模块。一般多用来生成静态库。 参数详解: -c:创建一个库。不管库存不存在都将创建 -r:在库中插入模块(替换) -v:程序执行时显示详细信息
4. 调用静态库并生成工程文件
gcc -o test main1.c libafile.a
在这里我们可以查看下静态库的生成的可执行文件的大小./test
size test
二、 动态库的生成与调用
声明:本博客的动态库与静态库是分别在不同的目录下进行的编译,这里的可执行文件名一致并没有发生冲突,但如果是在同一个目录下,请将两个不同的可执行文件进行不同命名。
1. 主要函数编译
主要函数沿用以上静态库所编译生成的sub_1.h、sumfloat.c、subfloat.c、main1.c,但.o文件不同。
2. 生成主要函数.o文件
gcc -c -fpic sumfloat.c subfloat.c
知识拓展:
-fpic: 作用于编译阶段,告诉编译器产生与位置无关代码(Position-Independent Code),则产生的代码中,没有绝对地址,全部使用相对地址,故而代码可以被加载器加载到内存的任意位置,都可以正确的执行。这正是共享库所要求的,共享库被加载时,在内存的位置不是固定的。(小模式,代码少)
3. 生成动态库.so
gcc -shared *.o -o libsofile.so
知识拓展:
参数详解: -shared:生成共享库 *.o:将当前文件目录下的.o文件批操作
4. 调用动态库并生成工程文件
gcc -o test main1.c libsofile.so
如果直接进行编写可执行文件,会出现报错。
因为在动态库中,程序运行时,先是到/usr/lib 中找动态库文件的,所以我们需要将libsofile.so拷贝到/usr/lib中去,输入以下命令:
sudo cp libsofile.so /usr/lib
现在再输入命令
gcc -o test main1.c libsofile.so
这时就不会报错了,并生成test可执行文件。
这里提供一下解决报错的
方法二 gcc -o test main1.c -L -lname 其中, -L:表示在当前目录下,可自行定义路径path,即使用-lpath 即可。 -lname:name:即对应库文件的名字(除开lib),即若使用libafile.a,则name 为afile;若要使用libsofile.so,则name 为sofile。
这里也查看一下动态库链接生成的可执行文件的大小./test
与静态库链接生成的可执行文件进行对比,发现可执行文件text静态库的代码明显多于动态库。size test
三、 二者之间的联系与区别
①静态库在程序编译时会被连接到目标代码中,程序运行时将不再需要该静态库。动态库在程序编译时并不会被连接到目标代码中,而是在程序运行是才被载入,因此在程序运行时还需要动态库存在。
②当静态库和动态库同名时,gcc 命令将优先使用动态库,默认去链接/usr/lib 和/lib 等目录中的动态库,所以在生成动态库时可以进行路径链接不用进行拷贝操作。 ③在静态库与动态库的可执行文件的大小比较中,发现动态库的可执行文件大小较于静态库的小很多。通过查找资料也证实了这一点,静态库是直接将需要的代码连接进可执行程序;动态库是在需要调用其中的函数时,根据函数映射表找到该函数然后调入堆栈执行。文件大小关系应该是做成静态库可执行文件本身比较大,但不必附带动态库。做成动态库可执行文件本身比较小,但需要附带动态库。四、 总结
在此次实例中,我理解到库在编程中是很重要的概念,在库中可以进行链接各种.c文件,在主函数中就可以直接调用库中的函数,不用在主函数中编译其他功能函数,减少了主函数的编译内容,对主函数也有了一定的拓展性。对静态库和动态库的调用,也使我熟悉了之间的命令操作,并在其中学习了静态库与动态库的联系与区别。
转载地址:https://blog.csdn.net/qq_45264808/article/details/109062246 如侵犯您的版权,请留言回复原文章的地址,我们会给您删除此文章,给您带来不便请您谅解!