FindDirectX.cmake 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244
  1. #
  2. # Copyright (c) 2008-2020 the Urho3D project.
  3. #
  4. # Permission is hereby granted, free of charge, to any person obtaining a copy
  5. # of this software and associated documentation files (the "Software"), to deal
  6. # in the Software without restriction, including without limitation the rights
  7. # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  8. # copies of the Software, and to permit persons to whom the Software is
  9. # furnished to do so, subject to the following conditions:
  10. #
  11. # The above copyright notice and this permission notice shall be included in
  12. # all copies or substantial portions of the Software.
  13. #
  14. # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  15. # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  16. # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  17. # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  18. # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  19. # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  20. # THE SOFTWARE.
  21. #
  22. # For MSVC compiler, find Microsoft DirectX installation in Windows SDK or in June 2010 DirectX SDK or later
  23. # For MinGW compiler, assume MinGW not only comes with the necessary headers & libraries but also has the headers & libraries directories in its default search path
  24. # (use 'echo |$MINGW_PREFIX-gcc -v -E -' and '$MINGW_PREFIX-gcc -print-search-dirs', respectively, to double check)
  25. # The MinGW headers on Linux host are usually shipped in a development package which should be installed automatically as part of the package dependency by the package manager when installing MinGW
  26. # (in Debian-based it is 'mingw-w64-dev' and in RedHat-based 'mingw64-headers' for 64-bit; 'mingw-w64-i686-dev' and 'mingw32-headers', respectively, for 32-bit)
  27. #
  28. # DIRECTX_FOUND (TRUE when any of the components is found)
  29. # DIRECTX_INCLUDE_DIRS
  30. # DIRECTX_LIBRARY_DIRS
  31. # HAVE_DIRECTX (Synonym to DIRECTX_FOUND)
  32. # USE_WINSDK_DIRECTX (TRUE when using Windows SDK or FALSE when using DirectX SDK; not defined when using MinGW)
  33. #
  34. # When corresponding component is being searched for and found:
  35. # DirectX_D3D_FOUND (Currently synonym to DirectX_D3D9_FOUND)
  36. # DirectX_D3D9_FOUND
  37. # DirectX_D3D11_FOUND
  38. # DirectX_DInput_FOUND
  39. # DirectX_DSound_FOUND
  40. # DirectX_XInput_FOUND
  41. #
  42. # When any of the Direct3D components is being searched for and found:
  43. # DIRECT3D_LIBRARIES
  44. # DIRECT3D_DLL
  45. #
  46. set (DIRECTX_HEADERS d3dcompiler.h d3d9.h d3d11.h ddraw.h dsound.h dinput.h dxgi.h xinput.h)
  47. # When corresponding header listed above is found:
  48. # HAVE_<UPCASE_NAME>_H
  49. # HAVE_XINPUT_GAMEPAD_EX
  50. # HAVE_XINPUT_STATE_EX
  51. # HAVE_D3D_H (Currently synonym to HAVE_D3D9_H)
  52. #
  53. # Optional input variables (see corresponding code comments for details):
  54. # DIRECTX_INC_SEARCH_PATHS
  55. # DIRECTX_LIB_SEARCH_PATHS
  56. # DIRECT3D_DLL_REDIST_SEARCH_PATHS
  57. #
  58. if (CMAKE_CL_64)
  59. set (PATH_SUFFIX x64)
  60. else ()
  61. set (PATH_SUFFIX x86)
  62. endif ()
  63. set (CMAKE_REQUIRED_INCLUDES_SAVED ${CMAKE_REQUIRED_INCLUDES})
  64. # Version older than VS2012 fallbacks to search for the DirectX SDK
  65. if (NOT MSVC_VERSION GREATER 1600 OR MINGW) # MinGW reuses the logic below to check for the existence of DirectX headers and libraries
  66. if (MINGW)
  67. # Intentionally searching for d3dcompiler(_XX) libraries in this particular order, avoiding unversioned d3dcompiler library so we know exactly which DLL to use
  68. set (D3DCOMPILER_NAMES d3dcompiler_47 d3dcompiler_46 d3dcompiler_43 d3dcompiler_42)
  69. if (NOT MINGW_SYSROOT)
  70. if (DEFINED ENV{MINGW_SYSROOT})
  71. file (TO_CMAKE_PATH $ENV{MINGW_SYSROOT} MINGW_SYSROOT)
  72. else ()
  73. execute_process (COMMAND ${CMAKE_COMMAND} -E echo "#include <_mingw.h>" COMMAND ${CMAKE_C_COMPILER} -E -M - OUTPUT_FILE ${CMAKE_BINARY_DIR}/find_mingw_sysroot_output ERROR_QUIET)
  74. file (STRINGS ${CMAKE_BINARY_DIR}/find_mingw_sysroot_output MINGW_SYSROOT REGEX _mingw\\.h)
  75. string (REGEX REPLACE "^[^ ]* *(.*)/include.*$" \\1 MINGW_SYSROOT "${MINGW_SYSROOT}") # Stringify for string replacement
  76. string (REPLACE "\\ " " " MINGW_SYSROOT "${MINGW_SYSROOT}")
  77. execute_process (COMMAND ${CMAKE_COMMAND} -E remove find_mingw_sysroot_output)
  78. endif ()
  79. if (NOT EXISTS ${MINGW_SYSROOT})
  80. message (FATAL_ERROR "Could not find MinGW system root. "
  81. "Use MINGW_SYSROOT environment variable or build option to specify the location of system root.")
  82. endif ()
  83. set (MINGW_SYSROOT ${MINGW_SYSROOT} CACHE PATH "Path to MinGW system root (MinGW only); should only be used when the system root could not be auto-detected" FORCE)
  84. endif ()
  85. # MinGW Cross-compiling uses CMAKE_FIND_ROOT_PATH while MinGW on Windows host uses CMAKE_PREFIX_PATH
  86. if (CMAKE_HOST_WIN32)
  87. set (CMAKE_PREFIX_PATH ${MINGW_SYSROOT})
  88. endif ()
  89. # MinGW does not usually need search paths as DirectX headers and libraries (when installed) are in its default search path
  90. # However, we do not explicitly unset the DIRECTX_INC_SEARCH_PATHS and DIRECTX_LIB_SEARCH_PATHS variables here, so module user could set these two variables externally when for some reasons the DirectX headers and libraries are not installed in MinGW default search path
  91. else ()
  92. set (D3DCOMPILER_NAMES d3dcompiler)
  93. # Module user could also prepopulate the DIRECTX_INC_SEARCH_PATHS and DIRECTX_LIB_SEARCH_PATHS variables externally when the following search paths do not work and the usage of DIRECTX_ROOT and DXSDK_DIR environment variables are not preferable
  94. list (APPEND DIRECTX_INC_SEARCH_PATHS
  95. "C:/Program Files (x86)/Microsoft DirectX SDK (June 2010)/Include"
  96. "C:/Program Files/Microsoft DirectX SDK (June 2010)/Include"
  97. $ENV{DIRECTX_ROOT}/Include
  98. $ENV{DXSDK_DIR}/Include)
  99. list (APPEND DIRECTX_LIB_SEARCH_PATHS
  100. "C:/Program Files (x86)/Microsoft DirectX SDK (June 2010)/Lib/${PATH_SUFFIX}"
  101. "C:/Program Files/Microsoft DirectX SDK (June 2010)/Lib/${PATH_SUFFIX}"
  102. $ENV{DIRECTX_ROOT}/Lib/${PATH_SUFFIX}
  103. $ENV{DXSDK_DIR}/Lib/${PATH_SUFFIX})
  104. if (NOT CMAKE_CL_64)
  105. list (APPEND DIRECTX_LIB_SEARCH_PATHS
  106. "C:/Program Files (x86)/Microsoft DirectX SDK (June 2010)/Lib"
  107. "C:/Program Files/Microsoft DirectX SDK (June 2010)/Lib"
  108. $ENV{DIRECTX_ROOT}/Lib
  109. $ENV{DXSDK_DIR}/Lib)
  110. endif ()
  111. endif ()
  112. find_path (DIRECTX_INCLUDE_DIRS NAMES ${DIRECTX_HEADERS} PATHS ${DIRECTX_INC_SEARCH_PATHS} DOC "DirectX include directory" CMAKE_FIND_ROOT_PATH_BOTH)
  113. if (DIRECTX_INCLUDE_DIRS)
  114. set (CMAKE_REQUIRED_INCLUDES ${DIRECTX_INCLUDE_DIRS})
  115. set (DIRECTX_LIBRARY_DIRS)
  116. set (DIRECT3D_LIBRARIES)
  117. find_library (DIRECTX_D3DCOMPILER NAMES ${D3DCOMPILER_NAMES} PATHS ${DIRECTX_LIB_SEARCH_PATHS} DOC "DirectX d3dcompiler library" CMAKE_FIND_ROOT_PATH_BOTH)
  118. if (DIRECTX_D3DCOMPILER)
  119. get_filename_component (NAME ${DIRECTX_D3DCOMPILER} NAME)
  120. string (REGEX REPLACE "^.*(d3dcompiler[_0-9]*).*$" \\1 D3DCOMPILER_LIB_NAME ${NAME})
  121. if (DirectX_FIND_REQUIRED_D3D11)
  122. set (DIRECT3D_LIB_NAMES d3d11 dxgi dxguid)
  123. else ()
  124. set (DIRECT3D_LIB_NAMES d3d9)
  125. if (NOT DirectX_FIND_REQUIRED_D3D AND NOT DirectX_FIND_REQUIRED_D3D9)
  126. # When using OpenGL we still want to reuse the logic below to find the DirectX library directory
  127. set (NO_DIRECT3D_COMPONENTS TRUE)
  128. endif ()
  129. endif ()
  130. foreach (NAME ${D3DCOMPILER_LIB_NAME} ${DIRECT3D_LIB_NAMES})
  131. string (REGEX REPLACE _[0-9]+$ "" BASE_NAME ${NAME})
  132. string (TOUPPER ${BASE_NAME} UPCASE_NAME)
  133. find_library (DIRECTX_${UPCASE_NAME} NAMES ${NAME} PATHS ${DIRECTX_LIB_SEARCH_PATHS} DOC "DirectX ${BASE_NAME} library" CMAKE_FIND_ROOT_PATH_BOTH)
  134. if (DIRECTX_${UPCASE_NAME})
  135. get_filename_component (PATH ${DIRECTX_${UPCASE_NAME}} PATH)
  136. list (APPEND DIRECTX_LIBRARY_DIRS ${PATH}) # All the libs should be found in a same place, but just in case
  137. if (NOT NO_DIRECT3D_COMPONENTS) # Discard the result when Direct3D component is not required
  138. list (APPEND DIRECT3D_LIBRARIES ${NAME})
  139. endif ()
  140. else ()
  141. set (MISSING_DIRECT3D_LIB TRUE)
  142. endif ()
  143. mark_as_advanced (DIRECTX_${UPCASE_NAME})
  144. endforeach ()
  145. if (NOT MISSING_DIRECT3D_LIB)
  146. if (NOT MINGW)
  147. set (USE_WINSDK_DIRECTX FALSE)
  148. endif ()
  149. set (HAVE_DIRECTX TRUE)
  150. if (DirectX_FIND_REQUIRED_D3D11)
  151. set (DirectX_D3D11_FOUND TRUE)
  152. elseif (DirectX_FIND_REQUIRED_D3D OR DirectX_FIND_REQUIRED_D3D9)
  153. set (DirectX_D3D9_FOUND TRUE)
  154. set (DirectX_D3D_FOUND TRUE)
  155. endif ()
  156. endif ()
  157. endif ()
  158. if (DIRECTX_LIBRARY_DIRS)
  159. list (REMOVE_DUPLICATES DIRECTX_LIBRARY_DIRS)
  160. endif ()
  161. endif ()
  162. if (MINGW)
  163. set (FAIL_MESSAGE "Could NOT find DirectX using MinGW default search paths")
  164. else ()
  165. set (FAIL_MESSAGE "Could NOT find DirectX using DirectX SDK default search paths")
  166. endif ()
  167. mark_as_advanced (DIRECTX_INCLUDE_DIRS)
  168. endif ()
  169. # Windows SDK can be used on VS2012 and above
  170. if (MSVC_VERSION GREATER 1600 OR MINGW) # MinGW reuses the logic below to find the runtime DLL for d3dcompiler library
  171. if (MINGW)
  172. # Search the corresponding DLL for the found d3dcompiler "import library"
  173. set (DIRECT3D_DLL_NAMES ${D3DCOMPILER_LIB_NAME}.dll)
  174. # Module user using older MinGW version could also prepopulate the DIRECT3D_DLL_REDIST_SEARCH_PATHS variable externally when the following search paths do not work, especially when older d3dcompiler_43.dll and d3dcompiler_42.dll is expected to be found elsewhere
  175. else ()
  176. set (DIRECT3D_DLL_NAMES d3dcompiler_47.dll d3dcompiler_46.dll)
  177. set (DIRECT3D_DLL_REDIST_SEARCH_PATHS)
  178. endif ()
  179. foreach (VERSION 10.0 8.1 8.0)
  180. list (APPEND DIRECT3D_DLL_REDIST_SEARCH_PATHS "[HKEY_LOCAL_MACHINE\\SOFTWARE\\Wow6432Node\\Microsoft\\Microsoft SDKs\\Windows\\v${VERSION};InstallationFolder]/Redist/D3D/${PATH_SUFFIX}")
  181. endforeach ()
  182. find_file (DIRECT3D_DLL NAMES ${DIRECT3D_DLL_NAMES} PATHS ${DIRECT3D_DLL_REDIST_SEARCH_PATHS} DOC "Direct3D DLL"
  183. NO_DEFAULT_PATH) # Do not use default paths such as the PATH variable, to potentially avoid using a wrong architecture DLL
  184. if (DIRECT3D_DLL AND NOT MINGW)
  185. set (USE_WINSDK_DIRECTX TRUE)
  186. set (HAVE_DIRECTX TRUE)
  187. if (DirectX_FIND_REQUIRED_D3D11)
  188. set (DIRECT3D_LIBRARIES d3dcompiler d3d11 dxgi dxguid)
  189. set (DirectX_D3D11_FOUND TRUE)
  190. elseif (DirectX_FIND_REQUIRED_D3D OR DirectX_FIND_REQUIRED_D3D9)
  191. set (DIRECT3D_LIBRARIES d3dcompiler d3d9)
  192. set (DirectX_D3D9_FOUND TRUE)
  193. set (DirectX_D3D_FOUND TRUE)
  194. endif ()
  195. endif ()
  196. mark_as_advanced (DIRECT3D_DLL)
  197. # The headers and libraries are in default search paths for both Windows SDK and MinGW, so set the search path variables to empty now
  198. set (DIRECTX_INCLUDE_DIRS "") # Need to be very explicit here because these variables are cached on MinGW, this is one way to reset the variables without losing the cached values
  199. set (DIRECTX_LIBRARY_DIRS "")
  200. if (NOT DirectX_FIND_REQUIRED_D3D11 AND NOT DirectX_FIND_REQUIRED_D3D AND NOT DirectX_FIND_REQUIRED_D3D9)
  201. set (DIRECT3D_DLL "")
  202. endif ()
  203. if (NOT MINGW)
  204. set (FAIL_MESSAGE "Could NOT find DirectX using Windows SDK search paths")
  205. endif ()
  206. endif ()
  207. # For now take shortcut for the other DirectX components by just checking on the headers and not the libraries
  208. include (CheckIncludeFiles)
  209. include (CheckIncludeFileCXX)
  210. include (CheckStructHasMember)
  211. foreach (NAME ${DIRECTX_HEADERS})
  212. string (REPLACE . _ BASE_NAME ${NAME})
  213. string (TOUPPER ${BASE_NAME} UPCASE_NAME)
  214. if (NAME STREQUAL xinput.h)
  215. # Workaround an issue in finding xinput.h using check_include_file() as it depends on windows.h but not included it by itself in WinSDK
  216. check_include_files (windows.h\;${NAME} HAVE_${UPCASE_NAME})
  217. check_struct_has_member (XINPUT_GAMEPAD_EX wButtons xinput.h HAVE_XINPUT_GAMEPAD_EX)
  218. check_struct_has_member (XINPUT_STATE_EX dwPacketNumber xinput.h HAVE_XINPUT_STATE_EX)
  219. else ()
  220. check_include_file_cxx (${NAME} HAVE_${UPCASE_NAME})
  221. endif ()
  222. endforeach ()
  223. if (HAVE_D3D9_H)
  224. set (HAVE_D3D_H TRUE)
  225. endif ()
  226. foreach (COMPONENT DInput DSound XInput)
  227. string (TOUPPER ${COMPONENT} UPCASE_NAME)
  228. if (HAVE_${UPCASE_NAME}_H)
  229. set (DirectX_${COMPONENT}_FOUND TRUE)
  230. set (HAVE_DIRECTX TRUE)
  231. endif ()
  232. endforeach ()
  233. set (CMAKE_REQUIRED_INCLUDES ${CMAKE_REQUIRED_INCLUDES_SAVED})
  234. include (FindPackageHandleStandardArgs)
  235. find_package_handle_standard_args (DirectX REQUIRED_VARS HAVE_DIRECTX HANDLE_COMPONENTS FAIL_MESSAGE ${FAIL_MESSAGE})