【Linux学习】基础IO——软硬链接 | 制作动静态库

news2024/10/6 8:36:14

🐱作者:一只大喵咪1201
🐱专栏:《Linux学习》
🔥格言:你只管努力,剩下的交给时间!
图

基础IO

  • 🍓软硬链接
    • 🌲软链接
    • 🌲硬链接
  • 🍓动静态库
    • 🌲静态库
    • 🌲动态库
  • 🍓动静态库的加载
    • 🌲动态库加载
    • 🌲静态库加载
  • 🍓文件的ACM
  • 🍓总结

在知道了文件是如何被管理,知道了inode等等后,还有很多和文件有关的知识。

🍓软硬链接

🌲软链接

  • 指令:ln -s 要链接的文件名 链接文件名
  • 功能:建立软链接

图
如上图所示,使用红色框中的指令建立了软连接。

  • 建立软连接后,会有新的文件产生,如上图绿色框中所示,此时文件类型是l,表示链接文件。
  • 链接文件和被链接文件的inode不相同,表示链接文件是一个独立的新文件。

链接文件可以使用rm来删除,但是最好用指令去解除链接文件。

  • 指令:unlink 链接文件名
  • 功能:删除链接文件

图
软链接的作用:

那么软连接掉地有什么用呢?

图
如上图中蓝色框中所示的可执行程序,它处于比较深的路径下,如果要执行该程序,就要像红色框中那样,输入很长的路径名。

图
在当前目录下建立深路径下可执行程序的软连接文件,此后直接执行软链接文件就可以。

软链接文件就像我们在windows下桌面上的快捷方式一样。

图
例如,点开谷歌浏览器的快捷方式图标的属性,可以看到有一个目标,目标中有一串路径。

  • 桌面的快捷方式就是软链接文件。
  • 属性中目标中的路径就是被链接的文件。

图
链接文件和被链接文件的inode是不相同的,如上图蓝色框中所示。

图
将链接关系中的被链接文件删除以后,链接文件就出错了,并且在闪烁。

图
再创建一个普通的同名文件,链接就恢复正常了。

  • 创建的文件是一个普通文件,并不是可执行文件。
  • 创建的文件和原来的文件inode不同,原来的是917833,现在是917844。
  • 只因文件名相同,链接关系就恢复正常了。

从上面的现象可以得出一个结论:软链接和inode无关,只和路径名有关。
也就是说,建立软链接后,并不是链接文件和另一个文件的inode绑定了,只是和文件名绑定了。

🌲硬链接

  • 指令:ln 链接文件名 被链接文件名
  • 功能:没有选项-s,建立硬链接

图
如上图,使用红色框中指令建立了硬链接。

  • 硬链接文件和被链接文件的inode相同。

inode相同,意味着它俩是一个文件,因为inode是一个文件时唯一标识,而且一个文件只有一个。所以说,硬链接创建的文件并不是一个独立的新文件,它是被链接文件的别名。

硬连接的本质:在指定路径下,新增文件名和inode编号的映射关系!!!

此时就不再是文件名和inode一一对应了,而是一个inode对应多个文件名,这是文件名都标识一个文件,只是叫法不同。

图
上图中,红色框中的数字表示文件的硬连接数,也就是一个inode有几个文件名字和它映射。

删除硬链接:

同样的,可以使用rm删除,也可以使用unlink指令来删除。

图
使用红色框中的指令可以删除硬链接文件。

  • 原本这个文件的硬链接数是2,并且inode是917832。
  • 删除掉硬链接文件以后,硬链接数变成了1,但是仍然存在inode为917832的文件。

这说明,文件没有被删掉,那么该如何删除这个文件呢?因为硬链接文件和链接文件其实是一个文件。

图
在inode中有一个变量count,它在进行引用计数。

  • 每当一个文件名和这个inode建立映射关系的时候,引用计数加1。
  • 也就是硬连接数每加1,引用计数就加1。

所以在删除这个文件的时候,使用unlink只是让硬链接数和引用计数减了1。只有引用计数减到0,这个文件的inode的位图才会被清0,这个文件才会被删除。

硬链接的作用:

tu

  • 目录一经创建,它的硬链接数就是2。
  • 普通文件一经创建,它的硬连接数是1。

