动静态库

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才是有效名

动态库的生成办法和放的位置和静态库类似

  1. 先生成.o文件

  2. 然后把.o文件打包成动态库.so

  3. 头文件放入一个文件夹里,.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.exeprintf的位置存的是printf在动态库lib.so的偏移地址(或偏移量)
  • 然后首先运行my.exe的时候,先将my.exe放到内存中,根据进程地址空间执行,按代码顺序依次执行
  • 当执行到printf的时候,cpu停止对my.exe的执行,找到printf所在的动态库即lib.so,将动态库放到内存中
  • 当动态库放到内存中时候,此时通过页表将动态库的物理地址转化为逻辑地址,将内容直接映射到共享区
  • 此时共享区就有了printf函数的动态库的在共享区的起始地址,那么再根据my.exeprintf存的偏移量,那么就能找到对应的函数实现了

所以对于多个同时使用同一个动态库的进程,只需要将一个动态库加载到内存,并且只加载一次就足够了,其他的进程都可以通过页表映射到自己的共享区,从而再通过共享区然后再映射到内存进行访问动态库,如下图

posted @ 2024-04-20 11:29  有志者事竟成1019  阅读(59)  评论(0)    收藏  举报