【Linux文件篇】软硬链接与动静态库链接的实用指南

news2024/12/26 1:34:05

W...Y的主页 😊

代码仓库分享💕


目录

文件的软硬链接

 动静态库

回归动静态库

创建动静态库

生成静态库

生成动态库

库搜索路径


文件的软硬链接

上篇文章中我们讲述了文件系统从硬件到软件,理解了如何创建一个文件的具体流程,今天我们先来看一下文件的软硬链接。

我们看如何创建一个硬链接:

 指令: ln 目标文件 硬链接文件名
硬链接创建的不是一个文件,其inode和目标文件的inode的是相同的,而且我们可以看出在没有创建硬链接时我们的test.txt权限和拥有者中间有一个数字从1变成了2这是什么呢?这个数字表示硬链接数。当有硬链接指向文件时,这个数字就会+1,当我们删除时这个数字就会-1,就好比C++中的引用一样。

当我们给test.txt中写入内容时,无论是test.txt还是link.hard都会指向相同的内存空间,显示相同的内容。当我们将test.txt删除后查看link.hard内容时我们照样可以查看。说明这个内存空间还没有被释放,知道硬链接数为0时才会将其释放。只有引用计数减到0才会将它的block bitmap 、inode bitmap对应的比特位清空。

当我们创建一个目录时,其默认的硬链接数就是2,那是因为进入目录后隐藏文件中有一个.的inode与当前目录i弄得相同,这就是为什么硬链接数为2的原因。

如果我们在dir目录中继续创建一个目录,那么dir的硬链接数就会成为3,因为再创建的目录中的上级目录..的inode也是这样。所以一个目录下有多少个子目录:硬链接数 -2得到的。 

如何给一个文件创建一个软链接:

 指令:ln -s + 目标文件  软连接文件名

我们可以看到软链接本质是一个文件,其有一个独立的inode。而软链接文件中存放的内容就是目标文件的路径。这就好比Windows中的快捷方式一样。

所以软链接的应用场景一般是创建快捷方式,如果一个可执行程序在目录中嵌套太深,我们每次想指向其程序要么就要进入到可执行程序的当前目录下,要么就要将可执行程序与当前用户所在的路径下的相对目录进行输入非常繁琐,所以我们可以使用软链接的方式进行简化。

Linux不允许给目录建立硬链接,因为寻找文件是通过路径寻找的,如果我们给根目录创建硬链接就会导致环路问题出现死循环递归。除非系统自己给目录建立硬链接!!

 动静态库

回归动静态库

动静态库是编程中两种常用的库文件类型,它们在程序的编译和链接过程中起到不同的作用:

  1. 静态库(Static Library)

    • 静态库文件通常具有.lib.a的文件扩展名(取决于操作系统)。
    • 它们在编译时被链接到最终的可执行文件中。这意味着静态库中包含的代码和资源在编译阶段被复制到最终的程序中。
    • 优点包括减少运行时依赖、可能提高程序的加载速度,以及在某些情况下提高程序的执行效率。
    • 缺点是生成的可执行文件体积较大,因为包含了库的代码。
  2. 动态库(Dynamic Library)

    • 动态库文件通常具有.dll(Windows)、.so(Linux)、.dylib(macOS)等文件扩展名。
    • 它们在程序运行时被加载。这意味着程序在运行时才链接到库文件,而不是在编译时。
    • 优点包括减少磁盘空间的使用,因为多个程序可以共享同一个库文件;动态库的更新也更加方便,不需要重新编译使用该库的所有程序。
    • 缺点是程序启动时需要加载库,可能会稍微增加启动时间;程序运行时依赖于库文件的存在,如果库文件被移动或删除,程序可能无法运行。

我们一般可以使用ldd + 可执行程序进行查看文件的动静态库使用情况。

上图我们可以看出使用了libc.so.6,去掉前缀lib去掉后缀.so.6就只有C了,证明使用了C库。

