Linux相关概念和易错知识点(21)(软硬链接、动静态库)

目录

1.软硬链接

(1)软链接

(2)硬链接

①实现方式及其功能

②硬链接在目录中的运用

③计算子目录数量

2.动静态库

(1)动态库

①动态链接和静态链接

②动态库的实现

③系统查找动态库问题

④解决系统查找动态库问题

a.拷贝动态库到系统默认路径下

b.在系统层面进行软链接

c.修改环境变量

d.全局配置路径

⑤动态库和头文件存放位置对编译过程的影响

a.动态库

b.头文件

(2)静态库

①和动态库的区别

②静态库打包

③静态编译


1.软硬链接

简单地说,对一个文件进行链接就是针对该文件创建快捷方式。不过软硬链接有所区别。

(1)软链接

使用ln -s (源文件) (快捷方式)可以创建一个软链接

软链接文件有独特的标识,最前面的标识符不是目录的d,也不是普通类型文件的-,而是l

针对软链接文件,对它进行访问操作,会自动根据软链接文件里面保存的路径直接访问目标文件。我们所有访问这个软链接文件的操作都会转为访问目标文件(vim、cat等),这是文件类型的特性。除此之外,软链接文件具有文件的一切属性(inode、权限、修改时间等),它是一个完整的、独立的文件,只不过具有快捷方式的功能,可以帮我们在其它地方快速访问文件。

软链接的内容是目标文件的路径,这就意味着如果目标文件的路径修改,这个软链接文件的内容无法指向指定文件,就会失效。

要特别注意软链接是通过路径来定位目标文件的,需要保证文件名、路径所途径的目录相同才能定位,而不是通过inode进行定位的。

我们把文件还原回来,软链接文件的内容又能链接上了,因此还能恢复软链接功能,而不是那种一旦失效就永久失效的文件。

(2)硬链接

软链接本质上就是通过文件和文件的映射来实现创建快捷方式的操作的。硬链接直接从inode入手。

①实现方式及其功能

使用ln (源文件) (快捷方式)可以创建一个硬链接

我们已经知道目录文件的内容就是文件名和inode的映射表。一个文件名对应一个inode,这个inode一般情况下只会在系统中出现一次,引用计数就是1。但硬链接本质就是在当前目录中新增一组新的文件名和inode的映射关系。相当于一个文件有了两个文件名。重命名过程就是依赖硬链接完成的。

硬链接是采用inode定位目标文件的,因此无论目标文件跑到哪,硬链接都能定位上。

硬链接通过inode引用计数的方式创建快捷方式,除了inode精准定位以外,还带来了一个很厉害的功能,就是无消耗备份

文件的inode属性在底层是保存在硬盘中的,当打开文件后读取inode,并会将新的inode属性写回去。其中inode属性就包含自己的引用计数。如果引用计数为0,就说明没有文件名指向inode,也就是说此时文件已经失效了,系统这时候就会删除文件。如果一个文件引用计数为2,那么当我们对文件进行删除时,系统不会删除文件,而是只会对文件inode的引用计数减1。这就意味着,当我们创建了一个硬链接时,可以认为对文件创建了一层备份,当误删文件时,由于引用计数的特性,文件会被保存下来。

②硬链接在目录中的运用

硬链接我们可以说是天天见。

这下我们能够进一步理解.和..的原理了。当我们创建目录时,这个目录里面就自动创建了两个硬链接,一个是指向本级目录,一个是指向上级目录。

我们还能由此解释,为什么创建目录时引用计数一来就是2

我们也能解释根目录是如何特殊处理cd ..命令的了,它只需要将根目录的上级目录硬链接自己就行了。所以我们在根目录cd上级目录还是根目录。但是有个细节需要注意,根目录的..会特殊处理,不会增加inode的引用计数,我们了解即可。

由于Linux存储结构是树形的,而目录的硬链接恰好会破坏树状结构

其实我们想想,目录和.本质上已经构成了环状结构,只不过紧挨着两级的环状结构退化成了线性结构。Linux为防止我们造出环状路径,让树状结构更混乱,因此Linux不允许我们针对目录文件进行硬链接,有且仅有.和..是硬链接。因此要对目录创建快捷方式,我们只能用软链接,软链接本质上只是个带路径并特殊处理的文件,所以软链接针对目录文件没有任何问题。

