CMake 关于 includes/dependencies 的 GLSLC 调用

CMake invocation of GLSLC with respect to includes/dependencies

我正在使用 glslc 编译带有 #includes 的 GLSL 着色器(不是核心规范 IIRC 的一部分,但在 shaderc 中受支持,它是 glslc 背后的引擎,分布式使用 LunarG Vulkan SDK) 到 SPIR-V for Vulkan 和 GL 4.5。 glslc 发出包含依赖信息的 gcc 风格的 depsfiles ([my_shader].[ext].d) 文件。

我的项目是用 cmake/ninja/MSVC 2017 构建的。

今天,当磁盘上的着色器发生更改时,我使用 cmake custom_command 调用 glslc,作为对我的主要目标的 post 构建步骤。但是,这不会捕捉到包含文件中的更改(根本不知道 .d 文件或其内容),因此当包含的 glsl 文件发生更改时重建着色器可能会使我自己和我团队中的其他人绊倒。

看起来 ninja 可以调用任意编译器,并且由于 ninja 知道如何处理 deps 文件,我应该能够强制 ninja 进入 运行 glslc -- 不确定其他构建系统,因为现在我们'重新标准化忍者。

那么我如何告诉 cmake 将 ninja 配置为对特定目标使用 glslc?还是有一种典型的方法来完成这项工作?看起来 cmake pull request to add support for glslc as a compiler 并没有在 2016 年左右进入 cmake,所以无论我做什么都将是一个解决方法。

CMake 在与 ninja 结合使用时可以理解 depfiles。

DEPFILE

Specify a .d depfile for the Ninja generator. A .d file holds dependencies usually emitted by the custom command itself. Using DEPFILE with other generators than Ninja is an error.

add_custom_command(
    OUTPUT ${source}.h
    DEPENDS ${source}
    COMMAND
        glslc
        -MD -MF ${source}.d
        -o ${source}.h -mfmt=num
        --target-env=opengl
        ${CMAKE_CURRENT_SOURCE_DIR}/${source}
    DEPFILE ${source}.d
)
  -M                Generate make dependencies. Implies -E and -w.
  -MM               An alias for -M.
  -MD               Generate make dependencies and compile.
  -MF <file>        Write dependency output to the given file.
  -MT <target>      Specify the target of the rule emitted by dependency
                    generation.

编辑:变得更漂亮

find_package(Vulkan COMPONENTS glslc)
find_program(glslc_executable NAMES glslc HINTS Vulkan::glslc)

function(compile_shader target)
    cmake_parse_arguments(PARSE_ARGV 1 arg "" "ENV;FORMAT" "SOURCES")
    foreach(source ${arg_SOURCES})
        add_custom_command(
            OUTPUT ${source}.${arg_FORMAT}
            DEPENDS ${source}
            DEPFILE ${source}.d
            COMMAND
                ${glslc_executable}
                $<$<BOOL:${arg_ENV}>:--target-env=${arg_ENV}>
                $<$<BOOL:${arg_FORMAT}>:-mfmt=${arg_FORMAT}>
                -MD -MF ${source}.d
                -o ${source}.${arg_FORMAT}
                ${CMAKE_CURRENT_SOURCE_DIR}/${source}
        )
        target_sources(${target} PRIVATE ${source}.${arg_FORMAT})
    endforeach()
endfunction()
add_executable(dummy dummy.c)
compile_shader(dummy
    ENV opengl
    FORMAT num
    SOURCES
        dummy.vert
        dummy.frag
)