如何通过CMake将add_custom_command生成文件复制到目标可执行文件相对路径?
解决CMake中复制编译后脚本到目标目录的问题
针对你需要将add_custom_command生成的编译脚本文件复制到可执行文件目录的Resources/Script下的需求,以下是两种可靠的解决方案,能解决你之前遇到的「无法感知脚本变更」「不必要复制」的问题:
方案一:改进POST_BUILD自定义命令
通过给POST_BUILD命令添加依赖,让CMake仅在编译后的脚本文件更新时执行复制操作,同时避免不必要的文件拷贝:
# 编译源脚本生成目标文件,保留原有的逻辑 add_custom_command( OUTPUT ${CompiledFile} COMMAND ${ScriptCompiler} ${ScriptFile} -o ${CompiledFile} DEPENDS ${ScriptFile} COMMENT "编译脚本 ${ScriptFile}" ) # 可选:若需将编译后的脚本作为静态库资源,保留此步骤(需指定链接语言避免CMake报错) add_library(CompiledScripts STATIC ${CompiledFile}) set_target_properties(CompiledScripts PROPERTIES LINKER_LANGUAGE CXX) # 定义主可执行文件 add_executable(Main main.cpp) # 添加POST_BUILD复制命令,关键新增DEPENDS和copy_if_different add_custom_command( TARGET Main POST_BUILD # 先确保目标目录存在 COMMAND ${CMAKE_COMMAND} -E make_directory "$<TARGET_FILE_DIR:Main>/Resources/Script/$<CONFIG>" # 仅当源文件与目标文件不同时才复制 COMMAND ${CMAKE_COMMAND} -E copy_if_different "${CompiledFile}" "$<TARGET_FILE_DIR:Main>/Resources/Script/$<CONFIG>/$<TARGET_FILE_NAME:${CompiledFile}>" # 依赖编译后的脚本文件,仅当该文件更新时才执行复制 DEPENDS ${CompiledFile} COMMENT "将编译后的脚本复制到Main的Resources目录" )
优势
- 逻辑简洁,直接绑定到可执行文件的构建流程
copy_if_different避免无意义的文件覆盖DEPENDS ${CompiledFile}确保仅在脚本源文件变更(触发CompiledFile更新)时执行复制
方案二:自定义复制目标+明确依赖链
若需要更清晰的文件跟踪逻辑,可通过自定义目标绑定复制操作,避免自定义目标始终处于过期状态:
# 编译源脚本生成目标文件 add_custom_command( OUTPUT ${CompiledFile} COMMAND ${ScriptCompiler} ${ScriptFile} -o ${CompiledFile} DEPENDS ${ScriptFile} COMMENT "编译脚本 ${ScriptFile}" ) add_library(CompiledScripts STATIC ${CompiledFile}) set_target_properties(CompiledScripts PROPERTIES LINKER_LANGUAGE CXX) add_executable(Main main.cpp) # 定义复制后的目标文件路径(含配置目录,适配Debug/Release等不同构建配置) set(CopiedScriptFile "$<TARGET_FILE_DIR:Main>/Resources/Script/$<CONFIG>/$<TARGET_FILE_NAME:${CompiledFile}>") # 定义复制操作的自定义命令,输出为目标路径的文件 add_custom_command( OUTPUT ${CopiedScriptFile} COMMAND ${CMAKE_COMMAND} -E make_directory "$<TARGET_FILE_DIR:Main>/Resources/Script/$<CONFIG>" COMMAND ${CMAKE_COMMAND} -E copy_if_different "${CompiledFile}" "${CopiedScriptFile}" DEPENDS ${CompiledFile} COMMENT "将编译后的脚本复制到Main的Resources目录" ) # 创建自定义目标,依赖复制后的文件(ALL参数确保默认构建时执行) add_custom_target(CopyScript ALL DEPENDS ${CopiedScriptFile}) # 让主可执行文件依赖复制目标,确保复制完成后再构建Main add_dependencies(Main CopyScript)
优势
- 通过
OUTPUT跟踪复制后的文件,CMake会自动判断是否需要重新执行复制操作,避免目标始终过期 - 依赖链清晰:
Main→CopyScript→CopiedScriptFile→CompiledFile→ScriptFile,源脚本变更会触发全流程更新
为什么之前的方案失效?
- add_custom_target问题:之前未通过
OUTPUT或BYPRODUCTS跟踪复制后的文件,导致CMake认为目标始终过期;且未正确设置依赖链,应让自定义目标依赖CompiledFile,再让Main依赖自定义目标。 - POST_BUILD问题:之前未添加
DEPENDS ${CompiledFile},导致无论编译后的脚本是否更新,每次构建都会执行复制操作。
内容的提问来源于stack exchange,提问作者Sam Coutteau
相关产品推荐
相关产品推荐