③计算子目录数量

我们借助.和..自动创建的特性,可以通过引用计数推断子目录的数量,毕竟每创建一个子目录,其父目录就会多一个硬链接..。

只要子目录下的..目录指向自己,都要加引用计数。软链接对应目录的上级目录一般不增加引用计数。

注意根目录也遵循这条规则,但根目录的..目录也指向自己,如果增加引用计数,那就不符合规则了,所以系统会特殊处理,其..不会增加引用计数。

2.动静态库

(1)动态库

①动态链接和静态链接

之前我介绍过动静态链接的区别,读者可自行查看。

简单来说,动态库就是.so文件,如果可执行程序采用动态链接,可执行程序必须要和.so联合才能正常执行(头文件不需要,预处理时就已经展开)。

静态库就是.a文件,如果可执行程序采用静态链接,只需要可执行程序就能正常执行(所有库方法都存入可执行程序里了)。

这次我将侧重于动静态库的模拟实现,进一步加深我们对动静态库的理解。

②动态库的实现

第一步,就是先将库的源文件变成.o文件,gcc -fPIC。这样生成的.o才能用于.so的生成

第二步,将所有的相关的.o文件都打包成.so文件。这些.o文件里面对应的就是函数具体实现,-shared选项告诉编译器不要形成可执行程序。

注意生成动态库的名字必须满足前缀lib,后缀.so,这会影响后续的识别

第三步,生成可执行程序,注意-I(大写的i),-L和-l(小写的L)三个选项的含义,定位到具体的头文件目录才能进一步查找(预处理)。定位到具体的目录和.so文件才知道调用的动态库(编译、链接)。

③系统查找动态库问题

按照上述步骤,我们本应能正常执行可执行程序了,但事实上还不行,因为ldd test看出我们的动态库并没有地址指向,这也就意味着当执行时系统不知道到哪里去找动态库的实现。

可是我们不是已经-L和-l定位了文件吗?

这是因为-L和-l是在gcc编译和链接时使用的,而我们是想让这个可执行程序变成一个进程,执行它时,系统找的时候会按照自己的默认路径去找,这和我们在gcc使用的-L和-l没有任何关系,所以是找不到我们的可执行程序的。从另一个角度上讲,动态库的存在就是为了脱离可执行程序,交由系统管理和调用,因此动态库的地址是不能存到在可执行程序里面的,这会增强耦合度。是系统在执行我们的程序时,按照默认的路径去找要调用的动态库,再正常执行。

因此,我们要解决的就是动态库的配置问题了,要让系统能够找到动态库。

④解决系统查找动态库问题

既然知道可执行程序和动态库解耦合,动态库全权交由系统管理和调用,因此唯一解决系统查找动态库的问题的方法就是让系统默认查找路径能够找到动态库。以下方法均遵循这个思路。

a.拷贝动态库到系统默认路径下

将.so文件放在系统/lib64或者/lib(根据系统决定,可自行尝试),这样系统就能查找到动态库,正确的加载动态库并执行

b.在系统层面进行软链接

利用ln -s 在/lib64或/lib里面创建软链接,本质原理还是让动态库保存在系统查找的必经之路上。

unlink (完成文件名)可以删掉软链接

c.修改环境变量

Linux系统中,OS查找动态库依赖环境变量提供的路径,OS按理来说是根据LD_LIBARY_PATH环境变量中查找,我们可以配置环境变量用于修改系统查找.so的默认路径。

但在Ubuntu下面,大多数人遇到的是这种情况。

​​​​​​​

这需要我们先进行一些设置操作,在~/.bashrc最底行添加下面的语句,保证该环境变量能被使用。​​​​​​​​​​​​​​

export 
LD\_LIBRARY\_PATH=$LD\_LIBRARY\_PATH:./lib:/lib:/lib64:/usr/lib:/usr/lib64:/usr/local/lib

