Linux软硬链接与动静态库
软硬链接
创建软连接
ln -s name.txt name.link
创建硬链接
ln name.txt name.link
属性
软连接是一个独立的文件,而硬链接不是独立的文件,它的inode用的是目标文件的inode。属性中第三列是硬链接数。
软连接包含目标文件所对应的路径字符串(快捷方式),打开它就是打开对应目标文件:
硬链接就是一个文件名和inode的映射关系,建立硬链接就是在指定目录下,添加一个文件名和inode的映射关系。如下面有两个硬链接和引用计数:
删掉一个硬链接,发现是硬链接数由3变成2,当硬链接数为0时,该文件就被彻底删除了(inode置0)。
因此,这个硬链接数就是文件的磁盘级引用计数,表示有多少的文件名字符串通过inode指向目标文件。
作用
软连接是为了更快的更便捷的找到该文件,硬链接可以做文件备份。
目录文件引用计数是2,因为该目录里面还有一个"."文件:
在目录里创建一个目录,会发现引用计数变成3,这是因为该目录中有一个".."文件指向的是上级目录,因此一个目录中有几个目录就是计数-2:
但是,Linux系统不允许建立目录指向它的硬链接,这是为了避免路径环绕,而"."和".."文件名是固定的,系统会识别不会造成路径环绕。
动静态库
查看可执行程序依赖的库
ldd exe
在Linux中.so结尾是动态库,.a结尾是静态库;在Windows中.dll是动态库,.lib是静态库。
静态库
.o的目标文件叫可重定位目标文件,最后可以形成exe文件。
现有一个头文件add.h和源文件add.c:
//add.h
#include<stdio.h>
int add(int a,int b);//add.c
#include"add.h"
int add(int a,int b)
{return a + b;
}
将add.c编译成目标文件,并把add.o和add.h拷贝到另一个目录下,编写main.c代码:
gcc -c add.c
#include"add.h"
int main()
{int a = 3;int b = 4;printf("a + b = %d\n",add(a,b));return 0;
}
编译,发现可以形成可执行程序,运行正确,这说明形成可执行程序不一定需要源代码
但是当目标文件太多,这样所也不是很好,因此可以对其打包。
形成静态库指令
库文件本质是把目标文件打包,可以提高开发效率。
ar -rc mylib.a *.o
编译,仍然可以使用
gcc main.c mylib.a
先创建一个文件下,形成如下结构:
将main.c编译(库名是去掉lib和后缀):
gcc main.c -I ./include -L ./lib/ -l my
-I 指定用户自定义的头文件路径
-L 指定用户自定义的库文件路径
-l 执行确认的第三方库名称
当然,如果不想带-I也可以在包含头文件时写明路径:
#include "include/add.h"
书名号表示在系统目录下搜索头文件,双引号表示在当前目录下寻找头文件。
动态库
形成动态库
制作动态库首先也要把源文件编译成为可执行程序,但是这里多了一个选项:
gcc -fPIC -c add.c
-fPIC 表示产生位置无关码
生成动态库:
gcc -shared *.o -o libmy.so
形成如下结构:
这里按照之前的编译方式-I,-L,-l都带上,结果发现自己写的库找不到,并且不能运行:
这里是因为路径只是告诉给编译器,编译器编过了,但是运行时找不到(静态库直接拷贝不需要),因此要配置路径。
动态库加载
系统默认查找路径是/lib,第一种方法是直接拷贝过去,但是不推荐;第二种方式是搞一个库的软连接到/lib中:
ln -s /home/syx/linux/linux/dll/use/lib/libmy.so /lib/libmy.so
第三种方式修改环境变量LD_LIBRARY_PATH:
LD_LIBRARY_PATH=$LD_LIBRARY_PATH:yourlibpath
如果没有记得export,想要永久保存要在.bashrc配置。
第四种方式是在系统配置,在该文件夹建立.conf文件,里面写着绝对路径就行,然后ldconfig。
动态库要映射到程序地址空间的共享区,不同程序使用一份动态库代码,因此动态库也叫共享库。
ELF格式:可执行程序要有头部,属性,汇编语句地址(平坦模式,给定一块区域依次编指)
这里也是虚拟地址(逻辑地址,平坦模式等价),ELF+加载器可以找到各个区域的起始结束地址,main函数地址,加载器:
创建一个进程,他的地址空间mm_struct初始信息就是由可执行程序来的,因此,虚拟地址创建需要有OS,编译器,加载器三方支持。
大致流程:创建内核数据结构,加载代码,虚拟地址页表左侧虚拟地址,右侧物理地址,PC找到main函数入口开始执行,库没有加载就要加载库,把库的地址映射到共享区。
管理库也要有对应的结构体,遍历结构体链表就知道该库是否加载。