| # pylint: disable=g-bad-file-header | 
 | # Copyright 2016 The Bazel Authors. All rights reserved. | 
 | # | 
 | # Licensed under the Apache License, Version 2.0 (the "License"); | 
 | # you may not use this file except in compliance with the License. | 
 | # You may obtain a copy of the License at | 
 | # | 
 | #    http://www.apache.org/licenses/LICENSE-2.0 | 
 | # | 
 | # Unless required by applicable law or agreed to in writing, software | 
 | # distributed under the License is distributed on an "AS IS" BASIS, | 
 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | 
 | # See the License for the specific language governing permissions and | 
 | # limitations under the License. | 
 | """Configuring the C++ toolchain on Windows.""" | 
 |  | 
 | load( | 
 |     "@bazel_tools//tools/cpp:lib_cc_configure.bzl", | 
 |     "auto_configure_fail", | 
 |     "auto_configure_warning", | 
 |     "auto_configure_warning_maybe", | 
 |     "escape_string", | 
 |     "execute", | 
 |     "resolve_labels", | 
 |     "write_builtin_include_directory_paths", | 
 | ) | 
 |  | 
 | _targets_archs = {"x64": "amd64", "x86": "amd64_x86", "arm": "amd64_arm", "arm64": "amd64_arm64"} | 
 | _targets_lib_folder = {"x86": "", "arm": "arm", "arm64": "arm64"} | 
 |  | 
 | def _lookup_env_var(env, name, default = None): | 
 |     """Lookup environment variable case-insensitve. | 
 |  | 
 |     If a matching (case-insensitive) entry is found in the env dict both | 
 |     the key and the value are returned. The returned key might differ from | 
 |     name in casing. | 
 |  | 
 |     If a matching key was found its value is returned otherwise | 
 |     the default is returned. | 
 |  | 
 |     Return a (key, value) tuple""" | 
 |     for key, value in env.items(): | 
 |         if name.lower() == key.lower(): | 
 |             return (key, value) | 
 |     return (name, default) | 
 |  | 
 | def _get_env_var(repository_ctx, name, default = None): | 
 |     """Returns a value from an environment variable.""" | 
 |     return _lookup_env_var(repository_ctx.os.environ, name, default)[1] | 
 |  | 
 | def _get_path_env_var(repository_ctx, name): | 
 |     """Returns a path from an environment variable. | 
 |  | 
 |     Removes quotes, replaces '/' with '\', and strips trailing '\'s.""" | 
 |     value = _get_env_var(repository_ctx, name) | 
 |     if value != None: | 
 |         if value[0] == "\"": | 
 |             if len(value) == 1 or value[-1] != "\"": | 
 |                 auto_configure_fail("'%s' environment variable has no trailing quote" % name) | 
 |             value = value[1:-1] | 
 |         if "/" in value: | 
 |             value = value.replace("/", "\\") | 
 |         if value[-1] == "\\": | 
 |             value = value.rstrip("\\") | 
 |     return value | 
 |  | 
 | def _get_temp_env(repository_ctx): | 
 |     """Returns the value of TMP, or TEMP, or if both undefined then C:\\Windows.""" | 
 |     tmp = _get_path_env_var(repository_ctx, "TMP") | 
 |     if not tmp: | 
 |         tmp = _get_path_env_var(repository_ctx, "TEMP") | 
 |     if not tmp: | 
 |         tmp = "C:\\Windows\\Temp" | 
 |         auto_configure_warning( | 
 |             "neither 'TMP' nor 'TEMP' environment variables are set, using '%s' as default" % tmp, | 
 |         ) | 
 |     return tmp | 
 |  | 
 | def _get_escaped_windows_msys_starlark_content(repository_ctx, use_mingw = False): | 
 |     """Return the content of msys cc toolchain rule.""" | 
 |     msys_root = "" | 
 |     bazel_sh = _get_path_env_var(repository_ctx, "BAZEL_SH") | 
 |     if bazel_sh: | 
 |         bazel_sh = bazel_sh.replace("\\", "/").lower() | 
 |         tokens = bazel_sh.rsplit("/", 1) | 
 |         if tokens[0].endswith("/usr/bin"): | 
 |             msys_root = tokens[0][:len(tokens[0]) - len("usr/bin")] | 
 |         elif tokens[0].endswith("/bin"): | 
 |             msys_root = tokens[0][:len(tokens[0]) - len("bin")] | 
 |  | 
 |     prefix = "mingw64" if use_mingw else "usr" | 
 |     tool_path_prefix = escape_string(msys_root) + prefix | 
 |     tool_bin_path = tool_path_prefix + "/bin" | 
 |     tool_path = {} | 
 |  | 
 |     for tool in ["ar", "cpp", "dwp", "gcc", "gcov", "ld", "nm", "objcopy", "objdump", "strip"]: | 
 |         if msys_root: | 
 |             tool_path[tool] = tool_bin_path + "/" + tool | 
 |         else: | 
 |             tool_path[tool] = "msys_gcc_installation_error.bat" | 
 |     tool_paths = ",\n        ".join(['"%s": "%s"' % (k, v) for k, v in tool_path.items()]) | 
 |     include_directories = ('        "%s/",\n        ' % tool_path_prefix) if msys_root else "" | 
 |     return tool_paths, tool_bin_path, include_directories | 
 |  | 
 | def _get_system_root(repository_ctx): | 
 |     """Get System root path on Windows, default is C:\\Windows. Doesn't %-escape the result.""" | 
 |     systemroot = _get_path_env_var(repository_ctx, "SYSTEMROOT") | 
 |     if not systemroot: | 
 |         systemroot = "C:\\Windows" | 
 |         auto_configure_warning_maybe( | 
 |             repository_ctx, | 
 |             "SYSTEMROOT is not set, using default SYSTEMROOT=C:\\Windows", | 
 |         ) | 
 |     return escape_string(systemroot) | 
 |  | 
 | def _add_system_root(repository_ctx, env): | 
 |     """Running VCVARSALL.BAT and VCVARSQUERYREGISTRY.BAT need %SYSTEMROOT%\\\\system32 in PATH.""" | 
 |     env_key, env_value = _lookup_env_var(env, "PATH", default = "") | 
 |     env[env_key] = env_value + ";" + _get_system_root(repository_ctx) + "\\system32" | 
 |     return env | 
 |  | 
 | def find_vc_path(repository_ctx): | 
 |     """Find Visual C++ build tools install path. Doesn't %-escape the result.""" | 
 |  | 
 |     # 1. Check if BAZEL_VC or BAZEL_VS is already set by user. | 
 |     bazel_vc = _get_path_env_var(repository_ctx, "BAZEL_VC") | 
 |     if bazel_vc: | 
 |         if repository_ctx.path(bazel_vc).exists: | 
 |             return bazel_vc | 
 |         else: | 
 |             auto_configure_warning_maybe( | 
 |                 repository_ctx, | 
 |                 "%BAZEL_VC% is set to non-existent path, ignoring.", | 
 |             ) | 
 |  | 
 |     bazel_vs = _get_path_env_var(repository_ctx, "BAZEL_VS") | 
 |     if bazel_vs: | 
 |         if repository_ctx.path(bazel_vs).exists: | 
 |             bazel_vc = bazel_vs + "\\VC" | 
 |             if repository_ctx.path(bazel_vc).exists: | 
 |                 return bazel_vc | 
 |             else: | 
 |                 auto_configure_warning_maybe( | 
 |                     repository_ctx, | 
 |                     "No 'VC' directory found under %BAZEL_VS%, ignoring.", | 
 |                 ) | 
 |         else: | 
 |             auto_configure_warning_maybe( | 
 |                 repository_ctx, | 
 |                 "%BAZEL_VS% is set to non-existent path, ignoring.", | 
 |             ) | 
 |  | 
 |     auto_configure_warning_maybe( | 
 |         repository_ctx, | 
 |         "Neither %BAZEL_VC% nor %BAZEL_VS% are set, start looking for the latest Visual C++" + | 
 |         " installed.", | 
 |     ) | 
 |  | 
 |     # 2. Use vswhere to locate all Visual Studio installations | 
 |     program_files_dir = _get_path_env_var(repository_ctx, "PROGRAMFILES(X86)") | 
 |     if not program_files_dir: | 
 |         program_files_dir = "C:\\Program Files (x86)" | 
 |         auto_configure_warning_maybe( | 
 |             repository_ctx, | 
 |             "'PROGRAMFILES(X86)' environment variable is not set, using '%s' as default" % program_files_dir, | 
 |         ) | 
 |  | 
 |     vswhere_binary = program_files_dir + "\\Microsoft Visual Studio\\Installer\\vswhere.exe" | 
 |     if repository_ctx.path(vswhere_binary).exists: | 
 |         result = repository_ctx.execute([vswhere_binary, "-requires", "Microsoft.VisualStudio.Component.VC.Tools.x86.x64", "-property", "installationPath", "-latest"]) | 
 |         auto_configure_warning_maybe(repository_ctx, "vswhere query result:\n\nSTDOUT(start)\n%s\nSTDOUT(end)\nSTDERR(start):\n%s\nSTDERR(end)\n" % | 
 |                                                      (result.stdout, result.stderr)) | 
 |         installation_path = result.stdout.strip() | 
 |         if not result.stderr and installation_path: | 
 |             vc_dir = installation_path + "\\VC" | 
 |             auto_configure_warning_maybe(repository_ctx, "Visual C++ build tools found at %s" % vc_dir) | 
 |             return vc_dir | 
 |  | 
 |     # 3. Check if VS%VS_VERSION%COMNTOOLS is set, if true then try to find and use | 
 |     # vcvarsqueryregistry.bat / VsDevCmd.bat to detect VC++. | 
 |     auto_configure_warning_maybe(repository_ctx, "Looking for VS%VERSION%COMNTOOLS environment variables, " + | 
 |                                                  "eg. VS140COMNTOOLS") | 
 |     for vscommontools_env, script in [ | 
 |         ("VS160COMNTOOLS", "VsDevCmd.bat"), | 
 |         ("VS150COMNTOOLS", "VsDevCmd.bat"), | 
 |         ("VS140COMNTOOLS", "vcvarsqueryregistry.bat"), | 
 |         ("VS120COMNTOOLS", "vcvarsqueryregistry.bat"), | 
 |         ("VS110COMNTOOLS", "vcvarsqueryregistry.bat"), | 
 |         ("VS100COMNTOOLS", "vcvarsqueryregistry.bat"), | 
 |         ("VS90COMNTOOLS", "vcvarsqueryregistry.bat"), | 
 |     ]: | 
 |         path = _get_path_env_var(repository_ctx, vscommontools_env) | 
 |         if path == None: | 
 |             continue | 
 |         script = path + "\\" + script | 
 |         if not repository_ctx.path(script).exists: | 
 |             continue | 
 |         repository_ctx.file( | 
 |             "get_vc_dir.bat", | 
 |             "@echo off\n" + | 
 |             "call \"" + script + "\" > NUL\n" + | 
 |             "echo %VCINSTALLDIR%", | 
 |             True, | 
 |         ) | 
 |         env = _add_system_root(repository_ctx, repository_ctx.os.environ) | 
 |         vc_dir = execute(repository_ctx, ["./get_vc_dir.bat"], environment = env) | 
 |  | 
 |         auto_configure_warning_maybe(repository_ctx, "Visual C++ build tools found at %s" % vc_dir) | 
 |         return vc_dir | 
 |  | 
 |     # 4. User might have purged all environment variables. If so, look for Visual C++ in registry. | 
 |     # Works for Visual Studio 2017 and older. (Does not work for Visual Studio 2019 Preview.) | 
 |     auto_configure_warning_maybe(repository_ctx, "Looking for Visual C++ through registry") | 
 |     reg_binary = _get_system_root(repository_ctx) + "\\system32\\reg.exe" | 
 |     vc_dir = None | 
 |     for key, suffix in (("VC7", ""), ("VS7", "\\VC")): | 
 |         for version in ["15.0", "14.0", "12.0", "11.0", "10.0", "9.0", "8.0"]: | 
 |             if vc_dir: | 
 |                 break | 
 |             result = repository_ctx.execute([reg_binary, "query", "HKEY_LOCAL_MACHINE\\SOFTWARE\\Wow6432Node\\Microsoft\\VisualStudio\\SxS\\" + key, "/v", version]) | 
 |             auto_configure_warning_maybe(repository_ctx, "registry query result for VC %s:\n\nSTDOUT(start)\n%s\nSTDOUT(end)\nSTDERR(start):\n%s\nSTDERR(end)\n" % | 
 |                                                          (version, result.stdout, result.stderr)) | 
 |             if not result.stderr: | 
 |                 for line in result.stdout.split("\n"): | 
 |                     line = line.strip() | 
 |                     if line.startswith(version) and line.find("REG_SZ") != -1: | 
 |                         vc_dir = line[line.find("REG_SZ") + len("REG_SZ"):].strip() + suffix | 
 |     if vc_dir: | 
 |         auto_configure_warning_maybe(repository_ctx, "Visual C++ build tools found at %s" % vc_dir) | 
 |         return vc_dir | 
 |  | 
 |     # 5. Check default directories for VC installation | 
 |     auto_configure_warning_maybe(repository_ctx, "Looking for default Visual C++ installation directory") | 
 |     for path in [ | 
 |         "Microsoft Visual Studio\\2019\\Preview\\VC", | 
 |         "Microsoft Visual Studio\\2019\\BuildTools\\VC", | 
 |         "Microsoft Visual Studio\\2019\\Community\\VC", | 
 |         "Microsoft Visual Studio\\2019\\Professional\\VC", | 
 |         "Microsoft Visual Studio\\2019\\Enterprise\\VC", | 
 |         "Microsoft Visual Studio\\2017\\BuildTools\\VC", | 
 |         "Microsoft Visual Studio\\2017\\Community\\VC", | 
 |         "Microsoft Visual Studio\\2017\\Professional\\VC", | 
 |         "Microsoft Visual Studio\\2017\\Enterprise\\VC", | 
 |         "Microsoft Visual Studio 14.0\\VC", | 
 |     ]: | 
 |         path = program_files_dir + "\\" + path | 
 |         if repository_ctx.path(path).exists: | 
 |             vc_dir = path | 
 |             break | 
 |  | 
 |     if not vc_dir: | 
 |         auto_configure_warning_maybe(repository_ctx, "Visual C++ build tools not found.") | 
 |         return None | 
 |     auto_configure_warning_maybe(repository_ctx, "Visual C++ build tools found at %s" % vc_dir) | 
 |     return vc_dir | 
 |  | 
 | def _is_vs_2017_or_2019(repository_ctx, vc_path): | 
 |     """Check if the installed VS version is Visual Studio 2017 or 2019.""" | 
 |  | 
 |     # The layout of VC folder in VS 2017 and 2019 is different from that in VS 2015 and older versions. | 
 |     # In VS 2017 and 2019, it contains only three directories: | 
 |     # "Auxiliary", "Redist", "Tools" | 
 |  | 
 |     vc_2017_or_2019_contents = ["auxiliary", "redist", "tools"] | 
 |     vc_path_contents = [d.basename.lower() for d in repository_ctx.path(vc_path).readdir()] | 
 |     vc_path_contents = sorted(vc_path_contents) | 
 |     return vc_path_contents == vc_2017_or_2019_contents | 
 |  | 
 | def _is_msbuildtools(vc_path): | 
 |     """Check if the installed VC version is from MSBuildTools.""" | 
 |  | 
 |     # In MSBuildTools (usually container setup), the location of VC is like: | 
 |     # C:\BuildTools\MSBuild\Microsoft\VC | 
 |     return vc_path.find("BuildTools") != -1 and vc_path.find("MSBuild") != -1 | 
 |  | 
 | def _find_vcvars_bat_script(repository_ctx, vc_path): | 
 |     """Find batch script to set up environment variables for VC. Doesn't %-escape the result.""" | 
 |     if _is_vs_2017_or_2019(repository_ctx, vc_path): | 
 |         vcvars_script = vc_path + "\\Auxiliary\\Build\\VCVARSALL.BAT" | 
 |     else: | 
 |         vcvars_script = vc_path + "\\VCVARSALL.BAT" | 
 |  | 
 |     if not repository_ctx.path(vcvars_script).exists: | 
 |         return None | 
 |  | 
 |     return vcvars_script | 
 |  | 
 | def _is_support_vcvars_ver(vc_full_version): | 
 |     """-vcvars_ver option is supported from version 14.11.25503 (VS 2017 version 15.3).""" | 
 |     version = [int(i) for i in vc_full_version.split(".")] | 
 |     min_version = [14, 11, 25503] | 
 |     return version >= min_version | 
 |  | 
 | def _is_support_winsdk_selection(repository_ctx, vc_path): | 
 |     """Windows SDK selection is supported with VC 2017 / 2019 or with full VS 2015 installation.""" | 
 |     if _is_vs_2017_or_2019(repository_ctx, vc_path): | 
 |         return True | 
 |  | 
 |     # By checking the source code of VCVARSALL.BAT in VC 2015, we know that | 
 |     # when devenv.exe or wdexpress.exe exists, VCVARSALL.BAT supports Windows SDK selection. | 
 |     vc_common_ide = repository_ctx.path(vc_path).dirname.get_child("Common7", "IDE") | 
 |     for tool in ["devenv.exe", "wdexpress.exe"]: | 
 |         if vc_common_ide.get_child(tool).exists: | 
 |             return True | 
 |     return False | 
 |  | 
 | def _get_vc_env_vars(repository_ctx, vc_path, msvc_vars_x64, target_arch): | 
 |     """Derive the environment variables set of a given target architecture from the environment variables of the x64 target. | 
 |  | 
 |        This is done to avoid running VCVARSALL.BAT script for every target architecture. | 
 |  | 
 |     Args: | 
 |         repository_ctx: the repository_ctx object | 
 |         vc_path: Visual C++ root directory | 
 |         msvc_vars_x64: values of MSVC toolchain including the environment variables for x64 target architecture | 
 |         target_arch: the target architecture to get its environment variables | 
 |  | 
 |     Returns: | 
 |         dictionary of envvars | 
 |     """ | 
 |     env = {} | 
 |     if _is_vs_2017_or_2019(repository_ctx, vc_path): | 
 |         lib = msvc_vars_x64["%{msvc_env_lib_x64}"] | 
 |         full_version = _get_vc_full_version(repository_ctx, vc_path) | 
 |         tools_path = "%s\\Tools\\MSVC\\%s\\bin\\HostX64\\%s" % (vc_path, full_version, target_arch) | 
 |  | 
 |         # For native windows(10) on arm64 builds host toolchain runs in an emulated x86 environment | 
 |         if not repository_ctx.path(tools_path).exists: | 
 |             tools_path = "%s\\Tools\\MSVC\\%s\\bin\\HostX86\\%s" % (vc_path, full_version, target_arch) | 
 |     else: | 
 |         lib = msvc_vars_x64["%{msvc_env_lib_x64}"].replace("amd64", _targets_lib_folder[target_arch]) | 
 |         tools_path = vc_path + "\\bin\\" + _targets_archs[target_arch] | 
 |  | 
 |     env["INCLUDE"] = msvc_vars_x64["%{msvc_env_include_x64}"] | 
 |     env["LIB"] = lib.replace("x64", target_arch) | 
 |     env["PATH"] = escape_string(tools_path.replace("\\", "\\\\")) + ";" + msvc_vars_x64["%{msvc_env_path_x64}"] | 
 |     return env | 
 |  | 
 | def setup_vc_env_vars(repository_ctx, vc_path, envvars = [], allow_empty = False, escape = True): | 
 |     """Get environment variables set by VCVARSALL.BAT script. Doesn't %-escape the result! | 
 |  | 
 |     Args: | 
 |         repository_ctx: the repository_ctx object | 
 |         vc_path: Visual C++ root directory | 
 |         envvars: list of envvars to retrieve; default is ["PATH", "INCLUDE", "LIB", "WINDOWSSDKDIR"] | 
 |         allow_empty: allow unset envvars; if False then report errors for those | 
 |         escape: if True, escape "\" as "\\" and "%" as "%%" in the envvar values | 
 |  | 
 |     Returns: | 
 |         dictionary of the envvars | 
 |     """ | 
 |     if not envvars: | 
 |         envvars = ["PATH", "INCLUDE", "LIB", "WINDOWSSDKDIR"] | 
 |  | 
 |     vcvars_script = _find_vcvars_bat_script(repository_ctx, vc_path) | 
 |     if not vcvars_script: | 
 |         auto_configure_fail("Cannot find VCVARSALL.BAT script under %s" % vc_path) | 
 |  | 
 |     # Getting Windows SDK version set by user. | 
 |     # Only supports VC 2017 & 2019 and VC 2015 with full VS installation. | 
 |     winsdk_version = _get_winsdk_full_version(repository_ctx) | 
 |     if winsdk_version and not _is_support_winsdk_selection(repository_ctx, vc_path): | 
 |         auto_configure_warning(("BAZEL_WINSDK_FULL_VERSION=%s is ignored, " + | 
 |                                 "because standalone Visual C++ Build Tools 2015 doesn't support specifying Windows " + | 
 |                                 "SDK version, please install the full VS 2015 or use VC 2017/2019.") % winsdk_version) | 
 |         winsdk_version = "" | 
 |  | 
 |     # Get VC version set by user. Only supports VC 2017 & 2019. | 
 |     vcvars_ver = "" | 
 |     if _is_vs_2017_or_2019(repository_ctx, vc_path): | 
 |         full_version = _get_vc_full_version(repository_ctx, vc_path) | 
 |  | 
 |         # Because VCVARSALL.BAT is from the latest VC installed, so we check if the latest | 
 |         # version supports -vcvars_ver or not. | 
 |         if _is_support_vcvars_ver(_get_latest_subversion(repository_ctx, vc_path)): | 
 |             vcvars_ver = "-vcvars_ver=" + full_version | 
 |  | 
 |     cmd = "\"%s\" amd64 %s %s" % (vcvars_script, winsdk_version, vcvars_ver) | 
 |     print_envvars = ",".join(["{k}=%{k}%".format(k = k) for k in envvars]) | 
 |     repository_ctx.file( | 
 |         "get_env.bat", | 
 |         "@echo off\n" + | 
 |         ("call %s > NUL \n" % cmd) + ("echo %s \n" % print_envvars), | 
 |         True, | 
 |     ) | 
 |     env = _add_system_root(repository_ctx, {k: "" for k in envvars}) | 
 |     envs = execute(repository_ctx, ["./get_env.bat"], environment = env).split(",") | 
 |     env_map = {} | 
 |     for env in envs: | 
 |         key, value = env.split("=", 1) | 
 |         env_map[key] = escape_string(value.replace("\\", "\\\\")) if escape else value | 
 |  | 
 |     if not allow_empty: | 
 |         _check_env_vars(env_map, cmd, expected = envvars) | 
 |     return env_map | 
 |  | 
 | def _check_env_vars(env_map, cmd, expected): | 
 |     for env in expected: | 
 |         if not env_map.get(env): | 
 |             auto_configure_fail( | 
 |                 "Setting up VC environment variables failed, %s is not set by the following command:\n    %s" % (env, cmd), | 
 |             ) | 
 |  | 
 | def _get_latest_subversion(repository_ctx, vc_path): | 
 |     """Get the latest subversion of a VS 2017/2019 installation. | 
 |  | 
 |     For VS 2017 & 2019, there could be multiple versions of VC build tools. | 
 |     The directories are like: | 
 |       <vc_path>\\Tools\\MSVC\\14.10.24930\\bin\\HostX64\\x64 | 
 |       <vc_path>\\Tools\\MSVC\\14.16.27023\\bin\\HostX64\\x64 | 
 |     This function should return 14.16.27023 in this case.""" | 
 |     versions = [path.basename for path in repository_ctx.path(vc_path + "\\Tools\\MSVC").readdir()] | 
 |     if len(versions) < 1: | 
 |         auto_configure_warning_maybe(repository_ctx, "Cannot find any VC installation under BAZEL_VC(%s)" % vc_path) | 
 |         return None | 
 |  | 
 |     # Parse the version string into integers, then sort the integers to prevent textual sorting. | 
 |     version_list = [] | 
 |     for version in versions: | 
 |         parts = [int(i) for i in version.split(".")] | 
 |         version_list.append((parts, version)) | 
 |  | 
 |     version_list = sorted(version_list) | 
 |     latest_version = version_list[-1][1] | 
 |  | 
 |     auto_configure_warning_maybe(repository_ctx, "Found the following VC versions:\n%s\n\nChoosing the latest version = %s" % ("\n".join(versions), latest_version)) | 
 |     return latest_version | 
 |  | 
 | def _get_vc_full_version(repository_ctx, vc_path): | 
 |     """Return the value of BAZEL_VC_FULL_VERSION if defined, otherwise the latest version.""" | 
 |     version = _get_env_var(repository_ctx, "BAZEL_VC_FULL_VERSION") | 
 |     if version != None: | 
 |         return version | 
 |     return _get_latest_subversion(repository_ctx, vc_path) | 
 |  | 
 | def _get_winsdk_full_version(repository_ctx): | 
 |     """Return the value of BAZEL_WINSDK_FULL_VERSION if defined, otherwise an empty string.""" | 
 |     return _get_env_var(repository_ctx, "BAZEL_WINSDK_FULL_VERSION", default = "") | 
 |  | 
 | def _find_msvc_tools(repository_ctx, vc_path, target_arch = "x64"): | 
 |     """Find the exact paths of the build tools in MSVC for the given target. Doesn't %-escape the result.""" | 
 |     build_tools_paths = {} | 
 |     tools = _get_target_tools(target_arch) | 
 |     for tool_name in tools: | 
 |         build_tools_paths[tool_name] = find_msvc_tool(repository_ctx, vc_path, tools[tool_name], target_arch) | 
 |     return build_tools_paths | 
 |  | 
 | def find_msvc_tool(repository_ctx, vc_path, tool, target_arch = "x64"): | 
 |     """Find the exact path of a specific build tool in MSVC. Doesn't %-escape the result.""" | 
 |     tool_path = None | 
 |     if _is_vs_2017_or_2019(repository_ctx, vc_path) or _is_msbuildtools(vc_path): | 
 |         full_version = _get_vc_full_version(repository_ctx, vc_path) | 
 |         if full_version: | 
 |             tool_path = "%s\\Tools\\MSVC\\%s\\bin\\HostX64\\%s\\%s" % (vc_path, full_version, target_arch, tool) | 
 |  | 
 |             # For native windows(10) on arm64 builds host toolchain runs in an emulated x86 environment | 
 |             if not repository_ctx.path(tool_path).exists: | 
 |                 tool_path = "%s\\Tools\\MSVC\\%s\\bin\\HostX86\\%s\\%s" % (vc_path, full_version, target_arch, tool) | 
 |     else: | 
 |         # For VS 2015 and older version, the tools are under: | 
 |         # C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\bin\amd64 | 
 |         tool_path = vc_path + "\\bin\\" + _targets_archs[target_arch] + "\\" + tool | 
 |  | 
 |     if not tool_path or not repository_ctx.path(tool_path).exists: | 
 |         return None | 
 |  | 
 |     return tool_path.replace("\\", "/") | 
 |  | 
 | def _find_missing_vc_tools(repository_ctx, vc_path, target_arch = "x64"): | 
 |     """Check if any required tool for the given target architecture is missing under given VC path.""" | 
 |     missing_tools = [] | 
 |     if not _find_vcvars_bat_script(repository_ctx, vc_path): | 
 |         missing_tools.append("VCVARSALL.BAT") | 
 |  | 
 |     tools = _get_target_tools(target_arch) | 
 |     for tool_name in tools: | 
 |         if not find_msvc_tool(repository_ctx, vc_path, tools[tool_name], target_arch): | 
 |             missing_tools.append(tools[tool_name]) | 
 |     return missing_tools | 
 |  | 
 | def _get_target_tools(target): | 
 |     """Return a list of required tools names and their filenames for a certain target.""" | 
 |     tools = { | 
 |         "x64": {"CL": "cl.exe", "LINK": "link.exe", "LIB": "lib.exe", "ML": "ml64.exe"}, | 
 |         "x86": {"CL": "cl.exe", "LINK": "link.exe", "LIB": "lib.exe", "ML": "ml.exe"}, | 
 |         "arm": {"CL": "cl.exe", "LINK": "link.exe", "LIB": "lib.exe"}, | 
 |         "arm64": {"CL": "cl.exe", "LINK": "link.exe", "LIB": "lib.exe"}, | 
 |     } | 
 |     if tools.get(target) == None: | 
 |         auto_configure_fail("Target architecture %s is not recognized" % target) | 
 |  | 
 |     return tools.get(target) | 
 |  | 
 | def _is_support_debug_fastlink(repository_ctx, linker): | 
 |     """Run linker alone to see if it supports /DEBUG:FASTLINK.""" | 
 |     if _use_clang_cl(repository_ctx): | 
 |         # LLVM's lld-link.exe doesn't support /DEBUG:FASTLINK. | 
 |         return False | 
 |     result = execute(repository_ctx, [linker], expect_failure = True) | 
 |     return result.find("/DEBUG[:{FASTLINK|FULL|NONE}]") != -1 | 
 |  | 
 | def find_llvm_path(repository_ctx): | 
 |     """Find LLVM install path.""" | 
 |  | 
 |     # 1. Check if BAZEL_LLVM is already set by user. | 
 |     bazel_llvm = _get_path_env_var(repository_ctx, "BAZEL_LLVM") | 
 |     if bazel_llvm: | 
 |         return bazel_llvm | 
 |  | 
 |     auto_configure_warning_maybe(repository_ctx, "'BAZEL_LLVM' is not set, " + | 
 |                                                  "start looking for LLVM installation on machine.") | 
 |  | 
 |     # 2. Look for LLVM installation through registry. | 
 |     auto_configure_warning_maybe(repository_ctx, "Looking for LLVM installation through registry") | 
 |     reg_binary = _get_system_root(repository_ctx) + "\\system32\\reg.exe" | 
 |     llvm_dir = None | 
 |     result = repository_ctx.execute([reg_binary, "query", "HKEY_LOCAL_MACHINE\\SOFTWARE\\WOW6432Node\\LLVM\\LLVM"]) | 
 |     auto_configure_warning_maybe(repository_ctx, "registry query result for LLVM:\n\nSTDOUT(start)\n%s\nSTDOUT(end)\nSTDERR(start):\n%s\nSTDERR(end)\n" % | 
 |                                                  (result.stdout, result.stderr)) | 
 |     if not result.stderr: | 
 |         for line in result.stdout.split("\n"): | 
 |             line = line.strip() | 
 |             if line.startswith("(Default)") and line.find("REG_SZ") != -1: | 
 |                 llvm_dir = line[line.find("REG_SZ") + len("REG_SZ"):].strip() | 
 |     if llvm_dir: | 
 |         auto_configure_warning_maybe(repository_ctx, "LLVM installation found at %s" % llvm_dir) | 
 |         return llvm_dir | 
 |  | 
 |     # 3. Check default directories for LLVM installation | 
 |     auto_configure_warning_maybe(repository_ctx, "Looking for default LLVM installation directory") | 
 |     program_files_dir = _get_path_env_var(repository_ctx, "PROGRAMFILES") | 
 |     if not program_files_dir: | 
 |         program_files_dir = "C:\\Program Files" | 
 |         auto_configure_warning_maybe( | 
 |             repository_ctx, | 
 |             "'PROGRAMFILES' environment variable is not set, using '%s' as default" % program_files_dir, | 
 |         ) | 
 |     path = program_files_dir + "\\LLVM" | 
 |     if repository_ctx.path(path).exists: | 
 |         llvm_dir = path | 
 |  | 
 |     if not llvm_dir: | 
 |         auto_configure_warning_maybe(repository_ctx, "LLVM installation not found.") | 
 |         return None | 
 |     auto_configure_warning_maybe(repository_ctx, "LLVM installation found at %s" % llvm_dir) | 
 |     return llvm_dir | 
 |  | 
 | def find_llvm_tool(repository_ctx, llvm_path, tool): | 
 |     """Find the exact path of a specific build tool in LLVM. Doesn't %-escape the result.""" | 
 |     tool_path = llvm_path + "\\bin\\" + tool | 
 |  | 
 |     if not repository_ctx.path(tool_path).exists: | 
 |         return None | 
 |  | 
 |     return tool_path.replace("\\", "/") | 
 |  | 
 | def _use_clang_cl(repository_ctx): | 
 |     """Returns True if USE_CLANG_CL is set to 1.""" | 
 |     return _get_env_var(repository_ctx, "USE_CLANG_CL", default = "0") == "1" | 
 |  | 
 | def _find_missing_llvm_tools(repository_ctx, llvm_path): | 
 |     """Check if any required tool is missing under given LLVM path.""" | 
 |     missing_tools = [] | 
 |     for tool in ["clang-cl.exe", "lld-link.exe", "llvm-lib.exe"]: | 
 |         if not find_llvm_tool(repository_ctx, llvm_path, tool): | 
 |             missing_tools.append(tool) | 
 |  | 
 |     return missing_tools | 
 |  | 
 | def _get_clang_version(repository_ctx, clang_cl): | 
 |     result = repository_ctx.execute([clang_cl, "-v"]) | 
 |     first_line = result.stderr.strip().splitlines()[0].strip() | 
 |  | 
 |     # The first line of stderr should look like "[vendor ]clang version X.X.X" | 
 |     if result.return_code != 0 or first_line.find("clang version ") == -1: | 
 |         auto_configure_fail("Failed to get clang version by running \"%s -v\"" % clang_cl) | 
 |     return first_line.split(" ")[-1] | 
 |  | 
 | def _get_msys_mingw_vars(repository_ctx): | 
 |     """Get the variables we need to populate the msys/mingw toolchains.""" | 
 |     tool_paths, tool_bin_path, inc_dir_msys = _get_escaped_windows_msys_starlark_content(repository_ctx) | 
 |     tool_paths_mingw, tool_bin_path_mingw, inc_dir_mingw = _get_escaped_windows_msys_starlark_content(repository_ctx, use_mingw = True) | 
 |     write_builtin_include_directory_paths(repository_ctx, "mingw", [inc_dir_mingw], file_suffix = "_mingw") | 
 |     msys_mingw_vars = { | 
 |         "%{cxx_builtin_include_directories}": inc_dir_msys, | 
 |         "%{mingw_cxx_builtin_include_directories}": inc_dir_mingw, | 
 |         "%{tool_paths}": tool_paths, | 
 |         "%{mingw_tool_paths}": tool_paths_mingw, | 
 |         "%{tool_bin_path}": tool_bin_path, | 
 |         "%{mingw_tool_bin_path}": tool_bin_path_mingw, | 
 |     } | 
 |     return msys_mingw_vars | 
 |  | 
 | def _get_msvc_vars(repository_ctx, paths, target_arch = "x64", msvc_vars_x64 = None): | 
 |     """Get the variables we need to populate the MSVC toolchains.""" | 
 |     msvc_vars = dict() | 
 |     vc_path = find_vc_path(repository_ctx) | 
 |     missing_tools = None | 
 |  | 
 |     if not vc_path: | 
 |         repository_ctx.template( | 
 |             "vc_installation_error_" + target_arch + ".bat", | 
 |             paths["@bazel_tools//tools/cpp:vc_installation_error.bat.tpl"], | 
 |             {"%{vc_error_message}": ""}, | 
 |         ) | 
 |     else: | 
 |         missing_tools = _find_missing_vc_tools(repository_ctx, vc_path, target_arch) | 
 |         if missing_tools: | 
 |             message = "\r\n".join([ | 
 |                 "echo. 1>&2", | 
 |                 "echo Visual C++ build tools seems to be installed at %s 1>&2" % vc_path, | 
 |                 "echo But Bazel can't find the following tools: 1>&2", | 
 |                 "echo     %s 1>&2" % ", ".join(missing_tools), | 
 |                 "echo for %s target architecture 1>&2" % target_arch, | 
 |                 "echo. 1>&2", | 
 |             ]) | 
 |             repository_ctx.template( | 
 |                 "vc_installation_error_" + target_arch + ".bat", | 
 |                 paths["@bazel_tools//tools/cpp:vc_installation_error.bat.tpl"], | 
 |                 {"%{vc_error_message}": message}, | 
 |             ) | 
 |  | 
 |     if not vc_path or missing_tools: | 
 |         write_builtin_include_directory_paths(repository_ctx, "msvc", [], file_suffix = "_msvc") | 
 |         msvc_vars = { | 
 |             "%{msvc_env_tmp_" + target_arch + "}": "msvc_not_found", | 
 |             "%{msvc_env_include_" + target_arch + "}": "msvc_not_found", | 
 |             "%{msvc_cxx_builtin_include_directories_" + target_arch + "}": "", | 
 |             "%{msvc_env_path_" + target_arch + "}": "msvc_not_found", | 
 |             "%{msvc_env_lib_" + target_arch + "}": "msvc_not_found", | 
 |             "%{msvc_cl_path_" + target_arch + "}": "vc_installation_error_" + target_arch + ".bat", | 
 |             "%{msvc_ml_path_" + target_arch + "}": "vc_installation_error_" + target_arch + ".bat", | 
 |             "%{msvc_link_path_" + target_arch + "}": "vc_installation_error_" + target_arch + ".bat", | 
 |             "%{msvc_lib_path_" + target_arch + "}": "vc_installation_error_" + target_arch + ".bat", | 
 |             "%{dbg_mode_debug_flag_" + target_arch + "}": "/DEBUG", | 
 |             "%{fastbuild_mode_debug_flag_" + target_arch + "}": "/DEBUG", | 
 |         } | 
 |         return msvc_vars | 
 |  | 
 |     if msvc_vars_x64: | 
 |         env = _get_vc_env_vars(repository_ctx, vc_path, msvc_vars_x64, target_arch) | 
 |     else: | 
 |         env = setup_vc_env_vars(repository_ctx, vc_path) | 
 |     escaped_tmp_dir = escape_string(_get_temp_env(repository_ctx).replace("\\", "\\\\")) | 
 |     escaped_include_paths = escape_string(env["INCLUDE"]) | 
 |  | 
 |     build_tools = {} | 
 |     llvm_path = "" | 
 |     if _use_clang_cl(repository_ctx): | 
 |         llvm_path = find_llvm_path(repository_ctx) | 
 |         if not llvm_path: | 
 |             auto_configure_fail("\nUSE_CLANG_CL is set to 1, but Bazel cannot find Clang installation on your system.\n" + | 
 |                                 "Please install Clang via http://releases.llvm.org/download.html\n") | 
 |  | 
 |         build_tools["CL"] = find_llvm_tool(repository_ctx, llvm_path, "clang-cl.exe") | 
 |         build_tools["ML"] = find_msvc_tool(repository_ctx, vc_path, "ml64.exe", "x64") | 
 |         build_tools["LINK"] = find_llvm_tool(repository_ctx, llvm_path, "lld-link.exe") | 
 |         if not build_tools["LINK"]: | 
 |             build_tools["LINK"] = find_msvc_tool(repository_ctx, vc_path, "link.exe", "x64") | 
 |         build_tools["LIB"] = find_llvm_tool(repository_ctx, llvm_path, "llvm-lib.exe") | 
 |         if not build_tools["LIB"]: | 
 |             build_tools["LIB"] = find_msvc_tool(repository_ctx, vc_path, "lib.exe", "x64") | 
 |     else: | 
 |         build_tools = _find_msvc_tools(repository_ctx, vc_path, target_arch) | 
 |  | 
 |     escaped_cxx_include_directories = [] | 
 |     for path in escaped_include_paths.split(";"): | 
 |         if path: | 
 |             escaped_cxx_include_directories.append("\"%s\"" % path) | 
 |     if llvm_path: | 
 |         clang_version = _get_clang_version(repository_ctx, build_tools["CL"]) | 
 |         clang_dir = llvm_path + "\\lib\\clang\\" + clang_version | 
 |         clang_include_path = (clang_dir + "\\include").replace("\\", "\\\\") | 
 |         escaped_cxx_include_directories.append("\"%s\"" % clang_include_path) | 
 |         clang_lib_path = (clang_dir + "\\lib\\windows").replace("\\", "\\\\") | 
 |         env["LIB"] = escape_string(env["LIB"]) + ";" + clang_lib_path | 
 |  | 
 |     support_debug_fastlink = _is_support_debug_fastlink(repository_ctx, build_tools["LINK"]) | 
 |     write_builtin_include_directory_paths(repository_ctx, "msvc", escaped_cxx_include_directories, file_suffix = "_msvc") | 
 |  | 
 |     msvc_vars = { | 
 |         "%{msvc_env_tmp_" + target_arch + "}": escaped_tmp_dir, | 
 |         "%{msvc_env_include_" + target_arch + "}": escaped_include_paths, | 
 |         "%{msvc_cxx_builtin_include_directories_" + target_arch + "}": "        " + ",\n        ".join(escaped_cxx_include_directories), | 
 |         "%{msvc_env_path_" + target_arch + "}": escape_string(env["PATH"]), | 
 |         "%{msvc_env_lib_" + target_arch + "}": escape_string(env["LIB"]), | 
 |         "%{msvc_cl_path_" + target_arch + "}": build_tools["CL"], | 
 |         "%{msvc_ml_path_" + target_arch + "}": build_tools.get("ML", "msvc_arm_toolchain_does_not_support_ml"), | 
 |         "%{msvc_link_path_" + target_arch + "}": build_tools["LINK"], | 
 |         "%{msvc_lib_path_" + target_arch + "}": build_tools["LIB"], | 
 |         "%{dbg_mode_debug_flag_" + target_arch + "}": "/DEBUG:FULL" if support_debug_fastlink else "/DEBUG", | 
 |         "%{fastbuild_mode_debug_flag_" + target_arch + "}": "/DEBUG:FASTLINK" if support_debug_fastlink else "/DEBUG", | 
 |     } | 
 |     return msvc_vars | 
 |  | 
 | def _get_clang_cl_vars(repository_ctx, paths, msvc_vars, target_arch): | 
 |     """Get the variables we need to populate the clang-cl toolchains.""" | 
 |     llvm_path = find_llvm_path(repository_ctx) | 
 |     error_script = None | 
 |     if msvc_vars["%{msvc_cl_path_" + target_arch + "}"] == "vc_installation_error_{}.bat".format(target_arch): | 
 |         error_script = "vc_installation_error_{}.bat".format(target_arch) | 
 |     elif not llvm_path: | 
 |         repository_ctx.template( | 
 |             "clang_installation_error.bat", | 
 |             paths["@bazel_tools//tools/cpp:clang_installation_error.bat.tpl"], | 
 |             {"%{clang_error_message}": ""}, | 
 |         ) | 
 |         error_script = "clang_installation_error.bat" | 
 |     else: | 
 |         missing_tools = _find_missing_llvm_tools(repository_ctx, llvm_path) | 
 |         if missing_tools: | 
 |             message = "\r\n".join([ | 
 |                 "echo. 1>&2", | 
 |                 "echo LLVM/Clang seems to be installed at %s 1>&2" % llvm_path, | 
 |                 "echo But Bazel can't find the following tools: 1>&2", | 
 |                 "echo     %s 1>&2" % ", ".join(missing_tools), | 
 |                 "echo. 1>&2", | 
 |             ]) | 
 |             repository_ctx.template( | 
 |                 "clang_installation_error.bat", | 
 |                 paths["@bazel_tools//tools/cpp:clang_installation_error.bat.tpl"], | 
 |                 {"%{clang_error_message}": message}, | 
 |             ) | 
 |             error_script = "clang_installation_error.bat" | 
 |  | 
 |     if error_script: | 
 |         write_builtin_include_directory_paths(repository_ctx, "clang-cl", [], file_suffix = "_clangcl") | 
 |         clang_cl_vars = { | 
 |             "%{clang_cl_env_tmp_" + target_arch + "}": "clang_cl_not_found", | 
 |             "%{clang_cl_env_path_" + target_arch + "}": "clang_cl_not_found", | 
 |             "%{clang_cl_env_include_" + target_arch + "}": "clang_cl_not_found", | 
 |             "%{clang_cl_env_lib_" + target_arch + "}": "clang_cl_not_found", | 
 |             "%{clang_cl_cl_path_" + target_arch + "}": error_script, | 
 |             "%{clang_cl_link_path_" + target_arch + "}": error_script, | 
 |             "%{clang_cl_lib_path_" + target_arch + "}": error_script, | 
 |             "%{clang_cl_ml_path_" + target_arch + "}": error_script, | 
 |             "%{clang_cl_dbg_mode_debug_flag_" + target_arch + "}": "/DEBUG", | 
 |             "%{clang_cl_fastbuild_mode_debug_flag_" + target_arch + "}": "/DEBUG", | 
 |             "%{clang_cl_cxx_builtin_include_directories_" + target_arch + "}": "", | 
 |         } | 
 |         return clang_cl_vars | 
 |  | 
 |     clang_cl_path = find_llvm_tool(repository_ctx, llvm_path, "clang-cl.exe") | 
 |     lld_link_path = find_llvm_tool(repository_ctx, llvm_path, "lld-link.exe") | 
 |     llvm_lib_path = find_llvm_tool(repository_ctx, llvm_path, "llvm-lib.exe") | 
 |  | 
 |     clang_version = _get_clang_version(repository_ctx, clang_cl_path) | 
 |     clang_dir = llvm_path + "\\lib\\clang\\" + clang_version | 
 |     clang_include_path = (clang_dir + "\\include").replace("\\", "\\\\") | 
 |     clang_lib_path = (clang_dir + "\\lib\\windows").replace("\\", "\\\\") | 
 |  | 
 |     clang_cl_include_directories = msvc_vars["%{msvc_cxx_builtin_include_directories_" + target_arch + "}"] + (",\n        \"%s\"" % clang_include_path) | 
 |     write_builtin_include_directory_paths(repository_ctx, "clang-cl", [clang_cl_include_directories], file_suffix = "_clangcl") | 
 |     clang_cl_vars = { | 
 |         "%{clang_cl_env_tmp_" + target_arch + "}": msvc_vars["%{msvc_env_tmp_" + target_arch + "}"], | 
 |         "%{clang_cl_env_path_" + target_arch + "}": msvc_vars["%{msvc_env_path_" + target_arch + "}"], | 
 |         "%{clang_cl_env_include_" + target_arch + "}": msvc_vars["%{msvc_env_include_" + target_arch + "}"] + ";" + clang_include_path, | 
 |         "%{clang_cl_env_lib_" + target_arch + "}": msvc_vars["%{msvc_env_lib_" + target_arch + "}"] + ";" + clang_lib_path, | 
 |         "%{clang_cl_cxx_builtin_include_directories_" + target_arch + "}": clang_cl_include_directories, | 
 |         "%{clang_cl_cl_path_" + target_arch + "}": clang_cl_path, | 
 |         "%{clang_cl_link_path_" + target_arch + "}": lld_link_path, | 
 |         "%{clang_cl_lib_path_" + target_arch + "}": llvm_lib_path, | 
 |         "%{clang_cl_ml_path_" + target_arch + "}": clang_cl_path, | 
 |         # LLVM's lld-link.exe doesn't support /DEBUG:FASTLINK. | 
 |         "%{clang_cl_dbg_mode_debug_flag_" + target_arch + "}": "/DEBUG", | 
 |         "%{clang_cl_fastbuild_mode_debug_flag_" + target_arch + "}": "/DEBUG", | 
 |     } | 
 |     return clang_cl_vars | 
 |  | 
 | def configure_windows_toolchain(repository_ctx): | 
 |     """Configure C++ toolchain on Windows.""" | 
 |     paths = resolve_labels(repository_ctx, [ | 
 |         "@bazel_tools//tools/cpp:BUILD.windows.tpl", | 
 |         "@bazel_tools//tools/cpp:windows_cc_toolchain_config.bzl", | 
 |         "@bazel_tools//tools/cpp:armeabi_cc_toolchain_config.bzl", | 
 |         "@bazel_tools//tools/cpp:vc_installation_error.bat.tpl", | 
 |         "@bazel_tools//tools/cpp:msys_gcc_installation_error.bat", | 
 |         "@bazel_tools//tools/cpp:clang_installation_error.bat.tpl", | 
 |     ]) | 
 |  | 
 |     repository_ctx.symlink( | 
 |         paths["@bazel_tools//tools/cpp:windows_cc_toolchain_config.bzl"], | 
 |         "windows_cc_toolchain_config.bzl", | 
 |     ) | 
 |     repository_ctx.symlink( | 
 |         paths["@bazel_tools//tools/cpp:armeabi_cc_toolchain_config.bzl"], | 
 |         "armeabi_cc_toolchain_config.bzl", | 
 |     ) | 
 |     repository_ctx.symlink( | 
 |         paths["@bazel_tools//tools/cpp:msys_gcc_installation_error.bat"], | 
 |         "msys_gcc_installation_error.bat", | 
 |     ) | 
 |  | 
 |     template_vars = dict() | 
 |     msvc_vars_x64 = _get_msvc_vars(repository_ctx, paths, "x64") | 
 |     template_vars.update(msvc_vars_x64) | 
 |     template_vars.update(_get_clang_cl_vars(repository_ctx, paths, msvc_vars_x64, "x64")) | 
 |     template_vars.update(_get_msys_mingw_vars(repository_ctx)) | 
 |     template_vars.update(_get_msvc_vars(repository_ctx, paths, "x86", msvc_vars_x64)) | 
 |     template_vars.update(_get_msvc_vars(repository_ctx, paths, "arm", msvc_vars_x64)) | 
 |     msvc_vars_arm64 = _get_msvc_vars(repository_ctx, paths, "arm64", msvc_vars_x64) | 
 |     template_vars.update(msvc_vars_arm64) | 
 |     template_vars.update(_get_clang_cl_vars(repository_ctx, paths, msvc_vars_arm64, "arm64")) | 
 |  | 
 |     repository_ctx.template( | 
 |         "BUILD", | 
 |         paths["@bazel_tools//tools/cpp:BUILD.windows.tpl"], | 
 |         template_vars, | 
 |     ) |