通常情况下,某个程序依赖于库版本 xy,另一个程序依赖于 xz,但据我所知,没有包管理器允许我同时安装 xy 和 xz 有时它们会允许两个主要版本(例如qt4 和 qt5,可以同时安装),但(似乎)从来没有小版本。
为什么是这样?例如,阻止它的限制因素是什么?我认为一定有充分的理由不允许这种看似有用的功能。例如,是否没有一个字段来指示加载共享对象时要加载的版本,因此 Linux 无法知道如何决定加载哪个版本?或者真的没有理由吗?就像所有小版本都应该兼容一样?
答案1
实际上,如果操作正确,您可以安装共享库的多个版本。
共享库通常命名如下:
lib<name>.so.<api-version>.<minor>
接下来,有以下名称的库的符号链接:
lib<name>.so
lib<name>.so.<api-version>
当开发人员链接到库以生成二进制文件时,.so
链接器找到的是以该文件名结尾的文件名。对于任何给定的情况,一次确实只能安装其中一个,<name>
但这仅意味着开发人员无法同时针对一个库的多个不同版本。对于包管理器,此符号链接是仅开发人员需要安装的.so
单独包的一部分。-dev
当链接器找到名称以 结尾的文件.so
并使用它时,它会在该库中查找名为的字段索纳姆。 soname 建议链接器将什么文件名嵌入到生成的二进制文件中,从而在运行时查找什么文件名。 soname 应该设置为lib<name>.so.<api-version>
.
因此,在运行时,动态链接器将寻找lib<name>.so.<api-version>
并使用它。
其意图是:
<minor>
升级不会改变库的 API,当库<minor>
升级到更高版本时,可以安全地将所有二进制文件升级到新版本。由于二进制文件都在名称下寻找库lib<name>.so.<api-version>
,这是最新安装的符号链接lib<name>.so.<api-version>.<minor>
,因此它们获得了升级。<api-version>
升级改变了库的API,让现有的二进制应用程序使用新版本是不安全的。在更改的情况下<api-version>
,由于这些应用程序正在查找名称lib<name>.so.<api-version>
但具有不同的值<api-version>
,因此它们将不会选择新版本。
包管理器通常不会在同一发行版中打包同一库的多个版本,因为整个发行版(包括使用该库的所有二进制文件)通常在发行版之前编译为使用每个库的一致版本。释放。确保一切都一致并且发行版中的一切都与其他一切兼容是发行商工作量的很大一部分。
但是,如果您已将系统从发行版的一个版本升级到另一个版本,并且仍然有一些旧软件包需要旧版本的库,那么您很容易会得到多个版本的库。例子:
- libmysqlclient16来自较旧的 Debian,包含
libmysqlclient.so.16.0.0
和 symlinklibmysqlclient.so.16
。 - libmysqlclient18从当前的 Debian 开始,包含
libmysqlclient.so.18.0.0
和 symlinklibmysqlclient.so.18
。
答案2
此功能并不是不允许的,只是由于大多数库编号的工作方式以及包名称更改的不便而不太常见。
如果使用点分版本号方案 XYZ,则“微”版本 Z 经常在错误修复时更改,“次要”版本号 Y 会在错误修复时更改向下兼容更改,并且“主要”版本号 X 必须根据 API 更改进行更改(有时会根据主要的额外功能进行更改)。
您不应该有任何理由不想修复最新的错误,并且向后兼容的更改也不应该破坏您的软件。
如果库是以这种方式开发的,您应该始终能够用 X.(Y+m).(Z+n) 替换 XYZ。对于任何给定的 m 和 n。也就是说,您应该始终能够用同一主要数字系列中的最新版本替换您的库。如果库开发人员很小心并且下一个主要编号是兼容的(例如,通过声明弃用某些东西,但尚未删除它们),您甚至可以使用下一个主要编号。
对于软件包开发人员来说,这意味着他们可以使用只有一个名称的名称,甚至没有数字名称,只需更新软件包即可为您提供最新版本。如果他们以软件包的形式提供库abc2
,那么他们就必须费尽周折才能移动自己的软件靠升级abc2
到使用abc3
,有时需要过渡包。如果适用于大多数依赖包,则从库中省略主版本号会更方便。因此,即使两者abc2
都abc3
应该在发行版中的某个时刻可用,也abc3
经常被调用(就像还没有时被调用abc
一样),并且一旦发行版中没有包依赖,就可以完全删除。abc2
abc3
abc2
abc2
编号方案并没有统一遵循,但我只能想象,随着互联网的出现,传播有关如何使用这种方案的信息,以及来自图书馆用户(包括发行版开发人员)的压力,要求在不进行任何操作的情况下明确诸如向后兼容性之类的重要内容。必须通读库中包含的 CHANGES 文件,这使得这种情况变得更加常见。
一个反例,但不是库的例子是 python intpreter,它在较小的数字更改上与其共享对象和酸洗格式不兼容。因此,您将看到 python 的包(2.7 系列中的最新版本)和 python3(当前 python3.4 系列中的最新版本)以及 python 2.6(越来越常见)和 python 3.3 的显式包。