I have a really tough time trying to figure out how DirectX 11 (specifically I'm interested in Direct3D) can be integrated with CMake on Windows 10.
Inside C:\Windows\System32
one can find the runtime libraries (DLLs) since nowadays DirectX is integrated into the installation of Windows 10 (important for my case are d3d11.dll
and d3dx11.dll
). However the DLLs are not really enough to develop code that uses DirectX.
For developing software on Windows 10 for Windows 10 one generally needs the Windows SDK. I have both 10 and 8.1. DirectX 9, 10, 11 and 12 related files can be found inside C:\Program Files (x86)\Windows Kits\10\Lib\10.0.17763.0\um\x86
or ...\x64
depending on whether you want 32 or 64bit. Inside C:\Program Files (x86)\Windows Kits\10\Include\10.0.17763.0\um
one can find the header files.
People say that simply doing
target_link_libraries(my_project PRIVATE d3d11 d3dx11)
should do the trick. However I get an error (using CMake 3.12 with Visual Studio 2017 Pro with the former being shipped as part of the latter) that the .lib
cannot be found.
I tried adding the following
link_directories("C:\\Program Files (x86)\\Windows Kits\\10\\Lib\\10.0.17763.0\\um\\x64")
include_directories("C:\\Program Files (x86)\\Windows Kits\\10\\Include\\10.0.17763.0\\um")
but nothing changes.
Here is the full CMakeLists.txt
of my simple project:
cmake_minimum_required (VERSION 3.12)
link_directories("C:\\Program Files (x86)\\Windows Kits\\10\\Lib\\10.0.17763.0\\um\\x64")
include_directories("C:\\Program Files (x86)\\Windows Kits\\10\\Include\\10.0.17763.0\\um")
get_property(dirs DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} PROPERTY INCLUDE_DIRECTORIES)
foreach(dir ${dirs})
message(STATUS "Include directory: \"${dir}\"")
endforeach()
get_property(dirs DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} PROPERTY LINK_DIRECTORIES)
foreach(dir ${dirs})
message(STATUS "Link directory: \"${dir}\"")
endforeach()
add_executable (DirectX11_CMake_Example "DirectX11_CMake_Example.cpp" "DirectX11_CMake_Example.h")
target_compile_definitions(DirectX11_CMake_Example PRIVATE "UNICODE" "_UNICODE")
target_link_libraries(DirectX11_CMake_Example PRIVATE d3d11 d3dx11)
I have basic 'game loops' with window, device, and swapchain for both DirectX 11 and DirectX 12 available on GitHub including both 'classic' Win32 projects and UWP apps. The repository primarily builds Visual Studio templates for VSIX, but I also provide a simple PowerShell script and CMakeLists.txt files to instance the templates for CMake. See the wiki.
The resulting CMakeLists.txt
for your scenario is:
cmake_minimum_required (VERSION 3.13)
project(CMakeDirect3DGame
DESCRIPTION "CMake example for Direct3D 11 Game (Win32)"
LANGUAGES CXX)
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_CXX_EXTENSIONS OFF)
set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/bin/CMake")
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/bin/CMake")
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/bin/CMake")
if(DEFINED VCPKG_TARGET_ARCHITECTURE)
set(DIRECTX_ARCH ${VCPKG_TARGET_ARCHITECTURE})
elseif(CMAKE_GENERATOR_PLATFORM MATCHES "^[Ww][Ii][Nn]32$")
set(DIRECTX_ARCH x86)
elseif(CMAKE_GENERATOR_PLATFORM MATCHES "^[Xx]64$")
set(DIRECTX_ARCH x64)
elseif(CMAKE_GENERATOR_PLATFORM MATCHES "^[Aa][Rr][Mm]$")
set(DIRECTX_ARCH arm)
elseif(CMAKE_GENERATOR_PLATFORM MATCHES "^[Aa][Rr][Mm]64$")
set(DIRECTX_ARCH arm64)
elseif(CMAKE_VS_PLATFORM_NAME_DEFAULT MATCHES "^[Ww][Ii][Nn]32$")
set(DIRECTX_ARCH x86)
elseif(CMAKE_VS_PLATFORM_NAME_DEFAULT MATCHES "^[Xx]64$")
set(DIRECTX_ARCH x64)
elseif(CMAKE_VS_PLATFORM_NAME_DEFAULT MATCHES "^[Aa][Rr][Mm]$")
set(DIRECTX_ARCH arm)
elseif(CMAKE_VS_PLATFORM_NAME_DEFAULT MATCHES "^[Aa][Rr][Mm]64$")
set(DIRECTX_ARCH arm64)
endif()
add_executable(${PROJECT_NAME} WIN32
Game.cpp
Game.h
Main.cpp
StepTimer.h
pch.h
)
if ((${CMAKE_VERSION} VERSION_GREATER_EQUAL "3.16") AND (NOT MINGW))
target_precompile_headers(${PROJECT_NAME} PRIVATE pch.h )
endif()
target_link_libraries(${PROJECT_NAME} PRIVATE
d3d11.lib dxgi.lib dxguid.lib uuid.lib
kernel32.lib user32.lib
comdlg32.lib advapi32.lib shell32.lib
ole32.lib oleaut32.lib
)
if(MSVC)
# Use max Warning Level
string(REPLACE "/W3 " "/Wall " CMAKE_CXX_FLAGS ${CMAKE_CXX_FLAGS})
string(REPLACE "/W3 " "/Wall " CMAKE_CXX_FLAGS_DEBUG ${CMAKE_CXX_FLAGS_DEBUG})
string(REPLACE "/W3 " "/Wall " CMAKE_CXX_FLAGS_RELEASE ${CMAKE_CXX_FLAGS_RELEASE})
target_compile_options(${PROJECT_NAME} PRIVATE /fp:fast "$<$<NOT:$<CONFIG:DEBUG>>:/guard:cf>")
target_link_options(${PROJECT_NAME} PRIVATE "$<$<NOT:$<CONFIG:DEBUG>>:/guard:cf>" /DYNAMICBASE /NXCOMPAT)
if((${CMAKE_SIZEOF_VOID_P} EQUAL 4) AND (NOT ${DIRECTX_ARCH} MATCHES "^arm"))
target_link_options(${PROJECT_NAME} PRIVATE /SAFESEH)
endif()
if((MSVC_VERSION GREATER_EQUAL 1928) AND (CMAKE_SIZEOF_VOID_P EQUAL 8)
AND ((NOT (CMAKE_CXX_COMPILER_ID MATCHES "Clang")) OR (CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL 13.0)))
target_compile_options(${PROJECT_NAME} PRIVATE "$<$<NOT:$<CONFIG:DEBUG>>:/guard:ehcont>")
target_link_options(${PROJECT_NAME} PRIVATE "$<$<NOT:$<CONFIG:DEBUG>>:/guard:ehcont>")
endif()
endif()
if(NOT ${DIRECTX_ARCH} MATCHES "^arm")
if (${CMAKE_SIZEOF_VOID_P} EQUAL "4")
set(ARCH_SSE2 $<$<CXX_COMPILER_ID:MSVC>:/arch:SSE2> $<$<NOT:$<CXX_COMPILER_ID:MSVC>>:-msse2>)
else()
set(ARCH_SSE2 $<$<NOT:$<CXX_COMPILER_ID:MSVC>>:-msse2>)
endif()
target_compile_options(${PROJECT_NAME} PRIVATE ${ARCH_SSE2})
endif()
if (MINGW OR VCPKG_TOOLCHAIN)
message("INFO: Using VCPKG for DirectXMath.")
find_package(directxmath CONFIG REQUIRED)
target_link_libraries(${PROJECT_NAME} PRIVATE Microsoft::DirectXMath)
# Uncomment if using the DirectX Tool Kit
# find_package(directxtk CONFIG REQUIRED)
# target_link_libraries(${PROJECT_NAME} PRIVATE Microsoft::DirectXTK)
endif()
if ( CMAKE_CXX_COMPILER_ID MATCHES "Clang|IntelLLVM" )
target_compile_options(${PROJECT_NAME} PRIVATE
-Wpedantic -Wextra
"-Wno-c++98-compat" "-Wno-c++98-compat-pedantic"
"-Wno-exit-time-destructors" "-Wno-global-constructors" "-Wno-language-extension-token"
"-Wno-missing-prototypes" "-Wno-missing-variable-declarations" "-Wno-reserved-id-macro")
if(BUILD_TEST_TEMPLATE)
target_compile_options(${PROJECT_NAME} PRIVATE "-Wno-unused-value")
endif()
endif()
if(MINGW)
target_compile_options(${PROJECT_NAME} PRIVATE -Wno-ignored-attributes)
target_link_options(${PROJECT_NAME} PRIVATE -municode)
endif()
if ( CMAKE_CXX_COMPILER_ID MATCHES "MSVC" )
target_compile_options(${PROJECT_NAME} PRIVATE
/sdl /permissive- /Zc:__cplusplus
"/wd4061" "/wd4365" "/wd4514" "/wd4571" "/wd4668" "/wd4710" "/wd4820" "/wd5039" "/wd5045")
if(ENABLE_CODE_ANALYSIS)
target_compile_options(${PROJECT_NAME} PRIVATE /analyze)
endif()
if (CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL 19.24)
target_compile_options(${PROJECT_NAME} PRIVATE /ZH:SHA_256)
endif()
if (CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL 19.26)
target_compile_options(${PROJECT_NAME} PRIVATE /Zc:preprocessor /wd5105)
endif()
if ((CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL 19.27) AND (NOT (${DIRECTX_ARCH} MATCHES "^arm")))
target_link_options(${PROJECT_NAME} PRIVATE /CETCOMPAT)
endif()
if(BUILD_TEST_TEMPLATE)
target_compile_options(${PROJECT_NAME} PRIVATE "/wd4555")
endif()
endif()
if ( CMAKE_CXX_COMPILER_ID MATCHES "^Intel$" )
target_compile_options(${PROJECT_NAME} PRIVATE /Qwd161)
endif()
if(WIN32)
target_compile_definitions(${PROJECT_NAME} PRIVATE _UNICODE UNICODE)
if (${DIRECTX_ARCH} MATCHES "^arm")
target_compile_definitions(${PROJECT_NAME} PRIVATE _WIN32_WINNT=0x0A00)
else()
target_compile_definitions(${PROJECT_NAME} PRIVATE _WIN32_WINNT=0x0601)
endif()
endif()
set_property(DIRECTORY PROPERTY VS_STARTUP_PROJECT ${PROJECT_NAME})
The
D3DX11
utility library is deprecated and was only available as part of the legacy DirectX SDK. For new projects, you should avoid it per this blog post. That said, if you really want to use it with CMake, you can make use of vcpkg and the dxsdk-d3dx port.