如何使用CMake将编译产物放置到目标可执行文件的同级目录
问题根因
你遇到的报错是因为 add_custom_command 的 OUTPUT 参数不支持使用带目标引用的生成器表达式。CMake 在配置阶段解析 add_custom_command 时,需要提前确定输出文件的路径,而 $<TARGET_FILE:${target_name}> 这类生成器表达式要到构建系统生成阶段才会求值,因此 CMake 无法在配置阶段识别出你已经创建了 mini-vk 目标,才会抛出目标不存在的错误。
另外你写法里用 $<TARGET_FILE:${target_name}>/../ 来取目标目录也不规范,CMake 提供了专门的生成器表达式 $<TARGET_FILE_DIR:${target_name}> 直接获取目标文件的所在目录。
最优修复方案
不需要硬编码路径,完全跟随目标的输出目录自动适配,同时支持增量编译:
function(target_shaders target_name) # 取除第一个参数外的所有入参作为着色器路径列表,无需手动封装引号 set(shader_paths ${ARGN}) add_custom_target("${target_name}_shaders" COMMENT "Compiling GLSL shaders for ${target_name}" VERBATIM ) foreach(path_in_raw ${shader_paths}) set(path_in "${CMAKE_CURRENT_SOURCE_DIR}/${path_in_raw}") # 直接用专用生成器表达式获取目标输出目录 set(path_out "$<TARGET_FILE_DIR:${target_name}>/${path_in_raw}.spv") # 改用 TARGET 型自定义命令,COMMAND 字段支持生成器表达式 add_custom_command(TARGET "${target_name}_shaders" PRE_BUILD COMMAND glslc ${path_in} -o ${path_out} MAIN_DEPENDENCY ${path_in} COMMENT "Compiling GLSL shader ${path_in}" ) endforeach() add_dependencies(${target_name} "${target_name}_shaders") endfunction()
对应的调用方式也可以简化,不需要用引号包裹着色器列表:
add_executable(mini-vk main.cpp) target_shaders(mini-vk basic.vert basic.frag)
可选适配方案
如果你需要兼容旧版CMake,也可以提前统一设置可执行目标的输出目录,适配多配置生成器(Visual Studio、XCode等):
# 全局设置所有可执行目标的输出目录,多配置生成器会自动追加配置名子目录 set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin) function(target_shaders target_name paths_in) set(paths_out "") foreach(path_in_raw ${paths_in}) set(path_in "${CMAKE_CURRENT_SOURCE_DIR}/${path_in_raw}") # 路径配置阶段即可确定,支持增量编译检测 set(path_out "${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/$<CONFIG>/${path_in_raw}.spv") add_custom_command(OUTPUT ${path_out} COMMAND glslc ${path_in} -o ${path_out} DEPENDS ${path_in} COMMENT "Compiling GLSL shader ${path_in}" ) list(APPEND paths_out ${path_out}) endforeach() add_custom_target("${target_name}_shaders" DEPENDS ${paths_out}) add_dependencies(${target_name} "${target_name}_shaders") endfunction()
内容的提问来源于stack exchange,提问作者janekb04
相关产品推荐
相关产品推荐

