【Linux系统编程】软硬链接和动静态库

一,硬链接

1-1,硬链接的认识

        Linux下的硬链接本质是在指定的目录下,插入新的文件名和目标文件的眏射关系,并让inode的引用计数加一,这里我们通过 ls 指令可查看到文件详细信息种的硬链接数。这里可参考文件系统的文章:文件系统

        Linux使用 ln [文件名] [硬链接名] 可创建对应文件的硬链接,具体如下图:

        上面现象可发现,硬链接的inode编号与对应文件的inode编号相同,而若inode编号一样,说明文件相同,若是一个独立的inode,那么inode编号将不会与其它文件相同。

        在文件系统的文章中所提到过这里inode对应的文件如同硬链接,删除文件时除非该文件的硬链接数是1时才能删除该文件的inode。也就是说硬链接如同文件重命名般,所有对应的操作都是在对应一个文件进行操作。若下图:

        建立硬链接其实是在系统中什么都没有做,只是在对应的目录下新建一个和指定文件之间新的文件名来做眏射关系,也就是从该目录下的一对文件名和inode的眏射关系变成了两对或多对,即硬链接数从一开始不断加一,对应文件inode结构中的引用计数加一,这就如同一个inode对应多个文件名的情况。

1-2,目录的硬链接

        文件的硬链接我们已明白,下面我们来说明有关目录的硬链接。

        当我们创一个目录时,其硬链接数默认是2。目录自身的文件名与inode是一种眏射关系,但目录默认里面存在 ‘.’ 和 ‘..’ ,一个 ‘.’ 也是文件名(表示当前目录),对应的也是当前目录下的inode,即一个inode对应两个文件名。若是在当前新建目录中再新建一个目录,由于新建目录中存在 ‘..’ 目录(上一级目录),而 ‘..’ 目录与 ‘.’ 目录同理,对应的都是相应目录文件下的inode,所以这时的硬链接数就会变成3。这也就是为什么运用 ‘.’ 或 ‘..’ 时,表示的都是当前目录或上一级目录的原因。我们可利用目录的硬链接数,很容易的计算出一个目录下有多少个子目录,即:硬链接数 - 2。

        注意:Linux中,用户不能给目录建立硬链接。若系统允许我们建立目录的硬链接,这里可假设一下我们在某个路径下建立起前缀目录的硬链接,当系统从根目录开始解析查找一个文件时,系统找到该硬链接时,将会又跑到上层的inode,出现环路问题。比如,当前路径是/home/who/day,当我们当day目录中建立根目录的硬链接dir且在dir里面创建文件并查找时,系统往上找到根目录往下解析后,当找到dir时,又将跑根目录逐层往下查找,出现闭合环路问题。系统自己拥有的目录硬链接会看作自己的一部分,能够将此区分开做特出处理。

1-3,硬链接的应用场景

        文件多人共享:由于硬链接指向的是同一个物理文件(具有相同的inode号),因此多个用户或进程可以通过不同的文件名来访问和共享同一个文件。这有助于节省存储空间和提高文件访问效率。

        文件备份:通过创建硬链接,可以在不占用额外存储空间的情况下生成文件的备份副本。这是因为硬链接和原始文件实际上是同一个文件的不同入口点。

        系统文件管理:一些系统文件经常需要在不同位置进行引用。通过创建硬链接,可以简化这些文件的管理和维护工作。例如,在Linux系统中,许多系统文件和目录都通过硬链接来实现多路径访问。

        目录结构的维护:硬链接在维护Linux的目录结构中起着重要作用。每个目录都包含至少两个硬链接(.和..),分别表示当前目录和上级目录。这种结构使得用户可以在目录间自由切换和访问文件。


二,软链接

2-1,软链接的认识

        软链接本质就是一个独立文件,软链接内容里面放的是目标文件的路径,类似Windows上的快捷方式,执行软链接相当于执行对应的程序。Linux中使用指令 ln -s [文件名] [软链接名] 可建立相应文件所对应的软链接。如下:

2-2,软链接的应用

        软链接的本质如同Windows上的快捷方式。通过建立软链接,可以在任意路径下快速找到相应的目标文件,并执行相应的程序。用户可以在任何需要的地方创建软链接,以便方便地访问远程位置的文件或目录。但若删除软链接对应的文件或程序后,软链接将无法使用,软链接只是提供了一种快捷方式,程序启动的根本在于源头。

        除此方便用户操作之外,软链接还在动态库版本管理方面具有重要应用。

