动态库和静态库
- 软链接
- 硬链接
- 硬链接要注意
- 自定义实现一个静态库(.a)
- 解决、使用方法
- 静态库的内部加载过程
- 自定义实现一个动态库(.so)
- 动态库加载过程
- 静态库和动态库的特点
软链接
命令:
ln -s 源文件名 目标文件名
软链接是独立连接文件的,他有自己的inode number,有自己的inode属性和内容。
软链接内部存放的是自己所指向文件的路径。
现实中,我们软链接的应用有,例如电脑桌面的快捷模式等。
inode number
不相同
硬链接
命令:
ln 源文件目标文件
硬链接,通过inode来重新链接一份文件,此文件的inode跟原文件的inode是一样的,可以理解为原文件的浅拷贝,两个文件内容是共享的,不管增加还是删除,这是因为他们的inode是相同的
inode
相等
硬链接要注意
硬链接是不可以给目录做硬链接的,这是因为当用户进行对目录硬链接时,容易造成环路问题,os无法识别那个是自己定义的硬链接。
了解目录隐藏文件
.
..
自定义实现一个静态库(.a)
- 系统已经预装了c/c++的头文件和库文件,头文件提供方法说明,库提供方法的实现,头和库是有对应关系的,是要组合在一起使用的。
- 头文件是在预处理阶段就引入的,链接本质就是链接库
方法一:头文件和.o文件在一块可直接应用
形成静态库文件
命令:ar -rc lib库名.a *.o
方法二:我们将库和头文件都带入到另一个文件进行重新编译运行
当我们使用时发现不可以正常使用
这是因为我们引入了第三方的库,编译器目前不认可这个库,需要我们手动
解决、使用方法
第三方库的使用错误解决方法:
- 需要指定所用的头文件和库文件
- 如果没有安装到对应的编译器路径下,用户必须指明对应的选项,告知编译器,头文件在哪里,库文件在哪里,库文件具体是谁。
- 将三方库拷贝到编译器路径下时,我们进行编译时,也需要使用
-l
指定具体使用的库
l
:只要库名即可(去掉lib以及版本号)
L
:链接库所在的路径
I
:链接库的头文件所在路劲
方法三:头文件放到include目录下,库文件放到lib目录下,将两个目录打包交给别人
静态库的内部加载过程
静态库不需要加载,静态库是将代码直接拷贝到程序中,因此内存中的代码和数据可能会存在多分,造成空间浪费。把静态库代码拷贝到内存中的代码区。
当我们将静态库加载过一次之后,在删除静态库后还是可以正常跑的
自定义实现一个动态库(.so)
形成动态库文件
shared
: 表示生成共享库格式fPIC
:产生位置无关码
动态库采用的是相对位置编址。只保存相对函数之间的偏量值(库起始地址+函数之间偏移量)
而静态库采用的为绝对地址,如果我们库位置有所变动,他就需要重新拷贝
与静态库使用发放三方式相同,但是需要注意的方面不一样
头文件放到include目录下,库文件放到lib目录下,将两个目录打包交给别人
为什么静态库就可以找到而动态库就不可以呢?
这是因为静态库的链接原则是将用户使用的二进制代码直接拷贝到目标可执行程序中但是动态库不会。
如何解决os找不到动态库问题?
- 配置环境变
LD_LIBRARY_PATH
(临时方案,当系统重启后需要重新配置)
- 软连接方案
去掉软连接方法
sudo unlink /lib64/libmy_math.so
- 配置文件方法
ls /etc/ld.so.conf.d
查看本地的路径配置文件
sudo touch /etc/ld.so.conf.d/myPath.conf
添加创建本地路径配置文件
系统重新启动也是可以直接使用的,因为我们已经把环境配置好了
动态库加载过程
动态库通过fPIC形成位置无关码,采用相对编址的方式,在程序链接时将对应库中的偏移量添加到程序中,库函数在程序运行时加载进来,经过页表,把库映射到虚拟地址空间后(共享区),库就具有了起始地址。通过起始地址和偏移地址,就可以找到要调用的库函数。
系统层面上会维护动态库的起始地址(虽然刚刚加载时不能确定起始地址,因为共享区是由OS分配的,但是加载完毕就不会改变了),直接建立页表与内存的映射,就可以直接跳转访问了。所以动态库加载一次就可以被多个进程共同使用。
动态库相对于静态库更节省内存,静态库由多个程序使用相同的库函数,加载到内存中就会导致内存中有多份重复的库函数代码,而动态库则是多个程序共用一份动态库,不会导致出现重复的库函数代码,就节省了内存空间。
静态库和动态库的特点
静态库的特点:
- 静态库在可执行程序链接时就加入到可执行代码中,在物理上成为可执行程序的一部分;程序运行时将不在需要该静态库。
- 相对于动态库链接生成的程序,静态还相当于编译器将代码补充完整了,因此执行程序会大一些,但是运行起来相对快一些。
- 静态库是牺牲了空间效率,换取了时间效率
动态库特点:- 动态库在程序编译时并不会被链接到目标程序中,而是在程序运行时才被载入,因此在程序运行时还需要动态库的存在。
动态库只要在程序执行时,那些需要的函数代码才被拷贝到内存中。这样就使可执行文件比教小,节省磁盘空间。- 由于运行时要去链接库会花费一定的时间,执行速度可能会相对慢一些。
动态库是牺牲了时间效率,换取了空间效率。