无CMake变更时如何强制重建version.h或基于SVN版本触发更新?
这个场景我太熟悉了——用configure_file生成版本文件时,默认只检查输入模板的修改时间,只要version.h.in没变,后续构建就不会更新输出文件,哪怕代码库的SVN版本已经变了。这里有两个实用的解决思路,按需选择:
方案一:强制每次构建都重建version.h
如果不管SVN版本有没有变化,你都希望每次构建时都重新生成版本文件,可以通过自定义目标实现。核心是让CMake认为生成版本文件的任务“永远过时”,每次构建都执行:
- 用
add_custom_target封装configure_file命令,并加上ALWAYS标记:
add_custom_target(GenerateVersionHeader ALL COMMAND ${CMAKE_COMMAND} -E configure_file( ${CMAKE_CURRENT_SOURCE_DIR}/version.h.in ${CMAKE_CURRENT_BINARY_DIR}/version/version.h @ONLY ) DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/version.h.in ALWAYS # 关键:强制该目标每次构建都执行 COMMENT "Generating version header..." )
- 让你的主项目目标依赖这个自定义目标,确保构建主项目前先生成版本文件:
# 假设你的主目标是MyProject,替换成实际的目标名 add_executable(MyProject main.cpp) add_dependencies(MyProject GenerateVersionHeader)
这个方法简单直接,但缺点是无论是否需要,每次构建都会执行生成操作,适合对构建效率要求不高的场景。
方案二:基于Subversion版本变更触发重建(更优)
如果想更高效,只在SVN版本变化时才重建version.h,可以通过跟踪SVN版本号的变化来触发更新,步骤如下:
步骤1:编写获取SVN版本的CMake脚本
在项目源码目录下创建GetSVNVersion.cmake文件,内容如下:
# GetSVNVersion.cmake # 从命令行参数获取源码目录和输出文件路径 set(SRC_DIR ${CMAKE_ARGV3}) set(OUT_FILE ${CMAKE_ARGV5}) # 获取当前SVN版本号 execute_process( COMMAND svnversion -n ${SRC_DIR} OUTPUT_VARIABLE SVN_VERSION OUTPUT_STRIP_TRAILING_WHITESPACE ERROR_QUIET ) # 如果svnversion命令失败,设置默认版本号 if(NOT SVN_VERSION) set(SVN_VERSION "unknown") endif() # 检查当前版本和已保存的版本是否一致,不一致则更新文件 if(EXISTS ${OUT_FILE}) file(READ ${OUT_FILE} OLD_SVN_VERSION) if(NOT OLD_SVN_VERSION STREQUAL SVN_VERSION) file(WRITE ${OUT_FILE} ${SVN_VERSION}) endif() else() file(WRITE ${OUT_FILE} ${SVN_VERSION}) endif()
步骤2:在CMakeLists.txt中配置依赖逻辑
# 定义自定义命令,每次构建时检查SVN版本并更新版本文件 set(SVN_VERSION_FILE ${CMAKE_CURRENT_BINARY_DIR}/svn_version.txt) add_custom_command( OUTPUT ${SVN_VERSION_FILE} COMMAND ${CMAKE_COMMAND} -P ${CMAKE_CURRENT_SOURCE_DIR}/GetSVNVersion.cmake ${CMAKE_CURRENT_SOURCE_DIR} ${SVN_VERSION_FILE} COMMENT "Checking Subversion version..." ) # 创建自定义目标,确保上述命令被执行 add_custom_target(CheckSVNVersion ALL DEPENDS ${SVN_VERSION_FILE} ) # 生成version.h,并让它依赖SVN版本文件 configure_file( ${CMAKE_CURRENT_SOURCE_DIR}/version.h.in ${CMAKE_CURRENT_BINARY_DIR}/version/version.h @ONLY ) # 添加SVN版本文件作为version.h的依赖,版本变化时触发重建 set_property( OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/version/version.h APPEND PROPERTY DEPENDS ${SVN_VERSION_FILE} ) # 让主项目目标依赖CheckSVNVersion add_executable(MyProject main.cpp) add_dependencies(MyProject CheckSVNVersion)
步骤3:在version.h.in中引用SVN版本
确保你的version.h.in模板中包含SVN版本变量,比如:
#ifndef VERSION_H #define VERSION_H #define SVN_VERSION "@SVN_VERSION@" #endif // VERSION_H
这个方案的优势在于:只有当SVN版本号变化时,才会重新生成version.h,既保证了版本号的准确性,又不会额外增加不必要的构建开销。
额外注意事项
- 确保构建环境中安装了
svnversion工具,如果找不到,脚本会自动将版本号设为unknown,你可以根据需求修改默认值。 - 如果你的项目使用的是CMake 3.14+,可以用
file(GENERATE)替代configure_file,但核心依赖逻辑是一致的。
内容的提问来源于stack exchange,提问作者the_storyteller
相关产品推荐
相关产品推荐