在这之后,我们每次登录就都能看到LD_LIBARY_PATH的值,当然我们也可以对它进行修改以满足我们寻找动态库的需求。注意LD_LIBARY_PATH里面的值是系统会默认查找的路径,但不是意味着只会到LD_LIBARY_PATH指定的路径查找,这只是我们添加系统默认查找路径的方法之一。我们可以通过修改.bashrc里面的路径,来保障系统会默认来指定的位置查找动态库。这就意味着我们不需要将这个动态库安装到/lib或者/lib64里面,相对而言比较灵活。

d.全局配置路径

系统默认的查找路径还会从/etc/ld.so.conf.d目录读取我们可以使用root身份,新建.conf文件,名字随便取保证后缀即可。使用echo强制在里面写读取路径(路径指向.so对应目录即可)。ldconfig更新配置文件​​​​​​​使其生效,之后我们就可以正常执行文件而不需要将动态库安装到/lib或者/lib64目录下了。

​​​​​​​

以上4种方式提供了动态库的查找问题,前两种的核心思想是想办法安装在系统中,后两种则是侧重于修改查找路径使得系统能够找到它。

⑤动态库和头文件存放位置对编译过程的影响

a.动态库

上面就解决可执行程序的执行已经讲解了存放动态库到系统目录/lib或者/lib64的重要性。将动态库安装在系统中,除了系统能够找到动态库,正常执行可执行程序之外,我们的编译过程gcc可以省去-L这个选项,可以不再指定目录进行编译链接。

但特别注意,-l(小写L)这个选项不能省去(就算一个目录里就只有一个动态库,这是统一规定),因为编译过程要面对的动态库很多,编译器在编译时只知道声明而不知道定义在哪,找不到我们的动态库,所以只有显式指定。执行可执行程序时不需要指定动态库名字、只需要路径的原因是可执行程序已经有了动态库的名字了,只需要路径就能找到。理解两者的差异,搞清楚为什么要这么做很重要。

b.头文件

/usr/include/是系统的头文件目录,如果我们将头文件放到该目录下,预处理时,使用<xxx.h>就能够找到,如果放在源文件目录下,需要用"xxx.h","xxx.h"会先在当级目录查找,再到系统查找,而<xxx.h>只会在系统中查找。除此之外,"xxx.h"在查完系统目录后还能在制定目录下查找,就是-I(大写的i)对应目录。

注意,头文件的展开是预处理干的事,预处理之后头文件就没意义了,所以上述注意事项是在gcc/g++编译时需要注意的。当生成可执行程序之后,头文件在不在、在哪都不会影响可执行程序的执行。

(2)静态库

①和动态库的区别

理解了动态库,静态库相对而言就比较简单了,大部分过程都是相似的。动态库是将.so安装在系统目录中或者让系统能够找到它,在执行程序时调用它,动态库不存放在可执行程序中,因此可执行程序相对较小。

静态库文件是.a文件,其命名规则是前缀lib,后缀.a,在编译后会将整个静态库文件的内容拷贝到可执行程序中。因此,gcc编译后的.a和头文件存不存在、在哪都不会影响程序的执行,一个可执行程序可以独立运行,但代价是可执行程序相对较大,很多函数的实现都放在里面。

在gcc编译过程中,同样需要面临静态库文件的定位问题,这和动态库的gcc定位问题解决方法一致,都是使用-I(大写i)、-L、-l(小写L)辅助定位头文件和静态库。

②静态库打包

我们将所有的库.c编译成.o,这样我们拿着所有的.o打包成一个静态库,和动态库思路一致。

静态库打包使用指令ar -rc(存在就replace,不存在就create)lib.a (前缀必须是lib,后缀必须是.a) 1.o 2.o 3.o,之后我们将库文件和对应头文件交给别人,他们就能正常使用我们的库了,而不会知道源文件是什么样子。

注意事项和动态库的差不多,相对而言静态库在操作上还要简单一些。

③静态编译

在编译代码时,若我们同时提供动静态库,gcc/g++默认使用动态库。我们只有提供选项-static强制静态链接,同时必须提供静态库,不然会报错。但如果我们只提供静态库,但链接方式是动态链接(只要没有指定静态链接,都默认动态链接)的话,gcc和g++没得选,会针对.a采用局部性静态链接。
​​​​​​​

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Leetcode 组合