图
我们知道,每个目下都有两个隐藏文件,分别是一个点和两个点,一个点表当前目,两个点表示上级目录。

  • dir这个目录名和917833这个inode构成一个映射关系。
  • dir目录下的一个点又和917833这个inode构成一个映射关系。

所以一个目录一被创建,硬链接数就是2,因为有两个映射关系到这个inode上。

图
此时目录dir的硬链接数就变成了3。

  • dir目录本身的名字和inode917833是一个映射。
  • ./dir中的一个点和inode也是一个映射。
  • ./dir/mydir中的两个点和inode也是一个映射。

一个点和两个点同样是目录名,只是名字是点而已。

图

给目录建立硬链接的时候,shell反馈目录不能建立硬链接,这是为什么?

  • 如果给根目录建立了硬链接,那么就会造成死循环,从下级目录中的根目录和最上级目录的根目录之间的死循环。

所以为了避免这种情况,操作系统直接就不让用户给目录创建硬链接,至于(.和…)这俩硬链接,是操作系统自己创建的。

最后,软硬链接的区别:链接文件是否有独立的inode。

🍓动静态库

先来简单回顾一下动静态库,详细内容可以看本喵的这篇文章动静态链接。

  • 动态库:库文件,以.a为后缀(Windows中为.lib)
  • 静态库:库文件,以.so为后缀(Windows中为.dll)
  • 库的命名规则:lib库名.后缀

所以见到一个库,掐头去尾才是它的库名。使用gcc进行编译的时候,默认是采用的动态链接,如果要使用静态链接需要加上选项-static。

图
静态链接形成的可执行程序比静态链接形成的要大,如上图中红色框所示。

🌲静态库

库源码及头文件:

图
将上诉代码接口给同学使用,并且不暴露源码,此时我们就可以选择将它制作成库。

制作静态库:

现在站在制作库的一方来看问题。

对源码进行预处理,编译,汇编,形成以.o为后缀的目标文件,再将这些文件交给同学。

图

现在将两个源文件编译成了两个以.o为后缀的目标文件,如上图蓝色框所示,它们是二进制形式的机器码,并不是源码。

图

将.o为后缀的目标文件以及头文件交给同学,让他去链接生成可执行程序。

图
同学给我们对的反馈如上图,成功链接了,并且成功执行了可执行程序。

库的原理和上面类似,只是将所有的.o为后缀的文件打包在了一起,形成了一个库,在使用的时候直接使用这个库就可以。

  • 指令:ar -rc libname.a [所有待打包.o]
  • 作用:将所有待打包的.o文件制作成静态库。

该指令中,ar是gnu的归档工具(Archive files),rc表示replace和create。
图
将要给同学的两个.o文件进行打包,制作成一个静态库。

图
我们可以写一个这样的Makefile,直接一步make到位,生成一个库文件。

  • 将所用到的头文件全部放在myliba/include目录下。
  • 将静态库文件放在myliba/lib目录下。

图
操作如上图所示。

图
可以通过指令来查看我们制作的库。

  • 指令:ar -tv 库文件名
  • 功能:列出静态库中的文件和详细信息。

图
正是我们打包的.o文件。
图
再使用打包工具tar,将库和头文件一起打包,如上图所示,将压缩包发生给同学。

此时我们的库就制作成了。

使用静态库:

此时我们站在使用者的角度,也就是那个同学的角度。

图
我们接收到了库的压缩包(和从网上下载一样),然后解压,得到了里面的文件。

图
进行make的时候,发现报错了,所以接下来就是怎么使用它,有俩种方法可以用。

  1. 安装在系统中

这种方法类似于我们安装软件,使用gcc的时候,它会自动去系统默认路径下搜索所需要的头文件和库文件,也就是C语言标准库所在的路径。

  • 头文件默认搜索路径:/usr/include;
  • 库文件默认搜索路径:/usr/lib64;

我们可以将同学给的头文件和库文件安装在gcc的默认搜索路径下。

图
如上图所示,将库和头文件安装到默认搜索路径下,当然在复制的过程中需要使用root权限。

图
但是在make的时候,发现,还是报错了,这次不是找不到头文件,而是找不到使用接口的定义,说明库出问题了。是因为gcc不知道该用这个默认路径下的哪个库。

