Bug 1892041 - Part 1: Update test262 features. r=spidermonkey-reviewers,dminor
[gecko.git] / build / moz.configure / windows.configure
blob66b3a2bbfcb6f95457f333036c077729755f7433
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/.
7 option(
8     "--with-windows-version",
9     nargs=1,
10     default="603",
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):
19     if not value:
20         die("Cannot build with --without-windows-version")
21     try:
22         version = int(value[0], 16)
23         if version in (0x603,):
24             return version
25     except ValueError:
26         pass
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(
35     "WINDOWSSDKDIR", "WINSYSROOT", winsysroot, target_windows_abi, host_windows_abi
37 def windows_sdk_dir(
38     value, winsysroot_env, winsysroot, target_windows_abi, host_windows_abi
40     if value:
41         if winsysroot_env:
42             die("WINDOWSSDKDIR and WINSYSROOT cannot be set together.")
43         if winsysroot:
44             die("WINDOWSSDKDIR cannot be set when using the bootstrapped WINSYSROOT")
45         return value
46     if target_windows_abi != "msvc" and host_windows_abi != "msvc":
47         return ()
49     if winsysroot:
50         return [os.path.join(winsysroot, "Windows Kits", "10")]
52     return set(
53         normalize_path(x[1])
54         for x in get_registry_values(
55             r"HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows Kits\Installed Roots"
56             r"\KitsRoot*",
57             get_32_and_64_bit=True,
58         )
59     )
62 @imports("glob")
63 def get_sdk_dirs(sdk, subdir):
64     def get_dirs_containing(sdk, stem, subdir):
65         return [
66             os.path.dirname(p) for p in glob.glob(os.path.join(sdk, stem, "*", subdir))
67         ]
69     def categorize(dirs):
70         return {os.path.basename(d): d for d in dirs}
72     include_dirs = categorize(get_dirs_containing(sdk, "Include", subdir))
73     lib_dirs = categorize(get_dirs_containing(sdk, "Lib", subdir))
75     valid_versions = sorted(set(include_dirs) & set(lib_dirs), reverse=True)
76     return [
77         namespace(
78             path=sdk,
79             lib=lib_dirs[vv],
80             include=include_dirs[vv],
81         )
82         for vv in valid_versions
83     ]
86 @imports(_from="mozbuild.shellutil", _import="quote")
87 def valid_windows_sdk_dir_result(value):
88     if value:
89         return "0x%04x in %s" % (value.version, quote(value.path))
92 @depends(
93     target_windows_abi,
94     host_windows_abi,
95     windows_sdk_dir,
96     valid_windows_version,
97     "WINDOWSSDKDIR",
99 @checking("for Windows SDK", valid_windows_sdk_dir_result)
100 @imports(_from="__builtin__", _import="Exception")
101 @imports(_from="__builtin__", _import="open")
102 def valid_windows_sdk_dir(
103     target_windows_abi,
104     host_windows_abi,
105     windows_sdk_dir,
106     target_version,
107     windows_sdk_dir_env,
109     if target_windows_abi != "msvc" and host_windows_abi != "msvc":
110         return None
111     if windows_sdk_dir_env:
112         windows_sdk_dir_env = windows_sdk_dir_env[0]
113     sdks = {}
114     for d in windows_sdk_dir:
115         sdklist = get_sdk_dirs(d, "um")
116         for sdk in sdklist:
117             maxver = None
118             winsdkver = os.path.join(sdk.include, "um", "winsdkver.h")
119             with open(winsdkver) as fh:
120                 for line in fh.readlines():
121                     if line.startswith("#define"):
122                         line = line.split(None, 2)
123                         assert line.pop(0) == "#define"
124                         if line.pop(0) == "WINVER_MAXVER":
125                             maxver = line.pop(0)
126                             break
128             if maxver:
129                 try:
130                     maxver = int(maxver, 0)
131                 except Exception:
132                     pass
133                 else:
134                     sdks[d] = maxver, sdk
135                     break
137         if d == windows_sdk_dir_env and d not in sdks:
138             raise FatalCheckError(
139                 "Error while checking the version of the SDK in "
140                 "WINDOWSSDKDIR (%s). Please verify it contains a valid and "
141                 "complete SDK installation." % windows_sdk_dir_env
142             )
144     valid_sdks = sorted(sdks, key=lambda x: sdks[x][0], reverse=True)
145     if valid_sdks:
146         biggest_version, sdk = sdks[valid_sdks[0]]
147     if not valid_sdks or biggest_version < target_version:
148         if windows_sdk_dir_env:
149             raise FatalCheckError(
150                 "You are targeting Windows version 0x%04x, but your SDK only "
151                 "supports up to version 0x%04x. Install and use an updated SDK, "
152                 "or target a lower version using --with-windows-version. "
153                 "Alternatively, try running the Windows SDK Configuration Tool "
154                 "and selecting a newer SDK. See "
155                 "https://developer.mozilla.org/En/Windows_SDK_versions for "
156                 "details on fixing this." % (target_version, biggest_version)
157             )
159         raise FatalCheckError(
160             "Cannot find a Windows SDK for version >= 0x%04x." % target_version
161         )
163     return namespace(
164         path=sdk.path,
165         include=sdk.include,
166         lib=sdk.lib,
167         version=biggest_version,
168     )
171 @imports(_from="mozbuild.shellutil", _import="quote")
172 def valid_ucrt_sdk_dir_result(value):
173     if value:
174         return "%s in %s" % (value.version, quote(value.path))
177 @depends(windows_sdk_dir, "WINDOWSSDKDIR", target_windows_abi, host_windows_abi)
178 @checking("for Universal CRT SDK", valid_ucrt_sdk_dir_result)
179 @imports("os")
180 @imports(_import="mozpack.path", _as="mozpath")
181 def valid_ucrt_sdk_dir(
182     windows_sdk_dir, windows_sdk_dir_env, target_windows_abi, host_windows_abi
184     if target_windows_abi != "msvc" and host_windows_abi != "msvc":
185         return None
186     if windows_sdk_dir_env:
187         windows_sdk_dir_env = windows_sdk_dir_env[0]
188     sdks = {}
189     for d in windows_sdk_dir:
190         sdklist = get_sdk_dirs(d, "ucrt")
191         for sdk in sdklist:
192             version = os.path.basename(sdk.include)
193             # We're supposed to always find a version in the directory, because
194             # the 8.1 SDK, which doesn't have a version in the directory, doesn't
195             # contain the Universal CRT SDK. When the main SDK is 8.1, there
196             # is, however, supposed to be a reduced install of the SDK 10
197             # with the UCRT.
198             if version != "include":
199                 sdks[d] = Version(version), sdk
200                 break
202         if d == windows_sdk_dir_env and d not in sdks:
203             # When WINDOWSSDKDIR is set in the environment and we can't find the
204             # Universal CRT SDK, chances are this is a start-shell-msvc*.bat
205             # setup, where INCLUDE and LIB already contain the UCRT paths.
206             ucrt_includes = [
207                 p
208                 for p in os.environ.get("INCLUDE", "").split(";")
209                 if os.path.basename(p).lower() == "ucrt"
210             ]
211             ucrt_libs = [
212                 p
213                 for p in os.environ.get("LIB", "").split(";")
214                 if os.path.basename(os.path.dirname(p)).lower() == "ucrt"
215             ]
216             if ucrt_includes and ucrt_libs:
217                 # Pick the first of each, since they are the ones that the
218                 # compiler would look first. Assume they contain the SDK files.
219                 include = os.path.dirname(ucrt_includes[0])
220                 lib = os.path.dirname(os.path.dirname(ucrt_libs[0]))
221                 path = os.path.dirname(os.path.dirname(include))
222                 version = os.path.basename(include)
223                 if version != "include" and mozpath.basedir(lib, [path]):
224                     sdks[d] = (
225                         Version(version),
226                         namespace(
227                             path=path,
228                             include=include,
229                             lib=lib,
230                         ),
231                     )
232                     continue
233             raise FatalCheckError(
234                 "The SDK in WINDOWSSDKDIR (%s) does not contain the Universal "
235                 "CRT." % windows_sdk_dir_env
236             )
238     valid_sdks = sorted(sdks, key=lambda x: sdks[x][0], reverse=True)
239     if not valid_sdks:
240         raise FatalCheckError(
241             "Cannot find the Universal CRT SDK. " "Please install it."
242         )
244     version, sdk = sdks[valid_sdks[0]]
245     minimum_ucrt_version = Version("10.0.17134.0")
246     if version < minimum_ucrt_version:
247         raise FatalCheckError(
248             "Latest Universal CRT SDK version found %s"
249             " and minimum required is %s. This or a later"
250             " version can be installed using the Visual"
251             " Studio installer." % (version, minimum_ucrt_version)
252         )
254     return namespace(
255         path=sdk.path,
256         include=sdk.include,
257         lib=sdk.lib,
258         version=version,
259     )
262 @depends(target_windows_abi, host_windows_abi, vc_toolchain_search_path)
263 @imports("os")
264 def vc_path(target_windows_abi, host_windows_abi, vc_toolchain_search_path):
265     if target_windows_abi != "msvc" and host_windows_abi != "msvc":
266         return
268     # In clang-cl builds, we need the headers and libraries from an MSVC installation.
269     vc_program = find_program("cl.exe", paths=vc_toolchain_search_path)
270     if not vc_program:
271         die("Cannot find a Visual C++ install for e.g. ATL headers.")
273     result = os.path.dirname(vc_program)
274     while True:
275         next, p = os.path.split(result)
276         if next == result:
277             die(
278                 "Cannot determine the Visual C++ directory the compiler (%s) "
279                 "is in" % vc_program
280             )
281         result = next
282         if p.lower() == "bin":
283             break
284     return os.path.normpath(result)
287 @depends(vc_path, valid_windows_sdk_dir, valid_ucrt_sdk_dir)
288 @imports("os")
289 def include_path(vc_path, windows_sdk_dir, ucrt_sdk_dir):
290     if not vc_path:
291         return
292     atlmfc_dir = os.path.join(vc_path, "atlmfc", "include")
293     if not os.path.isdir(atlmfc_dir):
294         die(
295             "Cannot find the ATL/MFC headers in the Visual C++ directory (%s). "
296             "Please install them." % vc_path
297         )
299     winrt_dir = os.path.join(windows_sdk_dir.include, "winrt")
300     if not os.path.isdir(winrt_dir):
301         die(
302             "Cannot find the WinRT headers in the Windows SDK directory (%s). "
303             "Please install them." % windows_sdk_dir.path
304         )
306     cppwinrt_dir = os.path.join(windows_sdk_dir.include, "cppwinrt")
307     if not os.path.isdir(cppwinrt_dir):
308         die(
309             "Cannot find the C++/WinRT headers in the Windows SDK directory (%s). "
310             "Please install them." % windows_sdk_dir.path
311         )
313     includes = []
314     include_env = os.environ.get("INCLUDE")
315     if include_env:
316         includes.append(include_env)
317     includes.extend(
318         (
319             os.path.join(vc_path, "include"),
320             atlmfc_dir,
321             os.path.join(windows_sdk_dir.include, "shared"),
322             os.path.join(windows_sdk_dir.include, "um"),
323             winrt_dir,
324             cppwinrt_dir,
325             os.path.join(ucrt_sdk_dir.include, "ucrt"),
326         )
327     )
328     # Set in the environment for old-configure
329     includes = ";".join(includes)
330     os.environ["INCLUDE"] = includes
331     return includes
334 set_config("INCLUDE", include_path)
336 # cppwinrt requires this on clang because of no coroutine support, which is okay
337 set_define("_SILENCE_CLANG_COROUTINE_MESSAGE", "")
340 @template
341 def lib_path_for(host_or_target):
342     @depends(
343         host_or_target,
344         dependable(host_or_target is host),
345         vc_path,
346         valid_windows_sdk_dir,
347         valid_ucrt_sdk_dir,
348         c_compiler,
349     )
350     @imports("os")
351     def lib_path(target, is_host, vc_path, windows_sdk_dir, ucrt_sdk_dir, compiler):
352         if not vc_path or target.os != "WINNT":
353             return
354         sdk_target = {
355             "x86": "x86",
356             "x86_64": "x64",
357             "arm": "arm",
358             "aarch64": "arm64",
359         }.get(target.cpu)
361         # MSVC2017 switched to use the same target naming as the sdk.
362         atlmfc_dir = os.path.join(vc_path, "atlmfc", "lib", sdk_target)
363         if not os.path.isdir(atlmfc_dir):
364             die(
365                 "Cannot find the ATL/MFC libraries in the Visual C++ directory "
366                 "(%s). Please install them." % vc_path
367             )
369         libs = []
370         lib_env = os.environ.get("LIB")
371         if lib_env and not is_host:
372             libs.extend(lib_env.split(";"))
373         libs.extend(
374             (
375                 os.path.join(vc_path, "lib", sdk_target),
376                 atlmfc_dir,
377                 os.path.join(windows_sdk_dir.lib, "um", sdk_target),
378                 os.path.join(ucrt_sdk_dir.lib, "ucrt", sdk_target),
379             )
380         )
381         if compiler.type == "clang-cl":
382             runtime_dir = check_cmd_output(
383                 compiler.compiler,
384                 "/clang:--print-runtime-dir",
385                 *compiler.flags,
386                 onerror=lambda: None,
387             ).strip()
388             if runtime_dir and os.path.exists(runtime_dir):
389                 # Put the clang runtime directory first, in case there is
390                 # a different version in some of the other directories (notably,
391                 # some versions of MSVC come with clang runtimes)
392                 libs.insert(0, runtime_dir)
393         return libs
395     return lib_path
398 @depends_if(lib_path_for(target), when=target_is_windows)
399 @imports("os")
400 def lib_path(libs):
401     # Set in the environment for old-configure
402     libs = ";".join(libs)
403     os.environ["LIB"] = libs
404     return libs
407 set_config("LIB", lib_path)
410 lib_path_for_host = lib_path_for(host)
413 @depends_if(lib_path_for_host, when=host_is_windows)
414 @imports(_from="mozbuild.shellutil", _import="quote")
415 def host_linker_libpaths(libs):
416     return ["-LIBPATH:%s" % quote(l) for l in libs]
419 @depends_if(lib_path_for_host, when=host_is_windows)
420 @imports(_from="mozbuild.shellutil", _import="quote")
421 def host_linker_libpaths_bat(libs):
422     # .bat files need a different style of quoting. Batch quoting is actually
423     # not defined, and up to applications to handle, so it's not really clear
424     # what should be escaped and what not, but most paths should work just
425     # fine without escaping. And we don't care about double-quotes possibly
426     # having to be escaped because they're not allowed in file names on
427     # Windows.
428     return ['"-LIBPATH:%s"' % l for l in libs]
431 set_config("HOST_LINKER_LIBPATHS", host_linker_libpaths)
432 set_config("HOST_LINKER_LIBPATHS_BAT", host_linker_libpaths_bat)
435 @depends(valid_windows_sdk_dir, valid_ucrt_sdk_dir, host)
436 @imports(_from="os", _import="environ")
437 def sdk_bin_path(valid_windows_sdk_dir, valid_ucrt_sdk_dir, host):
438     if not valid_windows_sdk_dir:
439         return
441     vc_host = {
442         "x86": "x86",
443         "x86_64": "x64",
444     }.get(host.cpu)
446     # From version 10.0.15063.0 onwards the bin path contains the version number.
447     versioned_bin = (
448         "bin"
449         if valid_ucrt_sdk_dir.version < "10.0.15063.0"
450         else os.path.join("bin", str(valid_ucrt_sdk_dir.version))
451     )
452     result = [
453         environ["PATH"],
454         os.path.join(valid_windows_sdk_dir.path, versioned_bin, vc_host),
455     ]
456     if vc_host == "x64":
457         result.append(os.path.join(valid_windows_sdk_dir.path, versioned_bin, "x86"))
458     return result
461 option(env="LINKER", nargs=1, when=target_is_windows, help="Path to the linker")
463 link = check_prog(
464     "LINKER",
465     ("lld-link",),
466     input="LINKER",
467     when=target_is_windows,
468     paths=clang_search_path,
471 option(env="HOST_LINKER", nargs=1, when=host_is_windows, help="Path to the host linker")
473 host_link = check_prog(
474     "HOST_LINKER",
475     ("lld-link",),
476     input="HOST_LINKER",
477     when=host_is_windows,
478     paths=clang_search_path,
481 add_old_configure_assignment("LINKER", link)
483 option(
484     "--with-redist",
485     env="WIN32_REDIST_DIR",
486     nargs="?",
487     help="{Package|Don't package} redistributable MSVCRT",
491 @depends("--with-redist", "MOZ_AUTOMATION", c_compiler, vc_path, target)
492 @imports("os")
493 def win32_redist_dir(redist, automation, c_compiler, vc_path, target):
494     if len(redist):
495         if os.path.isdir(redist[0]):
496             return redist[0]
497         configure_error(f"Invalid Win32 Redist directory: {redist[0]}")
498     if redist or (
499         automation and redist.origin == "default" and c_compiler.type == "clang-cl"
500     ):
501         if not vc_path:
502             configure_error("Cannot ship redistributable MSVCRT without MSVC")
503         # It would be too simple if the Redist dir had the same version number as
504         # the MSVC one.
505         base_redist_path = os.path.join(
506             os.path.dirname(os.path.dirname(os.path.dirname(vc_path))), "Redist", "MSVC"
507         )
508         redist_target = {
509             "x86": "x86",
510             "x86_64": "x64",
511             "aarch64": "arm64",
512         }.get(target.cpu)
513         if redist_target and os.path.isdir(base_redist_path):
514             versions = [Version(v) for v in os.listdir(base_redist_path)]
515             redist_path = os.path.join(
516                 base_redist_path,
517                 str(max(v for v in versions if v.major)),
518                 redist_target,
519             )
520             if os.path.isdir(redist_path):
521                 crt_path = max(p for p in os.listdir(redist_path) if p.endswith("CRT"))
522                 if crt_path:
523                     return os.path.join(redist_path, crt_path)
524         configure_error("Could not find redistributable MSVCRT files")
527 set_config("WIN32_REDIST_DIR", win32_redist_dir)