动态库版本管理:在软件开发中,动态库(如.so文件)的版本管理是一个重要问题。通过使用软链接,可以灵活地切换不同版本的动态库,以适应不同程序或开发阶段的需求。


三,动静态库

3-1,认识动静态库

         库分为动态库(.so文件)和静态库(.a文件)。大多数高级语言都提供了创建和使用库的工具或方法,以C/C++为例,我们平常写程序时都会直接或间接使用到库。C语言可执行程序链接的时候会使用C语言中的 /lib64/libc.so.6库(使用指令:ldd “可执行程序” 可观察到可执行程序所依赖的动态库,因为静态库在链接阶段会被完全复制到可执行文件中,所以静态库的信息不会出现在 ldd 的输出中。),而此库在CentOS7版本下又链接(软链接)的是 libc-2.17.so的库,这个库属于动态库。C++可执行程序链接的是 libstdc++.so.6库。这些库主要提供一些基础方法,如字符串的切割、字符串的封装和函数功能等,我们写的代码只是个文本而已,运行的时候会将代码与库中的实现代码相结合,生成最终的可执行文件,然后库还会对一些系统调用做封装,屏蔽不同操作系统下底层语言实现的差别,保证语言的跨平台性。

        大部分的操作系统默认安装的是动态库,以云服务器为例,它上面的静态库(如C标准库)是没有安装的,因此,当写完一个程序开始编译处理时,默认使用的是动态库,如果要使用静态库需要加选项 -static。这里可与系统处理程序的各个步骤联系起来:系统的编译处理过程 (有关C/C++的动静态库的使用和安装以及语言的处理过程里面已讲解,这里不再说明)。

        Linux64位系统下的库都在 /lib64 目录下(不同的系统平台也可能在 /lib 目录下),我们在系统上安装的库也都是在此目录下。这里要说一下,库的名称其实是 “lib(前缀)” + “库名称” + “.so(动态库)”或“.a(静态库)”后缀 组成的,而库的真实名字是中间的 “库名称” ,如C语言的库 libc.so.6 真实名是 c ,表示C标准库;C++的库 libstdc++.so.6 真实名是 stdc++ ,表示C++标准库。所谓的库其实就是类似把源代码文件形成有关的.o文件(二进制文件),由于.o文件可能有很多个,所以通常需要再用特定的方式进行打包,形成一个库文件。这样一来,它即让开发者重用库中的代码,不用多次编写,提高开发效率,又能隐藏源代码。下面我们来模拟制作静态库,并模拟将其传给用户使用。

        上面,我们先使用指令 gcc -c mymath.c 默认编译形成同名的.o二进制文件,然后使用指令 ar -rc libmyc.a mymath.o mystdio.o(ar指令可将其打包形成库文件),将 mymath.o 和 mystdio.o 打包形成静态库 libmyc.a,接下来我们只需将相关头文件(.h:方法的声明)和静态库libmyc.a(方法的实现)给予对方即可。用户拿到这两种文件后,只需链接即可实现程序,但问题是用户拿到后又该如何操作呢?我们先看以下情况。

        首先,若对方拿到相关头文件和库后直接编译运行,会出现链接错误,因为默认情况下编译器链接的是 /lib64/ 目录里面的标准库,要想链接自己编写的库,在编译时需加上 -l 选项,告诉编译器要使用自己链接的库,其次,默认情况下,编译器链接时用到的库会自动往 /lib64(或 /lib)目录下寻找,这里需使用 -L 选项告诉编译器 要在具体哪个路径下,若不想使用 -L 选项可把自定义的库拷贝到 /lib64(或 /lib)系统库目录下,这样编译器在编译时就会默认往此目录下去寻找,最后,使用自定义库时不能直接用库的全名,如上面 gcc -o main.exe main.c -llibmyc.a -L . 是错误的,必须使用库的真实名,如上面 gcc -o main.exe main.c -lmyc -L . 。

        下面我们再来模拟制作下动态库。这里要说一下,动态库的实现跟静态库的差别不大,这里需要在编译形成的.o文件时加用选项 -fPIC(产生位置无关码。后面会解释,这里先会用),如:gcc -c -fPIC mymath.c。打包时这里不需要其它工具,这里要使用gcc指令加用选项 -shared(表示生成共享库格式)和 -o选项 ,其中选项 -shared 要在选项 -o 前面,如:gcc -shared -o libmyc.so mymath.o mystdio.o。

        由于指令的繁琐,这里可使用makefile文件。makefile文件和make的使用以往已说明,基础的用法这里不再说明,若不明白的可观看此文章:makefile和make的使用

        这里说明一下makefile文件中 $^ $< 的区别,两者虽都表示依赖文件列表,但它们所对应的指令操作却有所不同。 Makefile文件中 $^表示依赖文件列表的全部内容,它会一次性直接将其拿过来使用指令进行操作,$< 表示的是把上面的依赖文件一个一个的拿过来依次进行指令操作。如:上面 gcc -c -fPIC $< 表示依次将依赖文件列表中的 .c文件编译成 .o文件,gcc -shared -o $@ $^ 表示一次性拿到 mymath.o 和mystdio.o 生成共享库,即:gcc -shared -o $@ mymath.o mystdio.o。

        动态库生成后,这里还不能直接使用。首先,它与静态库类似,需要使用 -l 选项说明要链接自定义的库,若是不把自定义库放入系统默认的搜索路径/lib64/下,还需使用 -L选项说明库的路径。其次,当编译源程序时,对于头文件,编译器会默认在两套路径下搜索,一个是当前目录,一个是系统默认的头文件目录(/usr/include/,此目录存放的是系统下对应的所有头文件)下,若源代码所包含的头文件都不在这两个目录下,那么程序编译时将会报错。这里可以使用选项 -I ,让编译器在查找源程序所包含的头文件时,除了会在两个默认的目录下查找外,还会在指定的路径下进行查找。如:gcc -o mytest main.c -I ./mylib/include -L ./mylib/lib -lmyc,编译时系统会搜索目录./mylib/include寻找头文件和搜索目录./mylib/lib -lmyc寻找库。同理,若不想使用 -L 选项和 -I选项,只需把对应的库文件和对应包含的头文件放入到系统默认搜索的目录中即可,需注意的是这里要使用root权限,不是root用户需使用sudo,如:sudo cp mylib/include/* /usr/include/       sudo cp ./mylib/lib/* /lib64/。之后,我们只需加一个 -l 选项告诉编译器还要使用自定义的库即可,如:gcc -o mytest main.c -lmyc。

        使用 ldd [可执行程序] 可查看程序所依赖的动态库,通过查看后发现程序成功使用。

        上面我们还看出,程序不仅依赖于自定义库libmyc.so,还依赖于C标准库libc.so.6。其实把所谓的库(或其它软件)安装到系统中,本质就是把对应的文件拷贝到系统默认指定的路径中,如:安装gcc软件时,C标准库自动安装在/lib64/目录下,相关的头文件安装在/usr/include/目录下。

        下面要说明的是,当可执行程序生成时,它还不能正常运行,但模拟实现的静态库不会出现这种问题。因为静态库的本质是把库中的代码拷贝到使用的程序中,也就是说编译形成的可执行程序中存在有关静态库中的代码,只要形成了可执行程序后就与静态库无关了,而链接动态库的程序运行时,操作系统必须动态加载相关的库文件,如果系统找不到所需的动态库,程序可能会无法运行或运行出错。

        注意,源代码的编译和编译后形成的可执行程序都需要相关动态库的加载。我们编译时链接的动态库只是相关工具的链接,如上面的演示中,在系统默认的路径下没有对应的动态库时,使用gcc及相关选项进行链接只是编译时工具gcc的链接,形成可执行程序后要想运行,必须还要操作系统层面的动态加载。解决系统层面的加载这里有四种方案:

        1,直接暴力把自定义的动态库拷贝到 /lib64目录下。当运行程序时,操作系统默认动态加载 /lib64目录下相关的动态库。

        2,

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

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

相关文章

Linux - 冯-诺依曼体系结构、初始操作系统

目录 冯•诺依曼体系 结构推导 内存提高效率的方法 数据的流动过程 体系结构相关知识 初始操作系统 定位 设计目的 操作系统之上之下分别有什么 管理精髓&#xff1a;先描述&#xff0c;再组织 冯•诺依曼体系 结构推导 计算机基本工作流程图大致如下&#xff1a; 输入设备&a…

Web3D:WebGL为什么在渲染性能上输给了WebGPU。

WebGL已经成为了web3D的标配&#xff0c;市面上有N多基于webGL的3D引擎&#xff0c;WebGPU作为挑战者&#xff0c;在渲染性能上确实改过webGL一头&#xff0c;由于起步较晚&#xff0c;想通过这个优势加持&#xff0c;赶上并超越webGL仍需时日。 贝格前端工场为大家分享一下这…

【微信小程序知识点】自定义构建npm

在实际开发中&#xff0c;随着项目的功能越来越多&#xff0c;项目越来越复杂&#xff0c;文件目录也变得很繁琐&#xff0c;为了方便进行项目的开发&#xff0c;开发人员通常会对目录结构进行优化调整&#xff0c;例如&#xff1a;将小程序源码放到miniprogram目录下。 &…

JuiceFS缓存特性

缓存 对于一个由对象存储和数据库组合驱动的文件系统&#xff0c;缓存是本地客户端与远端服务之间高效交互的重要纽带。读写的数据可以提前或者异步载入缓存&#xff0c;再由客户端在后台与远端服务交互执行异步上传或预取数据。相比直接与远端服务交互&#xff0c;采用缓存技…

SAP PP学习笔记28 - 生产订单的收货及品质管理

上一章讲了生产订单的很多概念&#xff0c;比如确认&#xff08;报工&#xff09;以及报工的各种形式&#xff0c;反冲&#xff0c;自动入库等。 SAP PP学习笔记27 - Confirmation(报工/确认&#xff09;(CO11&#xff0c;CO11N&#xff0c;CO15&#xff0c;CO12)&#xff0c;…

【算法】LRU缓存

难度&#xff1a;中等 题目&#xff1a; 请你设计并实现一个满足 LRU (最近最少使用) 缓存 约束的数据结构。 实现 LRUCache 类&#xff1a; LRUCache(int capacity) 以 正整数 作为容量 capacity 初始化 LRU 缓存int get(int key) 如果关键字 key 存在于缓存中&#xff0c;…

【HarmonyOS】关于鸿蒙消息推送的心得体会 (一)

【HarmonyOS】关于鸿蒙消息推送的心得体会&#xff08;一&#xff09; 前言 这几天调研了鸿蒙消息推送的实现方式&#xff0c;形成了开发设计方案&#xff0c;颇有体会&#xff0c;与各位分享。 虽然没做之前觉得很简单的小功能&#xff0c;貌似只需要和华为服务器通信&…

LDAPWordlistHarvester:基于LDAP数据的字典生成工具

关于LDAPWordlistHarvester LDAPWordlistHarvester是一款功能强大的字典列表生成工具&#xff0c;该工具可以根据LDAP中的详细信息生成字典列表文件&#xff0c;广大研究人员随后可以利用生成的字典文件测试目标域账号的非随机密码安全性。 工具特征 1、支持根据LDAP中的详细信…

高效运转!便携式果汁机必备霍尔板

文章目录 文章目录 前言 一、 直流电机原理 二、 通过霍尔传感器控制无刷直流电机 三、 霍尔在霍尔板上的位置 前言 今天给大家带来一款运用在果汁机上的霍尔板&#xff0c;饮料再好&#xff0c;终归是饮料&#xff0c;果汁再好喝&#xff0c;也不如自己亲自榨得健康。 生活水…

年化18.9%的创业板趋势策略,使用模块化策略模板重构(代码+数据)

原创文章第590篇&#xff0c;专注“AI量化投资、世界运行的规律、个人成长与财富自由"。 昨天咱们分享的文章&#xff1a;”以交易为生“&#xff0c;基础设施很重要。 传统backtrader写策略的步骤是如下&#xff1a; 1、定义因子&#xff0c;比如动量roc&#xff1a; …

django创建子应用、追加导包路径、默认用户模型类、自定义用户模型类、

一、创建用户模块子应用 1.准备apps包&#xff0c;用于管理所有应用 2.在apps包下创建应用users 查看项目导包路径 提示&#xff1a;若要知道如何导入users应用并完成注册&#xff0c;需要知道项目导包路径 已知导包路径&#xff1a;project/meiduo已知 users应用所在目录&…

网络安全高级工具软件100套

1、 Nessus&#xff1a;最好的UNIX漏洞扫描工具 Nessus 是最好的免费网络漏洞扫描器&#xff0c;它可以运行于几乎所有的UNIX平台之上。它不止永久升级&#xff0c;还免费提供多达11000种插件&#xff08;但需要注册并接受EULA-acceptance–终端用户授权协议&#xff09;。 它…

visual studio开发C++项目遇到的坑

文章目录 1.安装的时候&#xff0c;顺手安装了C模板&#xff0c;导致新建项目执行出问题2.生成的exe&#xff0c;打开闪退问题3.项目里宏的路径不对&#xff0c;导致后面编译没有输出4. vs编译ui&#xff0c;warning跳过&#xff0c;未成功5.vs编译.h&#xff0c;warning跳过&a…

【嵌入式DIY实例-ESP8266篇】-LCD ST7789显示DS1307 RTC时间数据

LCD ST7789显示DS1307 RTC时间数据 文章目录 LCD ST7789显示DS1307 RTC时间数据1、硬件准备与接线2、代码实现本文将介绍如何使用 ESP8266 NodeMCU 板和 DS1307 RTC 集成电路构建简单的实时时钟和日历 (RTCC),其中时间和日期打印在 ST7789 TFT 显示模块上。 ST7789 TFT 模块包…

图像处理:使用 OpenCV-Python 卡通化你的图像(2)

一、说明 在图像处理领域&#xff0c;将图像卡通化是一种新趋势。人们使用不同的应用程序将他们的图像转换为卡通图像。如今&#xff0c;玩弄图像是许多人的爱好。人们通常会点击图片并添加滤镜或使用不同的东西自定义图像并将其发布到社交媒体上。但我们是程序员&#xff0c;…

用node.js写一个简单的图书管理界面——功能:添加,删除,修改数据

涉及到的模块&#xff1a; var fs require(‘fs’)——内置模块 var ejs require(‘ejs’)——第三方模块 var mysql require(‘mysql’)——第三方模块 var express require(‘express’)——第三方模块 var bodyParser require(‘body-parser’)——第三方中间件 需要…

【论文阅读】MCTformer+:弱监督语义分割的多类令牌转换器

【论文阅读】MCTformer:弱监督语义分割的多类令牌转换器 文章目录 【论文阅读】MCTformer:弱监督语义分割的多类令牌转换器一、介绍1.1 WSSS背景1.2 WSSS策略 二、联系工作2.1 弱监督语义分割2.2 transformers的可视化应用 三、MULTI-CLASS TOKEN TRANSFORMER3.1 Multi-class t…

自建Web网站部署——案例分析

作者主页: 知孤云出岫 目录 作者主页:如何自建一个Web网站一、引言二、需求分析三、技术选型四、开发步骤1. 项目初始化初始化前端初始化后端 2. 前端开发目录结构示例代码App.jsHome.js 3. 后端开发目录结构示例代码app.jsproductRoutes.jsProduct.js 4. 前后端连接安装axio…

硕博电子智能控制器、触摸显示屏在集装箱跨运车上的应用

港口跨运车&#xff0c;又称跨运车或轮胎式龙门吊(RTG)&#xff0c;专门用于集装箱码头的装卸和搬运作业&#xff0c;能够迅速完成集装箱在码头前沿、堆场区域以及仓库之间的运输和堆垛&#xff0c;大幅度缩短了装卸周期&#xff0c;提高了港口物流周转效率。 现代跨运车往往配…

LabVIEW扬尘控制系统

设计了一套基于LabVIEW的扬尘控制系统&#xff0c;通过监测TsP&#xff08;总悬浮颗粒物&#xff09;浓度、风向和摄像头视频&#xff0c;实现对环境的综合监控和扬尘控制。系统可以自动判断扬尘位置&#xff0c;并驱动抑尘设备进行抑尘。硬件选用NI cDAQ-9178数据采集模块、Om…