使用file + 可执行程序就可以看出文件使用的是动态链接还是静态链接。 gcc与g++编译器默认链接的都是动态库,若我们想使用静态库进行链接就得使用static,指令为:g++ 目标文件  -static即可进行静态链接。

创建动静态库

一个可执行程序是由若干个头文件以及.c文件 + main函数文件进行编译合成的,实质是将许多.c文件先编译成.o文件,然后.o文件与.h文件进行组合成为可执行程序。但是当我们想隐藏源文件内容时,我们只需要将编译好的.o文件和.h打包再配合main.c文件即可。

那为什么要有库这个概念呢?1.提高开发效率。2.为了隐藏源代码

所以我们要学习怎样对许多.o文件变成库文件:

测试程序
/add.h/
#ifndef __ADD_H__
#define __ADD_H__
int add(int a, int b);
#endif // __ADD_H__
/add.c/
#include "add.h"
int add(int a, int b)
{
return a + b;
}
/sub.h/
#ifndef __SUB_H__
#define __SUB_H__
int sub(int a, int b);
#endif // __SUB_H__
/sub.c/
#include "sub.h"
int sub(int a, int b)
{
return a - b;
}
///main.c
#include <stdio.h>
#include "add.h"
#include "sub.h"
int main( void )
{
int a = 10;
int b = 20;
printf("add(10, 20)=%d\n", a, b, add(a, b));
a = 100;
b = 20;
printf("sub(%d,%d)=%d\n", a, b, sub(a, b));
}

生成静态库

[root@localhost linux]# ls
add.c add.h main.c sub.c sub.h
[root@localhost linux]# gcc -c add.c -o add.o
[root@localhost linux]# gcc -c sub.c -o sub.o
生成静态库
[root@localhost linux]# ar -rc libmymath.a add.o sub.o
ar是gnu归档工具,rc表示(replace and create)
查看静态库中的目录列表
[root@localhost linux]# ar -tv libmymath.a
rw-r--r-- 0/0 1240 Sep 15 16:53 2017 add.o
rw-r--r-- 0/0 1240 Sep 15 16:53 2017 sub.o
t:列出静态库中的文件
v:verbose 详细信息
[root@localhost linux]# gcc main.c -L. -lmymath
-L 指定库路径
-l 指定库名
测试目标文件生成后,静态库删掉,程序照样可以运行。

生成动态库

生成动态库和静态库的方法有所不同。

shared: 表示生成共享库格式
fPIC:产生位置无关码(position independent code)
库名规则:libxxx.so

首先我们想要生成.o文件时使用gcc/g++时不能直接进行gcc -c 而是要加上-c -FPIC这两个选项(一会讲述-FPIC有什么用)。然后进行打包,而打包也不使用ar -rc这个指令,直接使用gcc -shared即可。
示例:

[root@localhost linux]# gcc -fPIC -c sub.c add.c 
[root@localhost linux]# gcc -shared -o libmymath.so *.o 
[root@localhost linux]# ls 
add.c add.h add.o libmymath.so main.c sub.c sub.h sub.o

当我们生成了动态库后我们就可以进行编译了,编译的方法和静态库相同。使用gcc -L+相对路径 -l动态库名称(去掉前面lib,去掉后面.so即可)。因为我们做的动静态库都是第三方库,操作系统只会在自己默认的库中寻找,一般是lib64目录下进行的。

我们可以这么理解 L :你要链接的库在哪一个路径下。l:你要链接的库是谁。

但是编写库的人未来要给别人(用库的人),交付的是:头文件+库文件,不给源代码我们想要一键式发布直接交给别人我们应该怎么办:

lib=libmymath.a

$(lib):mymath.o
	ar -rc $@ $^
mymath.o:mymath.c
	gcc -c $^

.PHONY:clean
clean:
	rm -rf *.o *.a lib

