21

在 Linux 上创建库时,我使用这种方法:

  1. 构建:libhelloworld.so.1.0.0
  2. 链接:libhelloworld.so.1.0.0 libhelloworld.so
  3. 链接:libhelloworld.so.1.0.0 libhelloworld.so.1

版本控制是这样的,如果您更改面向公众的方法,您可以构建到 libhelloworld.so.2.0.0 例如(并将 1.0.0 保留在原处),这样使用旧库的应用程序就不会中断。

但是,将其命名为 1.0.0 有什么意义 - 为什么不坚持使用 libhelloworld.so 和 libhelloworld.so.1?

此外,最好的做法是使用 1.0.0 来命名您的库,还是仅使用 1?

g++ ... -Wl,-soname,libhelloworld.1

或者:

g++ ... -Wl,-soname,libhelloworld.1.0.0
4

5 回答 5

23

你应该形成 xyz 版本的方式是这样的:

  1. 第一个数字 (x) 是库的接口版本。每当您更改公共接口时,此数字都会增加。
  2. 第二个数字 (y) 是当前接口的版本号。每当您在不更改公共接口的情况下进行内部更改时,这个数字就会上升。
  3. 第三个数字 (z)不是内部版本号,它是向后兼容计数。这告诉您支持多少以前的接口。例如,如果接口版本 4 严格来说是接口 3 和 2 的超集,但与 1 完全不兼容,则 z=2(4-2 = 2,支持的最低接口号)

因此,x 和 z 数字对于系统确定给定应用程序是否可以使用给定库非常重要,给定应用程序的编译对象。y 数字主要用于跟踪错误修复。

于 2009-03-19T17:58:38.113 回答
19

库命名约定

根据Wheeler的说法,我们有real namesonamelinker name

  Real name  libfoo.so.1.2.3
     Soname  libfoo.so.1
Linker name  libfoo.so

real name是包含实际库代码的文件的名称。soname通常是指向 的符号链接,当real name接口以不兼容的方式更改时,其编号会增加。最后,这linker name是链接器在请求库时使用的,它是没有任何版本号的 soname。

因此,要首先回答您的最后一个问题,您应该在创建共享库时soname使用, libhelloworld.so.1, 作为链接器选项:

g++ ... -Wl,-soname,libhelloworld.so.1 ...

在本文档中,Kerrisk 提供了一个非常简短的示例,说明如何使用标准命名约定创建共享库。如果您想了解更多有关 Linux 库的信息,我认为KerriskWheeler都值得一读。

库编号约定

real name关于图书馆中每个数字的意图和目的存在一些混淆。我个人认为Apache Portable Runtime Project很好地解释了每个数字何时应该递增的规则。

简而言之,版本号可以被认为是libfoo.MAJOR.MINOR.PATCH.

  • PATCH对于与其他版本向前和向后兼容的更改增加。
  • MINOR如果库的新版本与旧版本的源代码和二进制兼容,则应递增。不同的次要版本相互向后兼容,但不一定向前兼容。
  • MAJOR当引入破坏 API 的更改或与先前版本不兼容的更改时递增。

这意味着PATCH版本可能仅在内部有所不同,例如功能的实现方式。不允许更改 API、公共函数的签名或函数参数的解释。

MINOR版本可能会引入新函数或常量,并弃用现有函数,但可能不会删除任何外部公开的内容。这确保了向后兼容性。换句话说,次要版本1.12.3可用于替换任何其他1.12.x 或更早版本,例如1.11.21.5.0。不过,它并不是替代品1.16.1,因为不同的次要版本不一定是向前兼容的。

随着新版本的发布,可以进行任何类型的更改MAJOR;常量可能会被删除或更改,(不推荐使用的)函数可能会被删除,当然,通常会增加MINORor数字的任何更改(尽管将此类更改也向后移植到以前的版本PATCH可能是值得的)。MAJOR

当然,还有一些因素会使这进一步复杂化。您可能已经开发了您的库,以便同一个文件可以同时保存多个版本,或者您可能使用. 但这是另一次讨论。:)libtoolcurrent:revision:age

于 2014-01-30T16:47:08.400 回答
4

这种方法的主要优点是很容易让用户知道他们拥有哪个版本的库。例如,如果我知道我遇到的错误已在 1.0.4 中修复,我可以轻松检查我链接的库版本,并知道这是否是修复错误的正确方法。

这个数字被称为“共享对象版本”或“soversion”,是 ELF 二进制标准的一部分。IBM 在http://www.ibm.com/developerworks/power/library/pa-spec12/上有很好的 ELF 概述。

于 2009-03-19T17:49:57.027 回答
3

从我发给同事的一封关于这个问题的旧电子邮件中:

我们以 libxml 为例。首先,共享对象存储在 /usr/lib 中,并带有一系列符号链接来表示可用库的版本:

lrwxrwxrwx 1 root root     16 Apr  4  2002 libxml.so -> libxml.so.1.8.14
lrwxrwxrwx 1 root root     16 Apr  4  2002 libxml.so.1 -> libxml.so.1.8.14
-rwxr-xr-x 1 root root 498438 Aug 13  2001 libxml.so.1.8.14

如果我是 libxml 的作者并且我推出了一个新版本 libxml 2.0.0,它破坏了与以前版本的接口兼容性,我可以将它安装为 libxml.so.2 和 libxml.so.2.0.0。请注意,由应用程序程序员负责他链接到的内容。如果我真的是肛门,我可以直接链接到 libxml.so.1.8.14,任何其他版本都会导致我的程序无法运行。或者我可以链接 libxml.so.1 并希望 libxml 开发人员在 1.X 版本中不会破坏我的符号兼容性。或者,如果您不在乎并且鲁莽,只需链接到 libxml.so 并获取任何版本。有时,当有足够多的人这样做时,图书馆作者必须在以后的版本中发挥创意。因此,libxml2:

lrwxrwxrwx 1 root root     17 Apr  4  2002 libxml2.so.2 -> libxml2.so.2.4.10
-rwxr-xr-x 1 root root 692727 Nov 13  2001 libxml2.so.2.4.10

请注意,此文件中没有 libxml2.so。看起来开发人员已经厌倦了不负责任的应用程序开发人员。

于 2009-03-19T23:05:32.403 回答
1

有几种命名库的方法:

  1. Solaris 风格:.so -> .so.1
  2. GNU 风格:.so -> .so.1 -> .so.1.2.3
  3. 随机:.so -> .so.1.2

看:

https://blogs.oracle.com/ali/entry/how_to_name_a_solaris http://www.gnu.org/software/libtool/manual/libtool.html#Versioning

于 2012-08-17T12:25:05.230 回答