解决Linux程序编译链接动态库版本的相关问题

2019-10-12 16:22:11于海丽

 $ readelf -d /lib64/libacl.so.1.1.0                     

Dynamic section at offset 0x6de8 contains 24 entries:
Tag Type    Name/Value
0x0000000000000001 (NEEDED)  Shared library: [libattr.so.1]
0x0000000000000001 (NEEDED)  Shared library: [libc.so.6]
0x000000000000000e (SONAME)  Library soname: [libacl.so.1]

这里省略了一部分,可以看到最后一行SONAME为libacl.so.1,所以/lib64才会有一个这样的软连接

再看libc-2.12.so文件,该文件并没有采用我们说的命名方式

 $ readelf -d /lib64/libc-2.12.so                     

Dynamic section at offset 0x18db40 contains 27 entries:
Tag Type    Name/Value
0x0000000000000001 (NEEDED)  Shared library: [ld-linux-x86-64.so.2]
0x000000000000000e (SONAME)  Library soname: [libc.so.6]

同样可以看到最后一行SONAME为libc.so.6,即便该动态库没有按版本号的方式命名,但仍旧有一个软链指向该动态库,而该软链的名字就是soname指定的名字

所以关键就是这个soname,它相当于一个中间者,当我们的动态库只是升级一个小版本时,我们可以让它的soname相同,而可执行程序只认soname指定的动态库,这样依赖这个动态库的可执行程序不需重新编译就能使用新版动态库的特性

可执行程序的编译

还是以hello动态库为例,我们写一个简单的程序

// filename:main.c
#include "hello.h"

int main()
{
 hello("handy");
 return 0;
}

现在目录下是如下结构

├── hello.c
├── hello.h
├── libhello.so.0 -> libhello.so.0.0.1
├── libhello.so.0.0.1
└── main.c

libhello.so.0.0.1是我们编译生成的动态库,libhello.so.0是通过ldconfig生成的链接,采用如下命令编译main.c

 $ gcc main.c -L. -lhello -o main                      
/usr/bin/ld: cannot find -lhello

报错找不到hello动态库,在Linux下,编译时指定-lhello,链接器会去寻找libhello.so这样的文件,当前目录下没有这个文件,所以报错。建立这样一个软链,目录结构如下

├── hello.c
├── hello.h
├── libhello.so -> libhello.so.0.0.1
├── libhello.so.0 -> libhello.so.0.0.1
├── libhello.so.0.0.1
└── main.c

让libhello.so链接指向实际的动态库文件libhello.so.0.0.1,再编译main程序

gcc main.c -L. -lhello -o main

这样可执行文件就生成了。通过以上测试我们发现,在编译可执行程序时,链接器会去找它依赖的libxxx.so这样的文件,因此必须保证libxxx.so的存在

用ldd查看其依赖的动态库

 $ ldd main                        
 linux-vdso.so.1 => (0x00007fffe23f2000)
 libhello.so.0 => not found
 libc.so.6 => /lib64/libc.so.6 (0x00007fb6cd084000)
 /lib64/ld-linux-x86-64.so.2 (0x00007fb6cd427000)