CMake:如何为已有目标构建仅按需更新的额外文件?
解决CMake主目标按需生成额外文件的问题
核心问题分析
你遇到的两个痛点本质是CMake对目标和文件的依赖处理逻辑不同:
add_custom_target本身没有输出文件,CMake无法通过时间戳判断它是否过时,所以每次构建都会执行命令add_dependencies只能接受CMake目标作为依赖项,不能直接关联add_custom_command生成的普通文件
正确解决方案:结合add_custom_command和add_custom_target
通过“自定义命令生成文件 + 自定义目标关联文件”的组合,既能实现依赖跟踪,又能让主目标触发文件生成:
function(register_translation_files) # 解析传入参数 set(options "") set(oneValueArgs TARGET) set(multiValueArgs INPUT) cmake_parse_arguments(ARG "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN}) set(TARGET ${ARG_TARGET}) set(INPUT_FILES ${ARG_INPUT}) foreach (LANG IN LISTS TRANSLATION_LANGUAGES) message ("Add translation '${LANG}' for target ${TARGET}") set(XLF_FILE "${TARGET}_${LANG}.xlf") # 定义生成文件的命令,实现依赖跟踪 add_custom_command( OUTPUT ${XLF_FILE} COMMAND scripts/cet2xlf.py --language ${LANG} ${XLF_FILE} ${INPUT_FILES} DEPENDS ${INPUT_FILES} WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} COMMENT "Generating translation file ${XLF_FILE}" ) # 创建自定义目标,依赖生成的文件(避免文件名冲突,增加前缀) set(TARGET_NAME "${TARGET}_${LANG}_xlf_target") add_custom_target( ${TARGET_NAME} ALL # 让这个目标默认被构建 DEPENDS ${XLF_FILE} ) # 让主目标依赖这个自定义目标 add_dependencies(${TARGET} ${TARGET_NAME}) endforeach() endfunction() # 使用示例 add_executable(MainTarget foo.cpp bla.cpp) register_translation_files(TARGET MainTarget INPUT file1 file2)
为什么这个方案有效
add_custom_command负责具体的文件生成逻辑,通过DEPENDS跟踪输入文件的变化,只有当输入文件更新时,才会重新运行脚本生成新的XLF文件- 自定义目标
${TARGET_NAME}依赖生成的XLF文件,CMake会检查XLF文件的时间戳:如果文件已经是最新的,这个目标不会执行任何操作 - 主目标依赖这个自定义目标,保证构建主目标时会自动触发文件生成,且完全遵循依赖更新规则
对之前错误写法的补充说明
- 直接用
add_dependencies(${TARGET} ${XLF_FILE})报错,是因为add_dependencies的第二个参数必须是CMake目标(比如add_executable/add_library/add_custom_target创建的对象),不能是普通文件 - 纯
add_custom_target每次执行,是因为它没有关联任何输出文件,CMake无法验证它的“最新状态”,只能默认每次都执行命令
内容的提问来源于stack exchange,提问作者JvO
相关产品推荐
相关产品推荐

