零基础Linux_15(基础IO_文件)软硬链接+动静态库详解

news2024/12/24 18:38:51

目录

1. 软硬链接

1.1 创建软链接

1.2 创建硬链接

2. 动静态库

2.1 制作静态库

2.2 查看和打包静态库

2.3 使用静态库

2.3.1 安装在默认搜索路径

2.3.2 告知路径+库路径+库名

2.4 制作动态库

2.5 使用动态库

2.5.1 安装在默认搜索路径

2.5.2 路径放在环境变量

2.5.3 路径放在配置文件

2.5.4 软链接到默认搜索路径

2.6 动态库加载和调用

2.7 静态库加载和调用

本篇完。


1. 软硬链接

上一篇:

 inode等知识也讲了,现在我们讲讲硬连接数的关联:软硬链接。

软硬链接的区别:

  • 软链接:是一个独立文件,有自己独立的 inode 和 inode 编号。
  • 硬链接:不是一个独立的文件,它和目标文件使用的是同一个 inode。硬链接就是单纯的在 Linux 指定的目录下,给指定的文件新增 文件名 和 inode 编号的映射关系。

我们可以通过如下命令,创建一个文件的软硬链接:

ln -s 文件名 链接文件名 // 创建软连接
ln 文件名 链接文件名 // 创建硬链接

1.1 创建软链接

这里创建linux_15目录,进去然后在里面创建一个 test.c 文件,随便写点东西:

编译运行:

软连接是给可执行程序的软连接,我们给test.exe 创建一个软连接,可以使用下面的指令:

ln -s 文件名 链接文件名 // 创建软连接

此时运行软连接依旧能执行程序。ll -i:

将链接关系中的被链接文件删除以后,链接文件就出错了,并且在闪烁。

再创建一个普通的同名文件,链接就恢复正常了。  

  • 创建的文件是一个普通文件,并不是可执行文件。
  • 创建的文件和原来的文件inode不同,原来的是920674,现在是92835。
  • 只是文件名相同,链接关系就恢复正常了。

从上面的现象可以得出一个结论:软链接和inode无关,只和路径名有关。
也就是说,建立软链接后,并不是链接文件和另一个文件的inode绑定了,只是和文件名绑定了。

可以发现test.exe和它的软链接的inode 是不同的。软链接有什么用途呢?:

我们创建一个比较深的路径,在里面写个程序:

编译运行:

如果我想在原来的linux_15运行呢:

这样也能运行,不过路径名太长太深的时候就很麻烦了,此时我们可以在linux_15路径下给test2.exe创建一个软连接,并且尝试运行:

成功运行,这就是软连接的作用。是不是有点像 Windows 下的 快捷方式? 软链接就是 Linux 下的快捷方式 。

上面我们演示的是让软链接链接一个可执行程序,未来我们可以用它来链接头文件、库文件,动静态库,这样就可以不需要让我们冗余的在去某些地方找这些库了。

1.2 创建硬链接

我们先给test.c创建一个硬链接看看:

可以发现他们的inode是一样的,并且打印test.c的硬链接也打印了test.c的内容,

此时我们在给test.exe创建硬链接看看,注意到此时test.exe的硬链接数为1。

test.exe的硬链接也可以运行,并且他们的硬链接数都为2了。

硬链接就是单纯的在 Linux 指定的目录下,给指定的文件新增文件名和 inode 编号的映射关系,你可以理解为起别名。

删掉test.exe的硬链接:

test.exe还可以运行,但是硬链接数变为了1,

前一篇:

了解过引用计数的就知道,此时这个删除就和引用计数类似了。

我们在删除文件时操作系统干了两件事情:

① 在目录中将对应的记录删除,

② 将硬连接数-1,如果为0,则将对应的磁盘释放。

删除的话可以直接 rm,但是我们还是建议使用专门的 取消链接 的指令:unlink

我们把存在的软硬链接都删除:

成功删除,到了最后发现,为什么d1目录的硬链接数是3?

我们把上面的东西全删了,重新创建一个文件和目录:

为什么创建普通文件,硬链接数默认是 1 ,目录硬链接数默认是 2 呢 ? 