图
在使用gcc编译的时候告诉编译器要使用的库名(掐头去尾后的库名),此时就能编译成功了,而且成功调用了同学给我们的库。

  • -l选项:指定使用的库名(掐头去尾后的库名)。
  • 注意:l可以和名字合在一起,如-lmylib。

我们平时可是没有加过-l选项的,各种库函数,比如printf这是都是可以调用的,为什么我们自己的库还需要告诉gcc库名呢?

  • 官方提供的标准库编译器是能够认识的,所以不用特别指出。

这种方式不建议使用,因为第三方库没有经过检测,会污染其他库和头文件。

比较好的是下一种方式。

  1. 告诉编译器头文件路径,库路径,库名

图

选项作用
-I(大写i)指定头文件路径
-L指定库文件路径
-l(小写L)指定库(掐头去尾后的库名)

如上图所示,这样一来,一个第三方库就可以正常使用了。

图
为了让这条指令更紧凑一点,选项和路径之间的空格可以省去。

🌲动态库

源码和头文件还是和制作静态库时的一样,要求也是一样,但是此时是给同学制作一个动态库。

制作动态库:

和制作静态库一样,将所有.o文件打包在一起,但不使用ar打包,而是使用gcc来打包。

站在制作者的角度:

  1. 形成位置无关码
    图
    在使用gcc形成.o文件的时候,再加一个选项-fPIC,生成位置无关码。如上图红色框所示。

位置无关码是什么呢?

图
如上图所示,假设绿色的星星在进行百米赛跑,在跑道的中间,也就是50米处有一个箭头标志。

描述星星的位置:

  • 绝对位置:80米处
  • 相对位置:箭头右侧30米处

如果这不是100米的跑道,而是变成了200米,500米呢?星星的绝对位置会变化,但是它的相对位置永远不变,处于箭头右侧30米处。

位置无关码就类似于箭头右侧30米处的30。 本质上它是一个偏移量,相对于库基地址的偏移量。

  1. 形成库文件
    图
    使用gcc,加-shared选项,告诉gcc生成动态库而不是可执行程序,如上图中红色框中所示。
选项作用
-fPIC生成位置无关码
-shared生成动态库

此时一个动态库就制作成了,同样的我们可以将生成动态库的步骤写到Makefile中。
图
每一个.o文件文件都会生成一个位置无关码。

图

如此一来,动态库就制作成功了。

图
同样将制作的动态库打包,形成压缩包发送给同学。

使用动态库:

此时站在使用者的角度:

动态库的使用方法有四种:

  1. 将头文件和库文件安装在系统默认搜索路径中
    本喵就不再演示了,和静态库的安装一样。
  • 将头文件复制到/sur/include路径下,将动态库文件安装在/usr/lib64路径下.
  • 并且在编译的时候使用-l选项告诉gcc使用的动态库名称。

同样,这种做法是最不推荐的。

  1. 将库文件路径放在环境变量里

不适用第一种方法,那么就需要告诉gcc头文件的路径,库的路径,还有库名。

图

  • 使用-I,-L,-l选项告诉gcc相应的信息后,编译成功了。
  • 执行可执行程序的时候报错动态库不存在。
  • 查看可执行程序的链接属性,发现找不到动态库。

信息都告诉gcc了,怎么编译不成功呢?

回顾:

  • 静态链接:将用到的库函数在编译的时候赋值到了源码中,所以编译成功就可以执行。
  • 动态链接:在编译的时候,只是将库的位置无关码(地址偏移量)复制到了源码中,等在运行可执行程序的时候再去动态库中根据偏移量找到应用的库函数。

仔细分析一下:

  • 我们将头文件路径,库文件路径,库文件名告诉了gcc。
  • 编译完成以后,和gcc就没有关系了,接下来的执行是操作系统的事情。
  • 那么操作系统就必须得知道所使用的动态库在哪里。

所以接下来的任务就是告诉操作系统我的动态库在哪里。

  • 在执行程序的时候,操作系统会从环境变量LD_LIBRARY_PATH中读取动态库的路径。

