将版本信息附加到 ELF 文件中

问题

工作中,C/C++ 编译出的程序在无要求下,不会携带版本信息。无版本信息下,定位问题时,会非常麻烦。
CICD 可注入版本信息,但对项目有一定侵入性,项目组较抵触。

解决方案

在 Linux 系统中,我们可以将版本号等信息附加到可执行文件中。这些信息对于错误报告和版本控制等场景都非常有用。

CMakeFiles.txt

...
include(gen_version.cmake)

gen_version_info()

add_executable(main src/main.cpp)
add_version_info(main)
...

gen_version.cmake

# 遵循语义化版本规范
set(VERSION_MAJOR 1)
set(VERSION_MINOR 3)
set(VERSION_PATCH 1)
set(VERSION_TWEAK 1)
set(APP_VERSION ${VERSION_MAJOR}.${VERSION_MINOR}.${VERSION_PATCH}.${VERSION_TWEAK})

find_program(OBJCOPY_EXECUTABLE objcopy)

macro(gen_version_info)
if(NOT CMAKE_CURRENT_BINARY_DIR)
message(FATAL_ERROR "Need printf for version embedding")
endif()
if(NOT ${CMAKE_CURRENT_BINARY_DIR}/version_info.bin)
file(WRITE ${CMAKE_CURRENT_BINARY_DIR}/version_info.bin "BuildVersion: ${APP_VERSION}")
message(STATUS "Generate version info file: ${CMAKE_CURRENT_BINARY_DIR}/version_info.bin")
endif()
endmacro()

macro(add_version_info target)
if(NOT OBJCOPY_EXECUTABLE)
message(FATAL_ERROR "Need objcopy for version embedding")
endif()
add_custom_command(TARGET ${target} POST_BUILD
COMMAND ${OBJCOPY_EXECUTABLE} --add-section .version_info=${CMAKE_CURRENT_BINARY_DIR}/version_info.bin $<TARGET_FILE:${target}>
)
message(STATUS "Embedding version info for ${target}")
endmacro()

检查

$ readelf -p .version_info ./build/main

String dump of section '.version_info':
[ 0] BuildVersion: 1.3.1.1

这里的 1.3.1.1 正好对应 gen_version.cmake 中的 APP_VERSION 变量。