CMake如何让add_custom_command或自定义函数仅首次调用时执行?
解决方案
问题根因
你当前的实现会给每个调用copyBla的目标都添加独立的POST_BUILD复制命令,并行构建时多个目标的后构建命令会同时执行copy_directory操作,同时写入同一个输出目录,触发文件系统冲突,就是你遇到的复制错误。
实现方案
通过CMake的全局目标唯一性特性,创建唯一的复制目标,所有调用copyBla的目标自动依赖该目标,CMake会保证该目标全局仅执行一次,完全避免并行冲突。
修改后的copyBla函数实现如下:
function(copyBla projectName) # 全局复制目标仅首次调用时定义一次 if(NOT TARGET copy_bla_dlls) add_custom_target(copy_bla_dlls COMMAND ${CMAKE_COMMAND} -E copy_directory ${SDK_PATH}/Bla/${BLA_VERSION}/x64/bin ${CMAKE_BINARY_DIR}/bin/$<CONFIGURATION> # 声明生成产物,方便构建系统做增量构建判断 BYPRODUCTS ${CMAKE_BINARY_DIR}/bin/$<CONFIGURATION> COMMENT "Copying Bla SDK DLLs to output directory" ) endif() # 给当前项目目标添加依赖,保证构建当前目标前已经完成DLL复制 add_dependencies(${projectName} copy_bla_dlls) endfunction()
方案优势
- 复制命令全局仅执行一次,无论多少个目标调用
copyBla都不会出现重复执行的情况,从根源解决并行复制冲突 - 不需要限制调用方,所有需要用到对应DLL的目标只需调用该函数即可自动处理依赖关系,不会出现漏依赖的问题
- 符合CMake原生依赖调度逻辑,增量构建时也只会在源DLL更新或者输出目录缺失时才执行复制操作,不会浪费构建时间
可选优化(增量构建加速)
如果需要实现增量复制(只有源DLL更新时才执行复制操作),可以在add_custom_target中添加DEPENDS参数,指定源目录下的DLL文件:
function(copyBla projectName) if(NOT TARGET copy_bla_dlls) # 扫描源目录下的所有DLL文件作为依赖判断依据 file(GLOB BLA_SDK_DLLS ${SDK_PATH}/Bla/${BLA_VERSION}/x64/bin/*.dll) add_custom_target(copy_bla_dlls COMMAND ${CMAKE_COMMAND} -E copy_directory ${SDK_PATH}/Bla/${BLA_VERSION}/x64/bin ${CMAKE_BINARY_DIR}/bin/$<CONFIGURATION> DEPENDS ${BLA_SDK_DLLS} BYPRODUCTS ${CMAKE_BINARY_DIR}/bin/$<CONFIGURATION> COMMENT "Copying Bla SDK DLLs to output directory" ) endif() add_dependencies(${projectName} copy_bla_dlls) endfunction()
内容的提问来源于stack exchange,提问作者NoSenseEtAl
相关产品推荐
相关产品推荐