使用回溯来解决此问题。 提供的代码使用了回溯法&#xff08;Backtracking&#xff09;&#xff0c;这是一种通过递归探索所有可能解的算法思想。以下是对算法思想的详细解释&#xff1a; 核心思想&#xff1a; 回溯法通过以下步骤解决问题&#xff1a; 路径选择&#xff1a…

工具学习_Docker

0. Docker 简介 Docker 是一个开源平台&#xff0c;旨在帮助开发者构建、运行和交付应用程序。它通过容器化技术将应用程序及其所有依赖项打包在一个标准化的单元&#xff08;即容器&#xff09;中&#xff0c;使得应用程序在任何环境中都能保持一致的运行效果。Docker 提供了…

【从零开始的LeetCode-算法】3233. 统计不是特殊数字的数字数量

给你两个 正整数 l 和 r。对于任何数字 x&#xff0c;x 的所有正因数&#xff08;除了 x 本身&#xff09;被称为 x 的 真因数。 如果一个数字恰好仅有两个 真因数&#xff0c;则称该数字为 特殊数字。例如&#xff1a; 数字 4 是 特殊数字&#xff0c;因为它的真因数为 1 和…

day06(单片机高级)PCB设计

目录 PCB设计 PCB设计流程 元器件符号设计 原理图设计 元器件封装设计 元器件库使用 PCB设计 目的&#xff1a;学习从画原理图到PCB设计的整个流程 PCB设计流程 元器件符号设计 元器件符号&#xff1a;这是电子元器件的图形表示&#xff0c;用于在原理图中表示特定的元器件。例…

Oracle JDK(通常简称为 JDK)和 OpenJDK区别

Java 的开发和运行时环境主要由两种实现主导&#xff1a;Oracle JDK&#xff08;通常简称为 JDK&#xff09;和 OpenJDK。尽管它们都基于同一个代码库&#xff0c;但在一些关键点上有所区别。以下是详细的对比&#xff1a; 1. 基础代码 Oracle JDK&#xff1a; 基于 OpenJD…

LeetCode 101题集(随时更新)

题集来源&#xff1a;GitHub - changgyhub/leetcode_101: LeetCode 101&#xff1a;力扣刷题指南 使用C完成相关题目&#xff0c;以训练笔试 贪心 采用贪心的策略&#xff0c;保证每次操作都是局部最优的&#xff0c;从而使最后得到的结果是全局最优的。 分配问题 455. 分发饼…

渗透测试笔记——shodan(4)

声明&#xff1a; 学习视频来自B站up主 【泷羽sec】有兴趣的师傅可以关注一下&#xff0c;如涉及侵权马上删除文章&#xff0c;笔记只是方便各位师傅的学习和探讨&#xff0c;文章所提到的网站以及内容&#xff0c;只做学习交流&#xff0c;其他均与本人以及泷羽sec团队无关&am…

06 —— Webpack优化—压缩过程

