什么是 .so.2 文件?

Posted

技术标签:

【中文标题】什么是 .so.2 文件?【英文标题】:What is a .so.2 file? 【发布时间】:2014-05-11 17:45:30 【问题描述】:

我使用 GCC 从源代码编译英特尔 TBB。它生成一个 libtbb.so 和 littbb.so.2。看起来.so.2 文件是真正的共享库,libtbb.so 只包含一行文本 INPUT (libtbb.so.2)

生成这两个文件而不是一个文件的目的是什么?对于INPUT (libtbb.so.2),语法是什么?我想了解更多。

【问题讨论】:

libtbb.so 的版本 2,而不是版本 1 或版本 3,或版本 4.2。 【参考方案1】:

通常当您构建共享对象 (.so) 时,您还会通过添加诸如 mylib.so.2.3.1 之类的后缀来处理版本。为确保您的程序可以加载此库或其他更高版本,您需要创建带有名称的链接

mylib.so -> mylib.so.2.3.1
mylib.so.2 -> mylib.so.2.3.1
mylib.so.2.3 -> mylib.so.2.3.1

所以,.so 之后的所有内容都代表 version.sub-version.build(或类似的) 此外,同一个库的多个版本可能与该方案共存,而将程序切换到使用特定版本所需要做的就是拥有适当的链接。

【讨论】:

我怎么知道 .so 文件是实际的 .so 文件,还是只包含指向某个真实文件的链接?有什么简单的方法而不是打印出内容? 链接显示在 ls -la 中,作为文件,它有几个字节大小。一个真正的 .so 包含所有库代码,因此它要大得多。你也可以使用file命令。 @Ryan:您可以使用file 命令。示例:file mylib.so 会说是 ASCII 文本还是 ELF 共享对象(如果是 Linux)。【参考方案2】:

动态链接的ELF 二进制文件(无论是另一个库还是可执行文件)使用shared-object name or soname 来标识可执行文件在执行时应链接到的库。

当一个库被创建为一个 ELF 共享库时,编译时链接编辑器在可执行文件中插入一个 DT_SONAME 字段,该库的 SONAME 到库本身。 DT_SONAME 在ELF standard 中定义为:

此元素保存以空字符结尾的字符串表偏移量 字符串,给出共享对象的名称。偏移量是一个索引 到DT_STRTAB 条目中记录的表中。请参阅“共享对象” 更多关于这些名称的信息。

所以现在当一个可执行文件被创建时,SONAME 被嵌入其中。当可执行文件运行时,链接器使用它在动态库的预定义位置的文件中查找库。 Windows 中的预定义位置是 DLL 所在的位置。在 Linux 和 Mac OS X 以及其他 System V 兼容系统中,它们将是 /lib/usr/lib 以及可能的其他位置,这取决于使用的链接器,并且可以在链接器自己的配置中定义。

在所有情况下,链接器都会查看在 soname 条目中命名的库是否存在于任何这些位置,如果存在,它将使用它。

请注意,该标准说 soname 是一个字符串,并且版本控制约定在事后成为事实上的标准,并且是这样的:

将 soname 设为 libmyname.so.A 并将库文件名设为 libmyname.so.A.B 或 libmyname.so.A.B.C(在 MacOSX 下为 libmyname.A.B.dylib)。创建从libmyname.so.A.B[.C]?libmyname.so.A 的软链接。

A 保持不变,而库的 ABI 保持不变。

B(或B.C)成为次要版本。

在 Linux 下,库版本与包版本号相同是很常见的。这有利有弊。

libtool 形式化

GNU libtool 被大量用于构建动态库,并且具有更正式的版本控制系统和强大的逻辑。 sonames 的 libtool 版本控制系统运行良好,并被复杂的库采用以保持正常。

在libtool下,版本如下:

libmylib-当前发布年龄 em>

在 libtool 下的想法是,随着库的发展,它们将添加和删除功能。

假设您正在开发一个库。首先使用0.0.0 的版本。

现在假设你修复了一些错误,你只会增加 release 数量。

所以新名称将是 libmylib.0.1.0 或 libmylib.0.2.0 等。对于每个仅修复错误但不更改任何 ABI 的版本。

按照你说的。啊!我本可以更好地完成这个子功能,所以你添加了一组新的函数来做更好的事情,但是因为其他人仍在使用你的库,所以你仍然保留旧的(已弃用的)功能。

