2

I'm working on a d3d application and i would like to compile my .hlsl shaders during to build using cmake. I have no idea where to start.

this is my current CMakeLists.txt

cmake_minimum_required(VERSION 3.20)
project(Direct3DTut)

set(CMAKE_CXX_STANDARD 17)

add_executable(${PROJECT_NAME} WIN32
                WinMain.cpp Window.cpp MessageHandler.cpp Graphics.cpp
                Keyboard.cpp Mouse.cpp
                Utils.cpp)

set(LIBS d3d11 D3DCompiler)
target_link_libraries(${PROJECT_NAME} ${LIBS})
2
  • Just list .hlsl files among source files for add_executable call. Visual Studio will automatically compile them. Commented Feb 28, 2022 at 19:48
  • I'm using Clion but the msvc compiler so i guess it work the same? Where can i find the ouput of the compilation? Commented Feb 28, 2022 at 20:15

1 Answer 1

5

I use this pattern for CMake shaders that works with both Ninja and the MSVC generators.

I assume your target name is ${PROJECT_NAME} below.

DirectX 11

# Build HLSL shaders
set(HLSL_SHADER_FILES VertexShader.hlsl PixelShader.hlsl)

set_source_files_properties(VertexShader.hlsl PROPERTIES ShaderType "vs")
set_source_files_properties(PixelShader.hlsl PROPERTIES ShaderType "ps")
set_source_files_properties(${HLSL_SHADER_FILES} PROPERTIES ShaderModel "4_0")

foreach(FILE ${HLSL_SHADER_FILES})
  get_filename_component(FILE_WE ${FILE} NAME_WE)
  list(APPEND CSO_SHADER_FILES ${CMAKE_BINARY_DIR}/${FILE_WE}.cso)
  get_source_file_property(shadertype ${FILE} ShaderType)
  get_source_file_property(shadermodel ${FILE} ShaderModel)
  add_custom_command(TARGET ${PROJECT_NAME} PRE_LINK
                     COMMAND fxc.exe /nologo /Emain /T${shadertype}_${shadermodel} $<IF:$<CONFIG:DEBUG>,/Od,/O1> /Zi /Fo ${CMAKE_BINARY_DIR}/${FILE_WE}.cso /Fd ${CMAKE_BINARY_DIR}/${FILE_WE}.pdb ${FILE}
                     COMMENT "HLSL ${FILE}"
                     WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
                     VERBATIM)
endforeach(FILE)

add_custom_command(TARGET ${PROJECT_NAME} POST_BUILD
                  COMMAND ${CMAKE_COMMAND} -E copy ${CSO_SHADER_FILES} $<TARGET_FILE_DIR:${PROJECT_NAME}>
                  COMMAND_EXPAND_LISTS)

I use this in my DirectX Tool Kit tutorials. You can also see the rest of the CMake on directx-vs-templates.|

DirectX 12

# Build HLSL shaders
set(HLSL_SHADER_FILES VertexShader.hlsl PixelShader.hlsl)

set_source_files_properties(VertexShader.hlsl PROPERTIES ShaderType "vs")
set_source_files_properties(PixelShader.hlsl PROPERTIES ShaderType "ps")

foreach(FILE ${HLSL_SHADER_FILES})
  get_filename_component(FILE_WE ${FILE} NAME_WE)
  list(APPEND CSO_SHADER_FILES ${CMAKE_BINARY_DIR}/${FILE_WE}.cso)
  get_source_file_property(shadertype ${FILE} ShaderType)
  add_custom_command(TARGET ${PROJECT_NAME} PRE_LINK
                     COMMAND dxc.exe /nologo /Emain /T${shadertype}_6_0 $<IF:$<CONFIG:DEBUG>,/Od,/O3> /Zi /Fo ${CMAKE_BINARY_DIR}/${FILE_WE}.cso /Fd ${CMAKE_BINARY_DIR}/${FILE_WE}.pdb ${FILE}
                     COMMENT "HLSL ${FILE}"
                     WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
                     VERBATIM)
endforeach(FILE)

add_custom_command(TARGET ${PROJECT_NAME} POST_BUILD
                  COMMAND ${CMAKE_COMMAND} -E copy ${CSO_SHADER_FILES} $<TARGET_FILE_DIR:${PROJECT_NAME}>
                  COMMAND_EXPAND_LISTS)

I use this in my DirectX Tool Kit tutorials. You can also see the rest of the CMake on directx-vs-templates.|

UPDATED: I updated this for a CMake 3.31 deprecation (CMP0175), added logic to ensure the .cso files are copied into the bin folder, and added the DX12 equivalent.

Sign up to request clarification or add additional context in comments.

3 Comments

It seems like the command gets evaluated to fxc.exe /nologo /Emain /T${shadertype}_${shadermodel} "" /Zi /Fo ${CMAKE_BINARY_DIR}/${FILE_WE}.cso /Fd ${CMAKE_BINARY_DIR}/${FILE_WE}.pdb ${FILE} in release mode with the empty double quotes in the command. That fails to run. Any ideas why this happens and how one can avoid this?
Interesting. DXC.EXE tolerates the "", but FXC doesn't.
The best solution is to use $<IF:$<CONFIG:DEBUG>,/Od,/O1> for FXC and use $<IF:$<CONFIG:DEBUG>,/Od,/O3> for DXC

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.