我正在为一个库制作一个Debian包,我称它为libmystuff。它目前的版本是4.0.0,下一个版本将是4.1.0,可能会破坏API的兼容性。该项目使用CMake构建。
如何在soname和包名中处理它?</ p>
我想最初将软件包版本设为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
的包文件,这看起来非常多余!
我该怎么办?
我想也许soname应该是0,即使库版本是4.0.0,并且当他们发布4.1.0等时我应该将soname设置为1.这将需要修补上游CMake构建系统,这是一种可接受的方法吗?虽然在那种情况下,soname的其他部分怎么样,我只是将它们设置为0?然后包将是soname 0.0.0。
否则,当他们发布4.1.0时,我必须将soname更改为5.0.0,这会非常混乱,对吗?
答案 0 :(得分:1)
简短回答:将当前SONAME设置为libmystuff.so.0,当您在4.1.0中断开ABI时,将SONAME设置为libmystuff.so.1。您需要修补构建系统并在相关位置引入set_property(TARGET mystuff PROPERTY SOVERSION 0 )
。
您的SONAME 不与您的图书馆版本相同,可能需要独立发展。
更长的答案: 库有点尴尬,因为它们有两个独立的方面可以有用地进行版本化:源兼容性和二进制兼容性。它们分别是 API 和 ABI 。库版本可以在破坏ABI和二进制不兼容的情况下维护API并保持源兼容,反之亦然。
幸运的是,需要自动化的唯一部分是运行时二进制兼容性。您可以告诉人们阅读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
,第三个版本为libmystuff.so.2
,依此类推。
完全独立于库版本 - 例如,glibc项目目前版本为2.24,并生成一个带有SONAME libc.so.6
的库(现在已经做了二十多年了) )。
如果您使用项目的版本作为SONAME,则每次更改版本,必须重建使用库的任何内容才能使用新库。针对4.0.0版构建的程序将嵌入字符串 libmystuff.so.4.0.0
,并且不会尝试加载libmystuff.so.4.0.1
。