当我在ls -l
中/usr/lib
时,我看到很多带有"sameName.so.*.*"
扩展名的库。
一个例子将有助于理解。
答案 0 :(得分:8)
这是用于版本共享对象文件的技巧。这是一种避免由于延迟链接而产生的可怕DLL地狱的方法。
延迟链接(或后期绑定)的优点是可以更改可执行文件的组件,而无需实际重新链接这些可执行文件。这允许在第三方组件中修复错误,而无需发送新的可执行文件等。
缺点与优点完全相同。您的可执行文件可以发现它对底层库所做的假设已被更改,这可能会导致各种问题。
共享对象的版本控制是避免这种情况的一种方法。另一个是不共享对象,但这也有利有弊,我不会在这里进入。
举例来说,假设你有xyz.so
的版本1。您有一个文件和指向该文件的符号链接:
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有一篇很好的文章介绍了它是如何完成的here。
创建共享对象时,会为其指定实名和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
的{{1}}。
当链接器在xyz.so.1
中链接时,它会跟随链接一直到xyz.so
并使用其xyz.so.1.5
SONAME
来存储在可执行文件中。然后,当您运行可执行文件时,它会尝试加载xyz.so.1
,这将指向特定的xyz.so.1
(不一定是版本1.5)。
因此,您可以安装xyz.so.1.N
并更新xyz.so.1.6
链接以指向它,而已链接的可执行文件将使用该链接。
这种多层方法的一个优点是,您可以拥有多个可能不兼容的同名库(xyz.so.1
,xyz.so.1.*
),但是,在每个主要版本中,您可以自由升级它们<因为它们应该是兼容的。
链接新的可执行文件时:
xyz.so.2.*
链接的人将获得最新主要版本的最新版本。xyz.so
关联的其他人将获得特定主要版本的最新版本。xyz.so.1
相关联的人会获得特定主要版本的特定次要版本。答案 1 :(得分:6)
这是一个versioning scheme for shared libraries。每个图书馆都应该有3个名字:
libfoo.so.1.2.3
libfoo.so.1.2
。该名称实际上是在库二进制文件本身内部编写的,并将在链接时记录在可执行文件中。它通常是库的真实姓名(通常是最新版本)的符号链接。假设您已安装libfoo
版本1:libfoo.so
- &gt; libfoo.so.1.0
- &gt; libfoo.so.1.0.0
。您使用bar
制作计划-lfoo
。它现在链接到libfoo
并且由于SONAME而在运行时加载libfoo.so.1.0
。然后通过替换实际二进制文件升级到修补但二进制兼容的libfoo.so.1.0.1
。 bar
仍然链接到libfoo.so.1.0
,无需重建。
现在想象一下你想要构建一个利用libfoo v1.1中不兼容的更改的新程序baz
。您安装了新版本,系统现在并行安装了两个版本:
libfoo.so.1.0
- &gt; libfoo.so.1.0.1
libfoo.so
- &gt; libfoo.so.1.1
- &gt; libfoo.so.1.1.0
注意链接器名称已更新为最新版本(这是与您在/usr/include
中安装的标头对应的版本。)
您构建baz
,它会链接到libfoo.so
并在运行时加载libfoo.so.1.1
。不是bar
仍然针对libfoo.so.1.0
运行,并且不需要更新。