编译后更改Linux共享库(.so文件)版本

我正在编译Linux库(对于Android,使用NDK的g ++,但是我敢打赌,我的问题对于任何Linux系统都是有意义的)。 将这些库提供给合作伙伴时,我需要用一个版本号来标记它们。 我还必须能够以编程方式访问版本号 (例如,在“关于”对话框或GetVersion函数中显示它)。

我首先编译带有未版本标志(版本为0.0 )的库,并且在完成testing之后,需要将此版本更改为真正的版本,然后将其发送给合作伙伴。 我知道修改源代码和重新编译会更容易,但是我们不想这样做(因为如果我们重新编译代码,我们应该再次testing所有东西,我们觉得这样做不太容易出错,请参阅这个注释最后是因为我们的开发环境是这样工作的:我们为Windows二进制文件执行这个过程:我们设置一个0.0版本的资源版本string(.rc),之后我们使用verpatch进行更改 …我们希望使用相同的运送Linux二进制文件时的过程)。

这里最好的策略是什么? 总而言之,要求是:

  1. 用“未设置”版本编译二进制文件( 0.0或其他)
  2. 能够修改这个“unset”版本到一个特定的版本,而不必重新编译二进制文件(理想情况下,运行第三方工具命令,就像我们在Windows下的verpatch一样)
  3. 能够让库代码在运行时检索它的版本信息

如果你的答案是“重命名.so”,那么请提供3的解决scheme:如何在运行时检索版本名称(即:文件名)。

我正在考虑一些解决scheme,但不知道他们是否可以工作以及如何实现这些解决scheme。

  • 在代码中有一个版本variables(一个string或3个int ),并且有办法在以后的二进制文件中更改它? 使用二进制sed …?
  • 在资源中有一个版本variables,并有办法在以后的二进制文件中更改它? (就像我们为win32 / win64所做的那样)
  • 使用.so(如SONAME)专用的字段,并有一个工具允许更改它…并使其可以从C ++代码访问。
  • 重命名lib +更改SONAME(没有find如何实现)…并find一种方法来从C ++代码中检索它。

请注意,我们使用QtCreator编译Android .so文件,但它们可能不依赖于Qt。 所以使用Qt资源不是一个理想的解决scheme。

恐怕你从最后开始解决你的问题。 首先SONAME在链接时作为链接器的参数提供,所以一开始你需要找到一种从源代码获取版本并传递给链接器的方法。 可能的解决方案之一 – 使用ident实用程序并在二进制文件中提供版本字符串,例如:

 const char version[] = "$Revision:1.2$" 

这个字符串应该以二进制形式出现, ident实用程序会检测到它 或者你可以直接用grep或类似的东西解析源文件。 如果有冲突的可能性加上附加的标记,以后可以使用它来检测这个字符串,例如:

 const char version[] = "VERSION_1.2_VERSION" 

因此,您可以从源文件或.o文件中检测版本号,并将其传递给链接器。 这应该工作。

至于版本为0.0的调试版,这很容易 – 只要避免在构建调试时进行检测,并无条件地使用0.0作为版本。

对于第三方构建系统,我会推荐使用cmake ,但这只是我个人的偏好。 解决方案也可以在标准的Makefile中轻松实现。 不过我不确定qmake

与Slava讨论使我意识到任何const char*实际上在二进制文件中是可见的,然后可以很容易地修补到其他任何东西。

所以这里是解决我自己的问题的一个好方法:

  1. 创建一个库:
    • const char version[] = "VERSIONSTRING:00000.00000.00000.00000"; (我们需要它足够长的时间,以后我们可以安全地修改二进制文件的内容,但不能扩展它…)
    • 一个GetVersion函数将清除上面的version变量(删除VERSIONSTRING:和无用的0 )。 它会返回:
      • 0.0如果versionVERSIONSTRING:00000.00000.00000.00000
      • 2.3如果versionVERSIONSTRING:00002.00003.00000.00000
      • 2.3.40 versionVERSIONSTRING:00002.00003.00040.00000
  2. 编译这个库,我们把它命名为mylib.so
  3. 从程序加载它,问它的版本(调用GetVersion ),它返回0.0 ,没有什么意外
  4. 创建一个小程序(用C ++编写,但可以用Python或其他语言编写):
    • 在内存中加载整个二进制文件内容(使用std::fstreamstd::ios_base::binary
    • 在其中找到VERSIONSTRING:00000.00000.00000.00000
    • 确认它只出现一次(确保我们不修改我们不想要的东西,这就是为什么我用字符串前缀VERSIONSTRING ,使其更独特…)
    • 如果预期的二进制数字是2.3.40其修补到VERSIONSTRING:00002.00003.00040.00000 2.3.40
    • 从修补的内容中保存二进制文件
  5. 使用上述工具修补mylib.so (例如请求版本2.3
  6. 运行与第3步相同的程序,现在报告2.3

没有重新编译也没有链接,你修补了二进制版本!