soname 的 Debian 软件包命名策略
Debian package naming policy for soname
我正在为一个库制作一个 Debian 包,我将其命名为 libmystuff。它目前的版本是 4.0.0,下一个版本将是 4.1.0,并且可能会破坏 API 兼容性。该项目使用CMake构建。
在 soname 和包名中应该如何处理?
我想使包版本初始为 4.0.0。如果我将包命名为 libmystuff,则会收到一个 lintian 错误,告诉我将包的 soname 放在包名称中 (package-name-doesnt-match-sonames)。很公平。
如果我将包命名为 libmystuff4,那么我会得到一个名为 libmystuff4-dev_4.0.0-1ubuntu8_amd64.deb
的包文件,这似乎有点多余,但没关系,该包适用于主要版本 4,软件版本为 4.0.0。但我仍然收到一个 lintian 错误提示,
libmystuff4: package-name-doesnt-match-sonames libmystuff4.0.0
所以这让我很惊讶,为什么 lintian 要我把 soname 的所有 3 部分都放在包名中,而不是只放第一部分?
无论如何,我把包名改成libmystuff4.0.0,现在lintian安静了,但是我得到了一个包文件,名字叫libmystuff4.0.0_4.0.0-1ubuntu8_amd64.deb
,看起来很多余!
我该怎么办?
我在想,即使库版本是 4.0.0,soname 也应该是 0,当他们发布 4.1.0 时我应该将 soname 设置为 1,等等。这需要修补上游 CMake 构建系统,这是一种可以接受的方法吗?尽管在那种情况下 soname 的其他部分又如何,我只是将它们设置为 0 吗?那么这个包就是 soname 0.0.0.
否则我不得不在他们发布 4.1.0 时将 soname 更改为 5.0.0,这会很混乱,对吗?
简答:设置当前的SONAME为libmystuff.so.0,4.1.0打破ABI时,设置SONAME为libmystuff.so ].1.您需要修补构建系统并在相关位置引入 set_property(TARGET mystuff PROPERTY SOVERSION 0 )
。
您的 SONAME 与您图书馆的版本不同,可能需要独立发展。
更长的答案:
库有点尴尬,因为它们有两个可以有用地进行版本控制的独立方面:source 兼容性和 binary 兼容性。它们分别是 API 和 ABI。库版本可以保持 API 和源代码兼容,同时破坏 ABI 和二进制不兼容,反之亦然。
幸运的是,需要自动化的唯一部分是运行时二进制兼容性。您可以告诉人们阅读您的文档,说明 API 在版本 4.0.0 和版本 4.1.0 之间中断;您不能告诉运行时动态链接器阅读您的文档。
于是SONAME
诞生了。链接到您的库的任何动态对象都嵌入了这个 字符串 ,它告诉动态链接器要加载哪个库文件来解析符号。
因为它是一个字符串,所以基本上对它没有任何要求 - 或者其中编码的信息。运行时链接器根本不会解释它;它只关心严格的字符串相等性。
这就是 Lintian 警告的来源 - 没有“soname 的第一部分”;你的 SONAME 是 字符串 libmystuff.so.4.0.0
。 4.0.0 部分对人类有意义,而不是链接器。
由于 SONAME 本质上是任意的,因此围绕它形成了惯例,惯例是 libmystuff
第一个版本的 SONAME 应该是 libmystuff.so.0
,然后是 '.0每次对 ABI 进行不向后兼容的更改时,' 都应增加 1。所以第一个版本是libmystuff.so.0
,第二个ABI是libmystuff.so.1
,第三个ABI是libmystuff.so.2
等等。
这 完全 独立于库版本 - 例如,glibc 项目当前的版本是 2.24 并生成一个带有 SONAME libc.so.6
的库(并且已经完成二十多年来)。
如果您使用项目的版本作为 SONAME,那么每次 更改版本时,必须重建任何使用该库的内容才能使用新库。针对版本 4.0.0 构建的程序将嵌入 字符串 libmystuff.so.4.0.0
,并且不会尝试加载 libmystuff.so.4.0.1
.
我正在为一个库制作一个 Debian 包,我将其命名为 libmystuff。它目前的版本是 4.0.0,下一个版本将是 4.1.0,并且可能会破坏 API 兼容性。该项目使用CMake构建。
在 soname 和包名中应该如何处理?
我想使包版本初始为 4.0.0。如果我将包命名为 libmystuff,则会收到一个 lintian 错误,告诉我将包的 soname 放在包名称中 (package-name-doesnt-match-sonames)。很公平。
如果我将包命名为 libmystuff4,那么我会得到一个名为 libmystuff4-dev_4.0.0-1ubuntu8_amd64.deb
的包文件,这似乎有点多余,但没关系,该包适用于主要版本 4,软件版本为 4.0.0。但我仍然收到一个 lintian 错误提示,
libmystuff4: package-name-doesnt-match-sonames libmystuff4.0.0
所以这让我很惊讶,为什么 lintian 要我把 soname 的所有 3 部分都放在包名中,而不是只放第一部分?
无论如何,我把包名改成libmystuff4.0.0,现在lintian安静了,但是我得到了一个包文件,名字叫libmystuff4.0.0_4.0.0-1ubuntu8_amd64.deb
,看起来很多余!
我该怎么办?
我在想,即使库版本是 4.0.0,soname 也应该是 0,当他们发布 4.1.0 时我应该将 soname 设置为 1,等等。这需要修补上游 CMake 构建系统,这是一种可以接受的方法吗?尽管在那种情况下 soname 的其他部分又如何,我只是将它们设置为 0 吗?那么这个包就是 soname 0.0.0.
否则我不得不在他们发布 4.1.0 时将 soname 更改为 5.0.0,这会很混乱,对吗?
简答:设置当前的SONAME为libmystuff.so.0,4.1.0打破ABI时,设置SONAME为libmystuff.so ].1.您需要修补构建系统并在相关位置引入 set_property(TARGET mystuff PROPERTY SOVERSION 0 )
。
您的 SONAME 与您图书馆的版本不同,可能需要独立发展。
更长的答案: 库有点尴尬,因为它们有两个可以有用地进行版本控制的独立方面:source 兼容性和 binary 兼容性。它们分别是 API 和 ABI。库版本可以保持 API 和源代码兼容,同时破坏 ABI 和二进制不兼容,反之亦然。
幸运的是,需要自动化的唯一部分是运行时二进制兼容性。您可以告诉人们阅读您的文档,说明 API 在版本 4.0.0 和版本 4.1.0 之间中断;您不能告诉运行时动态链接器阅读您的文档。
于是SONAME
诞生了。链接到您的库的任何动态对象都嵌入了这个 字符串 ,它告诉动态链接器要加载哪个库文件来解析符号。
因为它是一个字符串,所以基本上对它没有任何要求 - 或者其中编码的信息。运行时链接器根本不会解释它;它只关心严格的字符串相等性。
这就是 Lintian 警告的来源 - 没有“soname 的第一部分”;你的 SONAME 是 字符串 libmystuff.so.4.0.0
。 4.0.0 部分对人类有意义,而不是链接器。
由于 SONAME 本质上是任意的,因此围绕它形成了惯例,惯例是 libmystuff
第一个版本的 SONAME 应该是 libmystuff.so.0
,然后是 '.0每次对 ABI 进行不向后兼容的更改时,' 都应增加 1。所以第一个版本是libmystuff.so.0
,第二个ABI是libmystuff.so.1
,第三个ABI是libmystuff.so.2
等等。
这 完全 独立于库版本 - 例如,glibc 项目当前的版本是 2.24 并生成一个带有 SONAME libc.so.6
的库(并且已经完成二十多年来)。
如果您使用项目的版本作为 SONAME,那么每次 更改版本时,必须重建任何使用该库的内容才能使用新库。针对版本 4.0.0 构建的程序将嵌入 字符串 libmystuff.so.4.0.0
,并且不会尝试加载 libmystuff.so.4.0.1
.