因为 普通文件的文件名本身就和自己的 inode 具有映射关系,而且只有一个。

我们知道,任意一个目录一定存在一个点或两个点: .   ..

那么 ./ 为什么表示的是当前路径呢?因为 . 表示的当前文件,./ 就是当前所处的路径。

默认一个空目录创建一个 自己的名字 和 一个点,所以两个文件名指向它,所以是 2。

那么 .. 又是什么呢?.. 指向的是上级路径。

这就是为什么我们 cd .. 可以回到上级目录的原因,因为它可以指向上级目录。

2. 动静态库

动静态库即 动态库 (Dynamic Library) 与 静态库 (Static Library) 。

① 动态库:库文件,以.so为后缀(Windows中为.dll):程序在运行的时才去链接动态库的代码,多个程序共享使用库的代码。

② 静态库:库文件,以.a为后缀(Windows中为.lib):程序在编译链接的时候把库的代码链接到可执行文件中。程序运行的时候将不再需要静态库

linux_7学的;

2.1 制作静态库

我们先站在设计库的工程师的角度,学如何形成静态库。

我们直接实操式地讲解,下面我们会写一段简单的、包含头文件和源文件的代码。

像以前的函数声明和实现分开一样,写两个头文件和两个源文件,再写个main.c:

 

此时如果有同学(客户之类的)想使用上面的接口函数,并且写了下面的使用代码:

如果要将上诉代码接口给同学使用,并且不暴露源码,此时我们就可以选择将它制作成库。

制作静态库:

现在站在制作库的一方来看问题。

对源码进行预处理,编译,汇编,形成以.o为后缀的目标文件,再将这些文件交给同学。

现在将两个源文件编译成了两个以.o为后缀的目标文件,如上图所示,它们是二进制形式的机器码,并不是源码。

我们先试着链接生成可执行程序。

成功链接。

将.h和.o为后缀的目标文件以及头文件交给同学,让他去链接生成可执行程序。此时可以制作一个动态库给同学,库的原理和上面类似,只是将所有的.o为后缀的文件打包在了一起,形成了一个库,在使用的时候直接使用这个库就可以。

指令:ar -rc 静态库名字 所有待打包.o

ar是gnu归档工具,-rc表示(replace and create),静态库名字前面要加lib,后缀是.a

2.2 查看和打包静态库

成功制作了一个静态库。可以通过指令来查看我们制作的库:

  • 指令:ar -tv 库文件名
  • 功能:t:列出静态库中的文件,v:verbose 详细信息

如果要给同学的话,要给所有的头文件和还有静态库,是不是太麻烦了?

此时我们可以把他们放到一个目录下,此时我们可以写一个这样的Makefile,和前面制作静态库的步骤一起,直接一步make到位,生成一个库文件。

  • 将所用到的头文件全部放在outputlib/include目录下。
  • 将静态库文件放在outputlib/lib目录下。

复习一下Makefile:

 和前面制作静态库的步骤一起,直接一步make到位,生成一个库文件:

 make:

再使用打包工具tar,将库和头文件一起打包,即这个outputlib目录,就能将压缩包发生给同学。

2.3 使用静态库

此时我们站在使用者的角度,也就是那个同学的角度。

我们接收到了库的压缩包(和从网上下载一样),然后解压,得到了里面的文件:

(这里创建一个test目录,把main.c和mylib.tgz移动进去,然后解压)

运行下main.c:

发现报错了,没有找到mymath.h?接下来就是学学正确使用它,有俩种方法可以用。

2.3.1 安装在默认搜索路径

①安装在系统中

这种方法类似于我们安装软件,使用gcc的时候,它会自动去系统默认路径下搜索所需要的头文件和库文件,也就是C语言标准库所在的路径。

  • 头文件默认搜索路径:/usr/include;
  • 库文件默认搜索路径:/usr/lib64;

切换到root用户将头文件和库文件安装在gcc的默认搜索路径下:

发现还是报错了,这次不是找不到头文件,而是找不到使用接口的定义,说明库出问题了。是因为gcc不知道该用这个默认路径下的哪个库。 

