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

时间:2016-05-30 08:04:03

标签: c++ linux g++ shared-libraries versioning

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

我首先使用无版本标记(版本0.0)编译库,并且在我将测试发送给合作伙伴之前完成测试时需要将此版本更改为真实版本。我知道修改源代码并重新编译会更容易,但我们不想这样做(因为如果我们重新编译代码,我们应该再测试一下,我们觉得它不会出错,请参阅注释到这篇文章,最后因为我们的开发环境以这种方式工作:我们为Windows二进制文件执行此过程:我们设置了0.0资源版本字符串(.rc),我们稍后使用verpatch更改它。 。我们希望在运送Linux二进制文件时使用相同类型的过程。)

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

  1. 使用" unset"编译二进制文件版本(0.0或其他任何内容)
  2. 能够修改这个"未设置"版本到特定的版本而不必重新编译二进制文件(理想情况下,运行第三方工具命令,就像在Windows下使用verpatch一样)
  3. 能够让库代码在运行时检索它的版本信息
  4. 如果您的答案是"重命名.so",请提供3的解决方案:如何在运行时检索版本名称(即:文件名)。

    我在考虑一些解决方案,但不知道它们是否可以工作以及如何实现它们。

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

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

2 个答案:

答案 0 :(得分:2)

恐怕你从最后开始解决问题了。首先,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

答案 1 :(得分:2)

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

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

  1. 使用以下命令创建库:
    • const char version[] = "VERSIONSTRING:00000.00000.00000.00000";的定义(我们需要它足够长,因为我们以后可以安全地修改二进制文件内容但不能扩展它......)
    • 一个GetVersion函数,用于清除上面的version变量(删除VERSIONSTRING:和无用的0)。它将返回:
        如果0.0version ,则为
      • VERSIONSTRING:00000.00000.00000.00000 如果2.3version
      • ,则为
      • VERSIONSTRING:00002.00003.00000.00000 如果2.3.40version
      • ,则为
      • VERSIONSTRING:00002.00003.00040.00000
      • ...
  2. 编译库,我们将其命名为mylib.so
  3. 从程序中加载它,询问其版本(调用GetVersion),它返回0.0,毫不奇怪
  4. 创建一个小程序(在C ++中完成,但可以在Python或任何其他语言中完成),它将:
    • 将整个二进制文件内容加载到内存中(使用std::fstream std::ios_base::binary
    • 在其中找到VERSIONSTRING:00000.00000.00000.00000
    • 确认它只出现一次(为了确保我们不修改我们不想要的东西,这就是为什么我在字符串前面添加VERSIONSTRING,以使其更加单一......)
    • 如果预期二进制数为VERSIONSTRING:00002.00003.00040.00000 ,则
    • 将其修补为2.3.40
    • 从修补内容中保存二进制文件
  5. 使用上述工具(请求版本mylib.so
  6. 修补2.3
  7. 运行与步骤3相同的程序,现在报告2.3
  8. 没有重新编译也没有链接,你修补了二进制版本!