图
将自己的动态库路径放入到环境变量中,再执行刚刚生成的可执行程序,发现可以成功执行了,而且使用的是动态库中的函数接口。

这种做法并不能永久生效,因为每次启动shell的时候,它都会从配置文件中重新加载环境变量,我们这里给LD_LIBRARY_PATH赋值只是暂时的。

  1. 将库文件路径放在配置文件中

在使用gcc编译的时候和上面一样,在告诉操作系统库文件路径时不再放入环境变量中,而是放入系统配置文件中。

  • /etc/ld.so.conf.d/
  • 在这个路径中有很多配置文件

图
随意打开一个配置文件,发现里面放的也是路径。

图
此时我们再创建一个配置文件,名字随意,后缀是.conf的就行,在里面把我们动态库的路径放进去。这里的所有操作都需root权限。

图
此时再运行时,发现还是找不到动态库。

图

  • 使用sudo config指令更新刚刚添加的配置文件

此时操作系统就能找到我们对动态库了,而且这是一个永久的办法,不像将路径加到环境变量中那样是暂时的。

  1. 软链接到系统默认搜索路径中

图

  • 路径:/usr/lib64

在这个系统默认搜索库路径下,有很多的库文件,还有很多的软链接库文件。

图
将同学给我们的动态库软链接到系统默认搜索路径下,如上图所示。此时系统就能找到库了。

🍓动静态库的加载

🌲动态库加载

gcc在编译的时候,只是将库中的库函数生成了一个位置无关码(相对偏移量)放在了程序中,在程序执行的时候,需要操作系统先将整个库加载到内存中,然后再根据位置无关码调用这个库函数。

图

  • 进程被创建以后,将对应的代码加载到内存中。
  • 进程虚拟地址空间的代码段通过页表映射到了内存中,其中就包括生成的位置无关码。
  • 操作系统将指定的动态库也加载到了内存中,由于占据内存空间,所以给它分配了地址。
  • 当进程执行到调用库函数时,操作系统根据位置无关码,在动态库基地址的基础上偏移一定量的地址找到要调用的库函数,并且调用。

以上就是动态库的加载和调用过程。

🌲静态库加载

图

  • 在gcc进行编译时,编译器将要调用的库函数复制到了程序中,形成了可执行程序。
  • 进程被创建后,操作系统将复制了库函数的可执行程序加载到内存中去执行。

静态库的加载和操作系统没有关系,它是编译器完成的,就是将库函数源码复制一份到我们对源码中。

  • 如果使用静态库,同一个库函数被使用了十次,编译器就会在对应位置复制十分,使用100次,就会复制一百次。
  • 如果使用动态库,同一个库函数被使用十次,就会有十个位置无关码,使用100次就会有100个,在执行的时候,操作系统根据偏移量在内存中仅有的一个动态库中调用相应的函数。

所以使用静态库的程序都比使用静态库的程序要大,所占用的内存多。

再来看一个现象:

图

  • 此时只有静态库,没有动态库。
  • 告诉gcc各种信息,进行编译,采用的是静态库。
  • 查看可执行程序动态库信息,发现并没有我们的静态库。
  • 查看可执行程序的文件信息,发现依然是动态链接,并没有说静态链接。

这就奇怪了,我们明明用的静态库,但是还是说动态链接,这是为什么?

  • 编译器建议采取动态链接,默认时采用的是动态库,但是此时没有动态库只有静态库,所以编译器没办法只能采用静态链接。
  • 但是程序不仅仅会调用这一个静态库,还有调用其他动态库,只要有动态库的调用,就把它归位动态链接。
  • 即使只有一个静态库,没有动态库的调用,查看文件属性还是动态链接,因为这表达了编译器的建议,实际上是静态链接。

图

  • 只有在使用gcc的时候加上-static选项,要求进行静态链接,编译器才会进行静态链接。
  • 此时查看动态库调用,会显示没有调用动态库。
  • 查看文件信息时,显示的就是静态链接。

除非使用了-static选项,否则gcc就会进程动态链接,并且认为它编译的程序都是动态链接,即使调用了静态库。

🍓文件的ACM

图
每个文件都有上图红色框中所示的三个时间。

  • Access:文件访问时间。
  • Modify:文件内容修改时间。
  • Change:文件属性修改时间。

