Linux软硬链接和动静态库(20)

文章目录

  • 前言
  • 一、软硬链接
    • 基本认知
    • 实现原理
    • 应用场景
    • 取消链接
    • ACM时间
  • 二、动静态库
    • 认识库
    • 库的作用
  • 三、制作静态库
    • 静态库的打包
    • 静态库的使用
  • 四、制作动态库
    • 动态区的打包
    • 动态库的链接与使用
    • 动态库的链接原理
  • 总结


前言

在这里插入图片描述

  我有款非常喜欢玩的游戏,叫做《饥荒》,现在我下载了这一款游戏,但我不会跑到游戏所在目录中双击 .exe 打开游戏,大多数人都会通过桌面的快捷方式直接打开文件,而这个快捷方式实际就是对 .exe 的 软链接 文件; 当你在游戏中加载地图、道具等资源时,这些数据是存在 .exe 文件中的吗? 答案是当然不是,这些资源文件都以 库 的方式与 .exe 位于同一目录中,通常为动态库,在 Windows 中后缀为 dll,那么这些神奇的辅助文件是如何产生的? 其本质又是如何?本篇将带你一起揭晓。

另外还有一个小要求,请先回顾一下我上篇文章的 inode 这个概念,这在本篇仍很重要


一、软硬链接

基本认知

对文件进行软链接

ln -s file.txt file-soft.link

对文件进行硬链接

ln file.txt file-hard.link

源文件,软链接文件,硬链接文件如下:
在这里插入图片描述

注意: 可以对目录进行软链接,但不能对目录进行硬链接,具体原因后面再解释

  那么生成的软硬链接有什么用呢?

  像源文件一样使用即可,结果一模一样(因为当前软硬链接的都是同一个源文件)
在这里插入图片描述
同时我们发现这两种链接方式其本质上是有很大差别的:

  1. 软链接文件的 inode 编号与源文件不同(独立存在),软链接文件比源文件小得多,并且 软连接文件 -> 源文件
  2. 硬链接文件与源文件共用一个 inode 编号(对源文件其别名),硬链接文件与源文件一样大,并且硬链接文件与源文件的链接数变成了 2

软链接文件依赖于源文件,而硬链接文件是源文件的别名

当我们将源文件删除后,软链接失效; 硬链接仍然有效,不过硬链接数变为了 1
在这里插入图片描述

  同样是对源文件进行链接,为何两种链接方式差别如此大呢? 这就不得不谈一下它们的实现原理了

实现原理

  软链接又称为符号链接,它是一个单独存在的文件,拥有属于自己的 inode 属性及相应的文件内容,不过在软链接的 Data block 中存放的是源文件的地址,因此软链接很小,并且非常依赖于源文件

  在这里以QQ为例,可以看到快捷方式(软链接方式)中存放的是源文件的地址

在这里插入图片描述
  因此如果源文件被删除了,那么在执行软连接文件时,其中的地址就是一个无效地址(目标文件已丢失),此时就会报错 No such file or directory

  假设只是单纯的删除软连接文件,那么对源文件的内容没有丝毫影响,就好比 桌面上的快捷方式,有的人以为将快捷方式(软链接)文件删除了,就是在 “卸载” 软件,其实不是,如果想卸载软件,直接将其源文件相关文件夹全部删除即可

有多少人到现在还有误解呢?

  硬链接并非创建一个相同的文件进行链接,而是在源文件所目录下的 (inode编号 & 文件名) 对应表中,新增 inode 编号与 硬链接文件名 的映射关系,并将 inode 结构体中的引用计数 +1,表示当前已成功硬链接上了一个文件
在这里插入图片描述
  当删除当前 对应文件时,会 先判断 ref_count 是否为 1,如果是,才会将文件内容及其属性真正删除,否则删除的只是 文件名 与 inode 编号的映射关系inode

  这也就解释了为什么删除源文件后,硬链接文件不受任何影响,仅仅只是 硬链接数 - 1,同理,删除硬链接文件,也不会影响源文件

  为什么新建目录的硬链接数为 2 ?

  1. 因为一个目录在新建后,其中默认存在两个隐藏文件:. 与 …
  2. 其中 . 表示当前目录,… 表示上级目录

  Linux 中的目录结构为多叉树,即当前节点(目录)需要与父节点(上级目录)、子节点(下级目录)建立链接关系,并且还得知道当前目录的地址,否则就会导致切换目录时出现错误

