CMake条件性自定义命令问题:仅当DLL存在时自动复制至输出目录
解决CMake构建后仅在DLL存在时自动复制的问题
你的需求完全可以实现,以下是两种可行的解决方案,同时分析你之前尝试方案的问题所在:
方案一:使用生成器表达式实现简洁判断
利用CMake的生成器表达式在构建时动态检查文件是否存在,仅当DLL存在时执行复制操作,代码如下:
if(WIN32) # 定义DLL路径,使用生成器表达式获取当前构建配置 set(ASSIMP_DLL_PATH "${PROJECT_SOURCE_DIR}/build/vendor/assimp/bin/$<CONFIGURATION>/assimp-vc143-mtd.dll") add_custom_command(TARGET Game POST_BUILD # 用$<IF>根据文件是否存在选择执行复制或空操作 COMMAND ${CMAKE_COMMAND} -E $<IF:$<EXISTS:${ASSIMP_DLL_PATH}>,copy_if_different,true> ${ASSIMP_DLL_PATH} $<TARGET_FILE_DIR:Game> COMMENT "检查并复制assimp DLL..." ) endif()
原理说明
$<EXISTS:${ASSIMP_DLL_PATH}>:生成器表达式,在构建阶段检查文件是否存在(而非配置阶段),能正确识别不同构建配置(Debug/Release)下的路径。$<IF:条件,真分支命令,假分支命令>:根据前面的检查结果,选择执行copy_if_different复制文件,或true(空操作,什么都不做)。- 外层的
if(WIN32)确保仅在Windows平台执行该逻辑,符合你Linux下使用静态库的背景。
方案二:使用外部脚本处理复杂逻辑
如果需要更复杂的判断逻辑,可通过外部CMake脚本实现,核心是在调用脚本时传递必要的构建参数(如当前配置),避免生成器表达式在脚本中无法展开的问题:
1. 在主CMakeLists.txt中添加自定义命令
if(WIN32) add_custom_command(TARGET Game POST_BUILD COMMAND ${CMAKE_COMMAND} -P "${CMAKE_CURRENT_SOURCE_DIR}/copy_assimp_dll.cmake" --config $<CONFIGURATION> --source-dir "${PROJECT_SOURCE_DIR}" --target-dir $<TARGET_FILE_DIR:Game> COMMENT "检查并复制assimp DLL..." ) endif()
2. 编写copy_assimp_dll.cmake脚本
cmake_minimum_required(VERSION 3.10) # 解析命令行传入的参数 set(options "") set(oneValueArgs CONFIG SOURCE_DIR TARGET_DIR) set(multiValueArgs "") cmake_parse_arguments(PARSE_ARGV 0 ARG "${options}" "${oneValueArgs}" "${multiValueArgs}") # 拼接完整的DLL路径 set(ASSIMP_DLL_PATH "${ARG_SOURCE_DIR}/build/vendor/assimp/bin/${ARG_CONFIG}/assimp-vc143-mtd.dll") if(EXISTS "${ASSIMP_DLL_PATH}") message(STATUS "复制assimp DLL: ${ASSIMP_DLL_PATH} -> ${ARG_TARGET_DIR}") execute_process( COMMAND ${CMAKE_COMMAND} -E copy_if_different "${ASSIMP_DLL_PATH}" "${ARG_TARGET_DIR}" RESULT_VARIABLE COPY_RESULT ) if(NOT COPY_RESULT EQUAL 0) message(WARNING "复制assimp DLL失败") endif() else() message(STATUS "未找到assimp DLL: ${ASSIMP_DLL_PATH},跳过复制") endif()
原理说明
- 通过命令行参数传递
$<CONFIGURATION>等生成器表达式展开后的值,确保脚本能正确找到对应配置下的DLL。 - 使用
execute_process在脚本中执行复制命令,替代无法在脚本中使用的add_custom_command(后者是配置阶段命令,不能在运行时脚本中调用)。
你之前方案的错误分析
- 方案一错误:
add_custom_command的COMMAND字段是要执行的系统命令/CMake命令,不能直接嵌套CMake的if()控制语句,CMake会把这些语句当作命令的一部分解析,导致语法错误。 - 方案二错误:外部脚本是在构建阶段执行的,而
add_custom_command是配置阶段的命令,此时构建系统已经生成完成,在脚本中调用add_custom_command不会生效;同时生成器表达式$<CONFIGURATION>在脚本中不会被CMake自动展开,导致路径错误。 - 方案三错误:
add_custom_command属于CMake的配置阶段指令,只能在CMakeLists.txt的配置过程中使用,不能在-P模式运行的脚本(运行时执行)中调用,因此触发add_custom_command command is not scriptable错误。
内容的提问来源于stack exchange,提问作者J. Doe
相关产品推荐
相关产品推荐

