【linux深入剖析】动态库的使用(续) | 动静态库的链接

发布于:2024-04-20 ⋅ 阅读:(22) ⋅ 点赞:(0)

🍁你好,我是 RO-BERRY
📗 致力于C、C++、数据结构、TCP/IP、数据库等等一系列知识
🎄感谢你的陪伴与支持 ,故事既有了开头,就要画上一个完美的句号,让我们一起加油

在这里插入图片描述



回顾

  • 回顾上节,我们在创建了动态库libmymath.so

在这里插入图片描述

  • 我们使用指令

gcc main.c -L. -lmymath
-L .(-L + 路径表示myc这个库在哪个路径下,这里就是用的点来代表当前路径,)
-lmymath(指明要链接mymath这个动态库)
因为gcc默认是调用的是C语言标准库,所以我们要在这里指明要使用我们的库

在这里插入图片描述

编译生成了文件a.out,运行程序是可以运行的

在这里插入图片描述

  • 使用ldd查看文件是否是调用的我们所创建的库

在这里插入图片描述

其实际链接的是/lib64/libc.so.6,这就是C语言标准库,同时也依赖了我们自己的库,libmymath.so

结论:编写库的人:未来要给别人(用这个库的人),交付的是:头文件+库文件。


我们想让别人使用我们的库就需要我们对其进行发布
将我们的库发布出来就是Makefile中output部分

  1 libmymath.so:add.o sub.o
  2     gcc -shared -o $@ $^
  3 .o:.c
  4     gcc -shared -c $<
  5 #add.o:add.c
  6 #   gcc -c -fPIC $< -o $@
  7 #sub.o:sub.c
  8 #   gcc -c -fPIC $< -o $@
  9 .PHONY:clean
 10 clean:
 11   rm -f *.o libmymath.so
 12 
 13 .PHONY:output                                                                                                                                                                           
 14 output:
 15 	mkdir -p ./mylib/mylib/
 15 	mkdir -p ./mylib/Headfile/
 15	 	cp -rf libmymath.so ./mylib/mylib/
 15	 	cp -rf add.h sub.h ./mylib/Headfile/
 15	 	tar -czf mylib.tgz mylib

output的工作就是帮我们在user目录下创建一个mylib的文件以及将我们的库拷贝过去,并且帮我们在user目录下创建一个Headfile的文件以及将我们的头文件拷贝过去,最后一步是打包文件

在这里插入图片描述

这里的mylib.tgz就是我们的库打包文件

  • 我们新建一个目录然后将打包文件移动到此目录下,实行解压,解压之后删除压缩包

在这里插入图片描述

这样我们要使用这个库就可以轻松使用了


1. 打包库的使用

接下来我们对其进行使用

  1. 我们将main.c主文件移动到该路径下进行编译

在这里插入图片描述

编译是无法运行的,这里缺少了头文件

  1. 我们使用指令gcc -o mytest main.c -I ./mylib/Headfile

-I + 路径是让编译器查找头文件时不仅在当前路径以及库路径查找也要在这个路径下进行查找
这样依然会报错,这是因为没有用到我们的库

  1. 我们使用指令gcc -o mytest main.c -I ./mylib/Headfile/ -L ./mylib/lib -lmymath链接到我们自己的库

在这里插入图片描述

运行出来了,就可以看到我们的mytest文件


我们上面这一长串也还是太长了,我们要想只链接一下我们的库就能编译怎么操作?

gcc -o mytest main.c -lmymath


解决办法:

  • 方法一:我们将库安装到系统的默认路径

所谓的把库(其他软件)安装到系统中,本质就是把对应的文件拷贝到系统指定的路径中

  1. 首先我们的系统默认头文件路径一般都在系统的include路径下

在这里插入图片描述

  1. 我们想拷贝到这个路径下需要我们提升权限,这些系统路径一般都是机器规定好的,都是root权限

在这里插入图片描述

  1. 系统默认的库路径在我们的lib64目录下

在这里插入图片描述
4. 拷贝库文件到默认库里

在这里插入图片描述

  1. 测试

在这里插入图片描述

但是在这里我们是不推荐将我们写的不成熟的库与头文件写入系统里的,所以这种方法是不推荐的


2. 动态库可执行程序无法运行的问题

我们如果不将库文件以及头文件移动到系统里,我们就还是只能采取我们的老办法,但是为什么我们生成的文件无法运行呢?
在这里插入图片描述

这里的报错说明了我们找不到这个目录


静态库在编译的时候是不会出现这个问题的,静态库的本质是从库里面把它的代码拷贝到这个程序当中,所以对静态库来讲,只要形成了可执行程序,静态库在后续就不需要再被使用了,所以在我们后续使用的时候就不会再出现查找静态库的任何动作

反而对动态库来讲,我们编译的时候是我们自己给它指明了我们的库路径,所以它编译成功了,但是形成文件之后,它再次找不到库了,这也就是动态库与静态库的差别