在这里插入图片描述
  为了避免因用户的误操作而导致的目录环状问题,规定用户不能手动给目录建立硬链接关系,只能由 OS 自动建立硬链接,比如新目录后,默认与上级目录和当前目录建立硬链接文件,在当目录下创建新目录后,当前目录的硬链接数 + 1

所以说,将目录的硬链接数 - 2 ,得到的数字就是该目录下的目录数

在这里插入图片描述

  4 - 2 = 2,所以目录 gitQuest 下一共有2个目录,我们来验证一下:
在这里插入图片描述

应用场景

  软链接可以当作快捷方式使用,比如快速运行一个藏的很深的可执行程序
在这里插入图片描述
  而硬链接一是可以用来当作目录移动的工具二是可以用来给重要的源文件起别名并使用,一旦发生删除等不可逆行为时,可以确保源文件的安全

  注意: 硬链接并不是将源文件直接进行备份,而是新建立 inode 编号与硬链接文件名的映射关系,同时 struct inode 中的引用计数 ref_count++,只有当 ref_count == 1 时才会真正删除文件内容及属性, 否则都只是在取消映射关系和 ref_count–

取消链接

取消链接的方式有两种:

  1. 直接删除链接文件
  2. 通过 unlink 取消链接关系

ACM时间

  每一个文件都有三个时间:访问 Access、修改属性 Change、修改内容 Modify,简称为时间ACM

  可以通过 查看指定文件的 时间信息 statACM

在这里插入图片描述
这三个时间的刷新策略如下:

  • Access:最近一次查看内容的时间,具体实现取决于系统
  • Change:最近一次修改属性的时间
  • Modify:最近一次修改内容的时间(内容更改后,属性也会跟着修改)

  Access 是高频操作,如果每次查看都更新的话,会导致 效率变低,因此 实际变化取决于刷新策略:查看 N 次后刷新IO

  注意: 修改内容一定会导致属性时间被修改,但不一定会导致访问时间被修改,因为可以不打开文件,对文件进行操作

二、动静态库

认识库

常见的库文件:stdio.h stdlib.h string.h等

库分为 动态库 和 静态库

  • Linux 中,.a 后缀为静态库,.so 后缀为动态库
  • Windows 中,.lib 后缀为静态库,.dll 后缀为动态库
  • 虽然不同环境下的后缀有所不同,但其工作原理是一致的

库命名

  • 比如 libstdc++.so.6
  • 去掉前缀跟后缀,最终库名为 stdc++

  查找当前环境的库文件:

find /usr/lib64/libc*

在这里插入图片描述

  C++ 中具体库文件可以这样查看:

find /usr/lib64/libstdc*

在这里插入图片描述
  在编写程序时,一定离不开库文件,动态库优势比静态库明显,因此在编译代码时,默认采用动态链接的方式,如果想指定为静态链接编译,只需要在 gcc/g++ 语句后面加上 -static 即可(前提是得有静态库)

  关于动静态库的优缺点可以看看下面这个表格

区别动态库静态库
调用方式通过函数位置进行调用直接将需要的函数拷贝至程序中
依赖性(运行时)需要依赖于动态库可以独立于静态库运行
空间占用共享动态库中的代码,空间占用少拷贝代码会占用大量空间
加载速度调用函数,加载速度慢直接运行,加载速度快

  注意: 静态库是将所需要的函数代码拷贝到源文件中直接使用,而动态库是通过动态链接的方式,进行函数链接使用,别急,这个我们后面会再细细讲解

库的作用

  • 提高开发效率
  • 头和库是有对应关系的,需要组合使用
  • 头文件在预处理阶段就已经引入了,链接的本质就是在链接库

  简言之,如果没有库文件,那么你在开发时,需要自己手动将 等高频函数编写出来,因此库文件可以提高我们的开发效率,比如 中就有很多现成的库函数可以使用,效率很高,如:printf

我们在IDE环境下编码的时候,语法提示是如何做到的?

  1. 安装开发环境,实际上是在安装编译器、开发语言配套的库和头文件
  2. 编译器的 语法提示功能来源于头文件(语法提示其实就是搜索)

我们在写代码时,开发环境是怎么知道语法错误或其他错误的?

  1. 编译器有命令行模式,还有其他自动化模式,编写代码时,不断进行主动编译,排查错误

三、制作静态库

  现在有一些简单的计算 函数,能满足整型的 计算

在这里插入图片描述
  主函数中将对这些自定义的库函数进行调用
在这里插入图片描述

静态库的打包

  一共分为两步:

  1. 将源文件进行 预处理 -> 编译 -> 汇编,生成可链接的二进制 .o 文件
  2. 通过指令将 .o 文件打包为静态库

  将文件编译为 .o 二进制文件

