什么是 *.so.*.* 库

发布于 2024-09-19 02:09:44 字数 184 浏览 10 评论 0原文

当我在 /usr/lib 中执行 ls -l 时,我看到很多带有 "sameName.so.*.*" 扩展名的库。

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

一个例子会对理解有很大帮助。

When I do ls -l in /usr/lib I see lots of libs with "sameName.so.*.*" extension.

  1. What is the significance of these extensions?
  2. Why softlinks are created? what are their use?

One example will help a lot in understanding.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

桃扇骨 2024-09-26 02:09:45

这是一个共享库的版本控制方案。每个库应该有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。您可以使用 -lfoo 构建程序 bar。它现在链接到 libfoo 并将由于 SONAME 在运行时加载 libfoo.so.1.0 。然后,通过替换真正的二进制文件来升级到已修补但与二进制文件兼容的libfoo.so.1.0.1bar 仍然链接到 libfoo.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 运行并且不需要更新。

It's a versioning scheme for shared libraries. Every library should have 3 names:

  1. Real name: the actual library name, libfoo.so.1.2.3
  2. "SONAME": the name recorded in the executable, and the name dynamic linker looks for, libfoo.so.1.2. This name is actually written inside the library binary itself, and will be recorded in the executable at link time. It is usually a symlink to library's real name (usually latest version).
  3. Linker name: the name you give to the linker when building your program. Usually links to the latest SONAME.

Example

Say you have libfoo version 1 installed: libfoo.so -> libfoo.so.1.0 -> libfoo.so.1.0.0. You build your program bar with -lfoo. it now links to libfoo and will load libfoo.so.1.0 at runtime due to SONAME. Then you upgrade to a patched but binary-compatible libfoo.so.1.0.1 by replacing real binary. bar still links to libfoo.so.1.0 and doesn't need to be rebuilt.

Now imagine you want to build a new program baz that takes advantage of incompatible changes in libfoo v1.1. You install new version and your system now have two versions installed in parallel:

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

Note linker name was updated to the latest version (this is the version corresponding to the headers you installed in /usr/include).

You build baz, and it links to libfoo.so and loads libfoo.so.1.1 at runtime. Not that bar still runs against libfoo.so.1.0 and doesn't need to be updated.

南冥有猫 2024-09-26 02:09:44

这是用于对共享对象文件进行版本控制的技巧。这是避免由于惰性链接而产生的可怕的 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 似乎比仅仅遵循符号链接更智能地进行版本控制)。 IBMdeveloperWorks 在这里有一篇很好的文章介绍了它是如何完成的。

创建共享对象时,您需要为其指定真实名称和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 拥有 xyz.so.1SONAME

当链接器链接到 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链接的人将获得特定主要版本的特定次要版本。

This is a trick used to version shared object files. It's a way of avoiding the dreaded DLL hell which came about because of lazy linking.

The advantage of lazy linking (or late binding) is that components of your executable can be changed without actually re linking those executables. This allows for bug fixes in third party components without having to ship a new executable, among other things.

The disadvantage is exactly the same as the advantage. Your executable can find that assumptions it made about the underlying libraries have been changed and this is likely to cause all sorts of issues.

Versioning of shared objects is one way to avoid this. Another would be to not share objects at all but that also has pros and cons which I won't get into here.

By way of example, let's say you have version 1 of xyz.so. You have a file and a symbolic link to that file:

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

Now, when you create an executable file exe1, linking it with xyz.so, it will follow the symbolic link so that it stores xyz.so.1 in the executable as the thing it needs to load at runtime.

That way, when you upgrade the shared library thus:

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

your original executable exe1 will still load version 1 of the shared object.

However, any executables you create now (such as exe2) will be linked with version 2 of the shared object.


The actual implementation details may vary somewhat (I'm basing my answer on earlier UNIXes and Linux appears to do versioning a little more intelligently than just following symbolic links). IBM developerWorks has a nice article on how it's done here.

When you create a shared object, you give it both a real name and an soname. These are used to install the shared object (which creates both the object and a link to it).

So you can end up with the situation:

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

with xyz.so.1.5 possessing the SONAME of xyz.so.1.

When the linker links in xyz.so, it follows the links all the way to xyz.so.1.5 and uses its SONAME of xyz.so.1 to store in the executable. Then, when you run the executable, it tries to load xyz.so.1 which will point to a specific xyz.so.1.N (not necessarily version 1.5).

So you could install xyz.so.1.6 and update the xyz.so.1 link to point to it instead and already-linked executables would use that instead.

One advantage of this multi-layer method is that you can have multiple potentially incompatible libraries of the same name (xyz.so.1.*, xyz.so.2.*) but, within each major version, you can freely upgrade them since they're supposed to be compatible.

When you link new executables:

  • Those linking with xyz.so will get the latest minor version of the latest major version.
  • Others linking with xyz.so.1 will get the latest minor version of a specific major version.
  • Still others linking with xyz.so.1.2 will get a specific minor version of a specific major version.
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文