软硬链接和动静态库
- 1.软硬链接
- 2.动态库和静态库
- 2.1理解现象
- 2.2静态库的设计
- 2.3动态库
- 2.4动态库的配置
- 2.5动态库的理解
🌟🌟hello,各位读者大大们你们好呀🌟🌟
🚀🚀系列专栏:【Linux的学习】
📝📝本篇内容:软硬链接;动静态库
⬆⬆⬆⬆上一篇:基础IO(二)
💖💖作者简介:轩情吖,请多多指教(> •̀֊•́ ) ̖́-
1.软硬链接
①软链接是一个独立的链接文件,有自己的inode编号,因此也有自己的inode属性和内容,其内容是自己所指向的文件的路径,类似于windows快捷方式
创建软链接命令:ln -s
②硬链接和目标文件共用同一个inode编号,因此硬链接一定和目标文件使用同一个inode(属性)。硬链接没有独立的inode,在当前目录的内容中建立新的文件名和老的inode的映射关系
创建硬链接的命令:ln
仔细观察红色圈出来的地方,为什么它是2?
其实它指的是硬链接数,在inode属性中有一个来变量记录这个
大家注意看红色圈出来的地方,其中创建一个dir目录后,它的硬链接数为2,这是因为它本身是一个,再加上其内部的 . .,用来切换到上一级路径,也是指向这个目录,因此为2,。而这个目录中的 . 为3个硬链接数的原因是本身一个,上一级目录下它本身的目录名算一个,再者dir中有一个. .切换到上级目录也算一个。
但是只有OS能给目录建立硬链接,因为我们自己建立的容易造成环路路径问题(例如使用find,会引起死循环)
2.动态库和静态库
系统已经预装了C/C++的头文件和库文件,头文件是提供方法说明,库提供方法的实现,头和库是有对应关系的,是要组合在一起使用的
头文件是在预处理阶段就引入的,链接本质其实是链接库
查看C动态库:/usr/lib64/libc* 或 /lib64/libc*
查看C++动态库:/usr/lib64/libstdc* 或 /lib64/libstdc*
查看头文件:/usr/include
2.1理解现象
a.所有,我们在VS2019/2022下安装开发环境——安装编译器软件,安装要开发的语言配套的库和头文件
b.我们在使用编译器,都会有语法的自动提醒功能,需要包含头文件的。语法的提醒本质:编译器或编辑器,它会自动的将用户输入的内容,不断在被包含的头文件中进行搜索,自动提醒功能是依赖头文件的
c.我们在写代码的时候,我们的环境怎么知道我们的代码中有哪些地方有语法报错?其实是有命令行模式,还有其他自动化的模式帮我们不断在进行语法检查
d.库:静态库(.a);动态库(.so)
e.库名:lib stdc++.so.6
f.一般云服务器,默认只会存在动态库,不存在静态库,静态库需要单独安装
2.2静态库的设计
我们首先写一个函数的实现
再写一个普通的.c文件,其中包含了函数原型的头文件
此时我们再考虑一个问题,当我们的c文件在编译时,只要有函数的声明就不会出现报错,因为编译器认为,在后面链接的时候能够找到对应的实现,也就说到链接阶段时,.c文件已经变成了.o文件。因此我们可以认为我们的静态库里内容也应该为.o再被封装。
静态库设计命令:ar -rc libxxxx.a xxx.o
当我们有了库,接下来就要将库引入我们的项目,必须让编译器找到头文件和库文件
第三方库的使用:
①需要指定的头文件和库文件
②如果没有默认安装到系统gcc、g++默认的搜索路径下,用户必须指明对应的选项,来告诉编译器:a.头文件在哪 b.库文件在哪 c.库文件具体是谁
③将我们下载下来的库和头文件,拷贝到系统默认路径下——linux下安装库,对任何软件而言,安装和卸载的本质就是拷贝到系统特定的路径下
④如果我们安装的库是第三方的(除语言、操作系统接口)库,我们要正常使用,即便是已经全部安装到了系统中,g++/gcc必须要用-l指明具体库的名称
理解现象:
无论你是从网络中直接下好的库,或者是源代码(编译方法)——>make install 安装的命令——>cp,安装到系统中,我们安装大部分指令、库等都需要sudo或root操作
2.3动态库
在形成动态库时,我们的.o文件不能再是普通的二进制,而是与位置无关码
上图是生成动态库的命令
可是为什么生成了可执行程序执行不了呢,这是因为仅仅是把动态库告诉了编译器,并没有告诉OS。OS运行的时候,因为.so并没有在系统的默认路径下,所以OS找不到。而静态库的链接原则是将用户使用的二进制代码直接拷贝到目标可执行程序中,而动态库不会
2.4动态库的配置
①环境变量:LD_LIBRARY_PATH(临时方案)
②软链接
③配置文件方案
2.5动态库的理解
静态链接形成的可执行程序本身就有静态库中对应的方法实现,但是静态链接非常占用资源(磁盘、可执行程序体积变大、加载占用内存、下载周期变长、占用网络资源)
其中我们要先明白,代码数据本身就是在物理内存上的,之后在通过映射到虚拟地址空间
我们的可执行程序中的并没有函数的实现,只有函数的地址,就如上图的例子,进程A中有一个add函数,他只有一个地址,当运行进程A时,创建task_struct,并且有了虚拟地址空间,此时进程A中由于使用了math这个动态库,因此把add函数加载到内存中,并映射到内存映射区(共享区),当我们把库加载到内存,映射到进程的地址空间后,我们的代码执行库中的方法,就依旧还是在自己的地址空间内进行了函数跳转。
但是我们这样做必定会遇到一个问题:不同的进程,运行程度不同,当加载好几个进程,需要使用的第三方库是不同的,注定了每一个进程的共享空间中空闲位置是不确定的。因此地址分为绝对编址和相对编址,动态库中的所有编址,都是偏移量,默认从0地址开始。当一个库,真正的被映射进地址空间的时候,它的起始地址才能真正确定,所谓之前提到的于位置无关码,其实就是动态库中地址都是偏移量
补充:①动态库和静态库同时存在,系统默认采用动态链接
②编译器,在链接的时候,如果提供的库既有动又有静,优先动,只有静,没法,只能静态链接
🌸🌸基础IO(三)的知识大概就讲到这里啦,博主后续会继续更新更多Linux的相关知识,干货满满,如果觉得博主写的还不错的话,希望各位小伙伴不要吝啬手中的三连哦!你们的支持是博主坚持创作的动力!💪💪