.PHONY:output
output:
	mkdir -p lib/include
	mkdir -p lib/mymathlib
	cp *.h lib/include
	cp *.a lib/mymathlib

我们tree一下就可以发现将头文件全部放在include目录中,将库文件放在lib目录下。 

 

我们继续使用tar czf + 压缩包名 + 目标内容指令将mylib目录生成压缩包,然后将压缩包上传到一些网站上供别人使用 。但是这样的缺点就是头文件和库文件都不在同一个路径下,所以我们得使用gcc指令的选项就不仅仅使用l和L还要加一个I,I这个选项是告诉编译器头文件在哪个路径下的。

我们必须使用-I -L -l进行gcc编译出可执行程序。

动态库的使用也是有很多的小细节,使用不当也会产生找不到动态库或者找不到头文件的问题。 就像我们直接编译好了可执行程序,在运行时系统还是找不到我们的库在哪里。 这是为什么呢?

静态库和main函数在形成可执行程序后我们就可以直接运行程序,因为静态库的编译原理就是将我们的静态库内容拷贝到代码中,之后我们再也不需要库的内容。但是动态库不同,当我们使用动态库编译后形成可执行程序后运行程序时必须要找到对应的库的位置,因为动态库没有将内容拷贝到代码中,所以我们在运行时也需要动态库。当使用编译器的时候我们已经告诉动态库的位置,但是在运行时我们使用的是操作系统和编译器没有任何关系,所以OS也不知道动态库的位置,运行就会报错。

库搜索路径

从左到右搜索-L指定的目录。
由环境变量指定的目录 (LIBRARY_PATH)
由系统指定的目录
/usr/lib
/usr/local/lib

方法一:将头文件和库文件安装到系统中

如果我们不想这样编译一个代码,也可以将头文件拷贝到系统默认路径下,所谓把库安装到系统中本质就是把对应的文件拷贝到系统指定的路径下!(系统路径一般在/user/include路径下)但是路径的权限都是root,我们就要使用sudo来进行拷贝。库文件也是一样的,需要我们将其拷贝到/lib64路径下。这时我们就不用使用-L和-I了,只需要-l进行声明使用哪个库即可!

方法二:建立一个软链接

我们可以使用ln -s + 目标库绝对路径 /lib64/libmyc.so创建一个软连接即可。

方法三:修改环境变量

在环境变量中有一个LD_LIBRARY_PATH变量

我们的环境变量中可能有也可能没有这个环境变量,我们使用echo $LD_LIBRARY_PATH进行配置即可。

在系统运行时,动态库查找的辅助路径!!!

在我们的家目录下有配置文件.bash_profile和.bashrc,这两个隐藏文件里面就可以配置环境变量,我们也可以使用vim将我们需要的路径写入里面。

方法四:更改配置文件

Linux下含有一个文件夹其中包含有关动态库加载的配置文件,里面只含有一个路径。我们可以在其目录下创建一个相同格式的空白文件,再将我们库的路径填入其中保存即可。

系统中有一个ld.so.conf的配置文件在/etc/路径下:


 这时一个目录,我们在目录中可以在该目录下自定义用户级的配置文件,我们可以创建一个名字随便起后缀.conf的文件,在里面添加库文件路径即可。因为这些都是root权限的文件,所以我们使用root账户或者使用sudo来执行指令。

添加完毕后使用ldconfig进行配置文件生效后就可以使用动态库了!!!


以上就是本次的内容,感谢大家观看! 

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

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

相关文章

AI数字人的开源解决方案

目前&#xff0c;国内外已经涌现出一些优秀的数字人开源解决方案&#xff0c;这些解决方案为开发者提供了构建数字人应用的工具和基础设施。以下是一些比较知名的数字人开源解决方案。北京木奇移动技术有限公司&#xff0c;专业的软件外包开发公司&#xff0c;欢迎交流合作。 1…

java Springboot网上音乐商城(源码+sql+论文)

