库是一种可执行代码的二进制文件,可以被操作系统载入内存执行。
库可以分为两种:静态库和动态库
静态库:静态库就是一些目标文件的集合,以.a结尾。静态库在程序链接的时候使用,链接器会将程序中使用到函数的代码从库文件中拷贝到应用程序中。一旦链接完成,在执行程序的时候就不需要静态库了。由于每个使用静态库的应用程序都需要拷贝所用函数的代码,所以静态链接的文件会比较大。
动态库:某个程序在运行中要调用某个动态链接库函数的时候,操作系统首先会查看所有正在运行的程序,看在内存里是否已有此库函数的拷贝了。如果有,则让其共享那一个拷贝;只有没有才链接载入。在程序运行的时候,被调用的动态链接库函数被安置在内存的某个地方,所有调用它的程序将指向这个代码段。因此,这些代码必须使用相对地址,而不是绝对地址。在编译的时候,我们需要告诉编译器,这些对象文件是用来做动态链接库的,所以要用地址不无关代码(Position Independent Code (PIC))。
二者的不同点在于:
静态库的代码在编译的过程中已经被载入可执行程序,体积较大。
而动态库的代码是在可执行程序运行时才载入内存,在编译的过程中仅简单的引用,因此代码体积较小。
库是别人写好的现有的、成熟的、可以复用的代码,现实中每个程序都要依赖很多基础的底层库,不可能每个人的代码都从零开始,因此库的存在意义非同寻常。
静态库的后缀是.a,它的产生分两步
Step1.由源文件编译生成一堆.o,每个.o里都包含这个编译单元的符号表
Step2.ar命令将很多.o转换成.a,成为静态库
动态库的后缀是.so,它由gcc加特定参数编译产生。
在linux下,库文件一般放在/usr/lib和/lib下
静态库的名字一般为libxxxx.a,其中xxxx是该lib的名称
动态库的名字一般为libxxxx.so.major.minor,xxxx是该lib的名称,major是主版本号,minor是副版本号
ldd命令可以查看一个可执行程序依赖的共享库
静态库文件名的命名规范是以lib为前缀,紧接着跟静态库名,扩展名为.a。例如:我们将
创建的静态库名为myhello,则静态库文件名就是libmyhello.a。在创建和使用静态库时,需要注意这点。创建静态库用ar命令
动态库文件名命名规范和静态库文件名命名规范类似,也是在动态库名增加前缀lib,但其文件扩展名为.so。
根据加载和链接共享库的时机又可分为
l 隐式链接
应用程序自身加载时动态链接和加载共享库
基本思路是:当创建可执行文件时,静态执行一些链接(共享库的重定位和符号表信息,而非代码和数据),然后在应用程序加载时,动态完成链接过程。
l 显示链接
应用程序运行过程中动态链接和加载共享库
与A情况不同,此情况下:应用程序在运行过程中要求动态链接器加载和链接任意共享库,而无需编译时链接那些库到应用中。
此种情况下,源程序需要包含dlfcn.h头文件,此文件定义了调用动态链接库的函数的原型。
发现使用静态库和使用动态库编译成目标程序使用的gcc命令完全一样,那当静态库和动态库同名时,gcc命令会优先使用动态库。
-------------------------------------------------------------------------------------------------------------------------------------------------------
下面以简单计算器的例子来进行实验验证
1 编写实例文件(OS:Ubuntu15.04 gcc version 4.9.2)
/*add.c*/
int add(int a,int b)
{
return a+b;
}
/*sub.c*/
int sub(int a, int b)
{
return a-b;
}
#ifndef ADD_H
#define ADD_H
int add(int a,int b);
#endif
#ifndef SUB_H
#define SUB_H
int sub(int a,int b);
#endif
#include
#include"add.h"
#include"sub.h"
int main(void)
{
printf("5 + 3 = %d\n",add(5,3));
printf("5 - 3 = %d\n",sub(5,3));
return 0;
}
gcc -c add.c sub.c
输入ls指令,发现多出2个文件,add.o和sub.o
3 创建静态库
静态库创建指令为ar
ar rcs libmath.a add.o sub.o
此处ar中的rcs的意思是:r表明将模块加入到静态库中,c表示创建静态库,s表示生产索引。
此时多了一个文件:libmath.a
4 使用静态库,此处切记将所生成的库拷贝到系统的库文件目录,一般为/usr/lib/
cp mylib.so /usr/lib/mylib.so
5 删除静态库看查看运行结果
仍然可以正常运行,表明静态库中的公用函数已经连接到目标文件中了。
6 生成动态链接库
此处生成动态库的参数-fPIC和-fpic都可以产生目标独立代码,具体应用取决于平台,-fPIC是always work,尽管其产生的目标文件可能会大些; -fpic产生的代码小,执行速度快,但可能有平台依赖限制。
7 删除动态库后
程序运行出错。也进一步证明动态库在程序运行时是需要的。