库文件
库文件是编译好的二进制文件,用于在链接阶段同目标代码一起生成可执行文件,或者运行可执行文件的时候被加载,以便调用库文件中的某段代码。
库文件通过头文件向外导出接口。用户通过头文件找到库文件中找到函数实现的代码从而把这段代码链接到用户程序中去。
库的位置: /usr/lib /lib
我们开发的程序,无论是运行的时候,还是编译、链接的时候,一般都需要借助一些库来实现它们的功能,而很少直接只通过程序源代码生成完全独立的可执行文件。
库文件与可执行文件的区别
- 相同点:两者都是编译好的二进制文件(在此我们讨论的二进制文件,假设都是Linux上面最常见的ELF格式)
- 不同点:库文件无法直接执行(直观上来看它的源代码中没有main函数,而只是一些函数模块的定义和实现,没有运行的入口主函数,所以无法直接执行)。
静态库制作
在创建库前,我们先来准备举例用的源程序,并将函数库的源程序编译成.o文件。
add.c
int add(int a,int b)
{
return a+b;
}
add.h
int add(int ,int);
main.c
#include<stdio.h>
#include"add.h"
int main()
{
int a=10;
int b=20;
int d=add(a,b);
printf("d=%d\n",d);
}
无论静态库,还是动态库,都是由.o文件创建的
因此,我们必须将源程序add.c通过gcc先编译成add.o文件。
- 将add.c 文件编译成add.o
gcc -c add.c
- 由.o文件创建静态库
静态库文件名的命名规范是以lib为前缀,紧接着跟静态库名,扩展名为.a。
例如:我们将创建的静态库名为myadd,则静态库文件名就是libmyadd.a。
ar crv libmyadd.a add.o
静态库使用
只需要在使用到这些公用函数的源程序中包含这些公用函数的原型声明,然后在用gcc命令生成目标文件时指明静态库名,gcc将会从静态库中将公用函数连接到目标文件中。
gcc会在静态库名前加上前缀lib,然后追加扩展名.a得到的静态库文件名来查找静态库文件。
三种使用方法:
1.自定义的库时,main.c还可放在-L.和 –lmyadd之间,但是不能放在它俩之后,否则会提示add没定义。
但是是系统的库时,如g++ -o main(-L/usr/lib) -lpthread main.cpp就不出错。
2.
- 先生成main.o:gcc -c main.c ,
- 再生成可执行文件:gcc -o main main.o libmyadd.a,动态库连接时也可以这样做。
我们删除静态库文件试试公用函数add是否真的连接到目标文件 main中了。
程序照常运行,静态库中的公用函数已经连接到目标文件中了
静态库总结
动态库的制作
动态库文件名命名规范和静态库文件名命名规范类似,也是在动态库名增加 前缀lib,其文件扩展名为.so
例如:我们将创建的动态库名为myadd,则动态库文件名就是libmyadd.so。
- 将add.c 文件编译成add.o
gcc -c add.c
- 由.o文件创建动态库
gcc -shared -fPIC -o libmyadd.so add.o
动态库使用
在程序中使用动态库和使用静态库完全一样,也是在使用到这些公用函数的源程序中包含这些公用函数的原型声明,然后在用gcc命令生成目标文件时指明动态库名进行编译。
编译不会出错(没有libmyhello.so的话,会出错),但是运行会提示出错。
找不到动态库文件libmyhello.so。
因为虽然连接时用的是当前目录的动态库,但是程序在运行时,会在/usr/lib和/lib等目录中查找需要的动态库文件。若找到,则载入动态库,否则将提示类似上述错误而终止程序运行。
解决办法:将文件libmyhello.so复制到目录 /usr/lib中就OK了
编译参数解析
- shared 该选项指定生成动链接库(让链接器生成T类型的导出符号表,有时候也生成弱连接W类型的导出符号),不用该标志外部程序无法连接。相当于一个可执行文件。
- fPIC 表示编译为位置独立的代码,不用此选项的话编译后的代码是位置相关的所以动态载入时是通过代码拷贝的方式来满足不同进程的需要,而不能达到真正代码段共享的目的。
- L:表示要连接的库所在目录( L. 表示要连接的库在当前目录中)
- l:指定链接时需要的动态库,编译器查找动态连接库时有隐含的命名规则,即在给出的名字前面加上lib,后面加上.a或.so来确定库的名称。
静态库与共享库的使用区别
不同:
- 动态库是运行时系统调用库函数实现链接,代码较小巧,
而静态库是在链接时复制到代码中,代码量较庞大,冗余度高。 - 正因为静态库这种方式也决定了它,在链接后不再依赖静态库存在,即使静态库被删除程序依然可以正常运行,可移植性强。
而动态库因为是利用本机的库函数,所以可能移植到其他电脑会出现运行bug等问题,可移植性差。 - 在于链接过程的差异,和代码被载入的时刻不同 (动态库必须放在指定的目录下完成链接,而静态库给出链接文件路径即可 )
相同:
- 库文件中都不可以出现主main函数
- 这些库都是提供函数接口,满足功能的,不暴露源代码 。
- 目的增加代码复用,可共享性,减小冗余