在使用gcc编译的时候告诉编译器要使用的库名(掐头去尾后的库名),此时就能编译成功了。

  • -l选项:指定使用的库名(掐头去尾后的库名)。

 成功编译且运行,我们平时可是没有加过-l选项的,各种库函数,比如printf这是都是可以调用的,为什么我们自己的库还需要告诉gcc库名呢?

  • 官方提供的标准库编译器是能够认识的,所以不用特别指出。

这种方式其实就是库的安装,这种方式不建议使用,因为第三方库没有经过检测,会污染其他库和头文件,所以这里把复制过去的文件删了。

切换到普通用户,用第二种方法:

2.3.2 告知路径+库路径+库名

② 告诉编译器头文件路径,库路径,库名

gcc选项作用
-I(大写i)指定头文件路径
-L指定库文件路径
-l(小写L)指定库(掐头去尾后的库名)

现在试试第二种方法:

成功站在第三方的角度使用了静态库。

2.4 制作动态库

有了前面写的文件,制作动态库就简单点了。源码和头文件还是和制作静态库时的一样,要求也是一样,但是此时是给同学制作一个动态库。这里进入上级目录,然后make clean一下。

制作动态库:

和制作静态库一样,将所有.o文件打包在一起,但不使用ar打包,而是使用gcc来打包。

① 在使用gcc形成.o文件的时候,再加一个选项-fPIC,生成位置无关码:

成功生成.o文件,位置无关码是什么呢?

如上图所示,假设一火柴人在进行百米赛跑,在跑道的中间,也就是50米处有一个箭头标志。

如果这不是100米的跑道,而是变成了200米,500米呢?火柴人的绝对位置会变化,但是火柴人的相对位置永远不变,处于箭头右侧30米处。此时如果跑到两端变长变短也与我无瓜了。

位置无关码就类似于箭头右侧30米处的30。 本质上它是一个偏移量,相对于库基地址的偏移量。

② 形成库文件:使用gcc,加-shared选项,告诉gcc生成动态库而不是可执行程序,-o后面是动态库的名字,前面加lib,后缀是.so

此时一个动态库就制作成了,同样的我们可以将生成动态库的步骤和前面的静态库一起写到Makefile中。动静态库都要形成 .o,到底是位置有关还是位置无关?最终带来的结果就是不一样。所以名字要区分开来,最后弄好.so文件的移动和删除就行了:

.PHONY:all
all:librtx.a librtx.so

librtx.a:mymath.o myprint.o
	ar -rc librtx.a mymath.o myprint.o
mymath.o:mymath.c
	gcc -c mymath.c -o mymath.o
myprint.o:myprint.c
	gcc -c myprint.c -o myprint.o

librtx.so:mymath_s.o myprint_s.o
	gcc -shared mymath_s.o myprint_s.o -o librtx.so
mymath_s.o:
	gcc -fPIC -c mymath.c -o mymath_s.o
myprint_s.o:
	gcc -fPIC -c myprint.c -o myprint_s.o

.PHONY:output
output:
	mkdir -p outputlib/include
	mkdir -p outputlib/lib
	cp -rf *.h outputlib/include
	cp -rf *.a outputlib/lib
	cp -rf *.so outputlib/lib

.PHONY:clean
clean:
	rm -rf *.o *.a *so outputlib

 make clean再make:

此时动静态库和静态库就一起制作完成了。

2.5 使用动态库

make output就和静态库一起放到一个目录下了:(这里把mytest程序删了)

 同样将制作的动态库打包,形成压缩包发送给同学。

(这里创建一个test2目录,把test里的main.c拷贝过去,再压缩包移动进去,然后解压)

使用动态库:

此时站在使用者的角度:

动态库的使用方法有四种:

2.5.1 安装在默认搜索路径

① 将头文件和库文件安装在系统默认搜索路径中,这里不演示了,和静态库的情况一样。

  • 将头文件复制到/sur/include路径下,将动态库文件安装在/usr/lib64路径下.
  • 并且在编译的时候使用-l选项告诉gcc使用的动态库名称。

这种做法是最不推荐的。

2.5.2 路径放在环境变量

② 将库文件路径放在环境变量里

