编译后更改Linux共享库(.so文件)版本
Change Linux shared library (.so file) version after it was compiled
我正在编译 Linux 库(针对 Android,使用 NDK 的 g++,但我敢打赌我的问题对任何 Linux 系统都是有意义的)。在将这些库交付给合作伙伴时,我需要用版本号标记它们。 我还必须能够以编程方式访问版本号(例如在 "About" 对话框或 GetVersion
函数中显示它)。
我首先使用未版本化标志(版本 0.0
)编译库,并且在将其发送给合作伙伴之前完成测试后需要将此版本更改为真实版本。我知道修改源代码并重新编译会更容易,但我们不想那样做(因为如果我们重新编译代码,我们应该再次测试所有内容,我们觉得这样更不容易出错,请参阅对此的评论post 最后因为我们的开发环境是这样工作的:我们为 Windows 二进制文件执行此过程:我们设置了 0.0
资源版本字符串 (.rc),稍后我们使用 verpatch...我们希望在发送 Linux 二进制文件时使用相同类型的过程。
最好的策略是什么?
总而言之,要求是:
- 使用 "unset" 版本(
0.0
或其他版本)编译二进制文件
- 能够将此 "unset" 版本修改为特定版本,而无需重新编译二进制文件(理想情况下,运行 第 3 方工具命令,就像我们在 [=61= 下使用 verpatch 所做的那样])
- 能够让库代码在运行时间
检索它的版本信息
如果您的答案是"rename the .so",那么请提供3.的解决方案:如何在运行时间检索版本名称(即:文件名)。
我正在考虑一些解决方案,但不知道它们是否可行以及如何实现它们。
- 代码中有一个版本变量(一个
string
或3个int
),以后有办法在二进制文件中更改它吗?使用二进制 sed...?
- 资源中有一个版本变量,以后有办法在二进制文件中更改它吗? (正如我们为 win32/win64 所做的那样)
- 使用专用于此的 .so 字段(如 SONAME)并使用允许更改它的工具...并使其可从 C++ 代码访问。
- 重命名 lib + 更改 SONAME(未找到如何实现)...并找到一种从 C++ 代码中检索它的方法。
- ...
请注意,我们使用 QtCreator 来编译 Android.so 文件,但它们可能不依赖于 Qt。所以使用Qt资源并不是一个理想的解决方案。
恐怕你从头开始解决你的问题。首先,SONAME 是在 link 时间作为 linker 的参数提供的,所以一开始你需要找到一种方法从源代码中获取版本并传递给 linker。一种可能的解决方案 - 使用 ident
实用程序并在二进制文件中提供版本字符串,例如:
const char version[] = "$Revision:1.2$"
此字符串应以二进制形式出现,ident
实用程序会检测到它。或者您可以直接使用 grep
或类似的东西解析源文件。如果有可能发生冲突,请添加额外的标记,以便您稍后可以使用它来检测此字符串,例如:
const char version[] = "VERSION_1.2_VERSION"
因此您从源文件或 .o 文件中检测版本号,然后将其传递给 linker。这应该有效。
至于debug版本有0.0版本很简单-构建debug时避免检测,无条件使用0.0作为版本即可。
对于第 3 方构建系统,我建议使用 cmake
,但这只是我个人的偏好。解决方案也可以在标准 Makefile 中轻松实现。不过我不确定 qmake
。
与 Slava 的讨论让我意识到任何 const char*
在二进制文件中实际上是可见的,然后可以很容易地修补到其他任何东西。
所以这是解决我自己的问题的好方法:
- 创建一个库:
const char version[] = "VERSIONSTRING:00000.00000.00000.00000";
的定义(我们需要足够长的时间,因为我们以后可以安全地修改二进制文件内容但不扩展它...)
- a
GetVersion
函数将清除上面的 version
变量(删除 VERSIONSTRING:
和无用的 0
)。它会 return:
0.0
如果 version
是 VERSIONSTRING:00000.00000.00000.00000
2.3
如果 version
是 VERSIONSTRING:00002.00003.00000.00000
2.3.40
如果 version
是 VERSIONSTRING:00002.00003.00040.00000
- ...
- 编译库,我们命名为
mylib.so
- 从程序加载它,询问它的版本(调用
GetVersion
),它returns 0.0
,不出意外
- 创建一个小程序(用 C++ 完成,但可以用 Python 或任何其他语言完成)它将:
- 在内存中加载整个二进制文件内容(使用
std::fstream
和 std::ios_base::binary
)
- 在其中找到
VERSIONSTRING:00000.00000.00000.00000
- 确认它只出现一次(以确保我们不会修改我们无意修改的内容,这就是为什么我在字符串前加上
VERSIONSTRING
前缀,以使其更加统一...)
- 如果预期的二进制数是
2.3.40
,则将其修补为 VERSIONSTRING:00002.00003.00040.00000
- 从补丁内容中保存二进制文件
- 补丁
mylib.so
使用上述工具(例如请求版本 2.3
)
- 运行 与步骤 3. 相同的程序,它现在报告
2.3
!
没有重新编译也没有链接,你修补了二进制版本!
我正在编译 Linux 库(针对 Android,使用 NDK 的 g++,但我敢打赌我的问题对任何 Linux 系统都是有意义的)。在将这些库交付给合作伙伴时,我需要用版本号标记它们。 我还必须能够以编程方式访问版本号(例如在 "About" 对话框或 GetVersion
函数中显示它)。
我首先使用未版本化标志(版本 0.0
)编译库,并且在将其发送给合作伙伴之前完成测试后需要将此版本更改为真实版本。我知道修改源代码并重新编译会更容易,但我们不想那样做(因为如果我们重新编译代码,我们应该再次测试所有内容,我们觉得这样更不容易出错,请参阅对此的评论post 最后因为我们的开发环境是这样工作的:我们为 Windows 二进制文件执行此过程:我们设置了 0.0
资源版本字符串 (.rc),稍后我们使用 verpatch...我们希望在发送 Linux 二进制文件时使用相同类型的过程。
最好的策略是什么? 总而言之,要求是:
- 使用 "unset" 版本(
0.0
或其他版本)编译二进制文件 - 能够将此 "unset" 版本修改为特定版本,而无需重新编译二进制文件(理想情况下,运行 第 3 方工具命令,就像我们在 [=61= 下使用 verpatch 所做的那样])
- 能够让库代码在运行时间 检索它的版本信息
如果您的答案是"rename the .so",那么请提供3.的解决方案:如何在运行时间检索版本名称(即:文件名)。
我正在考虑一些解决方案,但不知道它们是否可行以及如何实现它们。
- 代码中有一个版本变量(一个
string
或3个int
),以后有办法在二进制文件中更改它吗?使用二进制 sed...? - 资源中有一个版本变量,以后有办法在二进制文件中更改它吗? (正如我们为 win32/win64 所做的那样)
- 使用专用于此的 .so 字段(如 SONAME)并使用允许更改它的工具...并使其可从 C++ 代码访问。
- 重命名 lib + 更改 SONAME(未找到如何实现)...并找到一种从 C++ 代码中检索它的方法。
- ...
请注意,我们使用 QtCreator 来编译 Android.so 文件,但它们可能不依赖于 Qt。所以使用Qt资源并不是一个理想的解决方案。
恐怕你从头开始解决你的问题。首先,SONAME 是在 link 时间作为 linker 的参数提供的,所以一开始你需要找到一种方法从源代码中获取版本并传递给 linker。一种可能的解决方案 - 使用 ident
实用程序并在二进制文件中提供版本字符串,例如:
const char version[] = "$Revision:1.2$"
此字符串应以二进制形式出现,ident
实用程序会检测到它。或者您可以直接使用 grep
或类似的东西解析源文件。如果有可能发生冲突,请添加额外的标记,以便您稍后可以使用它来检测此字符串,例如:
const char version[] = "VERSION_1.2_VERSION"
因此您从源文件或 .o 文件中检测版本号,然后将其传递给 linker。这应该有效。
至于debug版本有0.0版本很简单-构建debug时避免检测,无条件使用0.0作为版本即可。
对于第 3 方构建系统,我建议使用 cmake
,但这只是我个人的偏好。解决方案也可以在标准 Makefile 中轻松实现。不过我不确定 qmake
。
与 Slava 的讨论让我意识到任何 const char*
在二进制文件中实际上是可见的,然后可以很容易地修补到其他任何东西。
所以这是解决我自己的问题的好方法:
- 创建一个库:
const char version[] = "VERSIONSTRING:00000.00000.00000.00000";
的定义(我们需要足够长的时间,因为我们以后可以安全地修改二进制文件内容但不扩展它...)- a
GetVersion
函数将清除上面的version
变量(删除VERSIONSTRING:
和无用的0
)。它会 return:0.0
如果version
是VERSIONSTRING:00000.00000.00000.00000
2.3
如果version
是VERSIONSTRING:00002.00003.00000.00000
2.3.40
如果version
是VERSIONSTRING:00002.00003.00040.00000
- ...
- 编译库,我们命名为
mylib.so
- 从程序加载它,询问它的版本(调用
GetVersion
),它returns0.0
,不出意外 - 创建一个小程序(用 C++ 完成,但可以用 Python 或任何其他语言完成)它将:
- 在内存中加载整个二进制文件内容(使用
std::fstream
和std::ios_base::binary
) - 在其中找到
VERSIONSTRING:00000.00000.00000.00000
- 确认它只出现一次(以确保我们不会修改我们无意修改的内容,这就是为什么我在字符串前加上
VERSIONSTRING
前缀,以使其更加统一...) - 如果预期的二进制数是
2.3.40
,则将其修补为 - 从补丁内容中保存二进制文件
VERSIONSTRING:00002.00003.00040.00000
- 在内存中加载整个二进制文件内容(使用
- 补丁
mylib.so
使用上述工具(例如请求版本2.3
) - 运行 与步骤 3. 相同的程序,它现在报告
2.3
!
没有重新编译也没有链接,你修补了二进制版本!