gcc -c add.c sub.c

  将所有的 .o 文件打包为一个静态库(库名自定义),其中的 为库名mycalc

ar -rc libmycalc.a *.o

ar -tv 静态库文件
该指令可以查看打包的库文件
在这里插入图片描述

  获得静态库后,就可以进行使用了

静态库的使用

方法一:通过指定路径使用静态库

  如果直接编译程序,会出现编译失败的情况,因为编译器不认识第三方库(需要提供第三方库的路径及库名)

在这里插入图片描述

第一方库:语言提供
第二方库:操作系统提供
第三方库:other 提供的库,比如当前我们直接打包的静态库

对于自己写的的第三库的使用,需要标注三个参数:

  • -I 所需头文件的路径 需要将所需头文件的路径加上,此处为 ./stdc/include
  • -L 所需库文件的路径 这里加的是库文件的路径,也为 ./stdc/lib
  • -l 待链接静态库名 所需要链接的静态库名字,这里为 libmycalc.a

将选项加上后重新编译
在这里插入图片描述
在这里插入图片描述

方块二:将头文件和静态库文件安装至系统目录中

  除了这种比较麻烦的指定路径编译外,我们还可以将头文件与静态库文件直接安装在系统目录中,直接使用,无需指定路径(需要指定静态库名)

  所谓的安装软件,就是将自己的文件安装到系统目录下