不适用第一种方法,先试试告诉gcc头文件的路径,库的路径,还有库名。

gcc选项作用
-I(大写i)指定头文件路径
-L指定库文件路径
-l(小写L)指定库(掐头去尾后的库名)

和静态库的gcc选项一下:(输gcc指令的时候就想到gcc是默认使用动态链接的) 

输入ldd+程序名就验证了默认是使用动态链接的:

 为什么程序运行不了?

回顾:

  • 静态链接:将用到的库函数在编译的时候赋值到了源码中,所以编译成功就可以执行。
  • 动态链接:在编译的时候,只是将库的位置无关码(地址偏移量)复制到了源码中,等在运行可执行程序的时候再去动态库中根据偏移量找到应用的库函数。
  •  我们将头文件路径,库文件路径,库文件名告诉了gcc。
  •  编译完成以后,和gcc就没有关系了,接下来的执行是操作系统的事情。
  •  那么操作系统就必须得知道所使用的动态库在哪里。

所以接下来的任务就是告诉操作系统我的动态库在哪里。

  • 在执行程序的时候,操作系统会从环境变量LD_LIBRARY_PATH中读取动态库的路径。

(ld加载的意思,library库的意思,path路径的意思)将自己的动态库路径放入到环境变量中:

再执行刚刚生成的可执行程序,发现可以成功执行了,而且使用的是动态库中的函数接口。这种做法并不能永久生效,因为每次启动shell的时候,它都会从配置文件中重新加载环境变量,我们这里给LD_LIBRARY_PATH赋值只是暂时的。

为了不影响下面使用动态库的其它操作,这里重新登录一下xshell,就回到解放前了。

2.5.3 路径放在配置文件

将库文件路径放在配置文件中

在使用gcc编译的时候和上面一样,在告诉操作系统库文件路径时不再放入环境变量中,而是放入系统配置文件中。

  • /etc/ld.so.conf.d/
  • 在这个路径中有很多配置文件

随意看看一个配置文件,发现里面放的也是路径:

此时我们进入/etc/ld.so.conf.d/里创建一个配置文件,名字随意,后缀是.conf的就行,在里面把我们动态库的路径放进去。这里的所有操作都需root权限。这里换到root用户,学了sudo可以用sudo。

成功写入,此时切换到rtx2,回到原来路径:

 此时再运行时,发现还是找不到动态库,是因为没更新配置文件,切换到root更新再换回来:

此时操作系统就能找到我们对动态库了,而且这是一个永久的办法,不像将路径加到环境变量中那样是暂时的。

切换到root删掉再玩玩:

到这也学了个 更新配置文件的指令:ldconfig

但是这三种方法都这么麻烦,有没有简单点的?第4种就来了:

2.5.4 软链接到默认搜索路径

④ 软链接到系统默认搜索路径中

(依旧不太建议使用,感觉用第二种就好了)

在这个系统默认搜索库路径/usr/lib64下,有很多的库文件,还有很多的软链接库文件:

 root用户将动态库软链接到系统默认搜索路径下,此时系统就能找到库了。

ln -s 文件名 链接文件名 // 创建软连接

这里要带上绝对路径:(这里两个绝对路径最后的文件名应该是一样的) 

成功运行。

当然上面的各种使用动静态库的方法还有优化的地方或者别的方法,这里就不再演示了。

2.6 动态库加载和调用

gcc在编译的时候,只是将库中的库函数生成了一个位置无关码(相对偏移量)放在了程序中,在程序执行的时候,需要操作系统先将整个库加载到内存中,然后再根据位置无关码调用这个库函数。

  • 进程被创建以后,将对应的代码加载到内存中。
  • 进程虚拟地址空间的代码段通过页表映射到了内存中,其中就包括生成的位置无关码。
  • 操作系统将指定的动态库也加载到了内存中,由于占据内存空间,所以给它分配了地址。
  • 当进程执行到调用库函数时,操作系统根据位置无关码,在动态库基地址的基础上偏移一定量的地址找到要调用的库函数,并且调用。

以上就是动态库的加载和调用过程。