根据字面意思就可以知道他们代表着什么,一般情况下,修改文件内容,Modife和Change的时间都会改变,内容变了,属性一般都会发生变化。

Access的时间并不是访问一次就会变化,因为访问频率高的话,需要不停修改这个时间,也就意味着和磁盘会有频繁的访问,到降低效率。

  • 访问文件的次数累积到一定量时,Access的时间会改变。
  • 访问文件的时间达到一定量时,Access的时间也会改变。

🍓总结

学习完这篇文章后,对硬链接和软链接要有清楚的认识,并且要掌握动静态库的制作和使用,因为们以后会用到这些东西。结合前面两篇文章,基础IO部分就结束了。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/389915.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

BPMN2.0规范及流程引擎选型方案

BPMN2.0规范及流程引擎选型方案一、基本概念二、BPMN意义三、主要元素3.1 活动任务子流程调用活动事件子流程事务3.2 网关排他网关包容网关并行网关事件网关3.3 事件开始事件结束事件中间事件3.4 辅助泳道图注释与组数据存储四、图类型4.1 编排图4.2 会话图五、技术选型5.1 前端…

大数据ETL开发之图解Kettle工具

详细笔记参考:https://blog.csdn.net/yuan2019035055/article/details/120409547以下只是简单记录一下我学习过程中的心得3.1.5 JSON输入JSONPath 类似于 XPath 在 xml 文档中的定位,JsonPath 表达式通常是用来路径检索或设置Json的。其表达式可以接受“…

阶段二11_面向对象高级_学生管理系统案例2

