什么是动态库与静态库
我们在生成可执行文件时,都会链接一些基础库及自己的需要的一些开发库。
这里我们可以对一个简单binary的符号表进行分析
test的实现如下:
#include <stdio.h>
const char* static_a ();
const char* dynamic_b ();
int main() {
printf("%s\n", static_a());
printf("%s\n", dynamic_b());
return 0;
}
这里我们的main函数,同时引用了dynamic_b和static_a 为什么符号表中,一个dynamic_b显示未定义('U’字符表示未定义)呢?
我们不妨看下test程序的生成方式
gcc -o static_a.o -c static_a.c
gcc -o static_b.o -c static_b.c
ar rcs libstatic.a static_?.o #生成静态库
gcc -fPIC -o dynamic_a.o -c dynamic_a.c
gcc -fPIC -o dynamic_b.o -c dynamic_b.c
gcc -fPIC -shared -o libdynamic.so dynamic_?.o #生成动态库
gcc -g -o test main.c -L. -lstatic -ldynamic #链接动态库与静态库
在可执行程序编译生成时,会把其依赖的静态库中所有方法进行重定位和binary链接在一起,可以执行。对于其依赖的动态库中的方法会进行标记,在程序被执行时,从内存中进行查找动态库是否在内存中已被加载,若为加载,则加载之并对其依赖方法进行重定位;否则,可直接重定位。
对于静态库而言,所有依赖其的可执行程序均要加载之,在binary中拷贝一份。而对于动态库时,则是在程序执行时按需加载。
可见,动态库较静态库而言,
- 可以节约很多空间,多个进程依赖内存中一份即可。
- 升级方便,若动态库中方法实现发生变化时,无需重新编译可执行程序,只需要重启进程即可。
缺点是,重定位过程延迟到可执行程序运行时加载,第一次符合查找过程会慢于静态链接方式。
静态库的好处是,各个程序依赖的静态库版本不会相互干扰,进程依赖的所有库都在可执行程序中。不依赖其他库。
方法同时存在于静态库和动态库
当一个方法同时存在于静态库于动态库时,按照编译参数,链接库的顺序决定最终可执行程序中使用的是哪个库中的方法。
在libdynamic库中, static_a方法的实现如下
const char* static_a(){
return "fake static_a";
}
在libstatic库中, static_a方法的实现如下:
const char *static_a() {
return __FUNCTION__;
}
可见如果同一个方法在静态库和动态库同时存在时,会以先加载为准。