1.1 研究目的和意义 随着市场经济发展&#xff0c;尤其是我国加入WTO &#xff0c;融入经济全球化潮流&#xff0c;已进入国内外市场经济发展新时期&#xff0c;音乐与市场联系越来越紧密&#xff0c;我国音乐和网上业务也进入新历史发展阶段。为了更好地服务于市场&#xff0…

5.7 Python内置函数

文章目录 1. 内置模块Aabs()all()any()ascii() Bbin()bool()bytearra()bytes() Ccallable()chr()classmethod()compile()complex() Ddelattr()dict()dir()divmod() Eenumerate()eval()exec()execfile() Ffile()filter()float()format()frozenset() Ggetattr()globals() Hhasatt…

【分布式技术专题】「OceanBase深度解析」 探索OceanBase产品矩阵与核心设计

探索OceanBase产品矩阵与核心设计 OceanBase的六大特性高扩展高可用多租户&#xff08;资源隔离&#xff09;OceanBase架构和功能OceanBase广泛的数据源支持 OceanBase的六大特性 OceanBase以其卓越的产品平台整合方案&#xff0c;充分展现了六大核心特性的卓越与全面。这一方…

进击算法工程师深度学习课程

"进击算法工程师深度学习课程"旨在培养学员在深度学习领域的专业技能和实战经验。课程涵盖深度学习基础理论、神经网络架构、模型优化方法等内容&#xff0c;通过项目实践和算法实现&#xff0c;帮助学员掌握深度学习算法原理和应用&#xff0c;提升在算法工程师领域…

SAP Web IDE 安装使用

For training SAP Web IDE 是基于 Eclipse 内核的在线开发 IDE&#xff0c;可以使用在线的试用版本&#xff0c;但服务器在德国&#xff0c;访问的网速特别慢。也可以使用 Personal Edition&#xff0c;在本机启动和编写代码。 打开官网下载WEBIDE工具包&#xff0c;包含 Tri…

SAP ABAP 之面向对象OO

文章目录 前言一、类的理解二、如何创建ABAP类 a.类的定义与构成 b.类的访问区域 c.特殊方法 d.类的继承 三、类中参数的使用 a.IMPORTING / EXPORTING b.CHANGING c.RETURNING d.EX…

省市县选择三级联动(使用高德API实现)

省市县选择如果自己实现是比较麻烦的&#xff0c;最近发现可以使用高德实现省市县联动选择&#xff0c;实现后来记录一下供大家参考。 文章目录 最终效果&#xff1a;一、准备工作二、完整页面代码 最终效果&#xff1a; 实现单次点击获取省市县名称&#xff0c;选择完成后返回…

复旦微FMQL20SM全国产ARM+FPGA核心板,替代xilinx ZYNQ7020系列

FMQL20SM核心板一款全国产工业核心板。基于复旦微FMQL20S400M四核ARM Cortex-A7&#xff08;PS端&#xff09; FPGA可编程逻辑资源&#xff08;PL端&#xff09;异构多核SoC处理器设计的全国产工业核心板&#xff0c;PS端主频高达1GHz。 核心板简介 FMQL20SM核心板是一款全国…

键盘、鼠标、轴体选购指南

起因 买了块27寸的屏幕msi&#xff0c;一旦入坑爬不起来了。 这不是要配个键盘么。 鼠标的左键也不够灵敏&#xff0c;不知道是电池不足还是使用时间太久&#xff0c;也萌生换的念头。有一个重要原因也是跟电脑和鼠标垫整体不搭。 搜集信息 原本的一个键盘是ikbc国产牌子&am…

【C++】STL中stack和queue(适配器版)的模拟实现

前言&#xff1a;在此之前我们讲到了stack和queue还有deque的常见的使用方法&#xff0c;并且也在数据结构的时候用C语言去实现过栈和队列&#xff0c;今天我们将进一步的用C去模拟实现stack和queue &#x1f496; 博主CSDN主页:卫卫卫的个人主页 &#x1f49e; &#x1f449; …

