我目前正在按照this website学习Vulkan。目前,我需要将GLSL着色器编译为SPIR-V。与网站仅为着色器(例如,使用bash)创建单独的编译脚本的网站不同,我想完全使用Cmake编写代码。
由于该网站推荐的SPIR-V / GLSL编译器glslc已安装在我系统的路径上(稍后我会担心可移植性。),我决定在cmake函数中使用Cmake的add_custom_command
充当包装以添加要编译的着色器。
但是,当我尝试执行此操作时,好像完全没有对Cmake代码进行任何更改。我的树外生成文件夹或源文件夹中没有生成.spv
文件。当我使用C ++源代码在真实项目上运行VERBOSE=1 make
时,我会看到C ++编译器的命令,但看不到任何glslc
命令。
我认为,罪魁祸首可能是使用Cmake函数进行范围界定的,我通过复制和粘贴函数的源代码,然后手动替换其参数的值,将其中一个着色器调用移至任何函数调用之外。两种样式都显示在下面的MCVE中。
除add_custom_command
之外,Cmake还具有add_custom_target
功能,但是Cmake's documentation表示以下内容:
[add_custom_target]添加具有给定名称的目标,该目标将执行给定命令。目标没有输出文件,即使命令尝试使用目标名称创建文件,也始终将其视为已过期。使用add_custom_command()命令生成具有依赖性的文件。默认情况下,任何内容都不取决于自定义目标。 这不是我想要的,因为我不想每次运行Cmake时都构建我的着色器,而是仅当自上次构建以来已更改glsl文件时,才作为链接C ++应用程序的依赖项他们是,我希望Clion能够认识到这一点。
这是MCVE:
目录结构:
$ tree
.
├── CMakeLists.txt
├── CMakeLists.txt~
├── fragmentshader.glsl
└── vertexshader.glsl
在Linux上重现该问题的命令:
cd /path/to/folder/with/these/files
mkdir cmake-build-test
cd cmake-build-test
cmake ..
make
CMakeLists.txt:
cmake_minimum_required(VERSION 3.14)
project(vulkan_cmake)
function(add_spirv_shader SHADER_STAGE INPUT_FILE OUTPUT_FILE)
add_custom_command(
OUTPUT ${OUTPUT_FILE}
COMMAND "glslc -fshader-stage=${SHADER_STAGE} ${INPUT_FILE} -o ${OUTPUT_FILE}" #glslc is on the system path on my computer, so I am not currently worried about `find_package`ing it.
MAIN_DEPENDENCY ${INPUT_FILE}
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
)
endfunction()
add_spirv_shader(vector vertexshader.glsl vertexshader.hpv)
add_custom_command(
OUTPUT fragment.spv
COMMAND "glslc -fshader-stage=fragment fragmentshader.glsl -o fragment.spv" #glslc is on the system path on my computer, so I am not currently worried about `find_package`ing it.
MAIN_DEPENDENCY fragmentshader.glsl
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
)
fragmentshader.glsl:
#version 450
#extension GL_ARB_separate_shader_objects : enable
layout (location = 0) out vec4 outColor;
void main(){
outColor = vec4(1.0, 0.0, 0.0, 1.0);
}
vertexshader.glsl:
#version 450
#extension GL_ARB_separate_shader_objects : enable
vec2 positions[3] = vec2[](
vec2(0.0, -0.5),
vec2(-0.5, 0.5),
vec2(0.5, 0.5)
);
void main(){
gl_Position = vec4(positions[gl_VertexIndex], 0.0, 1.0);
}
答案 0 :(得分:0)
我是这样做的:
[...]
find_package(Vulkan REQUIRED COMPONENTS glslc)
find_program(glslc_executable NAMES glslc HINTS Vulkan::glslc)
#==============================================================================
# COMPILE SHADERS
#
set(SHADER_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/shaders)
set(SHADER_BINARY_DIR ${CMAKE_CURRENT_BINARY_DIR}/shaders)
file(GLOB SHADERS
${SHADER_SOURCE_DIR}/*.vert
${SHADER_SOURCE_DIR}/*.frag
${SHADER_SOURCE_DIR}/*.comp
${SHADER_SOURCE_DIR}/*.geom
${SHADER_SOURCE_DIR}/*.tesc
${SHADER_SOURCE_DIR}/*.tese
${SHADER_SOURCE_DIR}/*.mesh
${SHADER_SOURCE_DIR}/*.task
${SHADER_SOURCE_DIR}/*.rgen
${SHADER_SOURCE_DIR}/*.rchit
${SHADER_SOURCE_DIR}/*.rmiss)
add_custom_command(
COMMAND
${CMAKE_COMMAND} -E make_directory ${SHADER_BINARY_DIR}
OUTPUT ${SHADER_BINARY_DIR}
COMMENT "Creating ${SHADER_BINARY_DIR}"
)
foreach(source IN LISTS SHADERS)
get_filename_component(FILENAME ${source} NAME)
add_custom_command(
COMMAND
${glslc_executable}
# -MD -MF ${SHADER_BINARY_DIR}/${FILENAME}.d
-o ${SHADER_BINARY_DIR}/${FILENAME}.spv
${source}
OUTPUT ${SHADER_BINARY_DIR}/${FILENAME}.spv
DEPENDS ${source} ${SHADER_BINARY_DIR}
COMMENT "Compiling ${FILENAME}"
)
list(APPEND SPV_SHADERS ${SHADER_BINARY_DIR}/${FILENAME}.spv)
endforeach()
add_custom_target(shaders ALL DEPENDS ${SPV_SHADERS})
请注意,我注释掉了 -MD -MF
,因为它似乎不需要(在我的 linux 机器上)。
有关完整(和最新)版本,请参阅 my project on github