2.7 静态库加载和调用

  • 在gcc进行编译时,编译器将要调用的库函数复制到了程序中,形成了可执行程序。
  • 进程被创建后,操作系统将复制库函数的可执行程序加载到内存中去执行。

静态库的加载和操作系统没有关系,它是编译器完成的,就是将库函数源码复制一份到我们对源码中。

如果使用静态库,同一个库函数被使用了十次,编译器就会在对应位置复制十分,使用100次,就会复制一百次。

如果使用动态库,同一个库函数被使用十次,就会有十个位置无关码,使用100次就会有100个,在执行的时候,操作系统根据偏移量在内存中仅有的一个动态库中调用相应的函数。

所以使用静态库的程序都比使用静态库的程序要大,所占用的内存多。

本篇完。

下一篇:零基础Linux_16(基础IO_文件)笔试选择题:文件描述符+ionde和动静态库。

再下一篇是进程地址通信的内容了,语言开始向C++转变,环境学用一下VSCode。

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

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

相关文章

轻松虚拟gps定位 AnyGo中文 for mac

AnyGo是一款旨在帮助用户模拟和改变iPhone的GPS位置,以实现虚拟定位的功能。该软件适用于iOS设备,并提供了一系列强大的功能,让用户能够自由地模拟不同地理位置,以满足各种需求。 以下是AnyGo可能提供的一些主要功能和特点&#…

设置全局滚动条样式

