题
当我做 ls -l
在 /usr/lib
我看到了很多libs "sameName.so.*.*"
延期。
- 这些扩展的意义是什么?
- 为什么创建软链接?他们有什么用?
一个例子将有助于理解。
解决方案
这是用于版本共享对象文件的技巧。这是避免由于懒惰的链接而产生的可怕的DLL地狱的一种方式。
懒惰链接(或较晚绑定)的优点是,可以更改可执行文件的组件,而无需实际链接这些可执行文件。这允许在第三方组件中进行错误修复,而不必运送新的可执行文件等。
缺点与优势完全相同。您的可执行文件可以发现它对基础库的假设已更改,这可能会引起各种问题。
共享对象的版本控制是避免这种情况的一种方法。另一个是 不是 共享对象,但它也有利弊,我不会进入这里。
举例来说,假设您有版本1 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链接。
实际的实现细节可能会有所不同(我的答案是基于较早的Unixes,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
并使用它 SONAME
的 xyz.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
将获得特定主要版本的特定次要版本。
其他提示
它是 共享库的版本控制方案. 。每个库都应有3个名称:
- 真正的名字: 实际库名称,
libfoo.so.1.2.3
- “儿子”: 名称记录在可执行文件中,名称Dynamic Linker都在寻找,
libfoo.so.1.2
. 。该名称实际上是在二进制本身内写入的,并将在链接时间的可执行文件中记录。它通常是图书馆真实姓名(通常是最新版本)的符号链接。 - 链接器名称: 构建程序时,您给链接器的名称。通常链接到最新的儿子。
例子
说你有 libfoo
版本1安装: libfoo.so
-> libfoo.so.1.0
-> libfoo.so.1.0.0
. 。您构建程序 bar
和 -lfoo
. 。现在链接到 libfoo
并会加载 libfoo.so.1.0
在由于Soname的运行时。然后,您升级到一个修补但兼容的二进制 libfoo.so.1.0.1
通过更换真实的二进制。 bar
仍然链接到 libfoo.so.1.0
并且不需要重建。
现在想象您想构建一个新程序 baz
这利用了libfoo v1.1中不兼容的变化。您安装了新版本,并且系统现在并行安装了两个版本:
libfoo.so.1.0
->libfoo.so.1.0.1
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
并且不需要更新。