如何让CMake在构建前更新version.h并触发main.cpp每次编译?
问题描述
我有一个存储版本信息的头文件version.h,希望每次构建前CMake都能确保该文件的版本信息是最新的。作为测试,我设置CMake在每次构建前执行touch操作更新该文件,本应触发所有包含它的源文件(如main.cpp)每次都重新编译,但实际main.cpp仅隔次编译。
推测原因是CMake在更新version.h之前就已判断是否需要编译main.cpp:
- 若
version.h比main.obj新则标记main.cpp需要编译; - 执行
touch更新version.h; - 编译标记的文件。
导致编译后main.obj比version.h新时,下次构建不会编译main.cpp,反之则会。我使用的是Visual Studio 2022和Ninja,请问如何修改配置以实现每次构建都更新version.h并让main.cpp重新编译?
解决方案
核心思路是让CMake优先完成version.h的更新,再检查源文件的编译依赖,以下是两种可靠的实现方式:
方法一:自定义目标强制前置更新
- 创建一个始终执行的自定义目标,用于更新
version.h(示例用touch,实际可替换为生成版本信息的脚本):
add_custom_target(UpdateVersionHeader ALL COMMAND ${CMAKE_COMMAND} -E touch ${CMAKE_SOURCE_DIR}/version.h COMMENT "Updating version.h timestamp" )
- 将你的可执行目标与该自定义目标绑定依赖,确保构建前先更新头文件:
add_executable(MyApp main.cpp) add_dependencies(MyApp UpdateVersionHeader)
- 标记
version.h为生成文件,让CMake明确它是动态更新的产物:
set_source_files_properties(${CMAKE_SOURCE_DIR}/version.h PROPERTIES GENERATED TRUE)
Ninja会严格按照依赖顺序执行:先运行UpdateVersionHeader更新version.h,再检查main.cpp的依赖状态,此时version.h时间戳已晚于main.obj,必然触发重新编译。
方法二:显式标记源文件依赖
如果方法一仍有问题,可以给main.cpp添加强制依赖属性,明确其目标文件必须跟随version.h更新:
set_source_files_properties(main.cpp PROPERTIES OBJECT_DEPENDS ${CMAKE_SOURCE_DIR}/version.h)
结合方法一的自定义更新目标,可确保每次version.h变化时,main.cpp都会被重新编译。
注意事项
- 路径要使用
CMAKE_SOURCE_DIR或CMAKE_CURRENT_SOURCE_DIR,避免相对路径导致的依赖判断错误; - 实际场景中,可将
touch替换为生成真实版本信息的脚本(比如从Git commit、编译时间生成内容),逻辑完全通用; - Visual Studio 2022 + Ninja组合对上述CMake配置支持良好,无需额外调整IDE设置。
内容的提问来源于stack exchange,提问作者Magnar Myrtveit
相关产品推荐
相关产品推荐

