静态库和动态库

什么是库

  • 库文件是计算机上的一类文件,可以简单的把库文件看成一种代码仓库,它提供给使用者一些可以直接拿来用的变量、函数或类。
  • 库是一种特殊的程序,编写库的程序和编写一般的程序区别不大,只是库不能单独运行
  • 库文件有两种:静态库和动态库(共享库),区别:静态库在程序的链接阶段被复制到了程序中;动态库在链接阶段没有被复制到程序中,而是程序在运行时由系统动态加载到内存中供程序调用
  • 库的好处:1、代码保密 2、方便部署和分发

静态库的制作

在这里插入图片描述

实例

在这里插入图片描述
将上面四个函数文件生成.o文件

gcc -c add.c div.c mult.c sub.c

然后使用 ar rcs libxxx.a xxx.o
在这里插入图片描述

静态库的使用

将lesson04里面的calc和library文件复制一份到lesson05里面

注意看library
里面并非像calc文件夹一样,将所有文件放一起。而是将一个个文件分门别类。
而且include存放头文件,lib一般存放库文件,src文件存放源代码文件,然后main函数和各文件夹平级
在这里插入图片描述
fatal error:是因为head.h头文件并不是和main函数同级,编译器识别不到,需要使用 -I 来指定目录,或者把头文件拿出来(不推荐)

gcc main.c -o app -I ./include/

在这里插入图片描述
出现对add,subtract等未定义的引用错误 是因为找不到那个库函数,需要进行指定,这里指定库的名称并不是指定库文件的名字,另外使用-L来指定位置

gcc main.c -o app -I ./include/ -l calc -L lib

在这里插入图片描述
再编译一次,就可以编译通过了
在这里插入图片描述

重新回顾一下静态库的制作

  • 首先进入src文件,编译里面的函数生成一个.o文件
  • 通过ar指令对.o文件进行打包,打包生成一个.a文件,并将其移动到lib文件夹中
  • 头文件,库文件都有了,接下来对程序进行编译(-I指定头文件的位置 -L指定库文件的位置-l 指定库的名称)
  • 编译通过,并运行(./app)

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

动态库的制作

动态库的制作过程

在这里插入图片描述
通过gcc得到.o文件,得到和位置无关的代码
在这里插入图片描述

gcc -shared add.o sub.o mult.o div.o -o libcalc.so

生成动态库
在这里插入图片描述
将库文件放到lib目录下
在这里插入图片描述
然后将程序进行编译
在这里插入图片描述
最后编译成功,生成一个main可执行文件
在这里插入图片描述
但是执行过程中出错了
在这里插入图片描述
在解决这个问题之前,我们先了解一下动态库加载原理。

工作原理

  • 静态库:GCC进行链接时,会把静态库中代码打包到可执行程序中
  • 动态库:GCC进行链接时,动态库的代码不会被打包到可执行程序中
  • 程序启动之后,动态库会被动态加载到内存中,通过ldd(list dynamic dependencies)命令检查动态库依赖关系
  • 如何定位共享库文件?当系统加载可执行代码的时候,能够知道其所依赖的库的名字,但是还需要知道绝对路径。此时就需要系统的动态载入器来获取该绝对路径。对于elf格式的可执行程序,是由ld-linux.so来完成的,它先后搜索elf文件的 DT_RPATH段——>环境变量LD_LIBRARY_PATH——> /etc/id.so.cache文件列表——>/lib/,/usr/lib目录找到库文件后将其载入内存。

使用ldd加可执行程序可以将该程序所用到的动态库给列出来
在这里插入图片描述
解决办法:在DT_RPATH段或者环境变量LD_LIBRARY_PATH——> /etc/id.so.cache文件列表——>/lib/,/usr/lib目录 里面加入动态库的绝对路径,就可以找到动态库了

方法一:在终端使用export 添加环境变量(临时)

获取原先环境变量的内容
后面再拼接上新加入的值
在这里插入图片描述
通过echo来查看环境变量是否添加成功
在这里插入图片描述
通过ldd来查看动态库依赖关系已经找到,并且程序成功运行
在这里插入图片描述
上面这个方法是在终端进行配置,有一个缺陷就是你关机再重新链接linux运行那个程序就不能运行了(只是临时的)

方法二:永久配置环境变量(用户级别配置)

首先进入home目录下:cd ~
然后看一下所有文件 :ll 然后我们可以发现有一个隐藏文件 .bashrc
在这里插入图片描述
我们只需要配置 .bashrc 就可以了
vim .bashrc 进入
在这里插入图片描述
这里面也有其他的一些配置文件
我们在最下面加入我们的配置变量

export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/home/nowcoder/Linux/lesson06/library/lib

$LD_LIBRARY_PATH是 LD_LIBRARY_PATH里原有的环境变量,冒号(:)后面是我们要新加的环境变量(即动态库的路径)
在这里插入图片描述
在这里插入图片描述
配置好之后保存退出
退出之后还需要使配置生效,使用 . .bashrc 命令,或者说是当前目录下的 . ./.bashrc也可以使用source .bashrc

我们重新进入文件,查看动态依赖,发现可以找到了
在这里插入图片描述
找到之后,运行一下,发现可以运行,没毛病
在这里插入图片描述

方法二:永久配置环境变量(系统级别配置)

系统配置在 /etc/profile 这个目录下
在这里插入图片描述
进入添加环境变量,然后保存退出
在这里插入图片描述
保存好之后记得source一下,此时不用加sudo了
在这里插入图片描述

方法三:修改 /etc/ld.so.cache 文件列表

当我们使用vim进入 会发现里面都是些二进制内容
在这里插入图片描述
我们可以在 /etc/ld.so.conf 里面进行配置
我们进去之后,直接把路径复制粘贴到里面就好了
在这里插入图片描述
配置好之后我们使用 sudo ldconfig 进行更新
在这里插入图片描述
这样我们运行一下,发现也可以成功运行
在这里插入图片描述

方法四:把动态库文件放到 /lib/ 或 /usr/lib 文件中

不推荐
因为这两个文件夹里面包含很多系统自带的库文件,如果你的动态库文件和里面的重名了,可能会把系统自带的文件给替换掉,系统可能会出现异常。

静态库和动态库的对比

第一个区别就是链接方式不一样
在这里插入图片描述

gcc -c add.c div.c mult.c sub.c
ar rcs libcalc.a add.o sub.o mult.o div.o
gcc main.c -o app -I ./include/ -l calc -L lib

首先用gcc -c 将几个源文件编译成.o格式的文件
然后使用rcs将其连接成静态库文件,格式libxxx.c
最后编译程序,其中-I指定头文件的位置 -l指定静态库名称,-L指定静态库文件所在位置
在这里插入图片描述

动态库与静态库的一个最大区别就是要配置环境变量

在这里插入图片描述
一般库比较小的话,使用静态库。库比较大的时候,使用动态库

静态库的优缺点

优点

  • 静态库被打包到应用程序中加载速度快
  • 发布程序无需提供静态库移植方便

缺点

  • 消耗系统资源,浪费内存
  • 更新部署发布麻烦

在这里插入图片描述

动态库的优缺点

优点

  • 可以实现进程间的资源共享(共享库)
  • 更新部署发布简单
  • 可以控制何时加载动态库

缺点

  • 加载速度比静态库慢
  • 发布程序时需要提供依赖的动态库

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值