本文分别通过链接静态库和动态库来编译可执行文件,在使用gcc编译的过程中了解链接静态库和动态库的区别与联系,同时深入理解Linux系统上是如何将源程序一步步的编译组装成可执行文件的。
目录
(一)库文件
1.什么是库
本质上来说库是一种可执行代码的二进制形式,可以被操作系统载入内存执行。一些公用函数制作成函数库,供其它程序使用。函数库分为静态库和动态库两种。
- 静态库在程序编译时会被链接到目标代码中,程序运行时将不再需要该静态库。
- 动态库在程序编译时并不会被链接到目标代码中,而是在程序运行是才被载入,因此在程序运行时还需要动态库存在。
2.库命名规则
- 静态库
静态库的名字一般为libxxx.a,其中xxx是该lib的名称。 - 动态库
动态库的名字一般为libxxx.so.major.minor,xxx是该lib的名称,major是主版本号, minor是副版本号。
3.查找依赖库
使用命令ldd可以查看一个可执行文件依赖的动态库。
$ ldd main
linux-vdso.so.1 (0x00007ffc42bcc000)
libx2.so => /usr/lib/libx2.so (0x00007ff37f0fc000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007ff37ed0b000)
/lib64/ld-linux-x86-64.so.2 (0x00007ff37f500000)
由此可见,main可执行文件依赖于linux-vdso、libx2、libc、ld-linux-x86-64这四个动态库。
(二)编译时链接静态库文件
1.源程序
- main.c(主函数)
#include"sub1.h"
#include"sub2.h"
#include<stdio.h>
int main()
{
int x=2,y=9,n; //定义x和y变量
printf("%d/%d=%.2f\n",y,x,x2x(x,y)); //输出处理后的值,保留两位小数
printf("请输入斐波那契的第n项值:");
scanf("%d",&n);
printf("斐波那契数列第%d项为%d\n",n,x2y(n)); //输出斐波那契数列的第n项
return 0;
}
- sub1.h
#ifndef __SUB1_H
#define __SUB1_H
float x2x(int a,int b); //计算b除以a
#endif
- sub1.c(子函数1)
#include "sub1.h"
/*******************/
/* 参数:a */
/* 参数:b */
/* 返回值:b/a */
/*******************/
float x2x(int a,int b)
{
float ans;
ans=(float)b/a;
return ans;
}
- sub2.h
#ifndef __SUB2_H
#define __SUB2_H
int x2y(int); //计算斐波那契数列的第n项值
#endif
- sub2.c(子函数2)
#include "sub2.h"
/*********************************/
/* 参数:n */
/* 返回值:第n项斐波那契数列值 */
/*********************************/
int x2y(int n)
{
int a=1,b=1,i;
long c=0;
if(n<3) return 1;
else
{
for(i=0;i<=n-3;i++)
{
c=a+b;
a=b;
b=c;
}
return c;
}
}
2.编译静态库文件libx2.a
- 编译.o目标文件
输入命令gcc -c main.c sub1.c sub2.c
可以编译得到main.o、sub1.o、sub2.o三个目标文件
- 编译libx2.a静态库文件
使用命令ar -crv libx2.a sub1.o sub2.o
编译生成libx2.a静态库文件。
3.链接为可执行文件main
-
使用命令
gcc main.o libx2.a -o main
链接main.o和libx2.a文件生成可执行文件main
-
执行可执行文件main
使用命令./main
执行该可执行文件
-
测试是否真的静态库链接成功
删除静态库libx2.a目标文件,再次执行该可执行文件
以上说明静态库链接生成的可执行文件运行时不需要该静态库,因为该静态库已经被编译到可执行文件中了。
(三)编译时链接动态库文件
1.编译动态库文件libx2.so
.o目标文件已经在上面编译静态库文件时生成了,因此这里直接编译动态库文件。
使用命令gcc -shared -fPIC -o libx2.so sub1.o sub2.o
编译生成动态库文件libx2.so
2.链接为可执行文件
- 使用命令
gcc main.o libx2.so -o main
链接两个目标文件生成可执行文件main
- 执行生成的可执行文件main
使用命令./main
执行该可执行文件main- 发现报错如下:
- 原因:
程序在运行时, 会在/usr/lib 和/lib 等目录中查找需要的动态库文件。若找到,则载入动态库,否则将提示类似上述错误而终止程序运行。 - 解决方法:
将libx2.so 复制到目录/usr/lib 中,再次执行./main
运行(若提示权限不够则以使用sudo mv libx2.so /usr/lib
该命令)
- 发现报错如下:
- 使用命令
ldd main
查看main可执行文件的依赖项
3。链接静态库与动态库生成可执行文件的区别
静态库生成的可执行文件为8520字节,动态库生成的可执行文件为8456字节。从而可见动态库生成的可执行文件要比静态库生成的要更小,但是链接动态库需要依赖于该动态库。
(四)总结
通过使用静态库和动态库分别链接生成可执行文件main,我深入的了解到了不同库函数的链接的作用是不一样的。静态库链接是直接在程序编译时就将其组装到一起,可以不依赖于静态库就能运行;而动态库链接是在程序运行时才将其载入内存运行且不能够缺少,否则不能运行。
感谢该博主我的启发:
关于Linux静态库和动态库的分析