静态库和动态库对比
静态库
一些目标代码的集合。按照习惯,linux中一般一.a
作为文件名后缀。使用ar(archiver)命令可以创建静态库。
在可执行程序运行前就已经加入到执行码中,成为执行程序的一部分。
静态库在应用程序生成时,可以不必再编译,节省编译时间。
静态库会占用大量存储空间。
动态库
在执行程序启动时加载到执行程序中,可以被多个执行程序共享使用。
动态库不需要编译入程序, 运行时动态加载, 导致速度慢了一些
二者的适合场景:
- 静态库: 对空间要求较低, 对时间要求较高
- 动态库: 对时间要求较低, 对空间要求较高
静态库制作
先用gcc的-c参数将源文件编译成二进制文件, 再用ar命令封装静态库
1 | # 有文件add.c div1.c sub.c |
使用:
1 | # 将库直接加入编译的源文件中即可使用 |
静态库使用及头文件对应
隐式声明: 编译过程中没有遇到函数定义和函数声明, 编译器会帮助做隐式声明;
但是这种隐式声明只能对于返回值为int型的;
解决方法:
1 | /*添加头文件,防止头文件重复包含,一旦头文件被展开过一次,_MYMATH_H_就被定义过了,后面就不会再展开*/ |
然后将源文件和库联编即可, 注意源文件在前
1 | # 动态库存放在~/sys/staticLib/lib |
动态库制作
生成与位置无关的代码
将源文件.c编译为目标文件.o, 生成与位置无关的代码, 借助参数-fPIC
编译生成hello.o的时候, 各个函数的地址还是相对于main的地址, 链接阶段填入main的地址;
由于动态库的函数在库里, 不能像程序内部的函数一样直接填入main的地址, 动态函数在a.out中没有位置, 依赖于@plt, 进行延迟绑定;
查看二进制文件的反汇编代码:
objdump -dS test
输出重定向:
objdump -dS test > test.s
制作演示:
1 | # 1. 将.c文件生成.o文件(生成与位置无关的代码-fPIC): |
动态库加载错误原因及解决办法
上面的错误原因:
- 链接器:工作于链接阶段, 工作时需要指定-l和-L参数, 上面已经指定
- 动态链接器:工作于程序运行阶段, 工作时需要提供动态库所在目录
上面两者没有任何关系
方法1:
动态链接器要根据环境变量寻找动态库:
LD_LIBRARY_PATH
执行
export LD_LIBRARY_PATH=./lib
指定后就可以执行了(但是上面指定的只是临时的, 环境变量是进程的概念)
要想永久指定, 需要更改配置文件, 加入环境变量, 重启终端使之生效:
1 | # ~/.bashrc下加入 |
方法2:
像标准C库这种本身就在系统的环境变量里, 所以能找到;
滥竽充数法:将库文件放到系统根目录下的lib里就可以了;
ldd test
可以查看程序运行所需要的动态库
最后一种方法:修改配置文件法;
1 | sudo vim /etc/ld.so.conf |
动态库和静态库共存时, 编译器优先使用动态库;