Linux中动态库

我们在linux下开发项目,有时会对外提供动态库,像***.so.1.0.0这样子的文件,另外提供相应的头文件。用户拿到动态库和头文件说明,就可以使用动态库里的function。

那随之而来的一个问题是,动态库的升级问题,我们的动态库更改了一个bug,升级了一个版本,那使用我们动态库的应用程序需要重新编译吗?运行时会产生异常吗?linux下是怎么规范这些内容的呐?

大家一定听说过windows下的dll hell。

Linux中的.so文件 是动态链接的产物 
共享库理解为提供各种功能函数的集合,对外提供标准的接口
Linux中命名系统中共享库的规则

**主版本号:不同的版本号之间不兼容
次版本号:增量升级 向后兼容
发行版本号:对应次版本的错误修正和性能提升,不影响兼容性

下面说说linux下动态库的命名规范。

为方便管理依赖关系,创建或部署共享库时,必须遵循统一约定的规则才行,其中包括动态库的命名规则及其部署方式。

共享库命名约定

  1. 每个动态库有一个包含了真正的库代码的文件名,通常被称为库的 realname ,命名格式通常为libxxx.so.x.y.z,其中so后缀中的x为主版本号,y为副版本号,z为发行版本号。例如,我的linux系统机器上zlib共享库的realname为libz.so.1.2.8,这个文件是含有可执行的二进制代码的。

  2. 每个动态库都有一个以”lib”为前缀且以 ”.so.x”为结尾的被称为 so name的特定名称,其中x为主版本号,soname命名格式通常为libxxx.so.x(去掉副版本号和发行版本号)。例如,我的linux系统机器上zlib共享库的soname为libz.so.1。这个soname包含了动态库的主版本号,这个doname一般会包含在库代码的头文件中,这个可以使用 readelf -d 读取出来,使用这个动态库的程序的二进制ELF的头文件中包含有这个动态库的soname。程序运行时会按照这个名称去找真正的库文件。在Linux系统中,系统会为每个共享库所在的目录创建一个跟SO-NAME相同的并且指向它的软连接(Symbol Link)。 这个软连接会指向目录中主版本号相同、次版本号和发布版本号最新的共享库。也就是说,比如目录中有两个共享库版本分别为:/lib/libtest.so.3.8.2和/lib/libtest.so.3.7.5,么软连接/lib/libtest.so.3指向/lib/libtest.so.3.8.2

  3. 此外,编译链依赖了共享库的应用模块时,链接器只认不带任何版本号的共享库名, 可以将库名称作” linker name。也就是做软连接。例如,我的linux系统机器上zlib共享库的linkername为libz.so。也即,链接使用了动态库的程序时查找的动态库名称。例如:gcc -o test test.o -lz , 链接时就会找libz.so 。若没有这个文件,链接器就报错。

  4. Linux提供了一个工具——ldconfig,当系统中安装或更新一个共享库时,需要运行这个工具,它会遍历默认所有共享库目录,比如/lib,/usr/lib等,然后更新所有的软链接,使她们指向最新共享库。 当我们在编译器里使用共享库的时候,如用GCC的“-l”参数链接共享库libtXXX.so.3.8.1,只需要在编译器命令行指定 -l XXX 即可,省略了前缀和版本信息。