动态链接与静态链接的解释:
通过命令ldd+可执行文件名,可以查看可执行文件中调用的库
库文件名和引入库的名称
如:libc.so-> c库,去掉前缀lib,去掉后缀.so或.a。
使用动态链接生成的可执行程序体积小,依赖库,在程序运行时加载库函数,可以只有一份。
使用静态链接生成的可执行程序体积较大,它是将对应的代码拷贝到可执行程序中,不依赖与库,可移植性强。
动态链接与静态链接的工作原理
动态链接
静态链接
静态库与动态库
静态库(.a):程序在编译链接的时候把库里的代码链接到可执行文件中。程序运行的时候将不再需要静态库。
动态库(.so):程序在运行的时候才去链接动态库里的代码,多个程序共享使用库的代码。 一个与动态库链接的可执行文件仅仅包含它用到的函数入口地址的一个表,而不是外部函数所在目标文 件的整个机器码 。
在可执行文件开始运行以前,外部函数的机器码由操作系统从磁盘上的该动态库中复制到内存中,这个过程称为动态链接。
动态库可以在多个程序间共享,所以动态链接使得可执行文件更小,节省了磁盘空间。操作系统采用虚拟内存机制允许物理内存中的一份动态库被要用到该库的所有进程共用,节省了内存和磁盘空间
实例:
//myadd.h
#ifndef __MYADD_H__
#define __MYADD_H__
int add(int a,int b);
#endif
//myadd.c
#include"myadd.h"
int add(int a,int b)
{
return a+b;
}
//mysub.h
#ifndef __MYSUB_H__
#define __MYSUB_H__
int sub(int a, int b);
#endif
//mysub.c
#include"mysub.h"
int sub(int a,int b)
{
return a-b;
}
//main.c
#include<stdio.h>
#include"myadd.h"
#include"mysub.h"
int main()
{
int a=10;
int b=20;
printf("add(a,b)=%d\n",add(a,b));
printf("sub(a,b)=%d\n",sub(a,b));
}
生成静态库
将add.c、sub.c生成add.o和sub.o,然后进行打包生成静态库
将头文件和生成的静态库分别放在mylib目录下的include目录和lib目录下
生成静态库的语法格式
ar -rc 生成的静态库名称,想要打包的.o文件
[ztl@VM-4-11-centos study_10-5]$ gcc -c mysub.c -o mysub.o [ztl@VM-4-11-centos study_10-5]$ gcc -c myadd.c -o myadd.o [ztl@VM-4-11-centos study_10-5]$ ls makefile myadd.c myadd.h myadd.o mysub.c mysub.h mysub.o test.c //生成静态库 [ztl@VM-4-11-centos study_10-5]$ ar -rc libmymath.a *.o [ztl@VM-4-11-centos study_10-5]$ ls makefile myadd.c myadd.h myadd.o libmymath.a mysub.c mysub.h mysub.o test.c ar是gnu归档工具,rc表示(replace and create)
libmymath.a就是打包好的静态库
使用Makefile打包静态库
libmymath.a:myadd.o mysub.o ar -rc $@ $^ myadd.o:myadd.c gcc -c $< mysub.o:mysub.c gcc -c $< .PHONY:clean clean: rm -rf *.o output libmymath.a .PHONY:output output: mkdir -p mylib/include mkdir -p mylib/lib cp *.h ./mylib/include cp *.a ./mylib/lib #make output:发布,生成对应目录,并将头文件和库拷贝至指定目录
查看静态库中的目录列表 [ztl@VM-4-11-centos study_10-5]$ ar -tv mylibmath.a rw-rw-r-- 1001/1001 1240 Oct 5 14:01 2021 myadd.o rw-rw-r-- 1001/1001 1240 Oct 5 14:01 2021 mysub.o t:列出静态库中的文件 v:verbose 详细信息
使用静态库
Makefile中使用
test:test.c gcc test.c -o test -I./mylib/include -L./mylib/lib -lmymath -static .PHONY:clean clean: rm -f test # -I,因为我们的头文件不在系统的默认目录或路径下,所以需要向编译器说明我们的头文件在哪。-I选项 + 头文件路径就表示告知编译器我们的头文件的路径 # -L,同样我们的库也不在默认目录与路径下,也需要向编译器说明我们生成的静态库在哪。-L选项 + 库的位置 # -l,虽然告诉了编译器头文件和目录的位置,但实际上,编译器不知道我们要用哪个库啊,一个lib目录下可能有多个库,所以要说明使用的库的名字(去掉后缀和前缀) # -static 表示采用静态链接的方式编译,使用前需下载相关文件。使用命令:sudo yum install glibc-static
生成动态库
libmymath.so:myadd.o mysub.o gcc $^ -shared -o $@ myadd.o:myadd.c gcc -fPIC -c $< mysub.o:mysub.c gcc -fPIC -c $< .PHONY:clean clean: rm -rf *.o output libmymath.so .PHONY:output output: mkdir -p mylib/include mkdir -p mylib/lib cp *.h ./mylib/include cp *.so ./mylib/lib #shared: 表示生成共享库格式 #fPIC:产生位置无关码(position independent code) #库名规则:libxxx.so
使用动态库
编译选项
与静态库相同,只是少了-static选项
gcc test.c -o test -L./mylib/lib -I./mylib/include -lmymath
执行:执行报错
执行ldd命令查看可执行文件所需要的库,可以发现我们自己打包的动态库并没有被找到,因为我们是按动态链接来编译的,编译器知道我们的库在哪,但是操作系统不知道。
所以我们要引入一个人环境变量LD_LIBRARY_PATH,里面放着动态库的路径,我们要把自己的库的路径放进去。
于是,要执行命令 export LD_LIBRARY_PATH=./mylib/lib/
这时就可以正常执行了
Makefile使用动态库
test:test.c gcc $^ -o $@ -I./mylib/include -L./mylib/lib -lmymath .PHONY:clean clean: rm -f test