summaryrefslogtreecommitdiffstats
path: root/build/moz.configure/windows.configure
diff options
context:
space:
mode:
Diffstat (limited to 'build/moz.configure/windows.configure')
-rw-r--r--build/moz.configure/windows.configure535
1 files changed, 535 insertions, 0 deletions
diff --git a/build/moz.configure/windows.configure b/build/moz.configure/windows.configure
new file mode 100644
index 0000000000..568046c2e5
--- /dev/null
+++ b/build/moz.configure/windows.configure
@@ -0,0 +1,535 @@
+# -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*-
+# vim: set filetype=python:
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+option(
+ "--with-windows-version",
+ nargs=1,
+ default="603",
+ help="Windows SDK version to target. Win 8.1 (603) is currently"
+ "the minimum supported version.",
+)
+
+
+@depends("--with-windows-version")
+@imports(_from="__builtin__", _import="ValueError")
+def valid_windows_version(value):
+ if not value:
+ die("Cannot build with --without-windows-version")
+ try:
+ version = int(value[0], 16)
+ if version in (0x603,):
+ return version
+ except ValueError:
+ pass
+
+ die("Invalid value for --with-windows-version (%s)", value[0])
+
+
+option(env="WINDOWSSDKDIR", nargs=1, help="Directory containing the Windows SDK")
+
+
+@depends("WINDOWSSDKDIR", host, c_compiler)
+def windows_sdk_dir(value, host, compiler):
+ if value:
+ return value
+ # Ideally, we'd actually check for host/target ABI being MSVC, but
+ # that's waiting for bug 1617793.
+ if host.kernel != "WINNT" or compiler.type != "clang-cl":
+ return ()
+
+ return set(
+ x[1]
+ for x in get_registry_values(
+ r"HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows Kits\Installed Roots"
+ r"\KitsRoot*",
+ get_32_and_64_bit=True,
+ )
+ )
+
+
+# The Windows SDK 8.1 and 10 have different layouts. The former has
+# $SDK/include/$subdir, while the latter has $SDK/include/$version/$subdir.
+# The vcvars* scripts don't actually care about the version, they just take
+# the last alphanumerically.
+# The $SDK/lib directories always have version subdirectories, but while the
+# versions match the one in $SDK/include for SDK 10, it's "winv6.3" for SDK
+# 8.1.
+
+
+@imports("os")
+@imports("re")
+@imports(_from="__builtin__", _import="sorted")
+@imports(_from="__builtin__", _import="Exception")
+def get_sdk_dirs(sdk, subdir):
+ def get_dirs_containing(sdk, stem, subdir):
+ base = os.path.join(sdk, stem)
+ try:
+ subdirs = [
+ d for d in os.listdir(base) if os.path.isdir(os.path.join(base, d))
+ ]
+ except Exception:
+ subdirs = []
+ if not subdirs:
+ return ()
+ if subdir in subdirs:
+ return (base,)
+ # At this point, either we have an incomplete or invalid SDK directory,
+ # or we exclusively have version numbers in subdirs.
+ return tuple(
+ os.path.join(base, s)
+ for s in subdirs
+ if os.path.isdir(os.path.join(base, s, subdir))
+ )
+
+ def categorize(dirs):
+ return {os.path.basename(d): d for d in dirs}
+
+ include_dirs = categorize(get_dirs_containing(sdk, "include", subdir))
+ lib_dirs = categorize(get_dirs_containing(sdk, "lib", subdir))
+
+ if "include" in include_dirs:
+ include_dirs["winv6.3"] = include_dirs["include"]
+ del include_dirs["include"]
+
+ valid_versions = sorted(set(include_dirs) & set(lib_dirs), reverse=True)
+ if valid_versions:
+ return namespace(
+ path=sdk,
+ lib=lib_dirs[valid_versions[0]],
+ include=include_dirs[valid_versions[0]],
+ )
+
+
+@imports(_from="mozbuild.shellutil", _import="quote")
+def valid_windows_sdk_dir_result(value):
+ if value:
+ return "0x%04x in %s" % (value.version, quote(value.path))
+
+
+@depends(c_compiler, windows_sdk_dir, valid_windows_version, "WINDOWSSDKDIR")
+@checking("for Windows SDK", valid_windows_sdk_dir_result)
+@imports(_from="__builtin__", _import="sorted")
+@imports(_from="__builtin__", _import="Exception")
+@imports(_from="textwrap", _import="dedent")
+def valid_windows_sdk_dir(
+ compiler, windows_sdk_dir, target_version, windows_sdk_dir_env
+):
+ # Ideally, we'd actually check for host/target ABI being MSVC, but
+ # that's waiting for bug 1617793.
+ if compiler.type != "clang-cl":
+ return None
+ if windows_sdk_dir_env:
+ windows_sdk_dir_env = windows_sdk_dir_env[0]
+ sdks = {}
+ for d in windows_sdk_dir:
+ sdk = get_sdk_dirs(d, "um")
+ if sdk:
+ check = dedent(
+ """\
+ #include <winsdkver.h>
+ WINVER_MAXVER
+ """
+ )
+ um_dir = os.path.join(sdk.include, "um")
+ shared_dir = os.path.join(sdk.include, "shared")
+ result = try_preprocess(
+ compiler.wrapper
+ + [compiler.compiler]
+ + compiler.flags
+ + ["-X", "-I", um_dir, "-I", shared_dir],
+ "C",
+ check,
+ onerror=lambda: "",
+ )
+ if result:
+ maxver = result.splitlines()[-1]
+ try:
+ maxver = int(maxver, 0)
+ except Exception:
+ pass
+ else:
+ sdks[d] = maxver, sdk
+ continue
+ if d == windows_sdk_dir_env:
+ raise FatalCheckError(
+ "Error while checking the version of the SDK in "
+ "WINDOWSSDKDIR (%s). Please verify it contains a valid and "
+ "complete SDK installation." % windows_sdk_dir_env
+ )
+
+ valid_sdks = sorted(sdks, key=lambda x: sdks[x][0], reverse=True)
+ if valid_sdks:
+ biggest_version, sdk = sdks[valid_sdks[0]]
+ if not valid_sdks or biggest_version < target_version:
+ if windows_sdk_dir_env:
+ raise FatalCheckError(
+ "You are targeting Windows version 0x%04x, but your SDK only "
+ "supports up to version 0x%04x. Install and use an updated SDK, "
+ "or target a lower version using --with-windows-version. "
+ "Alternatively, try running the Windows SDK Configuration Tool "
+ "and selecting a newer SDK. See "
+ "https://developer.mozilla.org/En/Windows_SDK_versions for "
+ "details on fixing this." % (target_version, biggest_version)
+ )
+
+ raise FatalCheckError(
+ "Cannot find a Windows SDK for version >= 0x%04x." % target_version
+ )
+
+ return namespace(
+ path=sdk.path,
+ include=sdk.include,
+ lib=sdk.lib,
+ version=biggest_version,
+ )
+
+
+@imports(_from="mozbuild.shellutil", _import="quote")
+def valid_ucrt_sdk_dir_result(value):
+ if value:
+ return "%s in %s" % (value.version, quote(value.path))
+
+
+@depends(windows_sdk_dir, "WINDOWSSDKDIR", c_compiler)
+@checking("for Universal CRT SDK", valid_ucrt_sdk_dir_result)
+@imports("os")
+@imports(_from="__builtin__", _import="sorted")
+@imports(_import="mozpack.path", _as="mozpath")
+def valid_ucrt_sdk_dir(windows_sdk_dir, windows_sdk_dir_env, compiler):
+ # Ideally, we'd actually check for host/target ABI being MSVC, but
+ # that's waiting for bug 1617793.
+ if compiler.type != "clang-cl":
+ return None
+ if windows_sdk_dir_env:
+ windows_sdk_dir_env = windows_sdk_dir_env[0]
+ sdks = {}
+ for d in windows_sdk_dir:
+ sdk = get_sdk_dirs(d, "ucrt")
+ if sdk:
+ version = os.path.basename(sdk.include)
+ # We're supposed to always find a version in the directory, because
+ # the 8.1 SDK, which doesn't have a version in the directory, doesn't
+ # contain the Universal CRT SDK. When the main SDK is 8.1, there
+ # is, however, supposed to be a reduced install of the SDK 10
+ # with the UCRT.
+ if version != "include":
+ sdks[d] = Version(version), sdk
+ continue
+ if d == windows_sdk_dir_env:
+ # When WINDOWSSDKDIR is set in the environment and we can't find the
+ # Universal CRT SDK, chances are this is a start-shell-msvc*.bat
+ # setup, where INCLUDE and LIB already contain the UCRT paths.
+ ucrt_includes = [
+ p
+ for p in os.environ.get("INCLUDE", "").split(";")
+ if os.path.basename(p).lower() == "ucrt"
+ ]
+ ucrt_libs = [
+ p
+ for p in os.environ.get("LIB", "").split(";")
+ if os.path.basename(os.path.dirname(p)).lower() == "ucrt"
+ ]
+ if ucrt_includes and ucrt_libs:
+ # Pick the first of each, since they are the ones that the
+ # compiler would look first. Assume they contain the SDK files.
+ include = os.path.dirname(ucrt_includes[0])
+ lib = os.path.dirname(os.path.dirname(ucrt_libs[0]))
+ path = os.path.dirname(os.path.dirname(include))
+ version = os.path.basename(include)
+ if version != "include" and mozpath.basedir(lib, [path]):
+ sdks[d] = (
+ Version(version),
+ namespace(
+ path=path,
+ include=include,
+ lib=lib,
+ ),
+ )
+ continue
+ raise FatalCheckError(
+ "The SDK in WINDOWSSDKDIR (%s) does not contain the Universal "
+ "CRT." % windows_sdk_dir_env
+ )
+
+ valid_sdks = sorted(sdks, key=lambda x: sdks[x][0], reverse=True)
+ if not valid_sdks:
+ raise FatalCheckError(
+ "Cannot find the Universal CRT SDK. " "Please install it."
+ )
+
+ version, sdk = sdks[valid_sdks[0]]
+ minimum_ucrt_version = Version("10.0.17134.0")
+ if version < minimum_ucrt_version:
+ raise FatalCheckError(
+ "Latest Universal CRT SDK version found %s"
+ " and minimum required is %s. This or a later"
+ " version can be installed using the Visual"
+ " Studio installer." % (version, minimum_ucrt_version)
+ )
+
+ return namespace(
+ path=sdk.path,
+ include=sdk.include,
+ lib=sdk.lib,
+ version=version,
+ )
+
+
+@depends(c_compiler, host_c_compiler, vc_toolchain_search_path)
+@imports("os")
+def vc_path(c_compiler, host_c_compiler, vc_toolchain_search_path):
+ if c_compiler.type != "clang-cl" and host_c_compiler.type != "clang-cl":
+ return
+
+ # In clang-cl builds, we need the headers and libraries from an MSVC installation.
+ vc_program = find_program("cl.exe", paths=vc_toolchain_search_path)
+ if not vc_program:
+ die("Cannot find a Visual C++ install for e.g. ATL headers.")
+
+ result = os.path.dirname(vc_program)
+ while True:
+ next, p = os.path.split(result)
+ if next == result:
+ die(
+ "Cannot determine the Visual C++ directory the compiler (%s) "
+ "is in" % vc_program
+ )
+ result = next
+ if p.lower() == "bin":
+ break
+ return os.path.normpath(result)
+
+
+option(env="DIA_SDK_PATH", nargs=1, help="Path to the Debug Interface Access SDK")
+
+
+@depends(vc_path, "DIA_SDK_PATH")
+@checking("for the Debug Interface Access SDK", lambda x: x or "not found")
+@imports("os")
+def dia_sdk_dir(vc_path, dia_sdk_path):
+ if dia_sdk_path:
+ path = os.path.normpath(dia_sdk_path[0])
+
+ elif vc_path:
+ # This would be easier if we had the installationPath that
+ # get_vc_paths works with, since 'DIA SDK' is relative to that.
+ path = os.path.normpath(
+ os.path.join(vc_path, "..", "..", "..", "..", "DIA SDK")
+ )
+ else:
+ return
+
+ if os.path.exists(os.path.join(path, "include", "dia2.h")):
+ return path
+
+
+@depends(vc_path, valid_windows_sdk_dir, valid_ucrt_sdk_dir, dia_sdk_dir)
+@imports("os")
+def include_path(vc_path, windows_sdk_dir, ucrt_sdk_dir, dia_sdk_dir):
+ if not vc_path:
+ return
+ atlmfc_dir = os.path.join(vc_path, "atlmfc", "include")
+ if not os.path.isdir(atlmfc_dir):
+ die(
+ "Cannot find the ATL/MFC headers in the Visual C++ directory (%s). "
+ "Please install them." % vc_path
+ )
+
+ winrt_dir = os.path.join(windows_sdk_dir.include, "winrt")
+ if not os.path.isdir(winrt_dir):
+ die(
+ "Cannot find the WinRT headers in the Windows SDK directory (%s). "
+ "Please install them." % windows_sdk_dir.path
+ )
+
+ includes = []
+ include_env = os.environ.get("INCLUDE")
+ if include_env:
+ includes.append(include_env)
+ includes.extend(
+ (
+ os.path.join(vc_path, "include"),
+ atlmfc_dir,
+ os.path.join(windows_sdk_dir.include, "shared"),
+ os.path.join(windows_sdk_dir.include, "um"),
+ winrt_dir,
+ os.path.join(ucrt_sdk_dir.include, "ucrt"),
+ )
+ )
+ if dia_sdk_dir:
+ includes.append(os.path.join(dia_sdk_dir, "include"))
+ # Set in the environment for old-configure
+ includes = ";".join(includes)
+ os.environ["INCLUDE"] = includes
+ return includes
+
+
+set_config("INCLUDE", include_path)
+
+
+@template
+def dia_sdk_subdir(host_or_target, subdir):
+ @depends(dia_sdk_dir, host_or_target, dependable(subdir))
+ def dia_sdk_subdir(dia_sdk_dir, target, subdir):
+ if not dia_sdk_dir:
+ return
+ # For some reason the DIA SDK still uses the old-style targets
+ # even in a newer MSVC.
+ old_target = {
+ "x86": "",
+ "x86_64": "amd64",
+ "arm": "arm",
+ "aarch64": "arm64",
+ }.get(target.cpu)
+ if old_target is None:
+ return
+ # As old_target can be '', and os.path.join will happily use the empty
+ # string, leading to a string ending with a backslash, that Make will
+ # interpret as a "string continues on next line" indicator, use variable
+ # args.
+ old_target = (old_target,) if old_target else ()
+ return os.path.join(dia_sdk_dir, subdir, *old_target)
+
+ return dia_sdk_subdir
+
+
+set_config("WIN_DIA_SDK_BIN_DIR", dia_sdk_subdir(host, "bin"))
+
+
+@template
+def lib_path_for(host_or_target):
+ @depends(
+ host_or_target,
+ dependable(host_or_target is host),
+ vc_path,
+ valid_windows_sdk_dir,
+ valid_ucrt_sdk_dir,
+ dia_sdk_subdir(host_or_target, "lib"),
+ )
+ @imports("os")
+ def lib_path(
+ target, is_host, vc_path, windows_sdk_dir, ucrt_sdk_dir, dia_sdk_lib_dir
+ ):
+ if not vc_path:
+ return
+ sdk_target = {
+ "x86": "x86",
+ "x86_64": "x64",
+ "arm": "arm",
+ "aarch64": "arm64",
+ }.get(target.cpu)
+
+ # MSVC2017 switched to use the same target naming as the sdk.
+ atlmfc_dir = os.path.join(vc_path, "atlmfc", "lib", sdk_target)
+ if not os.path.isdir(atlmfc_dir):
+ die(
+ "Cannot find the ATL/MFC libraries in the Visual C++ directory "
+ "(%s). Please install them." % vc_path
+ )
+
+ libs = []
+ lib_env = os.environ.get("LIB")
+ if lib_env and not is_host:
+ libs.extend(lib_env.split(";"))
+ libs.extend(
+ (
+ os.path.join(vc_path, "lib", sdk_target),
+ atlmfc_dir,
+ os.path.join(windows_sdk_dir.lib, "um", sdk_target),
+ os.path.join(ucrt_sdk_dir.lib, "ucrt", sdk_target),
+ )
+ )
+ if dia_sdk_lib_dir:
+ libs.append(dia_sdk_lib_dir)
+ return libs
+
+ return lib_path
+
+
+@depends_if(lib_path_for(target))
+@imports("os")
+def lib_path(libs):
+ # Set in the environment for old-configure
+ libs = ";".join(libs)
+ os.environ["LIB"] = libs
+ return libs
+
+
+set_config("LIB", lib_path)
+
+
+lib_path_for_host = lib_path_for(host)
+
+
+@depends_if(lib_path_for_host)
+@imports(_from="mozbuild.shellutil", _import="quote")
+def host_linker_libpaths(libs):
+ return ["-LIBPATH:%s" % quote(l) for l in libs]
+
+
+@depends_if(lib_path_for_host)
+@imports(_from="mozbuild.shellutil", _import="quote")
+def host_linker_libpaths_bat(libs):
+ # .bat files need a different style of quoting. Batch quoting is actually
+ # not defined, and up to applications to handle, so it's not really clear
+ # what should be escaped and what not, but most paths should work just
+ # fine without escaping. And we don't care about double-quotes possibly
+ # having to be escaped because they're not allowed in file names on
+ # Windows.
+ return ['"-LIBPATH:%s"' % l for l in libs]
+
+
+set_config("HOST_LINKER_LIBPATHS", host_linker_libpaths)
+set_config("HOST_LINKER_LIBPATHS_BAT", host_linker_libpaths_bat)
+
+
+@depends(valid_windows_sdk_dir, valid_ucrt_sdk_dir, host)
+@imports(_from="os", _import="environ")
+def sdk_bin_path(valid_windows_sdk_dir, valid_ucrt_sdk_dir, host):
+ if not valid_windows_sdk_dir:
+ return
+
+ vc_host = {
+ "x86": "x86",
+ "x86_64": "x64",
+ }.get(host.cpu)
+
+ # From version 10.0.15063.0 onwards the bin path contains the version number.
+ versioned_bin = (
+ "bin"
+ if valid_ucrt_sdk_dir.version < "10.0.15063.0"
+ else os.path.join("bin", str(valid_ucrt_sdk_dir.version))
+ )
+ result = [
+ environ["PATH"],
+ os.path.join(valid_windows_sdk_dir.path, versioned_bin, vc_host),
+ ]
+ if vc_host == "x64":
+ result.append(os.path.join(valid_windows_sdk_dir.path, versioned_bin, "x86"))
+ return result
+
+
+option(env="LINKER", nargs=1, when=target_is_windows, help="Path to the linker")
+
+link = check_prog(
+ "LINKER",
+ ("lld-link",),
+ input="LINKER",
+ when=target_is_windows,
+ paths=clang_search_path,
+)
+
+option(env="HOST_LINKER", nargs=1, when=host_is_windows, help="Path to the host linker")
+
+host_link = check_prog(
+ "HOST_LINKER",
+ ("lld-link",),
+ input="HOST_LINKER",
+ when=host_is_windows,
+ paths=clang_search_path,
+)
+
+add_old_configure_assignment("LINKER", link)