对于动态库:这里有两套路径

编译时的库搜索路径是给gcc的
运行时的库搜索路径是给OS的

也就是说我们在程序运行的时候也需要给它库的路径


回归正题,我们使用指令ldd来查看一下可执行文件的库路径
在这里插入图片描述
可以很清楚的看到,我们自己的库处于找不到的境地


3. 动态库可执行程序运行解决方法

我们有四种方法去解决这个问题

3.1 将库安装到系统中(/lib64/)

在这里插入图片描述

可以看到拷贝过去之后,我们的可执行文件的库再也没有出现not found,并且程序已经可以运行


3.2 环境变量LD_LIBRARY_PATH

环境变量LD_LIBRARY_PATH :系统运行程序时,动态库查找的辅助路径

在这里插入图片描述
系统默认在/lib64/路径下找,但是程序运行时不仅仅在/lib64/下找,也会在这个辅助路径下进行寻找,以冒号为分隔符,在目录下寻找

  • 我们将库的目录添加到环境变量LD_LIBRARY_PATH 里即可
    在这里插入图片描述

但是环境变量有一个缺点,那就是我们重启xshell之后,这个环境变量是会回到初始状态的


3.3 对库文件建立软链接

使用如下指令,我们在库文件里添加同名库文件软链接

sudo ln -s /home/cmj/work/newfile/mylib/mylib/libmymath.so /lib64/libmymath.so

在这里插入图片描述

我们再来运行,即可运行

在这里插入图片描述

3.4 ldconfig 配置/etc/ld.so.conf.d/,ldconfig更新

删除软链接,文件变为not fount状态
在这里插入图片描述

我们先来认识一下/etc/系统配置文件路径

在这里插入图片描述

这里面有一个/etc/ld.so.conf.d/
名称含义 ld是链接,so就是动态库,conf就是配置文件,.d就是指它是个目录

它是允许我们去配置各种各样的文件的,我们创建一个我们自己的配置文件cmj.conf,里面没有写任何东西
在这里插入图片描述

这个配置文件只需要我们写入我们需要其去识别的库路径就可以了
配置后需要我们更新环境变量的配置系统,用到指令 ldconfig

在这里插入图片描述
文件就重新成功运行了


4. 动静态库的链接

我们先实现动静态库全创建并帮我们打包的Makefile

  1 libmymath.a:add.o sub.o
  2     ar -rc $@ $^
  3     rm *.o
  4 %.o:%.c
  5     gcc -c $<
  6   
  7 libmymath.so:add.o sub.o
  8     gcc -shared -o $@ $^
  9 %.o:%.c             
 10     gcc  -c -fPIC $<
 11 #add.o:add.c        
 12 #   gcc -c -fPIC $< 
 13 #sub.o:sub.c
 14 #   gcc -c -fPIC $<                             
 15 .PHONY:clean
 16 clean:       
 17   rm -f -rf *.o libmymath.so *.a mylib mylib.tgz
 18                                                                                                                                                                                         
 19 .PHONY:output                     
 20 output:                           
 21         mkdir -p ./mylib/mylib/  
 22         mkdir -p ./mylib/Headfile/  
 23         cp -rf *.so ./mylib/mylib/
 24         cp -rf *.a ./mylib/mylib/
 25         cp -rf *.h ./mylib/Headfile/
 26         tar -czf mylib.tgz mylib
  • 依次输入指令

make
make libmymath.so
make output

在这里插入图片描述

  • 再将我们打包的压缩包文件传入user,user是我们假装的外部用户

在这里插入图片描述
我提供的既有静态库又有动态库。
我们将文件进行编译
输入指令

gcc -o mytest main.c -I ./mylib/Headfile/ -L ./mylib/mylib/ -lmymath

我们在最后并没有指明其使用动态库还是静态库,我们使用的是库的名字
在这里插入图片描述

最后我们可以看到我们动态库和静态库同时提供的时候,gcc默认使用的是动态库!!!

我们也可以指定使用静态库,在当初的库名后面加上-static即可
在这里插入图片描述


  • 我们将库里的动态库移到上级目录,再次运行该程序

在这里插入图片描述
我们可以发现它不依赖我们自己写的静态库

如果我们只提供的静态库,那我们的可执行程序也没办法,只能对该库进行静态链接,但是程序不一定整体式静态链接的


  • 我们将动态库移动回来,将静态库移除

在这里插入图片描述

我们尝试加-static

在这里插入图片描述如果我们只提供动态库,默认只能动态链接,非得静态链接,会发生链接标错


结论:

  1. 如果我们同时提供动态库和静态库,gcc默认使用的是动态库
  2. 如果我们非要使用静态链接,我们必须使用的是动态库
  3. 如果我们只提供的静态库,那我们的可执行程序也没办法,只能对该库进行静态链接,但是程序不一定整体式静态链接的
  4. 如果我们只提供动态库,默认只能动态链接,非得静态链接,会发生链接标错