• 作者:老汪软件技巧
  • 发表时间:2024-01-01 15:00
  • 浏览量:

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

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

软硬链接的区别:

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

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

1.1创建软链接

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

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

编译运行:

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

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

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

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

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

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

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

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

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

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

从上面的现象可以得出一个结论:软链接和inode无关,只和路径名有关。

也就是说,建立软链接后,并不是链接文件和另一个文件的inode绑定了,只是和文件名绑定了。

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

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

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

编译运行:

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

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

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

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

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

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

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

1.2 创建硬链接

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

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

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

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

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

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

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

删掉test.exe的硬链接:

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

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

1.3 硬链接数和

前一篇:

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

2. 动静态库

动静态库即动态库( ) 与静态库( ) 。

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

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

学的;

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

2.1 制作静态库

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

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

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

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

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

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

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

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

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

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

制作静态库:

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

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

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

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

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

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

成功链接。

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

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

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

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

2.2 查看和打包静态库

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

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

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

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

复习一下:

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

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

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

make:

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

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

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

2.3 使用静态库

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

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

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

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

运行下main.c:

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

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

2.3.1 安装在默认搜索路径

①安装在系统中

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

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

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

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

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

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

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

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

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

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

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

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

gcc选项作用

-I(大写i)

指定头文件路径

-L

指定库文件路径

-l(小写L)

指定库(掐头去尾后的库名)

现在试试第二种方法:

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

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

2.4 制作动态库

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

制作动态库:

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

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

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

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

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

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

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

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

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

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

此时一个动态库就制作成了,同样的我们可以将生成动态库的步骤和前面的静态库一起写到中。动静态库都要形成 .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

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

make clean再make:

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

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

2.5使用动态库

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

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

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

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

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

使用动态库:

此时站在使用者的角度:

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

2.5.1 安装在默认搜索路径

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

这种做法是最不推荐的。

2.5.2路径放在环境变量

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

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

gcc选项作用

-I(大写i)

指定头文件路径

-L

指定库文件路径

-l(小写L)

指定库(掐头去尾后的库名)

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

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

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

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

为什么程序运行不了?

回顾:

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

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

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

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

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

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

2.5.3路径放在配置文件

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

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

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

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

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

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

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

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

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

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

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

切换到root删掉再玩玩:

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

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

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

2.5.4软链接到默认搜索路径

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

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

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

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

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

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

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

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

成功运行。

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

2.6 动态库加载和调用

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

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