Apache Doris 基础 -- 部分数据类型及操作

您还可以使用SHOW DATA TYPES;查看Doris支持的所有数据类型。 部分类型如下&#xff1a; Type nameNumber of bytesDescriptionSTRING/可变长度字符串&#xff0c;默认支持1048576字节(1Mb)&#xff0c;最大精度限制为2147483643字节(2gb)。大小可以通过BE配置string_type_le…

2. Revit API UI 之 IExternalCommand 和 IExternalApplication

2. Revit API UI 之 IExternalCommand 和 IExternalApplication 上一篇我们大致看了下 RevitAPI 的一级命名空间划分&#xff0c;再简单讲了一下Attributes命名空间下的3个类&#xff0c;并从一个代码样例&#xff0c;提到了Attributes和IExternalCommand &#xff0c;前者是指…

Cisco Packet Tracer实验(二)

二、用交换机构建 LAN 构建物件如下&#xff1a; 四个PC 两个交换机 一个Multi Switch多功能拓展控制器 连线必须是这个直线&#xff01;&#xff01;&#xff01;不是虚线 最后实现效果如下&#xff1a; 全部的线是绿的&#xff0c;就表示是通的。 尝试一下&#xff0c;看PC…

JVM性能优化案例:减少对象频繁创建

JVM性能优化案例&#xff1a;减少对象频繁创建 案例背景 某金融应用系统在处理大量并发交易时&#xff0c;响应时间过长&#xff0c;并且有时出现内存溢出&#xff08;OutOfMemoryError&#xff09;的问题。经过分析&#xff0c;发现问题主要出在频繁的对象创建和较差的内存管…

热门开源项目OpenHarmony

目录 1.概述 1.1.开源项目的意义 1.2.开源项目对软件行业的促进作用 1.3.小结 2.OpenHarmony 2.1.技术架构 2.2.分布式软总线 2.2.1.架构 2.2.2.代码介绍 2.2.2.1.代码目录 2.2.2.2.说明 2.2.2.3.发现组网和传输 2.2.2.3.1.发现 2.2.2.3.2.组网 2.2.2.3.3.传输…

力扣148. 排序链表

给你链表的头结点 head &#xff0c;请将其按 升序 排列并返回 排序后的链表 。 示例 1&#xff1a; 输入&#xff1a;head [4,2,1,3] 输出&#xff1a;[1,2,3,4] 示例 2&#xff1a; 输入&#xff1a;head [-1,5,3,4,0] 输出&#xff1a;[-1,0,3,4,5] 示例 3&…

数据分析常用6种分析思路(下)

作为一名数据分析师&#xff0c;你又没有发现&#xff0c;自己经常碰到一些棘手的问题就没有思路&#xff0c;甚至怀疑自己究竟有没有好好学过分析&#xff1f; 在上篇文章里&#xff0c;我们讲到了数据分析中的流程、分类、对比三大块&#xff0c;今天&#xff0c;我们继续讲…

PHP地方门户分类信息网站源码讯客分类信息系统源码(含手机版)

源码介绍 1.上传程序到网站根目录,访问http://域名/install/index.php 进行安装,不要直接打开网址&#xff0c;先直接安装; 2.安装完成后 后台恢复数据即可 默认帐号密码都是admin http://域名/admin/ 3.不要删除任何文件&#xff0c;因为删除文件或者修改代码可能造成错误 运…

vuejs3 pinia持久化存储

插件地址&#xff1a; 快速开始 | pinia-plugin-persistedstate 安装插件&#xff1a; 安装pinia后&#xff0c;再安装这个插件 npm i pinia-plugin-persistedstate 引入插件&#xff1a; 在main.ts或者main.js里 //main.ts或者main.js里import { createPinia } from pi…