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


不同的UNIX系统,链接动态库方法,实现细节不一样
 
编译PIC型.o中间文件的方法一般是采用C语言编译器的-KPIC或者-fpic选项,有的UNIX版本C语言编译器默认带上了PIC标准.创建最终动态库的方法一般采用C语言编译器的-G或者-shared选项,或者直接使用工具ld创建 。
最主要的是GCC命令行的一个选项:
-shared 该选项指定生成动态连接库(让连接器生成T类型的导出符号表,有时候也生成弱连接W类型的导出符号),不用该标志外部程序无法连接 。相当于一个可执行文件
-fPIC:表示编译为位置独立的代码,不用此选项的话编译后的代码是位置相关的所以动态载入时是通过代码拷贝的方式来满足不同进程的需要,而不能达到真正代码段共享的目的 。(转者注:共享库各段的加载地址并没有定死,可以加载到任意位置,因为指令中没有使用绝对地址(相对于链接后的可执行文件各segment来说),因此称为位置无关代码)
-L.:表示要连接的库在当前目录中
-ltest:编译器查找动态连接库时有隐含的命名规则,即在给出的名字前面加上lib,后面加上.so来确定库的名称
这里分别将源文件d1.c和d2.c编译为动态库d1.so和d2.so.
/************ d1.h***************/  void print();  /***************  d1.cpp *******************/    #include <iostream>  #include "d1.h"  using namespace std  int p = 1;  void print()    {        cout<< p <<endl;    }  /************ d2.h***************/  void print();  /***************  d2.cpp *******************/  #include <iostream>  #include "d2.h"  using namespace std;    int p = 2;  void print()  {      cout<< p <<endl;  }  LINUX和其他gcc编译器
g++ -fpic -c d1.cpp d2.cpp /* 编译为.o为扩展名的中间目标文件d1.o,d2.o*/
g++ -shared -o libd1.so d1.o /*根据中间目标文件d1.o创建动态库文件d1.so*/
g++ -shared -o libd2.so d2.o /*根据中间目标文件d2.o创建动态库文件d2.so*/
或者直接一步到位
g++ -O -fpic -shared -o libd1.so d1.cpp
g++ -O -fpic -shared -o libd2.so d2.cpp
某些版本的gcc上也可以使用-G替换-shared选项
 
调用动态库
隐式调用动态库
/**************  main.cpp *********************/    void print(); //或者用#include"d1.h"(#include"d2.h")替换  int main(int argc,char *argv[])  {      print();  }  #cp ./libd1.so libd.so (cp ./libd2.so libd.so )
# g++ -o dOut main.cpp ./libd.so (或者g++ -o dOut main.cpp -L./ -ld)
hc@linux-v07j:~/weiming/tt/dd> ldd dOut
linux-gate.so.1 => (0xffffe000)
libd.so => ./libd.so (0xb7f0f000)
libstdc++.so.6 => /usr/lib/libstdc++.so.6 (0xb7e2b000)
libm.so.6 => /lib/libm.so.6 (0xb7e06000)
libgcc_s.so.1 => /lib/libgcc_s.so.1 (0xb7dfa000)
libc.so.6 => /lib/libc.so.6 (0xb7cd8000)
/lib/ld-linux.so.2 (0xb7f12000)
 
ldd模拟运行一遍main,在运行过程中做动态链接,从而得知这个可执行文件依赖于哪些共享库,每个共享库都在什么路径下,加载到进程地址空间的什么地址 。
 
总之,共享库的搜索路径由动态链接器决定,从ld.so(8)的Man Page可以查到共享库路径的搜索顺序:
1. 首先在环境变量LD_LIBRARY_PATH所记录的路径中查找 。
2. 在程序链接时指定的 rpath 中查找,可以 readelf binfile | grep RPATH。
3. 然后从缓存文件/etc/ld.so.cache中查找 。这个缓存文件由/sbin/ldconfig命令读取配置文件/etc/ld.so.conf 之后生成 。
(也可以在 ld.so.conf.d 目录下增加 *.conf 文件,里面写入库路径,在 ld.so.conf 中 include ld.so.conf.d/*.conf )

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

文章插图
 
4. 如果上述步骤都找不到,则到默认的系统路径中查找,先是/usr/lib然后是/lib 。
不同的UNIX所依赖的动态库查找路径环境变量名称各不相同
UNIX版本 动态库查找路径环境变量
【.so Linux下动态库和静态库(.a) 的区别】


推荐阅读