需求:统一滚动条样式,不需要每次都要在页面一个一个的设置,整个项目只要内容超出了显示滚动条了就会是自己设置的那个滚动条样式显示 1.效果 2. 创建scroll.scss文件 滚动条样式如下,可以自行更改 /* // 滚动条样式重写-chrome …

新闻api接口,新闻资讯,社交媒体,体育赛事,全国热门带正文新闻查询API接口

一、接口介绍 解决同一类新闻在不同平台上的内容获取问题,在归档主流新闻平台的内容数据基础上,对外提供统一的调用方式来完成实时、最新的相关新闻的获取,极大方便各类企业在自有软件中集成新闻内容的功能。支持200余个新闻大站,…

官网安装Python包太慢?教你三种Pytorch的下载安装方式,保证你再也不用出现Error

这一期教大家如何在Anaconda中使用CUDA来进行加速、神经网络依赖cuDNN的下载安装,以及下载和安装Pytorch-GPU安装包的三种方式(conda、pip、轮子)。 还未下载安装 CUDA 和 Anaconda,请看往期文章,是全套系列的总结&am…

@Scope 注解失效了?咋回事

scope 属性,相信大家都知道,一共有六种: 取值含义生效条件singleton表示这个 Bean 是单例的,在 Spring 容器中,只会存在一个实例。prototype多例模式,每次从 Spring 容器中获取 Bean 的时候,才…

如何解决MidJourney错过付费后被暂停

问题 假定你已经成功订阅购买了 MidJourney 一段时间,下个月扣费周期到了。 如果你卡里余额不足,卡被封或失效了,或者你想着最近没啥用得上 MidJourney 的地方先省着不续费,等要用的时候就用不了。 如果想要去官网的续费页&…

软文撰写技巧:中小企业品牌形象塑造新方法

在激烈的市场竞争中,企业仅靠产品质量和服务态度很难站稳脚跟,在互联网时代下,品牌形象才是中小企业的取胜法宝,良好的品牌形象能够赢得消费者的信赖,还能让企业占据市场资源优势,软文推广就是帮助企业塑造…

机器人控制算法——两轮差速驱动运动模型

1.Introduction 本文主要介绍针对于两轮差速模型的逆运动学数学推导。因为在机器人控制领域,决策规划控制层给执行器输出的控制指令v(车辆前进速度)和w(角速度),因此,我们比较关心,当底层两个驱动电机接收到此信息,如何…

企业可以申请ov泛域名SSL证书吗

OV泛域名SSL证书是企事业单位和其他组织合法申请的数字证书,具有组织实名认证和域名解析授权的双重功能。与DV泛域名SSL证书相比,它的申请流程更加复杂,需要提交更多的资质和证明文件,当然,OV泛域名证书的安全等级也更…

如何提取视频文件中的元数据

最近在用gyroflow做视频稳定,但需要校准镜头,而校准需要知道拍摄时的一些设置参数,而用一些普通的工具获取到的视频元数据不全,所以就希望能有什么工具能获取到所有的元数据。找来找去发现Exiftool满足我的需求。 ExifTool 这是个…

机器人控制算法——移动机器人横向控制最优控制LQR算法

1.Introduction LQR (外文名linear quadratic regulator)即线性二次型调节器,LQR可得到状态线性反馈的最优控制规律,易于构成闭环最优控制。LQR最优控制利用廉价成本可以使原系统达到较好的性能指标(事实也可以对不稳定的系统进行整定) ,而且方法简单便于实现 ,同时利用 Ma…

vue3 封装自定义指令,监听元素宽高的变化

最近做一个项目,涉及到echart图,要去根据父元素去自适应宽高,所以需要监听到元素的宽高变化、 因为是监听某一元素的宽高变化,所以这里用的是ResizeObserver. ResizeObserver是可以监听到DOM元素,宽高的变化&#xf…

HarmonyOS/OpenHarmony原生应用开发-华为Serverless服务支持情况(三)

文档中的TS作者认为就是ArkTS之意。 一、云函数,从开发文档上已经说明,是已经支持HarmonyOS/OpenHarmony(Stage模型-API9),但是在开发语言上,没有ArkTS,是否支持,正在实践测试中。 文档地址: …

【PCIE732】基于Kintex UltraScale系列FPGA的2路40G光纤通道适配器(5GByte/s带宽)

PCIE732是一款基于PCIE总线架构的高性能数据传输卡,板卡具有1个PCIe x8主机接口、2个QSFP 40G光纤接口,可以实现2路QSFP 40G光纤的数据实时采集、传输。板卡采用Xilinx的高性能Kintex UltraScale系列FPGA作为实时处理器,板载2组独立的72位DDR…

计算机网络面试常问问题--保研及考研复试

前言: Hello大家好,我是Dream。今年保研上岸山东大学人工智能专业 (经验贴),现在将我自己的专业课备考知识点整理出来,分享给大家,希望可以帮助到大家!这是重点知识总结,…

idea插件开发javax.net.ssl.SSLException: No PSK available. Unable to resume.

idea插件开发,编译出错 javax.net.ssl.SSLException: No PSK available. Unable to resume.at java.base/sun.security.ssl.Alert.createSSLException(Alert.java:129)at java.base/sun.security.ssl.Alert.createSSLException(Alert.java:117)at java.base/sun.security.ssl.…

【网络基础】IP 子网划分(VLSM)

目录 一、 为什么要划分子网 二、如何划分子网 1、划分两个子网 2、划分多个子网 一、 为什么要划分子网 假设有一个B类IP地址172.16.0.0,B类IP的默认子网掩码是 255.255.0.0,那么该网段内IP的变化范围为 172.16.0.0 ~ 172.16.255.255,即…

202、RabbitMQ 之 使用 fanout 类型的Exchange 实现 Pub-Sub 消息模型---fanout类型就是广播类型

目录 ★ 使用 fanout 类型的Exchange 实现 Pub-Sub 消息模型代码演示:生产者:producer消费者:Consumer01消费者:Consumer02测试结果 完整代码ConnectionUtilPublisherConsumer01Consumer02pom.xml ★ 使用 fanout 类型的Exchange …

干货|小白也能自制电子相册赶紧码住~

你是否想拥有一个独一无二的电子相册,却又苦于不知道如何下手?今天教你一个简单的方法,即使你是小白,也能轻松自制电子相册! 一、选择合适的工具 首先,你需要选择一个合适的工具来制作电子相册。有很多工具…

四化智造MES(WEB)与金蝶云星空对接集成原材料/标准件采购查询(待采购)连通采购订单新增(原材料采购-采购订单(变更)-TEST)

四化智造MES(WEB)与金蝶云星空对接集成原材料/标准件采购查询(待采购)连通采购订单新增(原材料采购-采购订单(变更)-TEST) 对接系统四化智造MES(WEB) MES建立统一平台上通过物料防错防错、流程防错、生产统…