目录
- 1. 软硬链接
- 1.1 硬链接
- 1.2 软链接
- 1.3 软硬链接的对比
- 1.4 软硬链接的用途
- 2. 什么是库
- 3. 制作动静态库
- 3.1 静态库
- 3.1.1 静态库的生成
- 3.1.2 静态库的使用
- 3.2 动态库
- 3.2.1 动态库的生成
- 3.2.2 动态库的使用
- 问题1:
- 问题2:
1. 软硬链接
1.1 硬链接
我们看到, 真正找到磁盘上文件的并不是文件名, 而是inode, 其实在linux中可以让多个文件名对应于同一个inode.
- abc和def的链接状态完全相同, 他们被称为指向文件的硬链接, 内核记录了这个连接数, inode789665的硬连接数为2.
- 我们在删除文件时干了两件事情, 1. 在目录中将对应的记录删除 2. 将硬连接数-1, 如果为0, 则将对应的硬盘释放
1.2 软链接
硬链接是通过inode引用另外一个文件, 软链接是通过名字引用到另外一个文件, 但实际上, 新的文件和被引用的文件的inode不同, 应用场景上可以想象成一个快捷方式, 在shell中的做法:
1.3 软硬链接的对比
- 软链接是独立文件
- 硬链接只是文件名和目标文件inode的映射关系
1.4 软硬链接的用途
硬链接:
- . 和…就是硬链接
- 文件备份
软链接
- 类似快捷方式
2. 什么是库
库是写好的现有的, 成熟的, 可以复用的代码. 现实中每个程序都要依赖很多基础的底层库, 不可能每个人的代码都是从零开始, 因此库的存在意义非同寻常.
本质上来说库是一种可执行代码的二进制形式, 可以被操作系统载入内存执行. 库有两种:
- 静态库: .a[Linux], .lib[windows]
- 动态库: .so[Linux], .dll[windows]
Centos 动静态库
C:
C++:
3. 制作动静态库
预备工作:
3.1 静态库
-
静态库(.a) : 程序在编译链接的时候把库的代码链接到可执行文件中, 程序运行的时候将不再需要静态库.
-
一个可执行程序可能用到许多的库, 这些库的运行有的是静态库, 有的是动态库, 而我们的编译默认为动态链接库, 只有在该库下找不到动态.so 的时候才会采用同名静态库, 我们也可以使用gcc 的 -static 强制设置链接动态库.
3.1.1 静态库的生成
注释: ar 是 gnu归档工具 rc表示(replace and create)
t: 列出静态库中的文件
v: verbose 详细信息
3.1.2 静态库的使用
在任意目录下, 新建 main.c 引入库头文件
#include "my_stdio.h"
#include "my_string.h"
#include <stdio.h>
int main()
{const char *s = "abcdefg";printf("%s: %d\n", s, my_strlen(s));mFILE *fp = mfopen("./log.txt", "a");if(fp == NULL) return 1;mfwrite(s, my_strlen(s), fp);mfwrite(s, my_strlen(s), fp);mfwrite(s, my_strlen(s), fp);mfclose(fp);return 0;
}
- 场景一: 头文件和库文件都已经安装到系统路径下
头文件安装到系统路径下, 图下:
库文件安装到系统路径下, 图下:
此时进行gcc main.c 进行编译会出现链接错误, 这是因为系统路径下gcc默认只会链接C的库, 第三方库需要进行指明
使用如下代码:
$ gcc main.c -lmystdio
//-l 表示指定链接的库, 空格可带可不带
- 场景二: 头文件和库文件和我们自己的源文件在同一个路径下
头文件的查找规则是先查找同级目录, 在查找系统目录, 很显然头文件这里不会报错, 但是库找不到, 库只会在系统路径下查找, 这时候需要指明系统路径, 指明路径之后并且指明链接的库
使用如下代码:
$ gcc main.c -L. -lmymath
//-L表示指明库的路径
- 场景三: 头文件和库文件都不在当前路径下, 都有自己独立的路径
找不到头文件 , 头文件和main.c不在同一级目录下, 也不在系统目录下
此时头文件找到了, 现在库找不到了
有库的路径但不知道链接哪个库
此时编译成功.
使用如下代码:
$ gcc main.c -I头⽂件路径 -L库⽂件路径 -lmymath
// -I指明头文件路径
总结:
- 测试目标文件生成后, 静态库删掉, 程序照样可以运行
- 库文件名称和引入库文件名称: 去掉前缀lib, 去掉后缀 .so , .a : 如: libc.so -> c
3.2 动态库
- 动态库(.so) : 程序在运行的时候才去链接动态库的代码, 多个程序共享使用库的代码
- 一个与动态库链接的可执行文件仅仅包含他用到的函数入口地址的一个表, 而不是外部函数所在目标文件的整个机器码
- 在可执行文件开始运行以前, 外部函数的机器码由操作系统从磁盘上的该动态库中复制到内存中, 这个过程称为动态链接(dynamic linking)
- 动态库可以在多个程序间共享, 所以动态链接使得可执行文件更小, 节省了磁盘空间. 操作系统采用虚拟内存机制允许物理内存中的一份动态库被要用到该库的所有进程公用, 节省了内存和磁盘空间.
3.2.1 动态库的生成
- shared: 表示生成共享库格式
- fPIC: 产生位置无关码(position independent code)
- 库名规则: libxxx.so
3.2.2 动态库的使用
- 场景一: 头文件和库文件安装到系统路径下
此时我们直接编译会造成链接错误, 和静态库一样
使用如下代码:
$ gcc main.c -lmystdio
场景二: 头文件和库文件和我们自己的源文件在同一个路径下
$ gcc main.c -L. -lmymath // 从左到右搜索-L指定的⽬录
场景三: 头文件和库文件都有自己的独立路径
$ gcc main.c -I头⽂件路径 -L库⽂件路径 -lmymath
ldd查看可执行文件依赖哪些库
问题1:
如果我把库中的文件都删掉了, 就会报如下错误
因为是动态链接的, 删掉了就会造成链接错误, 而静态链接不会
解决方案:
- 拷贝.so 文件到系统共享路径下, 一般指/usr/lib, /usr/local/lib, /lib64或者开篇指明的库路径等
- 向系统共享路径下建立同名软连接
- linux系统中, OS会查找动态库和环境变量, 更改环境变量 : LD_LIBRARY_PATH
但是重启xshell之后自己导入的环境变量就没了, 此时可以添加到 .bashrc中
- ldconfig方案: 配置/etc/ld.so.conf.d/, ldconfig更新
把库的路径写入配置文件中, 系统会在配置文件中的路径寻找库, 自己创建一个配置文件, 如下
然后 命令行输入ldconfig, 此时即可
程序运行时和gcc没关系了, gcc是告诉编译器, 接下来OS要加载你的程序
如何给系统指定路径, 查找我自己的动态库, 如上就是解决方案
问题2:
如果同时提供.so .a gcc/g++默认使用什么库呢?
动态库
如果想要静态链接, 需要添加-static
注意
如果你要强制静态链接, 必须提供对应的静态库
如果你只提供静态库, 但是连接方式是动态链接, gcc, g++没得选, 只能针对你的.a局部采用静态链接, 所以把系统路径下的库删除, 运行也能跑
完, 您的点赞收藏是我更新的最大动力!!!