当前位置: 首页 > news >正文

Linux操作系统:软硬链接与动静态库

目录

前言:

一、硬链接

二、软链接

三、静态库

四、动态库 

总结:


前言:

我们上一篇文章已经讲完了文件系统,并把我们之前所学的进程,与文件系统关联了起来。而本节课我们将为大家带来有关于软硬链接与动静态库的有关知识点。

一、硬链接

我们经过文件系统的相关学习后,就应该知道了真正找到磁盘上文件的并不是文件名,而是inode!

其实在Linux上也可以让多个文件名对应于同一个inode,我们在当前目录下有一个file.txt文件:

随后,输入以下命令:ln file.txt File,让后者对前者进行硬链接:

可以看见,新形成的File文件,与file.txt的inode号码,是一模一样的,并且权限后面的数字,由1变成2了:

此时,File与file.txt文件其实是等价的,所有硬链接地位平等,没有“原始文件”和“链接”之分。

二者这种状态被称为:硬链接!

 我们给file.txt文件中写入hello world,其实就等于向File进行写入,因为二者的inode是一样的。

而数字1变为2,其实就相当于是一个引用计数,代表指向该inode文件的文件名的数量,这里有file.txt与File两个文件名,他们都与921122这个inode形成了映射关系,所以就是2

在我们进行硬链接之前,只有file.txt与该inode映射,所以是1。当我们把file.txt删除后,该引用计数也变为了1:

其实,上述过程就相当于进行了一次重命名操作。在我们执行重命名这个操作时,就相当于是进行了一次硬链接,我们对新的文件名进行一个硬链接,随后删除旧的文件名。

所以我们在linux下可以怎么对文件进行备份呢?

没错,就是进行硬链接就行了。


二、软链接

 输入以下命令:
ln -s File file.txt ,新建一个名为file.txt的文件,对File文件进行软连接:

可以看见 ,我们的原文件File与软链接形成的新文件,二者的inode是不一样的,新文件后面的->指向的是他的原文件。所以软链接形成的是一个全新的文件,而这个文件中,保存的是原文件的路径!!

说到路径,同学们想起来了什么吗?

没错,在上节课中,我们曾经提到了路径解析,如果我们有了一个文件的路径,可以通过文件解析的操作,找到他的inode与block,也就是说,我们可以通过软链接来访问到我们的File文件。

其实,在Windows中,软链接就相当于是他的一个快捷方式 ,我们在linux中也可以近似理解。


我们知道了关于引用计数的这个概念,那么我想问一下,当我们新建一个目录文件log,他的引用计数又是多少呢?目录不也是文件的一种吗?

可以看见,他的引用计数一开始就是2,为什么呢?

我们知道,每一个目录中,都存在两个被隐藏的文件: . 与..

.指向的是该目录自己,..指向的是该目录的上级目录。

我们可以通过cd ..,来达到返回上级目录的效果,这个是怎么做到的呢?

答案还是:硬链接!

没错,这个其实也是一种硬链接,也就说明了为什么我们新建一个目录,它的引用计数就为2的原因。

我们都知道,目录其实也是文件的一种,那么目录是否存在软硬链接呢?

我们可以看见,当我们想要尝试对目录文件log/进行硬链接时,被提示不能进行硬链接。而我们进行软链接时,却显示成功了。

为什么存在这样的差异呢?

 因为要防止目录循环,避免文件系统陷入无限递归的混乱状态,直白点说,就是防止出现循环目录。

目录在文件系统中是一个“文件名 → inode”的映射表。如果允许目录硬链接,可能会出现以下情况:

  • 目录 A 包含子目录 B,而 B 又硬链接回 A,形成 A → B → A 的循环。

  • 当工具(如 findrm -r)遍历目录时,会陷入无限循环,导致系统崩溃或资源耗尽。

而软链接的本质是路径跳转,不会破坏文件系统的拓扑结构,它存储的是目标目录的路径字符串,访问时,内核会解析路径,按正常目录层级遍历,不会形成循环依赖。所以我们就可以对目录进行软链接而不是硬链接。

但我们前面不是说. 与..它本质上也是硬链接吗?

哈哈,这就是允许州官放火,不允许百姓点灯了。

.(当前目录)和 ..(父目录)本质上确实是硬链接,但它们是由文件系统内核直接管理的特殊硬链接,所以,一般来说这两个文件都会被隐藏起来。


三、静态库

库是写好的现有的,成熟的,可以复⽤的代码。现实中每个程序都要依赖很多基础的底层库,不可能每个⼈的代码都从零开始写,因此库的存在意义⾮同寻常。
本质上来说库是⼀种可执⾏代码的⼆进制形式,可以被操作系统载⼊内存执行。
库有两种:
1、静态库 .a(Linux)、 .lib(windows)
2、动态库 .so(Linux) .dll(windows)

 

那么,静态库是指的什么呢?

:程序在编译链接的时候,直接把库的代码链接到可执行文件中,程序运行的时候就不再需要静态库了。

由于这种方式,导致程序大小会比较大,但是运行速度会相对较快,因为运行时已经不需要再去找静态库了。

那我们如何生成一个静态库呢?

假设我们有以下四个文件:

首先,我们需要编译源文件为目标文件.o:

 -c 表示“只编译不链接”,生成 test1.o 和 test2.o

随后,我们使用rs命令打包库:

 

