c++ - 如何使用 CMake 将文件放在目标文件位置旁边?
问题描述
我想自动将 GLSL 着色器构建到 SPIR-V,然后使用 CMake 将它们复制到可执行目标的位置。为此,我创建了以下函数:
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 "$<TARGET_FILE:${target_name}>/../${path_in_raw}.spv")
add_custom_command(OUTPUT ${path_out}
COMMAND glslc ${path_in} -o ${path_out}
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
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()
它需要一个目标名称和一个 GLSL 文件列表作为参数。我这样调用它:
add_executable(mini-vk main.cpp)
target_shaders(mini-vk "basic.vert;basic.frag")
我希望这能够编译basic.vert
并编译到位于同一目录中的basic.frag
相应文件。不幸的是,我收到以下错误:.spv
mini-vk.exe
[cmake] CMake Error at CMakeLists.txt:9 (add_custom_command):
[cmake] Error evaluating generator expression:
[cmake]
[cmake] $<TARGET_FILE:mini-vk>
[cmake]
[cmake] No target "mini-vk"
[cmake] Call Stack (most recent call first):
[cmake] CMakeLists.txt:26 (target_shaders)
我不确定为什么没有“没有目标mini-vk
”,因为它是在上面的行中创建的target_shaders
。
为清楚起见,如果我通过更改以下定义手动键入输出路径,则代码确实有效path_out
:
set(path_out "${CMAKE_CURRENT_SOURCE_DIR}/build/Debug/${path_in_raw}.spv")
不过,我不想使用这个 hack。
解决方案
这是一个涉及邮票文件的解决方案。与其使用“真实”路径作为 ,不如OUTPUT
使用一个空文件作为其时间戳,然后继续使用TARGET_FILE_DIR
生成器表达式运行您真正想要的命令。
cmake_minimum_required(VERSION 3.21)
project(test)
find_package(Vulkan REQUIRED)
function(target_shaders name)
set(shaders "")
foreach (input IN LISTS ARGN)
# Might want to add code to handle clashing names
# in different directories (e.g. ./basic.vert and
# ./subdir/basic.vert)
cmake_path(GET input FILENAME stem)
cmake_path(ABSOLUTE_PATH input
BASE_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}"
NORMALIZE)
add_custom_command(
OUTPUT "${stem}.stamp"
COMMAND Vulkan::glslc "${input}" -o "$<TARGET_FILE_DIR:${name}>/${stem}.spv"
COMMAND "${CMAKE_COMMAND}" -E touch "${stem}.stamp"
DEPENDS "${input}"
)
list(APPEND shaders "${stem}.stamp")
endforeach ()
add_custom_target("${name}.shaders" DEPENDS ${shaders})
add_dependencies("${name}" "${name}.shaders")
endfunction()
# Just to test changing the output directory
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY bin)
add_executable(mini-vk main.cpp)
target_shaders(mini-vk basic.vert "${CMAKE_CURRENT_SOURCE_DIR}/basic.frag")