diff options
Diffstat (limited to 'build/moz.configure/windows.configure')
-rw-r--r-- | build/moz.configure/windows.configure | 465 |
1 files changed, 465 insertions, 0 deletions
diff --git a/build/moz.configure/windows.configure b/build/moz.configure/windows.configure new file mode 100644 index 0000000000..dc66179d07 --- /dev/null +++ b/build/moz.configure/windows.configure @@ -0,0 +1,465 @@ +# -*- 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", "WINSYSROOT", c_compiler, host_c_compiler) +def windows_sdk_dir(value, winsysroot, compiler, host_compiler): + if value: + if winsysroot: + die("WINDOWSSDKDIR and WINSYSROOT cannot be set together.") + return value + # Ideally, we'd actually check for host/target ABI being MSVC, but + # that's waiting for bug 1617793. + if compiler.type != "clang-cl" and host_compiler.type != "clang-cl": + return () + + if winsysroot: + return [os.path.join(winsysroot[0], "Windows Kits", "10")] + + return set( + normalize_path(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, + ) + ) + + +@imports("glob") +def get_sdk_dirs(sdk, subdir): + def get_dirs_containing(sdk, stem, subdir): + return [ + os.path.dirname(p) for p in glob.glob(os.path.join(sdk, stem, "*", 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)) + + valid_versions = sorted(set(include_dirs) & set(lib_dirs), reverse=True) + return [ + namespace( + path=sdk, + lib=lib_dirs[vv], + include=include_dirs[vv], + ) + for vv in valid_versions + ] + + +@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, host_c_compiler, windows_sdk_dir, valid_windows_version, "WINDOWSSDKDIR" +) +@checking("for Windows SDK", valid_windows_sdk_dir_result) +@imports(_from="__builtin__", _import="Exception") +@imports(_from="textwrap", _import="dedent") +def valid_windows_sdk_dir( + compiler, host_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" and host_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: + sdklist = get_sdk_dirs(d, "um") + for sdk in sdklist: + 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 + break + + if d == windows_sdk_dir_env and d not in sdks: + 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, host_c_compiler) +@checking("for Universal CRT SDK", valid_ucrt_sdk_dir_result) +@imports("os") +@imports(_import="mozpack.path", _as="mozpath") +def valid_ucrt_sdk_dir(windows_sdk_dir, windows_sdk_dir_env, compiler, host_compiler): + # Ideally, we'd actually check for host/target ABI being MSVC, but + # that's waiting for bug 1617793. + if compiler.type != "clang-cl" and host_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: + sdklist = get_sdk_dirs(d, "ucrt") + for sdk in sdklist: + 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 + break + + if d == windows_sdk_dir_env and d not in sdks: + # 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) + + +@depends(vc_path, valid_windows_sdk_dir, valid_ucrt_sdk_dir) +@imports("os") +def include_path(vc_path, windows_sdk_dir, ucrt_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 + ) + + cppwinrt_dir = os.path.join(windows_sdk_dir.include, "cppwinrt") + if not os.path.isdir(cppwinrt_dir): + die( + "Cannot find the C++/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, + cppwinrt_dir, + os.path.join(ucrt_sdk_dir.include, "ucrt"), + ) + ) + # Set in the environment for old-configure + includes = ";".join(includes) + os.environ["INCLUDE"] = includes + return includes + + +set_config("INCLUDE", include_path) + +# cppwinrt requires this on clang because of no coroutine support, which is okay +set_define("_SILENCE_CLANG_COROUTINE_MESSAGE", "") + + +@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, + ) + @imports("os") + def lib_path(target, is_host, vc_path, windows_sdk_dir, ucrt_sdk_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), + ) + ) + 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) |