有人可以解释一下Linux库命名吗?

时间:2009-03-19 17:36:26

标签: c++ linux shared-libraries

当我在Linux上创建一个库时,我使用这个方法:

  1. 构建:libhelloworld.so.1.0.0
  2. 链接:libhelloworld.so.1.0.0 libhelloworld.so
  3. 链接:libhelloworld.so.1.0.0 libhelloworld.so.1
  4. 版本控制是这样的,如果您更改面向公众的方法,您可以构建到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 个答案:

答案 0 :(得分:23)

你应该形成x.y.z版本的方式是这样的:

  1. 第一个数字(x)是库的接口版本。每当您更改公共界面时,此数字都会增加。
  2. 第二个数字(y)是当前界面的修订号。无论何时在不更改公共界面的情况下进行内部更改,此数字都会增加。
  3. 第三个数字(z)一个内部版本号,它是向后兼容性计数。这告诉您支持多少以前的接口。因此,例如,如果接口版本4严格地是接口3和2的超集,但与1完全不兼容,那么z = 2(4-2 = 2,支持的最低接口数)
  4. 因此,对于系统来说,x和z数字对于确定给定应用程序是否可以使用给定库非常重要,因为应用程序的编译对象是什么。 y号主要用于跟踪错误修复。

答案 1 :(得分:12)

库命名约定

根据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。

因此,要首先回答您的上一个问题,您应该使用sonamelibhelloworld.so.1作为链接器选项when creating the shared library

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

In this document,Kerrisk提供了一个非常简短的示例,说明如何使用标准命名约定创建共享库。如果你想了解更多关于Linux库的信息,我认为KerriskWheeler非常值得一读。

图书馆编号惯例

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

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

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

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

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

发布新的MAJOR版本可以进行任何类型的更改;常量可能被删除或更改,(已弃用)函数可能会被删除,当然,任何通常会增加MINORPATCH数字的更改(尽管将这些更改反向移植可能是值得的)以前的MAJOR版本也是如此。

当然,有些因素会使这种情况进一​​步复杂化;您可能已经开发了库,以便同一文件可以hold multiple versions simultaneously,或者您可以使用libtool current:revision:age的约定。但这是另一次讨论。 :)

答案 2 :(得分:4)

此方法的主要优点是可以让用户轻松了解他们拥有的库版本。例如,如果我知道我在1.0.4中修复了一个错误,我可以轻松检查我链接的库的版本,并知道这是否是解决错误的正确方法。

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

答案 3 :(得分:2)

从我发给同事的旧电子邮件中提到这个问题:

让我们以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。看起来像开发者 厌倦了不负责任的应用程序开发人员。