动静态库
8. 动静态库
8.1静态库
静态库(.a):程序在编译链接的时候把库的代码链接到可执行文件中。程序运行的时候将不再需要静态库
静态库的名字一般是 libXXX.a ,有效名是XXX,去掉前缀lib去掉后缀.a
在进行链接的时候是链接相应的二进制文件,所以有
对于我们不想暴露自己的源代码的时候,我们可以提供相应的.o文件(可重定位目标二进制文件)以及头文件,让其他人可以来进行使用
(.o) :方法的实现
(.h) :方法的声明
我们尝试着将多个.o文件进行打包,给对方提供一个库文件即可,即在链接的时候去这个库里去找相应的实现
多个
.o文件 ------> 一个文件 ------->库------>动态库和静态库
库的本质就是.o文件的集合
所以我们可以尝试着写好一个实现以及打包的过程:
libmymath.a:my_add.o my_sub.o
ar -rc $@ $^
my_add.o:my_add.c
gcc -c my_add.c -o my_add.o
my_sub.o:my_sub.c
gcc -c my_sub.c -o my_sub.o
.PHONY:output #发布我的库,创建一个文件夹,然后把所有的.o文件放入一个目录里
#所有的.h文件放入一个目录里
output:
mkdir -p mylib/include
mkdir -p mylib/lib
cp -f *.a mylib/lib
cp -f *.h mylib/include
.PHONY:clean
clean:
rm -rf *.o libmymath.a mylib
⭐生成静态库的方法:
#生成静态库
ar -rc libmymath.a add.o sub.o
#ar是gnu归档工具,rc表示(replace and create)
对于下载好我的库的用户,在编译的时候,需要指定gcc去哪里找我的头文件,以及指定去哪里找库,以及找哪个库
gcc -o main main.c -I./mylib/include -L./mylib/lib -l mymath
#-I后边跟头文件的所在路径,-L后跟库的所在路径, -l后跟需要链接的库的名字
依次是指定路径中找头文件的,找库的路径,找哪个库(l+有效名)


- gcc的链接默认是动态的,但是如果你指定全是静态库,那么他就会按静态链接的办法
- 如果有动态库和静态库掺杂,那么动态的动态链接,静态的静态链接
- 只要有一个是动态链接的,那么就是动态链接
8.2 动态库
动态库: 在可执行程序运行阶段才去链接相应的动态库,找相应的代码实现
动态库的名称一般是 libXXX.so ,去掉前缀
lib去掉后缀.so才是有效名
动态库的生成办法和放的位置和静态库类似
-
先生成
.o文件 -
然后把
.o文件打包成动态库.so -
把
头文件放入一个文件夹里,.so文件放入一个文件夹里
但是在步骤1.时生成.o文件时需要加一个-fPIC选项
gcc -fPIC -c Add.c Sub.c
这里生成.o文件 ,fPIC:产生位置无关码(position independent code)
步骤2:将所有的.o文件打包位动态库,但是要加shared选项
gcc -shared -o libmymath.so *.o
步骤3:

此时我们按照静态库的办法编译的话:
gcc -o mymatn main.c -I ./mylib/include -L ./mylib/lib -l mymath
照样可以生成对应的可执行文件,但是运行不起来

用ldd查看链接会发现压根没有找到静态库

这是因为动态链接是在程序运行期间去找动态库的,去链接的,但是gcc编译的时候去找动态库了,这只是属于编译阶段,编译完后的其他阶段和gcc没有关系了
所以运行阶段的时候OS(操作系统)和shell需要知道动态库在哪里去找
让系统找到动态库的办法:
- 方法一:加入环境变量中或者系统的lib64路径下:(不推荐)
因为系统也会在环境变量中去找库,在系统中有一个叫做LD_RARY_PATH的环境变量
这个LD_RARY_PATH的环境变量就是系统查找库的时候的除了默认在系统环境变量下找,也会在这个环境变量下找
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:动态库所在路径
但是这个办法,每次重新打开shell就会没了,下次还是运行不起来mymath,这是因为这个环境变量是内存级的
- 方法二:配置
etc下的ld.so.conf.d文件

ld.so.conf.d里边的文件保存的都是路径,系统也会在这里找库
创建一个新文件,里边保存要放的动态库的路径即可


此时用sudo ldconfig指令使刚刚的文件在系统中更新一下即可运行了

-
方法三:创建软链接
- 1.在执行程序路径下创建软链接:
在要运行的程序的同一路径下创建一个软链接,程序运行会在同一目录下去找的,所以在和程序同一个路径下创建一个软链接,进而能让可执行程序在运行时进行动态链接

- 2.在系统lib64路径下创建一个软链接,跟上一个一样的软链接,放到
etc/lib64下,也可以
8.1 动态库的加载
对于静态库的加载,是直接在编译阶段将库的代码拷贝到源程序文件里,然后进行编译的,然后通过进程地址空间来进行cpu访问读取,运行程序

对于动态库来说,假设有一个可执行程序my.exe,里边调用了printf函数,用的是动态链接,那么他的加载过程是这样的:

- 先产生
lib.so(假设这个是printf的动态库),这个动态库是由产生位置无关码的.o文件生成的 my.exe在编译的时候,在my.exe中printf的位置存的是printf在动态库lib.so的偏移地址(或偏移量)- 然后首先运行
my.exe的时候,先将my.exe放到内存中,根据进程地址空间执行,按代码顺序依次执行 - 当执行到printf的时候,cpu停止对
my.exe的执行,找到printf所在的动态库即lib.so,将动态库放到内存中 - 当动态库放到内存中时候,此时通过页表将动态库的物理地址转化为逻辑地址,将内容直接映射到共享区
- 此时共享区就有了
printf函数的动态库的在共享区的起始地址,那么再根据my.exe中printf存的偏移量,那么就能找到对应的函数实现了
所以对于多个同时使用同一个动态库的进程,只需要将一个动态库加载到内存,并且只加载一次就足够了,其他的进程都可以通过页表映射到自己的共享区,从而再通过共享区然后再映射到内存进行访问动态库,如下图


浙公网安备 33010602011771号