1 # -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*-
2 # vim: set filetype=python:
3 # This Source Code Form is subject to the terms of the Mozilla Public
4 # License, v. 2.0. If a copy of the MPL was not distributed with this
5 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 "--with-windows-version",
11 help="Windows SDK version to target. Win 8.1 (603) is currently"
12 "the minimum supported version.",
16 @depends("--with-windows-version")
17 @imports(_from="__builtin__", _import="ValueError")
18 def valid_windows_version(value):
20 die("Cannot build with --without-windows-version")
22 version = int(value[0], 16)
23 if version in (0x603,):
28 die("Invalid value for --with-windows-version (%s)", value[0])
31 option(env="WINDOWSSDKDIR", nargs=1, help="Directory containing the Windows SDK")
34 @depends("WINDOWSSDKDIR", c_compiler, host_c_compiler)
35 def windows_sdk_dir(value, compiler, host_compiler):
38 # Ideally, we'd actually check for host/target ABI being MSVC, but
39 # that's waiting for bug 1617793.
40 if compiler.type != "clang-cl" and host_compiler.type != "clang-cl":
45 for x in get_registry_values(
46 r"HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows Kits\Installed Roots"
48 get_32_and_64_bit=True,
53 # The Windows SDK 8.1 and 10 have different layouts. The former has
54 # $SDK/include/$subdir, while the latter has $SDK/include/$version/$subdir.
55 # The vcvars* scripts don't actually care about the version, they just take
56 # the last alphanumerically.
57 # The $SDK/lib directories always have version subdirectories, but while the
58 # versions match the one in $SDK/include for SDK 10, it's "winv6.3" for SDK
64 @imports(_from="__builtin__", _import="Exception")
65 def get_sdk_dirs(sdk, subdir):
66 def get_dirs_containing(sdk, stem, subdir):
67 base = os.path.join(sdk, stem)
70 d for d in os.listdir(base) if os.path.isdir(os.path.join(base, d))
78 # At this point, either we have an incomplete or invalid SDK directory,
79 # or we exclusively have version numbers in subdirs.
83 if os.path.isdir(os.path.join(base, s, subdir))
87 return {os.path.basename(d): d for d in dirs}
89 include_dirs = categorize(get_dirs_containing(sdk, "include", subdir))
90 lib_dirs = categorize(get_dirs_containing(sdk, "lib", subdir))
92 if "include" in include_dirs:
93 include_dirs["winv6.3"] = include_dirs["include"]
94 del include_dirs["include"]
96 valid_versions = sorted(set(include_dirs) & set(lib_dirs), reverse=True)
101 include=include_dirs[vv],
103 for vv in valid_versions
107 @imports(_from="mozbuild.shellutil", _import="quote")
108 def valid_windows_sdk_dir_result(value):
110 return "0x%04x in %s" % (value.version, quote(value.path))
114 c_compiler, host_c_compiler, windows_sdk_dir, valid_windows_version, "WINDOWSSDKDIR"
116 @checking("for Windows SDK", valid_windows_sdk_dir_result)
117 @imports(_from="__builtin__", _import="Exception")
118 @imports(_from="textwrap", _import="dedent")
119 def valid_windows_sdk_dir(
120 compiler, host_compiler, windows_sdk_dir, target_version, windows_sdk_dir_env
122 # Ideally, we'd actually check for host/target ABI being MSVC, but
123 # that's waiting for bug 1617793.
124 if compiler.type != "clang-cl" and host_compiler.type != "clang-cl":
126 if windows_sdk_dir_env:
127 windows_sdk_dir_env = windows_sdk_dir_env[0]
129 for d in windows_sdk_dir:
130 sdklist = get_sdk_dirs(d, "um")
134 #include <winsdkver.h>
138 um_dir = os.path.join(sdk.include, "um")
139 shared_dir = os.path.join(sdk.include, "shared")
140 result = try_preprocess(
142 + [compiler.compiler]
144 + ["-X", "-I", um_dir, "-I", shared_dir],
150 maxver = result.splitlines()[-1]
152 maxver = int(maxver, 0)
156 sdks[d] = maxver, sdk
159 if d == windows_sdk_dir_env and d not in sdks:
160 raise FatalCheckError(
161 "Error while checking the version of the SDK in "
162 "WINDOWSSDKDIR (%s). Please verify it contains a valid and "
163 "complete SDK installation." % windows_sdk_dir_env
166 valid_sdks = sorted(sdks, key=lambda x: sdks[x][0], reverse=True)
168 biggest_version, sdk = sdks[valid_sdks[0]]
169 if not valid_sdks or biggest_version < target_version:
170 if windows_sdk_dir_env:
171 raise FatalCheckError(
172 "You are targeting Windows version 0x%04x, but your SDK only "
173 "supports up to version 0x%04x. Install and use an updated SDK, "
174 "or target a lower version using --with-windows-version. "
175 "Alternatively, try running the Windows SDK Configuration Tool "
176 "and selecting a newer SDK. See "
177 "https://developer.mozilla.org/En/Windows_SDK_versions for "
178 "details on fixing this." % (target_version, biggest_version)
181 raise FatalCheckError(
182 "Cannot find a Windows SDK for version >= 0x%04x." % target_version
189 version=biggest_version,
193 @imports(_from="mozbuild.shellutil", _import="quote")
194 def valid_ucrt_sdk_dir_result(value):
196 return "%s in %s" % (value.version, quote(value.path))
199 @depends(windows_sdk_dir, "WINDOWSSDKDIR", c_compiler, host_c_compiler)
200 @checking("for Universal CRT SDK", valid_ucrt_sdk_dir_result)
202 @imports(_import="mozpack.path", _as="mozpath")
203 def valid_ucrt_sdk_dir(windows_sdk_dir, windows_sdk_dir_env, compiler, host_compiler):
204 # Ideally, we'd actually check for host/target ABI being MSVC, but
205 # that's waiting for bug 1617793.
206 if compiler.type != "clang-cl" and host_compiler.type != "clang-cl":
208 if windows_sdk_dir_env:
209 windows_sdk_dir_env = windows_sdk_dir_env[0]
211 for d in windows_sdk_dir:
212 sdklist = get_sdk_dirs(d, "ucrt")
214 version = os.path.basename(sdk.include)
215 # We're supposed to always find a version in the directory, because
216 # the 8.1 SDK, which doesn't have a version in the directory, doesn't
217 # contain the Universal CRT SDK. When the main SDK is 8.1, there
218 # is, however, supposed to be a reduced install of the SDK 10
220 if version != "include":
221 sdks[d] = Version(version), sdk
224 if d == windows_sdk_dir_env and d not in sdks:
225 # When WINDOWSSDKDIR is set in the environment and we can't find the
226 # Universal CRT SDK, chances are this is a start-shell-msvc*.bat
227 # setup, where INCLUDE and LIB already contain the UCRT paths.
230 for p in os.environ.get("INCLUDE", "").split(";")
231 if os.path.basename(p).lower() == "ucrt"
235 for p in os.environ.get("LIB", "").split(";")
236 if os.path.basename(os.path.dirname(p)).lower() == "ucrt"
238 if ucrt_includes and ucrt_libs:
239 # Pick the first of each, since they are the ones that the
240 # compiler would look first. Assume they contain the SDK files.
241 include = os.path.dirname(ucrt_includes[0])
242 lib = os.path.dirname(os.path.dirname(ucrt_libs[0]))
243 path = os.path.dirname(os.path.dirname(include))
244 version = os.path.basename(include)
245 if version != "include" and mozpath.basedir(lib, [path]):
255 raise FatalCheckError(
256 "The SDK in WINDOWSSDKDIR (%s) does not contain the Universal "
257 "CRT." % windows_sdk_dir_env
260 valid_sdks = sorted(sdks, key=lambda x: sdks[x][0], reverse=True)
262 raise FatalCheckError(
263 "Cannot find the Universal CRT SDK. " "Please install it."
266 version, sdk = sdks[valid_sdks[0]]
267 minimum_ucrt_version = Version("10.0.17134.0")
268 if version < minimum_ucrt_version:
269 raise FatalCheckError(
270 "Latest Universal CRT SDK version found %s"
271 " and minimum required is %s. This or a later"
272 " version can be installed using the Visual"
273 " Studio installer." % (version, minimum_ucrt_version)
284 @depends(c_compiler, host_c_compiler, vc_toolchain_search_path)
286 def vc_path(c_compiler, host_c_compiler, vc_toolchain_search_path):
287 if c_compiler.type != "clang-cl" and host_c_compiler.type != "clang-cl":
290 # In clang-cl builds, we need the headers and libraries from an MSVC installation.
291 vc_program = find_program("cl.exe", paths=vc_toolchain_search_path)
293 die("Cannot find a Visual C++ install for e.g. ATL headers.")
295 result = os.path.dirname(vc_program)
297 next, p = os.path.split(result)
300 "Cannot determine the Visual C++ directory the compiler (%s) "
304 if p.lower() == "bin":
306 return os.path.normpath(result)
309 @depends(vc_path, valid_windows_sdk_dir, valid_ucrt_sdk_dir)
311 def include_path(vc_path, windows_sdk_dir, ucrt_sdk_dir):
314 atlmfc_dir = os.path.join(vc_path, "atlmfc", "include")
315 if not os.path.isdir(atlmfc_dir):
317 "Cannot find the ATL/MFC headers in the Visual C++ directory (%s). "
318 "Please install them." % vc_path
321 winrt_dir = os.path.join(windows_sdk_dir.include, "winrt")
322 if not os.path.isdir(winrt_dir):
324 "Cannot find the WinRT headers in the Windows SDK directory (%s). "
325 "Please install them." % windows_sdk_dir.path
328 cppwinrt_dir = os.path.join(windows_sdk_dir.include, "cppwinrt")
329 if not os.path.isdir(cppwinrt_dir):
331 "Cannot find the C++/WinRT headers in the Windows SDK directory (%s). "
332 "Please install them." % windows_sdk_dir.path
336 include_env = os.environ.get("INCLUDE")
338 includes.append(include_env)
341 os.path.join(vc_path, "include"),
343 os.path.join(windows_sdk_dir.include, "shared"),
344 os.path.join(windows_sdk_dir.include, "um"),
347 os.path.join(ucrt_sdk_dir.include, "ucrt"),
350 # Set in the environment for old-configure
351 includes = ";".join(includes)
352 os.environ["INCLUDE"] = includes
356 set_config("INCLUDE", include_path)
358 # cppwinrt requires this on clang because of no coroutine support, which is okay
359 set_define("_SILENCE_CLANG_COROUTINE_MESSAGE", "")
363 def lib_path_for(host_or_target):
366 dependable(host_or_target is host),
368 valid_windows_sdk_dir,
372 def lib_path(target, is_host, vc_path, windows_sdk_dir, ucrt_sdk_dir):
382 # MSVC2017 switched to use the same target naming as the sdk.
383 atlmfc_dir = os.path.join(vc_path, "atlmfc", "lib", sdk_target)
384 if not os.path.isdir(atlmfc_dir):
386 "Cannot find the ATL/MFC libraries in the Visual C++ directory "
387 "(%s). Please install them." % vc_path
391 lib_env = os.environ.get("LIB")
392 if lib_env and not is_host:
393 libs.extend(lib_env.split(";"))
396 os.path.join(vc_path, "lib", sdk_target),
398 os.path.join(windows_sdk_dir.lib, "um", sdk_target),
399 os.path.join(ucrt_sdk_dir.lib, "ucrt", sdk_target),
407 @depends_if(lib_path_for(target))
410 # Set in the environment for old-configure
411 libs = ";".join(libs)
412 os.environ["LIB"] = libs
416 set_config("LIB", lib_path)
419 lib_path_for_host = lib_path_for(host)
422 @depends_if(lib_path_for_host)
423 @imports(_from="mozbuild.shellutil", _import="quote")
424 def host_linker_libpaths(libs):
425 return ["-LIBPATH:%s" % quote(l) for l in libs]
428 @depends_if(lib_path_for_host)
429 @imports(_from="mozbuild.shellutil", _import="quote")
430 def host_linker_libpaths_bat(libs):
431 # .bat files need a different style of quoting. Batch quoting is actually
432 # not defined, and up to applications to handle, so it's not really clear
433 # what should be escaped and what not, but most paths should work just
434 # fine without escaping. And we don't care about double-quotes possibly
435 # having to be escaped because they're not allowed in file names on
437 return ['"-LIBPATH:%s"' % l for l in libs]
440 set_config("HOST_LINKER_LIBPATHS", host_linker_libpaths)
441 set_config("HOST_LINKER_LIBPATHS_BAT", host_linker_libpaths_bat)
444 @depends(valid_windows_sdk_dir, valid_ucrt_sdk_dir, host)
445 @imports(_from="os", _import="environ")
446 def sdk_bin_path(valid_windows_sdk_dir, valid_ucrt_sdk_dir, host):
447 if not valid_windows_sdk_dir:
455 # From version 10.0.15063.0 onwards the bin path contains the version number.
458 if valid_ucrt_sdk_dir.version < "10.0.15063.0"
459 else os.path.join("bin", str(valid_ucrt_sdk_dir.version))
463 os.path.join(valid_windows_sdk_dir.path, versioned_bin, vc_host),
466 result.append(os.path.join(valid_windows_sdk_dir.path, versioned_bin, "x86"))
470 option(env="LINKER", nargs=1, when=target_is_windows, help="Path to the linker")
476 when=target_is_windows,
477 paths=clang_search_path,
480 option(env="HOST_LINKER", nargs=1, when=host_is_windows, help="Path to the host linker")
482 host_link = check_prog(
486 when=host_is_windows,
487 paths=clang_search_path,
490 add_old_configure_assignment("LINKER", link)