sudo cp ./stdc/include/*.h /usr/include/
sudo cp ./stdc/lib/*.a /lib64/

在这里插入图片描述

  注意: 将自己写的文件安装到系统目录下是一件危险的事(导致系统环境被污染),用完后记得手动删除

在这里插入图片描述

四、制作动态库

动态区的打包

  动态库不同于静态库,动态库中的函数代码不需要加载到源文件中,而是通过 与位置无关码 ,对指定函数进行链接使用

动态库的打包也同样分为两步:

  1. 编译源文件,生成二进制可链接文件,此时需要加上 -fPIC 与位置无关码
  2. 通过 gcc/g++ 直接目标程序(此时不需要使用 ar 归档工具)

  将源文件编译为 .o 二进制文件,此时需要带上 fPIC 与位置无关码
在这里插入图片描述
  将所有的 .o 文件打包为动态库(借助 gcc/g++)

gcc -o libmycalc.so *.o -shared

  获得动态库后,就可以进行使用了
在这里插入图片描述

动态库的链接与使用

  像使用静态库一样使用动态库(指定路径及库名),编译成功,但运行失败!

  为什么会出现这种问题? 因为当前只告诉了编译器动态库的位置,没有告诉 OS

通过 查看程序链接情况:ldd
在这里插入图片描述
运行时, 是如何链接动态库?OS

  1. 环境变量 LD_LIBRARY_PATH (默认没有这个环境变量),将第三方动态库路径添加至此环境变量中(临时方案)
  2. sudo 在 /lib64/ 目录下建立动态库的软链接
  3. 更改配置文件 /etc/ld.so.conf.d 这个目录中都是各种动态库配置文件,创建文件 xx.conf 至目录中(文件中存储的是第三方动态库的路径)ldconfig 令配置文件生效

方法一:通过环境变量解决

  添加动态库路径至 环境变量中LD_LIBRARY_PATH

export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:路径

  环境变量 是程序在进行动态库查找时的默认搜索路径LD_LIBRARY_PATH

注意: 更改环境变量只是临时方案,重新登录后会失效

方法二:将动态库的软链接文件存入系统目录中

sudo ln -s 路径 /lib64/libmycalc.so

  注意: 创建软连接文件时,需要使用绝对路径!

方法三:更改配置文件中的信息

echo 路径 > lhq.conf
sudo mv lhq.conf /etc/ld.so.conf.d/
sudo ldconfig # 手动更新

  注意: 后两种方法都可以做到永久生效(因为存入了系统目录中),但在使用完后最好删除,避免污染系统环境

动态库的链接原理

  程序在链接动态库函数时,是通过 动态库起始地址 + 所链接函数偏移量 的方式进行链接访问的,而这个偏移量就是 fPIC 与位置无关码

  地址其实就两种:绝对地址和相对地址,静态链接时,将可链接的二进制文件加载至程序中,直接通过 绝对地址 进行链接,假设函数被调用了多次,就会导致代码冗余等问题; 动态链接采用 相对地址 的方式进行链接,同一个函数的 + 值相同,代码只需要加载一份,并且可以任意位置进行函数调用(与位置无关)动态库起始地址所链接函数偏移量

在这里插入图片描述

  动态库中所有地址都是偏移量,默认从 开始0

  只有当一个库被真正映射进地址空间后,它的起始地址才能真正确定

  • 链接库中的函数时,通过 动态库的起始地址 + 函数偏移量 的方式链接函数
  • 这种方法不论在什么位置,都可以随便链接函数(与位置无关)
  • 与位置无关码:动态库中地址,是偏移量

总结

最后还有需要总结的一些要点就是:

  1. 当同时拥有 静态库 和 动态库 时,默认采用动态链接
  2. 可以在编译的时候最后加上 -static 指定 静态链接
  3. 只有静态库,又不指定静态链接,这个时候是动态链接(内含静态库)
  4. 静态链接生成的程序比动态链接大得多,并且内含静态库的动态链接程序,也比纯粹的动态链接程序大,程序并非非静即动

  另外,你可不可以利用 Makefile 来简化步骤?

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

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

相关文章

【鸿蒙HarmonyOS】深入理解router与Navigation

5. 路由 1.页面路由(router模式) 1.概述 页面路由指的是在应用程序中实现不同页面之间的跳转,以及数据传递。 我们先明确自定义组件和页面的关系: 自定义组件:Component 装饰的UI单元,页面:即应用的UI…

Apache SeaTunnel:新一代开源、高性能数据集成工具

Apache SeaTunnel 是一款开源、分布式、高性能的数据集成工具,可以通过配置快速搭建数据管道,支持实时海量数据同步。 Apache SeaTunnel 专注于数据集成和数据同步,主要旨在解决数据集成领域的常见问题: 数据源多样性&#xff1a…

CF-Hero:自动绕过CDN找真实ip地址

CF-Hero:自动绕过CDN找真实ip地址 CF-Hero 是一个全面的侦察工具,用于发现受 Cloudflare 保护的 Web 应用程序的真实 IP 地址。它通过各种方法执行多源情报收集。目前仅支持Cloudflare的cdn服务查找真实ip,但从原理上来说查找方法都是通用的…

React-组件和props

1、类组件 import React from react; class ClassApp extends React.Component {constructor(props) {super(props);this.state{};}render() {return (<div><h1>这是一个类组件</h1><p>接收父组件传过来的值&#xff1a;{this.props.name}</p>&…

谈谈接口和抽象类有什么区别?

接口&#xff08;interface&#xff09;和抽象类&#xff08;abstract class&#xff09;都是 Java 中常用的“抽象”工具&#xff0c;用来定义类的规范和结构&#xff0c;但它们有一些本质的区别。下面我用一个简单明了的表格 说明来帮你理解&#xff1a; 对比点抽象类&…

使用Nacos 打造微服务配置中心

一、背景介绍 Nacos 作为服务注册中心的使用方式&#xff0c;同时 Nacos 还可以作为服务配置中心&#xff0c;用于集中式维护各个业务微服务的配置资源。 作为服务配置中心的交互流程图如下。 这样设计的目的&#xff0c;有一个明显的好处就是&#xff1a;有利于对各个微服务…

OpenCv高阶(十一)——物体跟踪

文章目录 前言一、OpenCV 中的物体跟踪算法1、均值漂移&#xff08;Mean Shift&#xff09;&#xff1a;2、CamShift&#xff1a;3、KCF&#xff08;Kernelized Correlation Filters&#xff09;&#xff1a;4、MIL&#xff08;Multiple Instance Learning&#xff09;&#xf…

声音分离人声和配乐base,vocals,drums -从头设计数字生命第6课, demucs——仙盟创梦IDE

demucs -n htdemucs --two-stemsvocals 未来之窗.mp3 demucs -n htdemucs --shifts5 之.mp3demucs -n htdemucs --shifts5 -o wlzcoutspl 未来之窗.mp3 伴奏提取人声分离技术具有多方面的重大意义&#xff0c;主要体现在以下几个领域&#xff1a; 音乐创作与制作 创作便利…

使用若依二次开发商城系统-4:商品属性

功能3&#xff1a;商品分类 功能2&#xff1a;商品品牌 功能1&#xff1a;搭建若依运行环境前言 商品属性功能类似若依自带的字典管理&#xff0c;分两步&#xff0c;先设置属性名&#xff0c;再设置对应的属性值。 一.操作步骤 1&#xff09;数据库表product_property和pro…

操作指南:vLLM 部署开源大语言模型(LLM)

vLLM 是一个专为高效部署大语言模型&#xff08;LLM&#xff09;设计的开源推理框架&#xff0c;其核心优势在于显存优化、高吞吐量及云原生支持。 vLLM 部署开源大模型的详细步骤及优化策略&#xff1a; 一、环境准备与安装 安装 vLLM 基础安装&#xff1a;通过 pip 直接安装…

32.768kHz晶振详解:作用、特性及与其他晶振的区别

一、32.768kHz晶振的核心作用 实时时钟&#xff08;RTC&#xff09;驱动&#xff1a; 提供精确的1Hz时钟信号&#xff0c;用于计时功能&#xff08;如电子表、计算机CMOS时钟&#xff09;。 分频公式&#xff1a; 1Hz 32.768kHz / 2^15&#xff08;通过15级二分频实现&#x…

第3讲、大模型如何理解和表示单词:词嵌入向量原理详解

1. 引言 大型语言模型&#xff08;Large Language Models&#xff0c;简称LLM&#xff09;如GPT-4、Claude和LLaMA等近年来取得了突破性进展&#xff0c;能够生成流畅自然的文本、回答复杂问题、甚至编写代码。但这些模型究竟是如何理解人类语言的&#xff1f;它们如何表示和处…

【Java面试笔记:进阶】19.Java并发包提供了哪些并发工具类?

Java 并发包(java.util.concurrent)提供了一系列强大的工具类,用于简化多线程编程、提升并发性能并确保线程安全。 1. Java 并发包的核心内容 并发包概述:java.util.concurrent 包及其子包提供了丰富的并发工具类,用于简化多线程编程。主要组成部分: 高级同步结构:如 C…

Matlab数字信号处理——小波阈值法去噪分析系统

&#x1f527; 系统简介 本系统通过 MATLAB GUI 图形界面&#xff0c;集成了 小波阈值去噪算法 的各个核心模块&#xff0c;可以实现以下功能&#xff1a; 打开语音文件&#xff1a;支持常见音频格式读取&#xff1b; 模拟加噪&#xff1a;系统内置白噪声模拟功能&#xff0…

EDI 如何与 ERP,CRM,WMS等系统集成

在数字化浪潮下&#xff0c;与制造供应链相关产业正加速向智能化供应链转型。传统人工处理订单、库存和物流的方式已难以满足下单客户对响应速度和数据准确性的严苛要求。EDI技术作为企业间数据交换的核心枢纽&#xff0c;其与ERP、CRM、WMS等业务系统的深度集成&#xff0c;成…

计算机组成原理-408考点-数的表示

常见题型&#xff1a;C语言中的有符号数和无符号数的表示。 【例】有如下C语言程序段: short si-32767&#xff1b;unsigned short usisi&#xff1b;执行上述两条语句后&#xff0c;usi的值为___。short和unsigned short均使用16位二进制数表示。 【分析】考点&#xff1a;同…

企业级AI开发利器:Spring AI框架深度解析与实战

企业级AI开发利器&#xff1a;Spring AI框架深度解析与实战 一、前言&#xff1a;Java生态的AI新纪元 在人工智能技术爆发式发展的今天&#xff0c;Java开发者面临着一个新的挑战&#xff1a;如何将大语言模型&#xff08;LLMs&#xff09;和生成式AI&#xff08;GenAI&#…

【金仓数据库征文】——选择金仓,选择胜利

目录 第一部分&#xff1a;金仓数据库——开创数据库技术的新时代 1.1 金仓数据库的技术底蕴 1.2 高可用架构与灾备能力 1.3 分布式架构与弹性扩展能力 第二部分&#xff1a;金仓数据库助力行业数字化转型 2.1 电信行业&#xff1a;核心系统国产化替代 2.2 医疗行业&…

用C语言实现——一个中缀表达式的计算器。支持用户输入和动画演示过程。

一、思路概要和知识回顾 1.思路概要 ①中缀表达式计算&#xff1a; 需要处理运算符的优先级&#xff0c;可能需要用到栈结构。 ❗❗如何将中缀表达式转换为后缀表达式&#xff1f;或者直接计算&#xff1f; 通常&#xff0c;中缀转后缀&#xff08;逆波兰式&#xff09;再…

Langchain_Agent+数据库

本处使用Agent数据库&#xff0c;可以直接执行SQL语句。可以多次循环查询问题 前文通过chain去联系数据库并进行操作&#xff1b; 通过链的不断内嵌组合&#xff0c;生成SQL在执行SQL再返回。 初始化 import os from operator import itemgetterimport bs4 from langchain.ch…