Linux下动态库(.so)和静态库(.a) 的区别

Linux下动态库(.so)和静态库(.a) 的区别

 

静态库在程序编译时会被连接到目标代码中,程序运行时将不再需要该静态库。编译之后程序文件大,但加载快,隔离性也好。 动态库在程序编译时并不会被连接到目标代码中,而是在程序运行是才被载入,因此在程序运行时还需要动态库存在。多个应用程序可以使用同一个动态库,启动多个应用程序的时候,只需要将动态库加载到内存一次即可。

 

编译动态库:

-shared 该选项指定生成动态连接库(让连接器生成T类型的导出符号表,有时候也生成弱连接W类型的导出符号),不用该标志外部程序无法连接。相当于一个可执行文件 -fPIC:表示编译为位置独立的代码,不用此选项的话编译后的代码是位置相关的所以动态载入时是通过代码拷贝的方式来满足不同进程的需要,而不能达到真正代码段共享的目的。 -L.:表示要连接的库在当前目录中 -ltest:编译器查找动态连接库时有隐含的命名规则,即在给出的名字前面加上lib,后面加上.so来确定库的名称

 

配置库位置: LD_LIBRARY_PATH:这个环境变量指示动态连接器可以装载动态库的路径。 当然如果有root权限的话,可以修改/etc/ld.so.conf文件,然后调用 /sbin/ldconfig来达到同样的目的,不过如果没有root权限,那么只能采用输出LD_LIBRARY_PATH的方法了。

ldd命令可以查看可执行文件依赖的库文件。

 

root@xxj-VirtualBox:~/interview# ldd gmedian
    linux-vdso.so.1 =>  (0x00007fff88c71000)
    libstdc++.so.6 => /usr/lib/x86_64-linux-gnu/libstdc++.so.6 (0x00007f4013945000)
    libgcc_s.so.1 => /lib/x86_64-linux-gnu/libgcc_s.so.1 (0x00007f401372f000)
    libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f4013368000)
    libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0x00007f4013062000)
    /lib64/ld-linux-x86-64.so.2 (0x00007f4013c5f000)

 

 

动态库(.so)链接静态库(.a)的情况总结

动态库(.so)链接静态库(.a)的情况总结 
一般来说在链接时想要使用静态库有三种方法:
1、link时加上 -static 选项;当加上 -static选项后,gcc会把所有用到的库都做静态连接。
2、link时直接指定想要静态连接的.a文件的绝对路径。优点是除非.a文件不存在,否则肯定有效;缺点也是很明显,拿到其他机器上编译时,.a文件也必须在相同的路径下存放。
3、在要静态连接的库前指定-Bstatic ,在要动态连接的库前指定-Bdynamic选项。连接器在看到-Bstatic时会优于去找静态库,如果找不到再去找动态库。 -Bdynamic也是同样的情况。(可是我实验的结果是这两个选项根本不起作用,我的环境是centos 6.2 gcc4.7.2, 仔细看了gcc 文档,这两个选项是针对VxWorks平台的,所以不起作用。)
 
当我们要编译一个so提供给外部使用,这个so本身依赖一些第三方库。但是我们却希望so的使用者不用关心该so对其他库的依赖。很自然的是会想到在编译so的时候把依赖到的第三方库静态链接进来。
 
我在这样做的时候碰到了问题:指定-static选项时,link失败,错误提示说要用到的object文件应该用-fPIC选项重新编译才行(也就是说,只有用-fPIC选项编译的object文件能被link到.so里);当直接给出.a的绝对路径的时候link成功,但是.so里却并没有直正包含所用到的符合连接。针对碰到的问题,我做了一些实验。实验如下:
static.c
#include <stdio.h>
 
const char* sz_static = "i'm a static str.";
 
void print_niuzai_said() {     printf("in static lib, niu zai said, i'm happy!\n"); }

dynamic.c
 
#include <stdio.h> #include "static.h"
 
void print_papa_said() {     print_niuzai_said();     printf("in dynamic lib, papa said, niu zai is wonderful!\n"); }
 

main.c
 
#include <unistd.h> #include "dynamic.h"
 
int main(int argc, char** argv) {     print_papa_said();     return 0; }
分别用两组命令编译出了两个.a 文件
1、gcc -o static.o -c static.c
      ar -r libstatic.a static.o
2、gcc -o static_shared.o -shared -fPIC -c static.c
      ar -r libstatic_shared.a static_shared.o
 
然后用此命令  "gcc -o dynamic.o -c dynamic.c"  编译出dynamic.o文件
接下来就是本文的主题了,链接生成libdynamic.so.此时有这么几种情况:
1、使用 "gcc -o libdynamic.so -shared -fPIC -L. -lstatic dynamic.o ",连接成功,但.so里实际上没有static.o里的内容。
2、使用"gcc -o libdynamic.so dynamic.o -shared -fPIC -L. -lstatic",连接失败 
3、使用 "gcc -o libdynamic.so -shared -fPIC -L. -lstatic_shared dynamic.o",连接成功,但.so里实际上没有static.o里还是没有的内容。
 
4、使用 "gcc -o libdynamic.so dynamic.o -shared -fPIC -L. -lstatic_shared",连接成功,.a的内容被连接到了.so里面。
 
 
另外,链接静态生成可执行程序时,静态库是不是用 "-shared -fPIC" 选项编译产生的没有影响。都能正常生成可执行程序。
综合以上情况,总结如下:
1、动态连接库中用到的object文件必须是用 "-shared -fPIC"选项编译产生的,否则连接时要么报错,要么被忽略。
2、静态库中的object文件最好也用"-shared -fPIC"选项编译,这样静态库就可以同时被连接到.so 或者可执行性文件中。
3、动态库只能连接用"-shared -fPIC"选项编译出来的静态库(和第1点是同一件事)
4、连接选项的顺序对连接器的行为有重要影响!
 

posted on 2018-11-11 15:24  lh03061238  阅读(19545)  评论(0编辑  收藏  举报

导航