主要内容: 添加学生 static关键字一.添加学生时判断id是否存在 0.思路图片: 04/图片/2_添加学生判断id存在的问题分析.png 1.思路实现详细步骤: StudentController【客服接待】 /** 接收到学生id后,判断该id在数组中是否存在 这…

SRS源码分析-SDP内容解析

前言 在学习SRS的RTC模块之前&#xff0c;首先来分析下SRS在将rtmp推流转成rtc流&#xff0c;通过浏览器拉取webrtc流场景下产生的SDP内容 SDP格式介绍 SDP数据是文本格式&#xff0c;由多个 <key><value> 表达式构成&#xff0c;<key>的值只能是一个字符…

第二讲:ambari编译复盘,如何实现一次性成功编译ambari

上节课我们已经讲解了如何成功编译ambari源码,安装ambari-server rpm包以及成功部署ambari。本节课我们来复盘一下上节课的编译过程,以及思考如何实现一次性成功编译ambari。 要想一次性成功编译ambari,那么就需要将预置工作做好,比如: maven镜像源配置,node_moudle模块…

Go项目(商品微服务-2)

文章目录简介handler商品分类轮播图品牌和品牌与分类oss前端直传库存服务数据不一致redis 分布式锁小结简介 开发商品微服务 API 层类似的&#xff0c;将 user-web 目拷贝一份&#xff0c;全局替换掉 user-web修改 config 去掉不用的配置更新本地和远程 nacos 配置文件 把 pro…

OpenGL环境配置

方法一&#xff1a;1.下载GLFW点击GLFW跳转2.下载后解压3.下载glad&#xff0c;解压后4.用vs2019新建Cmake项目5.在新建的Cmake项目下建立depend文件夹在depend里放置我们下载解压的glad和glfw-3.3.8.bin.WIN646.项目中可以看到我们加进来的文件7.编写我们项目的CMakeLists.txt…

Condition 源码解读

一、Condition 在并发情况下进行线程间的协调&#xff0c;如果是使用的 synchronized 锁&#xff0c;我们可以使用 wait/notify 进行唤醒&#xff0c;如果是使用的 Lock 锁的方式&#xff0c;则可以使用 Condition 进行针对性的阻塞和唤醒&#xff0c;相较于 wait/notify 使用…

路径规划-人工势场法

一.基本思想 目标点对机器人产生吸引力&#xff0c;障碍物对机器人产生排斥力&#xff1b; 所有力的合成构成机器人的控制律 二. 主要步骤 1.构建人工势场 目标点&#xff1a;吸引势场 障碍物&#xff1a;排斥势场 2.根据人工势场计算力 对势场求偏导 3.计算合力 计…

bpftrace 笔记

bpftrace -e BEFIN {printf("hello world!\n");}获取调用 vfs_read 函数的进程id, 每2s打印一次 bpftrace -e kprobe:vfs_read {ID pid;} interval:s:2 {printf{"ID:%d\n", ID);}用户态调试 bpftrace -e uprobe:/*/a.out:and {printf("ID:%d\n&qu…

费解的开关/翻硬币

&#x1f331;博客主页&#xff1a;大寄一场. &#x1f331;系列专栏&#xff1a; 算法 &#x1f618;博客制作不易欢迎各位&#x1f44d;点赞⭐收藏➕关注 题目&#xff1a;费解的开关 你玩过“拉灯”游戏吗&#xff1f; 25盏灯排成一个 55 的方形。 每一个灯都有一个开关&…

看完这篇入门性能测试

大家好&#xff0c;我是洋子。最近组内在进行服务端高并发接口的性能压测工作&#xff0c;起因是2023年2月2日&#xff0c;针对胡某宇事件进行新闻发布会直播&#xff0c;几十万人同时进入某媒体直播间&#xff0c;造成流量激增 从监控上可以看出&#xff0c;QPS到达某峰值后&…

brew安装问题

最近使用mac安装了Python和PyCharm&#xff0c;使用python中的绘制图像的turtle库后&#xff0c;执行报错&#xff1a; import _tkinter # If this fails your Python may not be configured for Tk ModuleNotFoundError: No module named _tkinter 查询后需在mac 命令行执行&…

【网络监控】Zabbix详细安装部署(最全)

文章目录Zabbix详细安装部署环境准备安装依赖组件访问初始化配置Zabbix详细安装部署 Zabbix 是一个高度集成的网络监控解决方案&#xff0c;可以提供企业级的开源分布式监控解决方案&#xff0c;由一个国外的团队持续维护更新&#xff0c;软件可以自由下载使用&#xff0c;运作…

【前端必看】极大提高开发效率的网页 JS 调试技巧

大家好&#xff0c;我是前端西瓜哥。本文讲解如何使用浏览器提供的工具进行 JS 代码的断点调试。 debugger 在代码中需要打断点的地方&#xff0c;加上 debugger&#xff0c;表示一个断点。浏览器代码执行到该位置时&#xff0c;会停下来&#xff0c;进入调试模式。 示例代码…

java内存模型的理解

java内存模型的理解并发问题产生的源头缓存导致的可见性问题线程切换导致的原子性问题编译优化带来的有序性问题小结Java内存模型: 解决可见性和有序性问题Java内存模型与JVM内存模型的区别volatile关键字Happens-Before规则小结思考题参考并发问题产生的源头 缓存导致的可见性…

【Verilog】——Verilog简介

目录 1.简介 2.什么是HDL以及HDL的功能 3.Verilog和C语言的比较 4.Verilog的用途 5.数字系统的抽象层次 1.系统级 2.算法级 3.RTL级&#xff08;寄存器变换级&#xff09; 6.数字系统抽象层级 7.自顶向下的结构化设计方法 8.Verilog建模 9.Verilog概述 10.Verilog模块的基本…

Django学习17 -- ManytoManyField

1. ManyToManyField &#xff08;参考&#xff1a;Django Documentation Release 4.1.4&#xff09; 类定义 class ManyToManyField(to, **options)使用说明 A many-to-many relationship. Requires a positional argument: the class to which the model is related, which w…

推导部分和——带权并查集

题解&#xff1a; 带权并查集 引言&#xff1a; 带权并查集是一种进阶的并查集&#xff0c;通常&#xff0c;结点i的权值等于结点i到根节点的距离&#xff0c;对于带权并查集&#xff0c;有两种操作需要掌握——Merge与Find&#xff0c;涉及到路径压缩与维护权值等技巧。 带…

用Python批量重命名文件

案例 今天,我们来整理文件夹中的文件,给某个文件夹下的所有文件重新命名。要求是给所有文件按照修改时间,按顺序在文件名前面加上编号。比如将文件资料.xlsx重命名为1. 资料.xlsx import osdef Get_modify_time(file):return os.path.getmtime(file) #获取文件修改时间path…