【Linux】软硬链接和动静态库

🔥 个人主页:大耳朵土土垚
🔥 所属专栏:Linux系统编程

这里将会不定期更新有关Linux的内容,欢迎大家点赞,收藏,评论🥳🥳🎉🎉🎉

文章目录

  • 1. 软硬链接
    • 💥硬链接(Hard Link)
    • 💥软链接(Symbolic Link)
  • 2. 动静态库
    • 💥静态库(Static Libraries)
    • 💥动态库(Dynamic Libraries)

1. 软硬链接

  在Linux系统中,文件链接分为两种类型:硬链接(Hard Link)和软链接(也称为符号链接或Symbolic Link)。它们都是用于创建文件的额外入口点,但是工作原理和使用场景有所不同。

💥硬链接(Hard Link)

  • 定义:硬链接是一个指向原始文件的直接链接。硬链接是一个与原始文件共享inode的文件,它们在文件系统中实际上是同一个文件

每个文件在Linux系统中都有一个inode,它包含了文件的所有元数据信息,如权限、所有者等,但不包含文件名。当创建一个硬链接时,实际上是为同一个inode创建了一个新的文件名,这意味着两个或多个硬链接实际上指向的是同一个文件数据

  • 特性
    • 硬链接不能跨文件系统。
    • 不能对目录创建硬链接(除了ln命令的特殊选项外,这通常是为了安全考虑)。
    • 对一个文件的修改会反映在所有的硬链接上
    • 如果原始文件被删除,只要还有一个硬链接存在,文件的数据就不会被删除。

删除原始文件后,硬链接仍然可以访问原始文件的内容,这是因为Linux系统在创建硬链接时,会使用引用计数的方式,记录一个文件共有多少个硬链接,当删除一个文件时,只有将其所有的硬链接都删除,这个文件才算真正的删除,否则都可以通过任意一个硬链接访问文件内容。

  • 创建方法:使用ln命令。例如,要为文件file.txt创建一个名为file-hard.link的硬链接,可以执行命令 ln file.txt file-hard.link。(注意文件的后缀可以随意选择)
    在这里插入图片描述

最开始创建file.txt文件,只有它自己,所以引用计数为1,后来为它新建了一个硬链接file-hard.link,引用计数就变为2,因为它们两个本质上是同一个文件,所以file-hard.link的引用计数也为2,与file.txt保持一致。

关于引用计数:
  新建一个目录文件,它一开始的硬链接引用计数就是2,除了它自己以外,它里面还包含一个隐藏文件.,这个其实也是该目录的硬链接,如下图所示:
在这里插入图片描述

而上图中的..文件则是指向上一级目录的硬链接,每个目录在创建的时候都会自动创建这两个文件。


💥软链接(Symbolic Link)

  • 定义:软链接是一个指向原始文件或目录的特殊文件,它包含了另一个文件或目录的路径名。通过访问软链接,可以间接访问源文件。

这意味着软链接形成的文件是不同于原始文件的,它们有着不同的inode编号,与硬链接不同

  • 特性

    • 软链接可以跨文件系统。
    • 可以对文件或目录创建软链接。
    • 如果原始文件或目录被移动或删除,软链接将失效(变为“断开”状态)。
    • 原始文件的权限信息、时间戳等软链接都是不保留的,它仅仅保存了原始文件的路径名。
  • 创建方法:使用ln -s命令。例如,要为文件sfile.txt创建一个名为sfile-soft.link的软链接,可以执行命令 ln -s sfile.txt sfile-soft.link

在这里插入图片描述

使用场景:

  • 硬链接适合于需要确保文件不会因为原文件的删除而丢失的情况,尤其是在同一文件系统内。减少磁盘空间占用以及创建备份文件等场景。
  • 软链接则更灵活,适用于需要跨文件系统链接或者链接到可能经常变动的位置的情况。此外,软链接可以更容易地识别和管理,因为它们本质上是文本形式的路径。

总结起来,软连接有独立的inode,软连接内容上保存的是目标文件的路径,当原始文件删除后,软链接将会失效;例如windows的快捷方式。而硬链接不是独立的文件,没有独立的inode,本质是一组文件名与目标文件的映射关系(别名),删除原始文件后,因为引用计数的存在,本质目标文件并没被删除,硬链接仍然可以访问原始文件的内容。


2. 动静态库

  在Linux系统中,库文件分为静态库(Static Libraries)和动态库(Dynamic Libraries)。这两种类型的库各有优缺点,适用于不同的场景。

💥静态库(Static Libraries)


定义

  • 静态库是在编译阶段就被链接到目标代码中的库。这意味着当一个程序被编译时,它会包含它所依赖的静态库的副本。

