4

当我这样做ls -l时,/usr/lib我看到很多带有"sameName.so.*.*"扩展名的库。

  1. 这些扩展的意义是什么?
  2. 为什么要创建软链接?它们有什么用?

一个例子将有助于理解。

4

2 回答 2

8

这是用于版本共享目标文件的技巧。这是一种避免由于延迟链接而出现的可怕的 DLL 地狱的方法。

延迟链接(或后期绑定)的优点是可以更改可执行文件的组件,而无需实际重新链接这些可执行文件。这允许在第三方组件中修复错误,而无需发布新的可执行文件等。

缺点与优点完全相同。您的可执行文件可以发现它对底层库所做的假设已更改,这可能会导致各种问题。

共享对象的版本控制是避免这种情况的一种方法。另一个是根本不共享对象,但这也有优点和缺点,我不会在这里讨论。

例如,假设您有xyz.so. 您有一个文件和指向该文件的符号链接:

pax> ls -al xyz*
-rw-r--r--  1 pax paxgroup    12345 Nov 18  2009 xyz.so.1
lrwxrwxrwx  1 pax paxgroup        0 Nov 18  2009 xyz.so -> xyz.so.1

现在,当您创建一个可执行文件时exe1,将其与 链接xyz.so,它将遵循符号链接,以便它xyz.so.1作为运行时需要加载的内容存储在可执行文件中。

这样,当您升级共享库时:

pax> ls -al xyz*
-rw-r--r--  1 pax paxgroup    12345 Nov 18  2009 xyz.so.1
-rw-r--r--  1 pax paxgroup    67890 Nov 18  2009 xyz.so.2
lrwxrwxrwx  1 pax paxgroup        0 Nov 18  2009 xyz.so -> xyz.so.2

您的原始可执行文件exe1仍将加载共享对象的版本 1。

但是,您现在创建的任何可执行文件(例如exe2)都将与共享对象的版本 2 链接。


实际的实现细节可能会有所不同(我的答案基于早期的 UNIX,而 Linux 似乎比仅仅遵循符号链接更智能地进行版本控制)。IBM developerWorks 有一篇很好的文章,介绍了它是如何完成

当你创建一个共享对象时,你给它一个真实的名字和一个soname. 这些用于安装共享对象(创建对象和指向它的链接)。

因此,您最终可能会遇到以下情况:

pax> ls -al xyz*
-rw-r--r--  1 pax paxgroup    12345 Nov 18  2009 xyz.so.1.5
lrwxrwxrwx  1 pax paxgroup        0 Nov 18  2009 xyz.so.1 -> xyz.so.1.5
lrwxrwxrwx  1 pax paxgroup        0 Nov 18  2009 xyz.so -> xyz.so.1

拥有xyz.so.1.5的。SONAME_xyz.so.1

当链接器链接到 时xyz.so,它会一直跟随链接到xyz.so.1.5并使用其存储在可执行文件中SONAMExyz.so.1然后,当您运行可执行文件时,它会尝试加载xyz.so.1指向特定xyz.so.1.N​​(不一定是 1.5 版)的文件。

因此,您可以安装xyz.so.1.6并更新xyz.so.1链接以指向它,而已经链接的可执行文件将使用它。

这种多层方法的一个优点是您可以拥有多个可能不兼容的同名库(xyz.so.1.*, xyz.so.2.*),但是在每个主要版本中,您可以自由升级它们,因为它们应该是兼容的。

当您链接新的可执行文件时:

  • 链接的xyz.so人将获得最新主要版本的最新次要版本。
  • 其他链接的人xyz.so.1将获得特定主要版本的最新次要版本。
  • 还有其他链接xyz.so.1.2将获得特定主要版本的特定次要版本。
于 2010-09-15T05:28:17.423 回答
6

这是共享库的版本控制方案。每个库都应该有 3 个名称:

  1. 真实姓名:实际库名,libfoo.so.1.2.3
  2. “SONAME”:记录在可执行文件中的名称,动态链接器查找的名称,libfoo.so.1.2. 这个名字实际上是写在库二进制文件中的,并且会在链接时记录在可执行文件中。它通常是库真实名称(通常是最新版本)的符号链接。
  3. 链接器名称:您在构建程序时给链接器的名称。通常链接到最新的 SONAME。

例子

假设您安装了libfoo版本 1:libfoo.so-> libfoo.so.1.0-> libfoo.so.1.0.0。您bar使用-lfoo. 由于 SONAME,它现在链接到libfoo并在运行时加载。然后,您通过替换真正的二进制文件libfoo.so.1.0升级到已修补但二进制兼容的版本。仍然链接到并且不需要重建。libfoo.so.1.0.1barlibfoo.so.1.0

现在假设您要构建一个新程序baz,以利用 libfoo v1.1 中不兼容的更改。您安装了新版本,您的系统现在并行安装了两个版本:

  1. libfoo.so.1.0->libfoo.so.1.0.1
  2. libfoo.so-> libfoo.so.1.1->libfoo.so.1.1.0

注意链接器名称已更新到最新版本(这是与您安装的头文件对应的版本/usr/include)。

您构建baz,它链接到libfoo.so并在运行时加载libfoo.so.1.1。并不是说bar仍然存在冲突libfoo.so.1.0并且不需要更新。

于 2010-09-15T05:53:57.003 回答