规则如下:

    从每个 libtool 库的版本信息“0:0:0”开始。

    仅在公开之前更新版本信息 发布您的软件。不需要更频繁的更新,并且 只保证当前接口号越大越快。

    如果库源代码自上次更新后发生了变化, 然后增加修订('c:r:a' 变为'c:r+1:a')。

    如果自上次以来添加、删除或更改了任何接口 更新,增加当前,并将修订设置为 0。

    如果自上次公开发布以来添加了任何接口,则增加年龄。

    如果自上次公开以来已删除或更改任何接口 释放,然后将年龄设置为 0。

您可以在libtool documentation了解更多信息

更新...

以下是我的解释有错误的评论。它不需要,这需要比可以放入答案评论更多的细节,所以见下文。

原反对意见

这里有一个错误:在linux上,版本的形式是 libmylib.(current-age).release.age,其中括号表示 要评估的表达式。例如 GLPK 4.54 与 current:revision:age = 37:1:1 on linux 安装库文件 libglpk.so.36.1.1。有关更多信息,请参阅,例如, .

反驳

TLDR:autotools.io 不是权威来源。 解释

虽然 Flameeyes 是一位了不起的开发人员,并且他是 Gentoo 的维护者之一,但正是 犯了错误,并创建了对 libtool 规范的“经验法则”松散解释。虽然这不会在 99% 的情况下破坏系统,但如果我们遵循更新 current 的临时方式:

处理这些值时的经验法则是:

始终增加修订值。

每当添加接口时增加当前值, 删除或更改。

仅当对 ABI 所做的更改是 向后兼容。

然后他接着说维护多个版本的 Gtk 最好只是将库版本附加到库 NAME 中并简单地转储版本号。 (就像他们在 GTK+ 中所做的那样):

在这种情况下,最好的选择是附加库的一部分 版本信息到库的名称,例如 Glib 的 libglib-2.0.so.0 soname。为此,声明中的 Makefile.am 必须是这样的:

lib_LTLIBRARIES = libtest-1.0.la

libtest_1_0_la_LDFLAGS = -version-info 0:0:0

嗯,这只是破坏动态链接和符号解析版本控制功能的克罗克波特方法,完全没有实际意义!。他说关掉就好了。马鼻屎!难怪即使是经验丰富的开发人员也很难构建和维护开源项目,而且每次安装新版本的库时,我们都会不断遇到二进制文件死机(因为它们会相互破坏)。

libtool 版本控制方法是经过深思熟虑的。它是一个算法,它的步骤是有序指令16每次有一个更新动态链接库的代码。

对于新的和现有的开发人员,请仔细阅读它们,并想象在您出色的软件的整个生命周期中库版本号会发生什么变化。如果您这样做,您会注意到以前链接的每个软件将始终正确使用您惊人库的最新和准确版本,并且没有一个永远不会破坏或互相跺脚,并且你永远不必在你的图书馆的名字中添加一个盛开的数字(除非它是为了娱乐或美学)。

【讨论】:

这里有一个错误:在linux上,版本的形式是libmylib.(current-age).release.age,其中括号表示要计算的表达式。例如,Linux 上带有current:revision:age = 37:1:1 的GLPK 4.54 会安装库文件libglpk.so.36.1.1。有关详细信息,请参阅例如 autotools.io/libtool/version.html>。 (一旦这个问题在答案中得到纠正,我将删除我的反对票。) 零人怎么会认为这个答案有帮助?有时这个网站很疯狂。感谢您写出如此详细的答案。这是一个很好的教学参考。 @equaeghe 我将在这里为其他人添加答案。 您的反驳讨论了与我的评论无关的内容,这指向了未区分发布版本控制36.1.1 与 libtool 版本控制37:1:1 的问题。 (注意 :.。)这也是我提到 autotools.io/libtool/version.html> 的原因,其中指出:“警告 一个常见的错误是假设三个值通过到-version-info 直接映射到库名末尾的三个数字。 […] 对于 Linux,[…],虽然最后两个值直接从命令行映射,但第一个值是通过从 current 中减去 age 计算得出的。 […]”。

以上是关于什么是 .so.2 文件?的主要内容,如果未能解决你的问题,请参考以下文章

升级后 gcc 编译失败 - 找不到共享文件对象 (libmpc.so.2)

UnsatisfiedLinkError: /tmp/snappy-1.1.4-libsnappyjava.so 加载共享库 ld-linux-x86-64.so.2 时出错:没有这样的文件或目录

java.lang.UnsatisfiedLinkError /tmp/javacpp94368173067/libopencv_core.so.2.4:无法打开共享对象文件:没有这样的文件或目录

利用caffe自带的Makefile编译自定义so文件

共享库文件ldconfig 配置导致*.so找不到

解决linux安装软件:/lib/ld-linux.so.2: bad ELF interpreter: 没有那个文件或目录