优点

  • 程序运行时不需要外部库文件,因为所有需要的代码都已经被整合进可执行文件中。
  • 可以确保程序总是使用特定版本的库,避免了所谓的“DLL地狱”问题(在Windows环境中常见,指的是由于不同应用程序可能依赖于不同版本的同一个库而导致的问题)。

缺点

  • 每个使用该库的程序都会有一个库的副本,这会导致磁盘空间的浪费。
  • 如果静态库需要更新,那么所有使用这个库的应用程序都需要重新编译和链接。

创建静态库

  1. 编写源代码并将其编译为目标文件(.o):gcc -c mystdio.c -o mystdio.o
  2. 创建静态库文件可以使用 ar 命令:ar rc libmystdio.a mystdio.o
  • libmystdio.a 是静态库文件的名称
  • mystdio.o 是要打包进库文件的目标文件
  • rc表示replace create

静态库通常具有 .a 扩展名。

使用静态库

方法一:使用带路径的库进行链接
gcc myprogram.c -I/path/to/include -L/path/to/library -lmylib -o myprogram

  • -I/path/to/include指定头文件所在的路径

  • -L/path/to/library 指定库文件所在的路径

  • -lmylib 指定要链接的库文件的名称(省略了前缀 lib 和文件扩展名 .a

  • 使用静态库进行链接时,可以使用 -l-L 选项指定库文件的位置和名称,-l指定库的名字

gcc在查动静态库时不会在当前目录下查,所以我们需要指定路径

方法二:将库安装到系统中直接使用

  1. 首先,编译源代码生成静态库文件(通常以.a为文件扩展名)。可以使用gccg++命令进行编译。例如,编译一个名为libexample.a的静态库文件可以使用以下命令:
gcc -c example.c                      # 编译源代码生成目标文件
ar rc libexample.a example.o         # 使用ar工具将目标文件打包成静态库
  1. 将生成的静态库文件复制到系统目录中,例如/lib64/。可以使用cp命令进行复制,例如:
sudo cp libexample.a /lib64/  # 将静态库文件复制到系统目录
sudo cp  libexample.h /usr/include/ #将静态库头文件复制到系统目录
  1. 更新库缓存。在某些Linux发行版中,需要手动更新库缓存以使系统可以找到新安装的库。可以使用以下命令更新库缓存:
sudo ldconfig                        # 更新库缓存
  1. 确认安装成功。可以使用ls命令检查静态库文件是否已经复制到系统目录中,例如:
ls /lib64/libexample.a        # 检查静态库文件
  1. 在编译和链接其他程序时,可以使用-l选项指定使用安装的静态库。例如,使用gcc命令编译一个名为example_program.c的程序,并链接使用静态库libexample.a可以使用以下命令:
gcc example_program.c -o example_program -lexample

链接库时需要省去前缀lib和后缀.a,动态库也是一样,直接 -lexample即可

这样,就可以将静态库安装到系统中,并且可以直接在其他程序中使用该库。

💥动态库(Dynamic Libraries)


定义

  • 动态库(也称为共享库)是在程序运行时被加载的。这意味着多个程序可以共享同一份库文件,从而节省内存和磁盘空间。

优点

  • 节省磁盘空间和内存,因为多个程序可以共享同一个库文件。
  • 库更新时不需要重新编译或重新链接应用程序,只需替换库文件即可(前提是API没有改变)。

缺点

  • 程序运行时需要有相应的动态库存在,否则可能会导致程序无法启动。

创建动态库

  • 动态库通常具有 .so (shared object) 扩展名。
  • 创建动态库可以使用 gcc 编译器的 -fPIC-shared 选项。

例如,编译一个名为libexample.so的动态库文件可以使用以下命令:

gcc -fPIC -c example.c   #编译.o文件
gcc -shared -o libexample.so example.o    # 编译源代码生成动态库

-fPIC:形成与位置无关码

使用动态库

方法一:使用带路径的库进行链接

这里与静态库一致

gcc myprogram.c -I/path/to/include -L/path/to/library -lmylib -o myprogram

  • -I/path/to/include指定头文件所在的路径

  • -L/path/to/library 指定库文件所在的路径

  • -lmylib 指定要链接的库文件的名称(省略了前缀 lib 和文件扩展名 .a

  • 使用动态库进行链接时,可以使用 -l-L 选项指定库文件的位置和名称,-l指定库的名字

  • 可以使用 ldd 命令查看一个程序所依赖的动态库列表,例如:ldd myprogram

gcc在查动静态库时不会在当前目录下查,所以我们需要指定路径

注意链接动态库形成可执行程序后,运行可执行文件时,系统是需要找到动态库的位置,也就是运行可执行程序时,动态库是需要加载的,所以如何让系统找到动态库?

  1. 将动态库文件复制到系统目录中,系统会默认在该目录下寻找
  2. 在系统路径建立动态库文件的软链接
  3. Linux系统中除了会在系统路径下寻找动态库,还会在环境变量中寻找,该环境变量为LD_LIBRARY_PATH
  4. ldconfig 配置/etc/ld.so.conf.d/,ldconfig更新

方法二:将库安装到系统中直接使用

  1. 将生成的动态库文件复制到系统目录中,例如/lib64。可以使用cp命令进行复制,例如:
sudo cp libexample.so /lib64/    # 将动态库文件复制到系统目录
sudo cp  libexample.h /usr/include/ #将静态库头文件复制到系统目录
  1. 更新库缓存。在某些Linux发行版中,需要手动更新库缓存以使系统可以找到新安装的库。可以使用以下命令更新库缓存:
sudo ldconfig                        # 更新库缓存
  1. 确认安装成功。可以使用ls命令检查动态库文件是否已经复制到系统目录中,例如:
ls /lib64/libexample.so      # 检查动态库文件
  1. 在编译和运行其他程序时,可以使用-l选项指定使用安装的动态库。例如,使用gcc命令编译一个名为example_program.c的程序,并链接使用动态库libexample.so可以使用以下命令:
gcc example_program.c -o example_program -lexample

这样,就可以将动态库安装到系统中,并且可以直接在其他程序中使用该库。此外,编译形成可执行程序后,如果删除了需要的动态库,程序也是不可以运行的。

原理上理解动态库:

在这里插入图片描述

进程在链接动态库时,操作系统会先将动态库加载到内存中,然后将动态库在内存中的地址通过页表映射到进程地址空间的共享区,这样进程在执行库方法的时候就是在自己的地址空间中跳转运行的。当另一个程序也要使用同一个动态库时就不需要再重复加载该动态库到内存里了,只需要通过进程的页表进行映射之前加载到内存的动态库即可,多个程序也是这样。

总结
  如果同时提供动态库与静态库,gcc/g++默认使用动态库;如果要使用静态库必须使用静态链接-static来指明;如果使用动态链接但是只有静态库,那么gcc/g++只能选择静态库进行链接。
  选择使用静态库还是动态库取决于具体的需求。如果关注程序的独立性和稳定性,且不介意较大的程序大小,可以选择静态库;如果更关心资源的有效利用,并且可以保证目标系统上有适当的动态库版本,那么使用动态库是更好的选择。

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

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

相关文章

Orleans集群及Placement设置

服务端界面使用相同的clusterid和serviceid,相同ip地址,不同网关端口号和服务端口号,启动两个silo服务,并使用MySql数据库做Silo间信息同步,实现集群。 silo服务启动代码如下(从nuget下载Microsoft.Orleans…

iphone怎么删除重复的照片的新策略

Phone用户常常面临存储空间不足的问题,其中一个主要原因是相册中的重复照片。这些重复项不仅占用了大量的存储空间,还会影响设备的整体性能。本文将向您展示iphone怎么删除重复的照片的方法,包括一些利用工具来自动化这个过程的创新方法。 识…

C++ 的第一个程序

目录 一 . C的第一个程序 二 . 命名空间 2.1 namespace的价值 2.1 namespace 的定义 7.3 命名空间的使用 三 . C输入&输出 四 . 缺省参数 五 . 函数重载 六 . 引用 6.1 引用的概念和定义 6.2 引用的特性 6.3 引用的使用 6.4 const 引用 6.5 指针和引用的关系&…

C#开发基础:WPF和WinForms关于句柄使用的区别

1、前言 在 Windows 应用程序开发中,WPF(Windows Presentation Foundation)和 WinForms(Windows Forms)是两种常见的用户界面(UI)框架。它们各自有不同的架构和处理方式,其中一个显…

WPS Office手机去广高级版

工具介绍功能特点 WPS Office是使用人数最多的移动办公软件,独有手机阅读模式,字体清晰翻页流畅;完美支持文字,表格,演示,PDF等51种文档格式;新版本具有海量精美模版及高级功能 安装环境 [名称…

【Three.js基础学习】21.Realistic rendering

前言 课程回顾 渲染器 1.色调映射 值意在将高动态范围](HDR)值转换为低动态范围(LDR) Three.is中的色调映射实际上会伪造将LDR转换为HDR的过程,即使颜色不是HDR, 结果会产生非常逼真的渲染效果 THREE .NoToneMapping (default) 无色调映射 THREE.Linear…

TeamTalk知识点梳理一(单聊)

文章目录 db_proxy_serverdb_proxy_server reactor响应处理流程连接池redis连接池MySQL连接池 单聊消息消息如何封装?如何保证对端完整解析一帧消息?协议格式?单聊消息流转流程消息序号(msg_id )为什么使用redis生成&a…

LLaMA-Factory学习笔记(1)——采用LORA对大模型进行SFT并采用vLLM部署的全流程

该博客是我根据自己学习过程中的思考与总结来写作的,由于初次学习,可能会有错误或者不足的地方,望批评与指正。 1. 安装 1.1 LLaMA-Factory安装 安装可以参考官方 readme (https://github.com/hiyouga/LLaMA-Factory/blob/main/…

Linux -- 进程初印象

目录 预备知识 切入点 PCB 看见进程 pid getpid 函数 预备知识 Linux -- 冯诺依曼体系结构(硬件)-CSDN博客https://blog.csdn.net/2301_76973016/article/details/143598784?spm1001.2014.3001.5501 Linux -- 操作系统(软件&#xf…

342--358作业整理(错误 + 重点)

目录 1. 在需要运行的类中 定义 main 方法 2. this 。访问逻辑:先访问本类中,再访问父类中可以访问的成员(不包括和本类中重名的成员) 3. super 。访问逻辑:super(父类对象)直接访问父类及以…

Jekins篇(搭建/安装/配置)

目录 一、环境准备 1. Jenkins安装和持续集成环境配置 2. 服务器列表 3. 安装环境 Jekins 环境 4. JDK 环境 5. Maven环境 6. Git环境 方法一:yum安装 二、JenKins 安装 1. JenKins 访问 2. jenkins 初始化配置 三、Jenkins 配置 1. 镜像配置 四、Mave…

【Linux】冯诺依曼体系结构

目录 一、冯诺依曼体系结构二、冯诺依曼体系结构的基本组成三、关于冯诺依曼体系结构的一些问题结尾 一、冯诺依曼体系结构 冯诺依曼体系结构,也称为普林斯顿结构,是现代计算机设计的基础框架。这一体系结构由数学家冯诺依曼在20世纪40年代提出&#xf…

M1M2 MAC安装windows11 虚拟机的全过程

M1/M2 MAC安装windows11 虚拟机的全过程 这两天折腾了一下windows11 arm架构的虚拟机,将途中遇到的坑总结一下。 1、虚拟机软件:vmware fusion 13.6 或者 parallel 19 ? 结论是:用parellel 19。 这两个软件都安装过&#xff0…

NAT、代理服务与内网穿透技术全解析

🍑个人主页:Jupiter. 🚀 所属专栏:Linux从入门到进阶 欢迎大家点赞收藏评论😊 目录 NAT 技术背景NAT IP 转换过程NAPTNAT 技术的缺陷 代理服务器正向代理工作原理功能特点应用场景 反向代理基本原理应用场景 NAT 和代理…

优选算法 - 1 ( 双指针 移动窗口 8000 字详解 )

一&#xff1a;双指针 1.1 移动零 题目链接&#xff1a;283.移动零 class Solution {public void moveZeroes(int[] nums) {for(int cur 0, dest -1 ; cur < nums.length ; cur){if(nums[cur] 0){}else{dest; // dest 先向后移动⼀位int tmp nums[cur];nums[cur] num…

qt配合映美精取图开发

最近开发一个项目&#xff0c;用映美精相机配合halcon做取图开发&#xff0c;由于网上资料小特意写个记录。到映美精官网下载驱动&#xff0c;映美精官网&#xff0c;下载映美精的工具开发包SDK 映美精的SDK下载SDK后找到classlib文件夹 里面就是SDK新建一个qt程序&#xff0c…

华为云计算HCIE-Cloud Computing V3.0试验考试北京考场经验分享

北京试验考场 北京考场位置 1.试验考场地址 北京市海淀区北清路156号中关村环保科技示范园区M地块Q21楼 考试场选择北京&#xff0c;就是上面这个地址&#xff0c;在预约考试的时候会显示地址&#xff0c;另外在临近考试的时候也会给你发邮件&#xff0c;邮件内会提示你考试…

LeetCode 509.斐波那契数

动态规划思想 五步骤&#xff1a; 1.确定dp[i]含义 2.递推公式 3.初始化 4.遍历顺序 5.打印dp数组 利用状态压缩&#xff0c;简化空间复杂度。在原代码中&#xff0c;dp 数组保存了所有状态&#xff0c;但实际上斐波那契数列的计算只需要前两个状态。因此&#xff0c;我们…

反向代理开发

1 概念 1.1 反向代理概念 反向代理是指以代理服务器来接收客户端的请求&#xff0c;然后将请求转发给内部网络上的服务器&#xff0c;将从服务器上得到的结果返回给客户端&#xff0c;此时代理服务器对外表现为一个反向代理服务器。 对于客户端来说&#xff0c;反向代理就相当于…

RabbitMQ — 异步调用

RabbitMQ 是一个开源的消息代理中间件&#xff0c;它使用高级消息队列协议&#xff08;AMQP, Advanced Message Queuing Protocol&#xff09;来实现不同系统之间的消息传递。它以 Erlang 语言编写&#xff0c;具有高可靠性、灵活性和易于扩展的特点&#xff0c;被广泛应用于异…