css代码提取后想要压缩 —— 使用css-minimizer-webpack-plugin插件 下载 css-minimizer-webpack-plugin 本地软件包 npm install css-minimizer-webpack-plugin --save-dev 配置 webpack.config.js 让webpack拥有该功能 const CssMinimizerPlugin require(css-minimizer-…

【Android】android compat理解

1&#xff0c;前提 即便是在同一手机上安装的不同apk&#xff0c;其编译的apk不同&#xff0c;也会导致行为上的差异。如SDK34有限制后台启动&#xff0c;但如果安装的apk所依赖的sdk是33&#xff0c;则不会表现出此差异。这是如何实现的呢&#xff1f;其实&#xff0c;本质是…

蓝桥杯每日真题 - 第21天

题目&#xff1a;(空间) 题目描述&#xff08;12届 C&C B组A题&#xff09; 解题思路&#xff1a; 转换单位&#xff1a; 内存总大小为 256MB&#xff0c;换算为字节&#xff1a; 25610241024268,435,456字节 计算每个整数占用空间&#xff1a; 每个 32 位整数占用…

MongoDB进阶篇-索引(索引概述、索引的类型、索引相关操作、索引的使用)

文章目录 1. 索引概述2. 索引的类型2.1 单字段索引2.2 复合索引2.3 其他索引2.3.1 地理空间索引&#xff08;Geospatial Index&#xff09;2.3.2 文本索引&#xff08;Text Indexes&#xff09;2.3.3 哈希索引&#xff08;Hashed Indexes&#xff09; 3. 索引相关操作3.1 查看索…

做一个FabricJS.cc的中文文档网站——面向markdown编程

&#x1f4e2;欢迎点赞 &#xff1a;&#x1f44d; 收藏 ⭐留言 &#x1f4dd; 如有错误敬请指正&#xff0c;赐人玫瑰&#xff0c;手留余香&#xff01;&#x1f4e2;本文作者&#xff1a;由webmote 原创&#x1f4e2;作者格言&#xff1a;新的征程&#xff0c;用爱发电&#…

自动驾驶之激光雷达

这里写目录标题 1 什么是激光雷达2 激光雷达的关键参数3 激光雷达种类4 自动驾驶感知传感器5 激光雷达感知框架5.1 pointcloud_preprocess5.2 pointcloud_map_based_roi5.3 pointcloud_ground_detection5.4 lidar_detection5.5 lidar_detection_filter5.6 lidar_tracking 1 什么…

Label-studio-ml-backend 和YOLOV8 YOLO11自动化标注,目标检测,实例分割,图像分类,关键点估计,视频跟踪

这里写目录标题 1.目标检测 Detection2.实例分割 segment3.图像分类 classify4.关键点估计 Keypoint detection5.视频帧检测 video detect6.视频帧分类 video classify7.旋转目标检测 obb detect8.替换yolo11模型 给我点个赞吧&#xff0c;谢谢了附录coco80类名称 笔记本 华为m…

Laravel对接SLS日志服务

Laravel对接SLS日志服务&#xff08;写入和读取&#xff09; 1、下载阿里云的sdk #通过composer下载 composer require alibabacloud/aliyun-log-php-sdk#对应的git仓库 https://github.com/aliyun/aliyun-log-php-sdk2、创建sdk请求的service <?phpnamespace App\Ser…

uniapp接入高德地图

下面代码兼容安卓APP和H5 高德地图官网&#xff1a;我的应用 | 高德控制台 &#xff0c;绑定服务选择《Web端(JS API)》 /utils/map.js 需要设置你自己的key和安全密钥 export function myAMap() {return new Promise(function(resolve, reject) {if (typeof window.onLoadM…

初识WGCLOUD - 监测磁盘空间还能使用多久

WGCLOUD是一款免费开源的运维监控软件&#xff0c;性能优秀&#xff0c;部署简单&#xff0c;轻巧使用&#xff0c;支持大部分的Linux和Windows、安卓、MacOS等平台安装部署 最近发布的新版本 v3.5.4&#xff0c;WGCLOUD新增了可以自动计算每个磁盘剩余空间的可使用天数&#x…

【Xbim+C#】创建圆盘扫掠IfcSweptDiskSolid

基础回顾 https://blog.csdn.net/liqian_ken/article/details/143867404 https://blog.csdn.net/liqian_ken/article/details/114851319 效果图 代码示例 在前文基础上&#xff0c;增加一个工具方法&#xff1a; public static IfcProductDefinitionShape CreateDiskSolidSha…

数据结构 ——— 堆排序算法的实现

目录 前言 向下调整算法&#xff08;默认建大堆&#xff09; 堆排序算法的实现&#xff08;默认升序&#xff09; 前言 在之前几章学习了如何用向上调整算法和向下调整算法对数组进行建大/小堆数据结构 ——— 向上/向下调整算法将数组调整为升/降序_对数组进行降序排序代码…

图像预处理之图像滤波

目录 图像滤波概览 均值滤波&#xff08;Mean Filter&#xff09; 中值滤波&#xff08;Median Filter&#xff09; 高斯滤波&#xff08;Gaussian Filter&#xff09; 双边滤波&#xff08;Bilateral Filter&#xff09; 方框滤波&#xff08;Box Filter&#xff09; S…