Pass a span to the NFC filters
[openal-soft.git] / cmake / FindWindowsSDK.cmake
blob3fcc3bf48dde4e6bc2a23cd6fc2461ed627ec79d
1 # - Find the Windows SDK aka Platform SDK
3 # Relevant Wikipedia article: http://en.wikipedia.org/wiki/Microsoft_Windows_SDK
5 # Pass "COMPONENTS tools" to ignore Visual Studio version checks: in case
6 # you just want the tool binaries to run, rather than the libraries and headers
7 # for compiling.
9 # Variables:
10 #  WINDOWSSDK_FOUND - if any version of the windows or platform SDK was found that is usable with the current version of visual studio
11 #  WINDOWSSDK_LATEST_DIR
12 #  WINDOWSSDK_LATEST_NAME
13 #  WINDOWSSDK_FOUND_PREFERENCE - if we found an entry indicating a "preferred" SDK listed for this visual studio version
14 #  WINDOWSSDK_PREFERRED_DIR
15 #  WINDOWSSDK_PREFERRED_NAME
17 #  WINDOWSSDK_DIRS - contains no duplicates, ordered most recent first.
18 #  WINDOWSSDK_PREFERRED_FIRST_DIRS - contains no duplicates, ordered with preferred first, followed by the rest in descending recency
20 # Functions:
21 #  windowssdk_name_lookup(<directory> <output variable>) - Find the name corresponding with the SDK directory you pass in, or
22 #     NOTFOUND if not recognized. Your directory must be one of WINDOWSSDK_DIRS for this to work.
24 #  windowssdk_build_lookup(<directory> <output variable>) - Find the build version number corresponding with the SDK directory you pass in, or
25 #     NOTFOUND if not recognized. Your directory must be one of WINDOWSSDK_DIRS for this to work.
27 #  get_windowssdk_from_component(<file or dir> <output variable>) - Given a library or include dir,
28 #     find the Windows SDK root dir corresponding to it, or NOTFOUND if unrecognized.
30 #  get_windowssdk_library_dirs(<directory> <output variable>) - Find the architecture-appropriate
31 #     library directories corresponding to the SDK directory you pass in (or NOTFOUND if none)
33 #  get_windowssdk_library_dirs_multiple(<output variable> <directory> ...) - Find the architecture-appropriate
34 #     library directories corresponding to the SDK directories you pass in, in order, skipping those not found. NOTFOUND if none at all.
35 #     Good for passing WINDOWSSDK_DIRS or WINDOWSSDK_DIRS to if you really just want a file and don't care where from.
37 #  get_windowssdk_include_dirs(<directory> <output variable>) - Find the
38 #     include directories corresponding to the SDK directory you pass in (or NOTFOUND if none)
40 #  get_windowssdk_include_dirs_multiple(<output variable> <directory> ...) - Find the
41 #     include directories corresponding to the SDK directories you pass in, in order, skipping those not found. NOTFOUND if none at all.
42 #     Good for passing WINDOWSSDK_DIRS or WINDOWSSDK_DIRS to if you really just want a file and don't care where from.
44 # Requires these CMake modules:
45 #  FindPackageHandleStandardArgs (known included with CMake >=2.6.2)
47 # Original Author:
48 # 2012 Ryan Pavlik <rpavlik@iastate.edu> <abiryan@ryand.net>
49 # http://academic.cleardefinition.com
50 # Iowa State University HCI Graduate Program/VRAC
52 # Copyright Iowa State University 2012.
53 # Distributed under the Boost Software License, Version 1.0.
54 # (See accompanying file LICENSE_1_0.txt or copy at
55 # http://www.boost.org/LICENSE_1_0.txt)
57 set(_preferred_sdk_dirs) # pre-output
58 set(_win_sdk_dirs) # pre-output
59 set(_win_sdk_versanddirs) # pre-output
60 set(_win_sdk_buildsanddirs) # pre-output
61 set(_winsdk_vistaonly) # search parameters
62 set(_winsdk_kits) # search parameters
65 set(_WINDOWSSDK_ANNOUNCE OFF)
66 if(NOT WINDOWSSDK_FOUND AND (NOT WindowsSDK_FIND_QUIETLY))
67         set(_WINDOWSSDK_ANNOUNCE ON)
68 endif()
69 macro(_winsdk_announce)
70         if(_WINSDK_ANNOUNCE)
71                 message(STATUS ${ARGN})
72         endif()
73 endmacro()
75 set(_winsdk_win10vers
76         10.0.18362.0 # Windows 10 Version 1903
77         10.0.17763.0 # Windows 10 Version 1809
78         10.0.17134.0 # Windows 10 Version 1803 (April 2018 Update)
79         10.0.16299.0 # Windows 10 Version 1709 (Fall Creators Update)
80         10.0.15063.0 # Windows 10 Version 1703 (Creators Update)
81         10.0.14393.0 # Redstone aka Win10 1607 "Anniversary Update"
82         10.0.10586.0 # TH2 aka Win10 1511
83         10.0.10240.0 # Win10 RTM
84         10.0.10150.0 # just ucrt
85         10.0.10056.0
88 if(WindowsSDK_FIND_COMPONENTS MATCHES "tools")
89         set(_WINDOWSSDK_IGNOREMSVC ON)
90         _winsdk_announce("Checking for tools from Windows/Platform SDKs...")
91 else()
92         set(_WINDOWSSDK_IGNOREMSVC OFF)
93         _winsdk_announce("Checking for Windows/Platform SDKs...")
94 endif()
96 # Appends to the three main pre-output lists used only if the path exists
97 # and is not already in the list.
98 function(_winsdk_conditional_append _vername _build _path)
99         if(("${_path}" MATCHES "registry") OR (NOT EXISTS "${_path}"))
100                 # Path invalid - do not add
101                 return()
102         endif()
103         list(FIND _win_sdk_dirs "${_path}" _win_sdk_idx)
104         if(_win_sdk_idx GREATER -1)
105                 # Path already in list - do not add
106                 return()
107         endif()
108         _winsdk_announce( " - ${_vername}, Build ${_build} @ ${_path}")
109         # Not yet in the list, so we'll add it
110         list(APPEND _win_sdk_dirs "${_path}")
111         set(_win_sdk_dirs "${_win_sdk_dirs}" CACHE INTERNAL "" FORCE)
112         list(APPEND
113                 _win_sdk_versanddirs
114                 "${_vername}"
115                 "${_path}")
116         set(_win_sdk_versanddirs "${_win_sdk_versanddirs}" CACHE INTERNAL "" FORCE)
117         list(APPEND
118                 _win_sdk_buildsanddirs
119                 "${_build}"
120                 "${_path}")
121         set(_win_sdk_buildsanddirs "${_win_sdk_buildsanddirs}" CACHE INTERNAL "" FORCE)
122 endfunction()
124 # Appends to the "preferred SDK" lists only if the path exists
125 function(_winsdk_conditional_append_preferred _info _path)
126         if(("${_path}" MATCHES "registry") OR (NOT EXISTS "${_path}"))
127                 # Path invalid - do not add
128                 return()
129         endif()
131         get_filename_component(_path "${_path}" ABSOLUTE)
133         list(FIND _win_sdk_preferred_sdk_dirs "${_path}" _win_sdk_idx)
134         if(_win_sdk_idx GREATER -1)
135                 # Path already in list - do not add
136                 return()
137         endif()
138         _winsdk_announce( " - Found \"preferred\" SDK ${_info} @ ${_path}")
139         # Not yet in the list, so we'll add it
140         list(APPEND _win_sdk_preferred_sdk_dirs "${_path}")
141         set(_win_sdk_preferred_sdk_dirs "${_win_sdk_dirs}" CACHE INTERNAL "" FORCE)
143         # Just in case we somehow missed it:
144         _winsdk_conditional_append("${_info}" "" "${_path}")
145 endfunction()
147 # Given a version like v7.0A, looks for an SDK in the registry under "Microsoft SDKs".
148 # If the given version might be in both HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Microsoft SDKs\\Windows
149 # and HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows Kits\\Installed Roots aka "Windows Kits",
150 # use this macro first, since these registry keys usually have more information.
152 # Pass a "default" build number as an extra argument in case we can't find it.
153 function(_winsdk_check_microsoft_sdks_registry _winsdkver)
154         set(SDKKEY "HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Microsoft SDKs\\Windows\\${_winsdkver}")
155         get_filename_component(_sdkdir
156                 "[${SDKKEY};InstallationFolder]"
157                 ABSOLUTE)
159         set(_sdkname "Windows SDK ${_winsdkver}")
161         # Default build number passed as extra argument
162         set(_build ${ARGN})
163         # See if the registry holds a Microsoft-mutilated, err, designated, product name
164         # (just using get_filename_component to execute the registry lookup)
165         get_filename_component(_sdkproductname
166                 "[${SDKKEY};ProductName]"
167                 NAME)
168         if(NOT "${_sdkproductname}" MATCHES "registry")
169                 # Got a product name
170                 set(_sdkname "${_sdkname} (${_sdkproductname})")
171         endif()
173         # try for a version to augment our name
174         # (just using get_filename_component to execute the registry lookup)
175         get_filename_component(_sdkver
176                 "[${SDKKEY};ProductVersion]"
177                 NAME)
178         if(NOT "${_sdkver}" MATCHES "registry" AND NOT MATCHES)
179                 # Got a version
180                 if(NOT "${_sdkver}" MATCHES "\\.\\.")
181                         # and it's not an invalid one with two dots in it:
182                         # use to override the default build
183                         set(_build ${_sdkver})
184                         if(NOT "${_sdkname}" MATCHES "${_sdkver}")
185                                 # Got a version that's not already in the name, let's use it to improve our name.
186                                 set(_sdkname "${_sdkname} (${_sdkver})")
187                         endif()
188                 endif()
189         endif()
190         _winsdk_conditional_append("${_sdkname}" "${_build}" "${_sdkdir}")
191 endfunction()
193 # Given a name for identification purposes, the build number, and a key (technically a "value name")
194 # corresponding to a Windows SDK packaged as a "Windows Kit", look for it
195 # in HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows Kits\\Installed Roots
196 # Note that the key or "value name" tends to be something weird like KitsRoot81 -
197 # no easy way to predict, just have to observe them in the wild.
198 # Doesn't hurt to also try _winsdk_check_microsoft_sdks_registry for these:
199 # sometimes you get keys in both parts of the registry (in the wow64 portion especially),
200 # and the non-"Windows Kits" location is often more descriptive.
201 function(_winsdk_check_windows_kits_registry _winkit_name _winkit_build _winkit_key)
202         get_filename_component(_sdkdir
203                 "[HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows Kits\\Installed Roots;${_winkit_key}]"
204                 ABSOLUTE)
205         _winsdk_conditional_append("${_winkit_name}" "${_winkit_build}" "${_sdkdir}")
206 endfunction()
208 # Given a name for identification purposes and the build number
209 # corresponding to a Windows 10 SDK packaged as a "Windows Kit", look for it
210 # in HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows Kits\\Installed Roots
211 # Doesn't hurt to also try _winsdk_check_microsoft_sdks_registry for these:
212 # sometimes you get keys in both parts of the registry (in the wow64 portion especially),
213 # and the non-"Windows Kits" location is often more descriptive.
214 function(_winsdk_check_win10_kits _winkit_build)
215         get_filename_component(_sdkdir
216                 "[HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows Kits\\Installed Roots;KitsRoot10]"
217                 ABSOLUTE)
218         if(("${_sdkdir}" MATCHES "registry") OR (NOT EXISTS "${_sdkdir}"))
219                 return() # not found
220         endif()
221         if(EXISTS "${_sdkdir}/Include/${_winkit_build}/um")
222                 _winsdk_conditional_append("Windows Kits 10 (Build ${_winkit_build})" "${_winkit_build}" "${_sdkdir}")
223         endif()
224 endfunction()
226 # Given a name for indentification purposes, the build number, and the associated package GUID,
227 # look in the registry under both HKLM and HKCU in \\SOFTWARE\\Microsoft\\MicrosoftSDK\\InstalledSDKs\\
228 # for that guid and the SDK it points to.
229 function(_winsdk_check_platformsdk_registry _platformsdkname _build _platformsdkguid)
230         foreach(_winsdk_hive HKEY_LOCAL_MACHINE HKEY_CURRENT_USER)
231                 get_filename_component(_sdkdir
232                         "[${_winsdk_hive}\\SOFTWARE\\Microsoft\\MicrosoftSDK\\InstalledSDKs\\${_platformsdkguid};Install Dir]"
233                         ABSOLUTE)
234                 _winsdk_conditional_append("${_platformsdkname} (${_build})" "${_build}" "${_sdkdir}")
235         endforeach()
236 endfunction()
239 # Detect toolchain information: to know whether it's OK to use Vista+ only SDKs
241 set(_winsdk_vistaonly_ok OFF)
242 if(MSVC AND NOT _WINDOWSSDK_IGNOREMSVC)
243         # VC 10 and older has broad target support
244         if(MSVC_VERSION LESS 1700)
245                 # VC 11 by default targets Vista and later only, so we can add a few more SDKs that (might?) only work on vista+
246         elseif("${CMAKE_VS_PLATFORM_TOOLSET}" MATCHES "_xp")
247                 # This is the XP-compatible v110+ toolset
248         elseif("${CMAKE_VS_PLATFORM_TOOLSET}" STREQUAL "v100" OR "${CMAKE_VS_PLATFORM_TOOLSET}" STREQUAL "v90")
249                 # This is the VS2010/VS2008 toolset
250         else()
251                 # OK, we're VC11 or newer and not using a backlevel or XP-compatible toolset.
252                 # These versions have no XP (and possibly Vista pre-SP1) support
253                 set(_winsdk_vistaonly_ok ON)
254                 if(_WINDOWSSDK_ANNOUNCE AND NOT _WINDOWSSDK_VISTAONLY_PESTERED)
255                         set(_WINDOWSSDK_VISTAONLY_PESTERED ON CACHE INTERNAL "" FORCE)
256                         message(STATUS "FindWindowsSDK: Detected Visual Studio 2012 or newer, not using the _xp toolset variant: including SDK versions that drop XP support in search!")
257                 endif()
258         endif()
259 endif()
260 if(_WINDOWSSDK_IGNOREMSVC)
261         set(_winsdk_vistaonly_ok ON)
262 endif()
265 # MSVC version checks - keeps messy conditionals in one place
266 # (messy because of _WINDOWSSDK_IGNOREMSVC)
268 set(_winsdk_msvc_greater_1200 OFF)
269 if(_WINDOWSSDK_IGNOREMSVC OR (MSVC AND (MSVC_VERSION GREATER 1200)))
270         set(_winsdk_msvc_greater_1200 ON)
271 endif()
272 # Newer than VS .NET/VS Toolkit 2003
273 set(_winsdk_msvc_greater_1310 OFF)
274 if(_WINDOWSSDK_IGNOREMSVC OR (MSVC AND (MSVC_VERSION GREATER 1310)))
275         set(_winsdk_msvc_greater_1310 ON)
276 endif()
278 # VS2005/2008
279 set(_winsdk_msvc_less_1600 OFF)
280 if(_WINDOWSSDK_IGNOREMSVC OR (MSVC AND (MSVC_VERSION LESS 1600)))
281         set(_winsdk_msvc_less_1600 ON)
282 endif()
284 # VS2013+
285 set(_winsdk_msvc_not_less_1800 OFF)
286 if(_WINDOWSSDK_IGNOREMSVC OR (MSVC AND (NOT MSVC_VERSION LESS 1800)))
287         set(_winsdk_msvc_not_less_1800 ON)
288 endif()
291 # START body of find module
293 if(_winsdk_msvc_greater_1310) # Newer than VS .NET/VS Toolkit 2003
294         ###
295         # Look for "preferred" SDKs
296         ###
298         # Environment variable for SDK dir
299         if(EXISTS "$ENV{WindowsSDKDir}" AND (NOT "$ENV{WindowsSDKDir}" STREQUAL ""))
300                 _winsdk_conditional_append_preferred("WindowsSDKDir environment variable" "$ENV{WindowsSDKDir}")
301         endif()
303         if(_winsdk_msvc_less_1600)
304                 # Per-user current Windows SDK for VS2005/2008
305                 get_filename_component(_sdkdir
306                         "[HKEY_CURRENT_USER\\Software\\Microsoft\\Microsoft SDKs\\Windows;CurrentInstallFolder]"
307                         ABSOLUTE)
308                 _winsdk_conditional_append_preferred("Per-user current Windows SDK" "${_sdkdir}")
310                 # System-wide current Windows SDK for VS2005/2008
311                 get_filename_component(_sdkdir
312                         "[HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Microsoft SDKs\\Windows;CurrentInstallFolder]"
313                         ABSOLUTE)
314                 _winsdk_conditional_append_preferred("System-wide current Windows SDK" "${_sdkdir}")
315         endif()
317         ###
318         # Begin the massive list of SDK searching!
319         ###
320         if(_winsdk_vistaonly_ok AND _winsdk_msvc_not_less_1800)
321                 # These require at least Visual Studio 2013 (VC12)
323                 _winsdk_check_microsoft_sdks_registry(v10.0A)
325                 # Windows Software Development Kit (SDK) for Windows 10
326                 # Several different versions living in the same directory - if nothing else we can assume RTM (10240)
327                 _winsdk_check_microsoft_sdks_registry(v10.0 10.0.10240.0)
328                 foreach(_win10build ${_winsdk_win10vers})
329                         _winsdk_check_win10_kits(${_win10build})
330                 endforeach()
331         endif() # vista-only and 2013+
333         # Included in Visual Studio 2013
334         # Includes the v120_xp toolset
335         _winsdk_check_microsoft_sdks_registry(v8.1A 8.1.51636)
337         if(_winsdk_vistaonly_ok AND _winsdk_msvc_not_less_1800)
338                 # Windows Software Development Kit (SDK) for Windows 8.1
339                 # http://msdn.microsoft.com/en-gb/windows/desktop/bg162891
340                 _winsdk_check_microsoft_sdks_registry(v8.1 8.1.25984.0)
341                 _winsdk_check_windows_kits_registry("Windows Kits 8.1" 8.1.25984.0 KitsRoot81)
342         endif() # vista-only and 2013+
344         if(_winsdk_vistaonly_ok)
345                 # Included in Visual Studio 2012
346                 _winsdk_check_microsoft_sdks_registry(v8.0A 8.0.50727)
348                 # Microsoft Windows SDK for Windows 8 and .NET Framework 4.5
349                 # This is the first version to also include the DirectX SDK
350                 # http://msdn.microsoft.com/en-US/windows/desktop/hh852363.aspx
351                 _winsdk_check_microsoft_sdks_registry(v8.0 6.2.9200.16384)
352                 _winsdk_check_windows_kits_registry("Windows Kits 8.0" 6.2.9200.16384 KitsRoot)
353         endif() # vista-only
355         # Included with VS 2012 Update 1 or later
356         # Introduces v110_xp toolset
357         _winsdk_check_microsoft_sdks_registry(v7.1A 7.1.51106)
358         if(_winsdk_vistaonly_ok)
359                 # Microsoft Windows SDK for Windows 7 and .NET Framework 4
360                 # http://www.microsoft.com/downloads/en/details.aspx?FamilyID=6b6c21d2-2006-4afa-9702-529fa782d63b
361                 _winsdk_check_microsoft_sdks_registry(v7.1 7.1.7600.0.30514)
362         endif() # vista-only
364         # Included with VS 2010
365         _winsdk_check_microsoft_sdks_registry(v7.0A 6.1.7600.16385)
367         # Windows SDK for Windows 7 and .NET Framework 3.5 SP1
368         # Works with VC9
369         # http://www.microsoft.com/en-us/download/details.aspx?id=18950
370         _winsdk_check_microsoft_sdks_registry(v7.0 6.1.7600.16385)
372         # Two versions call themselves "v6.1":
373         # Older:
374         # Windows Vista Update & .NET 3.0 SDK
375         # http://www.microsoft.com/en-us/download/details.aspx?id=14477
377         # Newer:
378         # Windows Server 2008 & .NET 3.5 SDK
379         # may have broken VS9SP1? they recommend v7.0 instead, or a KB...
380         # http://www.microsoft.com/en-us/download/details.aspx?id=24826
381         _winsdk_check_microsoft_sdks_registry(v6.1 6.1.6000.16384.10)
383         # Included in VS 2008
384         _winsdk_check_microsoft_sdks_registry(v6.0A 6.1.6723.1)
386         # Microsoft Windows Software Development Kit for Windows Vista and .NET Framework 3.0 Runtime Components
387         # http://blogs.msdn.com/b/stanley/archive/2006/11/08/microsoft-windows-software-development-kit-for-windows-vista-and-net-framework-3-0-runtime-components.aspx
388         _winsdk_check_microsoft_sdks_registry(v6.0 6.0.6000.16384)
389 endif()
391 # Let's not forget the Platform SDKs, which sometimes are useful!
392 if(_winsdk_msvc_greater_1200)
393         _winsdk_check_platformsdk_registry("Microsoft Platform SDK for Windows Server 2003 R2" "5.2.3790.2075.51" "D2FF9F89-8AA2-4373-8A31-C838BF4DBBE1")
394         _winsdk_check_platformsdk_registry("Microsoft Platform SDK for Windows Server 2003 SP1" "5.2.3790.1830.15" "8F9E5EF3-A9A5-491B-A889-C58EFFECE8B3")
395 endif()
397 # Finally, look for "preferred" SDKs
399 if(_winsdk_msvc_greater_1310) # Newer than VS .NET/VS Toolkit 2003
402         # Environment variable for SDK dir
403         if(EXISTS "$ENV{WindowsSDKDir}" AND (NOT "$ENV{WindowsSDKDir}" STREQUAL ""))
404                 _winsdk_conditional_append_preferred("WindowsSDKDir environment variable" "$ENV{WindowsSDKDir}")
405         endif()
407         if(_winsdk_msvc_less_1600)
408                 # Per-user current Windows SDK for VS2005/2008
409                 get_filename_component(_sdkdir
410                         "[HKEY_CURRENT_USER\\Software\\Microsoft\\Microsoft SDKs\\Windows;CurrentInstallFolder]"
411                         ABSOLUTE)
412                 _winsdk_conditional_append_preferred("Per-user current Windows SDK" "${_sdkdir}")
414                 # System-wide current Windows SDK for VS2005/2008
415                 get_filename_component(_sdkdir
416                         "[HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Microsoft SDKs\\Windows;CurrentInstallFolder]"
417                         ABSOLUTE)
418                 _winsdk_conditional_append_preferred("System-wide current Windows SDK" "${_sdkdir}")
419         endif()
420 endif()
423 function(windowssdk_name_lookup _dir _outvar)
424         list(FIND _win_sdk_versanddirs "${_dir}" _diridx)
425         math(EXPR _idx "${_diridx} - 1")
426         if(${_idx} GREATER -1)
427                 list(GET _win_sdk_versanddirs ${_idx} _ret)
428         else()
429                 set(_ret "NOTFOUND")
430         endif()
431         set(${_outvar} "${_ret}" PARENT_SCOPE)
432 endfunction()
434 function(windowssdk_build_lookup _dir _outvar)
435         list(FIND _win_sdk_buildsanddirs "${_dir}" _diridx)
436         math(EXPR _idx "${_diridx} - 1")
437         if(${_idx} GREATER -1)
438                 list(GET _win_sdk_buildsanddirs ${_idx} _ret)
439         else()
440                 set(_ret "NOTFOUND")
441         endif()
442         set(${_outvar} "${_ret}" PARENT_SCOPE)
443 endfunction()
445 # If we found something...
446 if(_win_sdk_dirs)
447         list(GET _win_sdk_dirs 0 WINDOWSSDK_LATEST_DIR)
448         windowssdk_name_lookup("${WINDOWSSDK_LATEST_DIR}"
449                 WINDOWSSDK_LATEST_NAME)
450         set(WINDOWSSDK_DIRS ${_win_sdk_dirs})
452         # Fallback, in case no preference found.
453         set(WINDOWSSDK_PREFERRED_DIR "${WINDOWSSDK_LATEST_DIR}")
454         set(WINDOWSSDK_PREFERRED_NAME "${WINDOWSSDK_LATEST_NAME}")
455         set(WINDOWSSDK_PREFERRED_FIRST_DIRS ${WINDOWSSDK_DIRS})
456         set(WINDOWSSDK_FOUND_PREFERENCE OFF)
457 endif()
459 # If we found indications of a user preference...
460 if(_win_sdk_preferred_sdk_dirs)
461         list(GET _win_sdk_preferred_sdk_dirs 0 WINDOWSSDK_PREFERRED_DIR)
462         windowssdk_name_lookup("${WINDOWSSDK_PREFERRED_DIR}"
463                 WINDOWSSDK_PREFERRED_NAME)
464         set(WINDOWSSDK_PREFERRED_FIRST_DIRS
465                 ${_win_sdk_preferred_sdk_dirs}
466                 ${_win_sdk_dirs})
467         list(REMOVE_DUPLICATES WINDOWSSDK_PREFERRED_FIRST_DIRS)
468         set(WINDOWSSDK_FOUND_PREFERENCE ON)
469 endif()
471 include(FindPackageHandleStandardArgs)
472 find_package_handle_standard_args(WindowsSDK
473         "No compatible version of the Windows SDK or Platform SDK found."
474         WINDOWSSDK_DIRS)
476 if(WINDOWSSDK_FOUND)
477         # Internal: Architecture-appropriate library directory names.
478         if("${CMAKE_VS_PLATFORM_NAME}" STREQUAL "ARM")
479                 if(CMAKE_SIZEOF_VOID_P MATCHES "8")
480                         # Only supported in Win10 SDK and up.
481                         set(_winsdk_arch8 arm64) # what the WDK for Win8+ calls this architecture
482                 else()
483                         set(_winsdk_archbare /arm) # what the architecture used to be called in oldest SDKs
484                         set(_winsdk_arch arm) # what the architecture used to be called
485                         set(_winsdk_arch8 arm) # what the WDK for Win8+ calls this architecture
486                 endif()
487         else()
488                 if(CMAKE_SIZEOF_VOID_P MATCHES "8")
489                         set(_winsdk_archbare /x64) # what the architecture used to be called in oldest SDKs
490                         set(_winsdk_arch amd64) # what the architecture used to be called
491                         set(_winsdk_arch8 x64) # what the WDK for Win8+ calls this architecture
492                 else()
493                         set(_winsdk_archbare ) # what the architecture used to be called in oldest SDKs
494                         set(_winsdk_arch i386) # what the architecture used to be called
495                         set(_winsdk_arch8 x86) # what the WDK for Win8+ calls this architecture
496                 endif()
497         endif()
499         function(get_windowssdk_from_component _component _var)
500                 get_filename_component(_component "${_component}" ABSOLUTE)
501                 file(TO_CMAKE_PATH "${_component}" _component)
502                 foreach(_sdkdir ${WINDOWSSDK_DIRS})
503                         get_filename_component(_sdkdir "${_sdkdir}" ABSOLUTE)
504                         string(LENGTH "${_sdkdir}" _sdklen)
505                         file(RELATIVE_PATH _rel "${_sdkdir}" "${_component}")
506                         # If we don't have any "parent directory" items...
507                         if(NOT "${_rel}" MATCHES "[.][.]")
508                                 set(${_var} "${_sdkdir}" PARENT_SCOPE)
509                                 return()
510                         endif()
511                 endforeach()
512                 # Fail.
513                 set(${_var} "NOTFOUND" PARENT_SCOPE)
514         endfunction()
515         function(get_windowssdk_library_dirs _winsdk_dir _var)
516                 set(_dirs)
517                 set(_suffixes
518                         "lib${_winsdk_archbare}" # SDKs like 7.1A
519                         "lib/${_winsdk_arch}" # just because some SDKs have x86 dir and root dir
520                         "lib/w2k/${_winsdk_arch}" # Win2k min requirement
521                         "lib/wxp/${_winsdk_arch}" # WinXP min requirement
522                         "lib/wnet/${_winsdk_arch}" # Win Server 2003 min requirement
523                         "lib/wlh/${_winsdk_arch}"
524                         "lib/wlh/um/${_winsdk_arch8}" # Win Vista ("Long Horn") min requirement
525                         "lib/win7/${_winsdk_arch}"
526                         "lib/win7/um/${_winsdk_arch8}" # Win 7 min requirement
527                 )
528                 foreach(_ver
529                         wlh # Win Vista ("Long Horn") min requirement
530                         win7 # Win 7 min requirement
531                         win8 # Win 8 min requirement
532                         winv6.3 # Win 8.1 min requirement
533                 )
535                 list(APPEND _suffixes
536                         "lib/${_ver}/${_winsdk_arch}"
537                         "lib/${_ver}/um/${_winsdk_arch8}"
538                         "lib/${_ver}/km/${_winsdk_arch8}"
539                 )
540                 endforeach()
542                 # Look for WDF libraries in Win10+ SDK
543                 foreach(_mode umdf kmdf)
544                         file(GLOB _wdfdirs RELATIVE "${_winsdk_dir}" "${_winsdk_dir}/lib/wdf/${_mode}/${_winsdk_arch8}/*")
545                         if(_wdfdirs)
546                                 list(APPEND _suffixes ${_wdfdirs})
547                         endif()
548                 endforeach()
550                 # Look in each Win10+ SDK version for the components
551                 foreach(_win10ver ${_winsdk_win10vers})
552                         foreach(_component um km ucrt mmos)
553                                 list(APPEND _suffixes "lib/${_win10ver}/${_component}/${_winsdk_arch8}")
554                         endforeach()
555                 endforeach()
557                 foreach(_suffix ${_suffixes})
558                         # Check to see if a library actually exists here.
559                         file(GLOB _libs "${_winsdk_dir}/${_suffix}/*.lib")
560                         if(_libs)
561                                 list(APPEND _dirs "${_winsdk_dir}/${_suffix}")
562                         endif()
563                 endforeach()
564                 if("${_dirs}" STREQUAL "")
565                         set(_dirs NOTFOUND)
566                 else()
567                         list(REMOVE_DUPLICATES _dirs)
568                 endif()
569                 set(${_var} ${_dirs} PARENT_SCOPE)
570         endfunction()
571         function(get_windowssdk_include_dirs _winsdk_dir _var)
572                 set(_dirs)
574                 set(_subdirs shared um winrt km wdf mmos ucrt)
575                 set(_suffixes Include)
577                 foreach(_dir ${_subdirs})
578                         list(APPEND _suffixes "Include/${_dir}")
579                 endforeach()
581                 foreach(_ver ${_winsdk_win10vers})
582                         foreach(_dir ${_subdirs})
583                                 list(APPEND _suffixes "Include/${_ver}/${_dir}")
584                         endforeach()
585                 endforeach()
587                 foreach(_suffix ${_suffixes})
588                         # Check to see if a header file actually exists here.
589                         file(GLOB _headers "${_winsdk_dir}/${_suffix}/*.h")
590                         if(_headers)
591                                 list(APPEND _dirs "${_winsdk_dir}/${_suffix}")
592                         endif()
593                 endforeach()
594                 if("${_dirs}" STREQUAL "")
595                         set(_dirs NOTFOUND)
596                 else()
597                         list(REMOVE_DUPLICATES _dirs)
598                 endif()
599                 set(${_var} ${_dirs} PARENT_SCOPE)
600         endfunction()
601         function(get_windowssdk_library_dirs_multiple _var)
602                 set(_dirs)
603                 foreach(_sdkdir ${ARGN})
604                         get_windowssdk_library_dirs("${_sdkdir}" _current_sdk_libdirs)
605                         if(_current_sdk_libdirs)
606                                 list(APPEND _dirs ${_current_sdk_libdirs})
607                         endif()
608                 endforeach()
609                 if("${_dirs}" STREQUAL "")
610                         set(_dirs NOTFOUND)
611                 else()
612                         list(REMOVE_DUPLICATES _dirs)
613                 endif()
614                 set(${_var} ${_dirs} PARENT_SCOPE)
615         endfunction()
616         function(get_windowssdk_include_dirs_multiple _var)
617                 set(_dirs)
618                 foreach(_sdkdir ${ARGN})
619                         get_windowssdk_include_dirs("${_sdkdir}" _current_sdk_incdirs)
620                         if(_current_sdk_libdirs)
621                                 list(APPEND _dirs ${_current_sdk_incdirs})
622                         endif()
623                 endforeach()
624                 if("${_dirs}" STREQUAL "")
625                         set(_dirs NOTFOUND)
626                 else()
627                         list(REMOVE_DUPLICATES _dirs)
628                 endif()
629                 set(${_var} ${_dirs} PARENT_SCOPE)
630         endfunction()
631 endif()