目录
[1. 介绍](#1. 介绍)
[2.1 如何理解硬链接?](#2.1 如何理解硬链接?)
[2.2 如何理解软连接?](#2.2 如何理解软连接?)
[1.1 使用](#1.1 使用)
[1.2 什么是库?](#1.2 什么是库?)
[2.1 静态库](#2.1 静态库)
[2.2 动态库:](#2.2 动态库:)
软硬链接
1. 介绍
1.1 软连接
是一个独立文件,具有独立的 inode ,也有独立的数据块,它的数据块里面保存的是指向的文件的路径,公用 inode
建立软连接
ln -s myfile.txt soft_file.link
1.2 硬链接
硬连接的 inode 是一样的,不是一个独立的文件,本质其实就是在特定目录的数据块中新增,文件名和指向的文件的 inode 编号的映射关系!!
ln 建立连接,由后者指向前者,硬链接数
观察 inode 编号可以发现,软硬链接的区别:是否具有独立的Inode。
软链接具有独立的Inode:可以被当作独立的文件看待。
2.理解
2.1 如何理解硬链接?
任意一个文件,无论是目录,还是普通文件,都有 inode
每一个 inode 内部,都有一个叫做引用计数的计数器,有多少个文件名指向我
通常用来进行路径定位,采用硬链接,可以进行目录间切换
硬链接没有独立的Inode,那硬链接该如何理解呢?或者建立一个硬链接究竟是做了什么?
通过实践我们可以发现,创建目录会发现硬链接数会增加
在目录当中的运用
删文件就是解除映射关系,连接数--
这就是为什么硬链接不会一次被删除
应用场景
一个. 表示当前目录,inode 是一样的,相当于在另一个场景下的重命名,..为 3,返回的是上级路径的 inode
eg: / 硬链接数为 21,可知旗下有 19 个目录
❓ linux 不允许对目录硬链接,为什么?
如下图:
那为什么目录内部有./..,不是目录的硬链接吗??
系统搜索时,并没有调用./..,诞生相对路径是为了方便搜索,也是当前目录的内容,相当于这个的硬链接是由系统设计好了的
2.2 如何理解软连接?
特别像我们在 windows 当中的创建快捷方式,路径直接跳转
🗝️ 为什么要有?
上线了一个软件,要给客户看,可执行程序 exe 路径太深了,这时候可以通过提出来 ln -s ,形成软连接,就能直接 test.exe ,不带路径执行啦
软链接有自己独立的Inode和内容,当我们删除myfile.txt,软链接就出错,但是我们知道Inode还在。换一个角度思考,怎么不算是一种置后的重命名呢
软链接里面保存的是与文件所处路径的映射关系。
当把文件删除时,这个映射关系就出错了。unlink 的使用
注:对文件的权限最终解释权归目标文件,软连接不能影响
软连接可以和之后的动态库结合使用
动静态库
1.介绍
静态库(.a结尾) :程序在编译链接的时候把库的代码拷贝到可执行文件中。程序运行的时候将不再需要静态库。
动态库(.so结尾) :程序在运行的时候才去加载动态库的代码,多个程序共享使用库的代码。
各自缺点:
动态库:受到库升级或被删除等影响
静态库:形成可执行程序太大
命名: 例如动态库 libxxx.so
lib前缀**.** so后缀去掉前缀和后缀,剩下的就是库名称
1.1 使用
在Linux中,动态链接和静态链接是链接器在编译程序时使用库的不同方式。动态链接器在运行时加载共享库(通常带有 .so
后缀),而静态链接器在编译时将库的代码直接合并到可执行文件中(通常带有 .a
后缀)。以下是对您提供内容的格式化:
在Linux中使用GCC编译静态链接的可执行文件
命令行示例
gcc test.c -o mytest -static
注意
- 如果系统中只提供
.so
文件,则只能使用动态链接。- 如果只提供
.a
文件,即使不指定-static
,也是静态链接。- 如果动态库和静态库都存在,默认使用动态库。
安装C静态库
sudo yum install -y glibc-static
安装C++静态库
sudo yum install -y libstdc++-static
关于Linux的动静态库问题
- 在Windows下,原理是一样的。
- 默认形成可执行程序:动态链接
- Windows下动态库后缀为
.dll
,静态库后缀为.lib
- 注意 :系统本身为了支持编程,除了提供标准库
.h
,还提供了标准库的实现.so
/.a
1.2 什么是库?
程序在经过预处理,编译,汇编,之后,就要链接了,链接就是将.o文件和库链接起来形成可执行程序。
下面我们将演示类似与库的思想。
vim 小技巧:
在 Vim 编辑器中,使用 :vs(vertical split)命令可以创建一个垂直分割的窗口。若要在这两个窗口之间切换,可以使用下面方法:在 Vim 中,Ctrl + w 是一个前缀键,用于执行与窗口相关的操作,而
j
、k
、h
和l
键用于指定方向
库的连接
下面是一个简单的示例,展示了如何编写一个 add
函数,并且如何将它们编译成目标文件(.o
文件),最后将这些目标文件链接起来形成一个可执行文件。
首先,我们需要创建 2 个源文件:
my_add.c
- 包含add
函数的实现。main.c
- 包含main
函数,用于调用add
函数。
my_add.c
// my_add.c
int add(int a, int b) {
return a + b;
}
main.c
// main.c
#include <stdio.h>
extern int add(int a, int b);
int main() {
int a = 10;
int b = 5;
printf("Add: %d + %d = %d\n", a, b, add(a, b));
return 0;
}
extern
告诉编译器 add
函数存在,但它的定义(函数体)在其他地方
现在,我们将这些源文件编译成目标文件,并链接它们来创建一个可执行文件。
编译和链接步骤
在 Linux 命令行中执行以下命令:
gcc -c my_add.c -o my_add.o # 编译 my_add.c 到 my_add.o
gcc -c main.c -o main.o # 编译 main.c 到 main.o
gcc -o mymath main.o my_add.o # 链接 main.o, my_add.o 到 mymath
最后,运行可执行文件 mymath
:
./mymath
这应该会输出:
这样,我们就测试了 Linux 下的 GCC 编译器如何将 .o
文件链接起来形成可执行文件。
2.生成
2.1 静态库
为了将上诉代码接口给同学使用,并且不暴露源码,此时我们就可以选择将它制作成库。
制作如下:
可以先将.h 和.c 打包成 .o
库的原理和上面类似,只是将所有的.o为后缀的文件打包在了一起,形成了一个库,在使用的时候直接使用这个库就可以。
- 指令:ar -rc libname.a [所有待打包.o]
- 作用:将所有待打包的.o文件制作成静态库。
该指令中,ar是gnu的归档工具(Archive files),rc表示replace和create。
❗ 方法 2: 一步到位
libmylib.a:add.o
ar -rc libmylib.a add.o
add.o:add.c
gcc -c add.c -o add.o
sub.o:subc
gcc -c sub.c -o sub.o
.PHONY:output
output:
mkdir -p myliba/include
mkdir -p myliba/lib
cp -f *.h myliba/include
cp -f *.a myliba/lib
.PHONY:clean
clean:
rm -rf *.o libmylib.a myliba
我们可以写一个这样的Makefile,直接一步make到位,生成一个库文件。
- 将所用到的头文件全部放在myliba/include目录下。
- 将静态库文件放在myliba/lib目录下。
可以通过指令来查看我们制作的库。
- 指令:ar -tv 库文件名
- 功能:列出静态库中的文件和详细信息。
再使用打包工具tar,将库和头文件一起打包,如上图所示,将压缩包发生给同学。
此时我们的库就制作成了。
使用静态库:
此时我们站在使用者的角度,也就是那个同学的角度。
- 安装在系统中
- 头文件默认搜索路径:/usr/include;
- 库文件默认搜索路径:/usr/lib64;
gcc不知道该用这个默认路径下的哪个库,要告诉编译器使用该库
在使用gcc编译的时候告诉编译器要使用的库名(掐头去尾后的库名),此时就能编译成功了,而且成功调用了同学给我们的库。
- -l选项:指定使用的库名(掐头去尾后的库名)。
- 注意:l可以和名字合在一起,如-lmylib。
这种方式不建议使用,因为第三方库没有经过检测,会污染其他库和头文件。
比较好的是下一种方式。
- 告诉编译器头文件路径,库路径,库名
|---------|---------------|
| 选项 | 作用 |
| -I(大写i) | 指定头文件路径 |
| -L | 指定库文件路径 |
| -l(小写L) | 指定库(掐头去尾后的库名) |
这样一来,一个第三方库就可以正常使用了。
2.2 动态库:
- 形成位置无关码
|---------|---------|
| 选项 | 作用 |
| -fPIC | 生成位置无关码 |
| -shared | 生成动态库 |
位置无关码就类似于箭头右侧30米处的30。 本质上它是一个偏移量,相对于库基地址的偏移量。
如果这不是100米的跑道,而是变成了200米,500米呢?星星的绝对位置会变化,但是它的相对位置永远不变,处于箭头右侧30米处
- 形成库文件
- 我们将头文件路径,库文件路径,库文件名告诉了gcc。
- 编译完成以后,和gcc就没有关系了,接下来的执行是操作系统的事情。
- 那么操作系统就必须得知道所使用的动态库在哪里。所以我们可以进行如下操作
每次启动shell的时候,它都会从配置文件中重新加载环境变量,我们这里给LD_LIBRARY_PATH赋值只是暂时的
**方法二:**软链接到系统默认搜索路径中
在 /usr/lib64 这个系统默认搜索库路径下,有很多的库文件,还有很多的软链接库文件,我们可以自主来实现链接
将同学给我们的动态库软链接到系统默认搜索路径下,如上图所示。此时系统就能找到库啦