ar:归档工具,用于创建静态库。

rcs 参数:

r:替换已存在的成员。c:创建库(如果不存在)。

s:写入索引(加快链接速度)。

libtest.a:静态库文件名(约定以 lib 开头,.a 结尾)。

test1.o test2.o:要打包的目标文件。

于是,一个静态库文件就打包好了,如果我们想要使用这个静态库的话:

假设当前目录下,有一个 main.c 调用 test1 和 test2 的函数:

我们只需要输入:

gcc main.c -L. -ltest -o main

命令就可以生成main的可执行文件了。 

-L.:告诉编译器在当前目录查找库。

-ltest:链接 libtest.a(省略 lib 和 .a)。

 关于静态库的使用,还有多种方法,我们这里就不再赘述。有兴趣同学可以自己下来深入去了解一下。

四、动态库 

动态库(.so)是什么呢?
动态库(在 Linux 中称为共享库, .so 文件)是程序运行时才加载的库文件。与静态库不同,动态库不会在编译时被直接嵌入到可执行文件中,而是在程序启动或运行时动态加载。

也就是说,我们使用gcc命令时要指明动态库,运行程序时,也要指明动态库!

因为在我们运行程序时,程序的代码会被加载到内存上,随后要使用到库的代码了,就需要把库也加载到内存上(运行时指明了动态库),如果此时,有其他程序也会用到该动态库的代码,会把该程序的PCB内的虚拟地址空间部分的页表进行映射,实现共享动态库。

其实就是两个进程的PCB都映射到了该内存地址,于是都能使用同一份代码,这也就是为什么我们说它节省空间的原因。

 那么我们应该怎么生成一个动态库呢?

同样是以上四个文件,我们要生成一个动态库,就需要先对其源文件生成位置无关代码,这是动态库必需的,因为库可能被加载到不同的内存地址:

我们使用-fPIC

随后生成动态库(.so 文件):

-shared:告诉 gcc 生成的是动态库。

-o libtest.so:指定输出的库文件名(通常以 lib 开头,.so 结尾)。

 如果我们想要编译程序并链接动态库

可以使用如下命令:

gcc main.c -L. -ltest -o main

-L.:告诉编译器在当前目录查找库文件。

-ltest:链接 libtest.so(编译器会自动补全 lib 和 .so)。

想要运行程序的话,动态库就麻烦了很多。由于动态库是运行时加载的,系统需要知道去哪里找 .so 文件。有几种方法:

方法 1:临时设置 LD_LIBRARY_PATH

export LD_LIBRARY_PATH=.:$LD_LIBRARY_PATH
./main

LD_LIBRARY_PATH 是一个环境变量,告诉系统去哪里找动态库。

当然这个方法只在当前终端有效,关闭后失效。

方法 2:永久配置

将 .so 文件复制到系统库目录(如 /usr/local/lib),然后更新动态库缓存:

sudo cp libtest.so /usr/local/lib/
sudo ldconfig

ldconfig:更新系统的动态库缓存,使新库生效。

方法 3:编译时指定 rpath

gcc main.c -L. -ltest -Wl,-rpath=. -o main

-Wl,-rpath=.:告诉程序运行时在当前目录找 .so 文件。

 这个方法适合我们平常调试代码,避免频繁修改环境变量。


总结:

本篇文章为大家带来了软硬链接与动静态库的相关概念,如果有疑问的欢迎评论区或者私信指正交流!!

希望对大家有所帮助,谢谢!

http://www.lryc.cn/news/582120.html

相关文章:

  • ClickHouse介绍与应用
  • 迁移GitLab,在新Linux中用Docker重新部署GitLab备份还原
  • C#中的BindingList有什么作用?
  • 【机器学习深度学习】多分类评估策略:混淆矩阵计算场景模拟示例
  • 亚马逊运营进阶指南:如何用AI工具赋能广告运营
  • 诊断工程师进阶篇 --- 车载诊断怎么与时俱进?
  • English Practice - Day 2
  • vite打包的简单配置
  • react状态管理库 - zustand
  • 风电自动化发电中的通信桥梁:CAN主站转MODBUS TCP网关解析
  • 【MyBatis】MyBatis与Spring和Spring Boot整合原理
  • 5种方法将联系人从iPhone转移到OnePlus
  • C++--map和set的使用
  • 仿mudou库one thread oneloop式并发服务器
  • 达梦数据库的信息查询
  • Redisson 分布式锁原理解析
  • Navicat Premium可视化工具使用查询控制台优化SQL语句
  • 商品中心—库存分桶高并发的优化文档
  • 力扣 3258 统计满足 K 约束的子字符串数量 I 题解
  • Java工具类,对象List提取某个属性为List,对象List转为对象Map其中某个属性作为Key值
  • RAG实战指南 Day 8:PDF、Word和HTML文档解析实战
  • UI自动化常见面试题
  • day08-Elasticsearch
  • 云计算领域“XaaS”是什么?
  • Python编译器(Pycharm Jupyter)
  • 第4.2节 Android App生成追溯关系
  • 【Mac 从 0 到 1 保姆级配置教程 19】- 英语学习篇-我的英语工作流分享(AI 辅助学习)
  • JavaWeb笔记07
  • 比亚迪6月销量38.25万辆,同比增长11.9%
  • window显示驱动开发—BGRA 扫描输出支持