aboutsummaryrefslogtreecommitdiff
path: root/cc/private/toolchain/windows_cc_configure.bzl
diff options
context:
space:
mode:
Diffstat (limited to 'cc/private/toolchain/windows_cc_configure.bzl')
-rw-r--r--cc/private/toolchain/windows_cc_configure.bzl703
1 files changed, 703 insertions, 0 deletions
diff --git a/cc/private/toolchain/windows_cc_configure.bzl b/cc/private/toolchain/windows_cc_configure.bzl
new file mode 100644
index 0000000..598d4b2
--- /dev/null
+++ b/cc/private/toolchain/windows_cc_configure.bzl
@@ -0,0 +1,703 @@
+# 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(
+ ":lib_cc_configure.bzl",
+ "auto_configure_fail",
+ "auto_configure_warning",
+ "auto_configure_warning_maybe",
+ "escape_string",
+ "execute",
+ "resolve_labels",
+ "write_builtin_include_directory_paths",
+)
+
+def _get_path_env_var(repository_ctx, name):
+ """Returns a path from an environment variable.
+
+ Removes quotes, replaces '/' with '\', and strips trailing '\'s."""
+ if name in repository_ctx.os.environ:
+ value = repository_ctx.os.environ[name]
+ 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
+ else:
+ return None
+
+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", "compat-ld", "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."""
+ if "PATH" not in env:
+ env["PATH"] = ""
+ env["PATH"] = env["PATH"] + ";" + _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. 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"),
+ ]:
+ if vscommontools_env not in repository_ctx.os.environ:
+ continue
+ script = _get_path_env_var(repository_ctx, vscommontools_env) + "\\" + script
+ if not repository_ctx.path(script).exists:
+ continue
+ repository_ctx.file(
+ "get_vc_dir.bat",
+ "@echo off\n" +
+ "call \"" + script + "\"\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
+
+ # 3. 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.)
+ # TODO(laszlocsomor): check if "16.0" also has this registry key, after VS 2019 is released.
+ 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
+
+ # 4. Check default directories for VC installation
+ auto_configure_warning_maybe(repository_ctx, "Looking for default Visual C++ installation directory")
+ 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,
+ )
+ 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(vc_path):
+ """Check if the installed VS version is Visual Studio 2017."""
+
+ # In VS 2017 and 2019, the location of VC is like:
+ # C:\Program Files (x86)\Microsoft Visual Studio\2017\BuildTools\VC\
+ # In VS 2015 or older version, it is like:
+ # C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\
+ return vc_path.find("2017") != -1 or vc_path.find("2019") != -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(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(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").get_child("IDE")
+ for tool in ["devenv.exe", "wdexpress.exe"]:
+ if vc_common_ide.get_child(tool).exists:
+ return True
+ return False
+
+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(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 verisons:\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."""
+ if "BAZEL_VC_FULL_VERSION" in repository_ctx.os.environ:
+ return repository_ctx.os.environ["BAZEL_VC_FULL_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 repository_ctx.os.environ.get("BAZEL_WINSDK_FULL_VERSION", default = "")
+
+def _find_msvc_tool(repository_ctx, vc_path, tool):
+ """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(vc_path):
+ full_version = _get_vc_full_version(repository_ctx, vc_path)
+ if full_version:
+ tool_path = "%s\\Tools\\MSVC\\%s\\bin\\HostX64\\x64\\%s" % (vc_path, full_version, 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\\amd64\\" + 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):
+ """Check if any required tool is missing under given VC path."""
+ missing_tools = []
+ if not _find_vcvars_bat_script(repository_ctx, vc_path):
+ missing_tools.append("VCVARSALL.BAT")
+
+ for tool in ["cl.exe", "link.exe", "lib.exe", "ml64.exe"]:
+ if not _find_msvc_tool(repository_ctx, vc_path, tool):
+ missing_tools.append(tool)
+
+ return missing_tools
+
+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 repository_ctx.os.environ.get("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"])
+ if result.return_code != 0:
+ auto_configure_fail("Failed to get clang version by running \"%s -v\"" % clang_cl)
+
+ # Stderr should look like "clang version X.X.X ..."
+ return result.stderr.splitlines()[0].split(" ")[2]
+
+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,
+ "%{mingw_tool_bin_path}": tool_bin_path_mingw,
+ "%{mingw_tool_paths}": tool_paths_mingw,
+ "%{tool_bin_path}": tool_bin_path,
+ "%{tool_paths}": tool_paths,
+ }
+ return msys_mingw_vars
+
+def _get_msvc_vars(repository_ctx, paths):
+ """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.bat",
+ paths["@rules_cc//cc/private/toolchain:vc_installation_error.bat.tpl"],
+ {"%{vc_error_message}": ""},
+ )
+ else:
+ missing_tools = _find_missing_vc_tools(repository_ctx, vc_path)
+ 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. 1>&2",
+ ])
+ repository_ctx.template(
+ "vc_installation_error.bat",
+ paths["@rules_cc//cc/private/toolchain: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 = {
+ "%{dbg_mode_debug_flag}": "/DEBUG",
+ "%{fastbuild_mode_debug_flag}": "/DEBUG",
+ "%{msvc_cl_path}": "vc_installation_error.bat",
+ "%{msvc_cxx_builtin_include_directories}": "",
+ "%{msvc_env_include}": "msvc_not_found",
+ "%{msvc_env_lib}": "msvc_not_found",
+ "%{msvc_env_path}": "msvc_not_found",
+ "%{msvc_env_tmp}": "msvc_not_found",
+ "%{msvc_lib_path}": "vc_installation_error.bat",
+ "%{msvc_link_path}": "vc_installation_error.bat",
+ "%{msvc_ml_path}": "vc_installation_error.bat",
+ }
+ return msvc_vars
+
+ env = setup_vc_env_vars(repository_ctx, vc_path)
+ escaped_paths = escape_string(env["PATH"])
+ escaped_include_paths = escape_string(env["INCLUDE"])
+ escaped_lib_paths = escape_string(env["LIB"])
+ escaped_tmp_dir = escape_string(_get_temp_env(repository_ctx).replace("\\", "\\\\"))
+
+ 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")
+ cl_path = _find_llvm_tool(repository_ctx, llvm_path, "clang-cl.exe")
+ link_path = _find_llvm_tool(repository_ctx, llvm_path, "lld-link.exe")
+ if not link_path:
+ link_path = _find_msvc_tool(repository_ctx, vc_path, "link.exe")
+ lib_path = _find_llvm_tool(repository_ctx, llvm_path, "llvm-lib.exe")
+ if not lib_path:
+ lib_path = _find_msvc_tool(repository_ctx, vc_path, "lib.exe")
+ else:
+ cl_path = _find_msvc_tool(repository_ctx, vc_path, "cl.exe")
+ link_path = _find_msvc_tool(repository_ctx, vc_path, "link.exe")
+ lib_path = _find_msvc_tool(repository_ctx, vc_path, "lib.exe")
+
+ msvc_ml_path = _find_msvc_tool(repository_ctx, vc_path, "ml64.exe")
+ 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, cl_path)
+ 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("\\", "\\\\")
+ escaped_lib_paths = escaped_lib_paths + ";" + clang_lib_path
+
+ support_debug_fastlink = _is_support_debug_fastlink(repository_ctx, link_path)
+
+ write_builtin_include_directory_paths(repository_ctx, "msvc", escaped_cxx_include_directories, file_suffix = "_msvc")
+ msvc_vars = {
+ "%{dbg_mode_debug_flag}": "/DEBUG:FULL" if support_debug_fastlink else "/DEBUG",
+ "%{fastbuild_mode_debug_flag}": "/DEBUG:FASTLINK" if support_debug_fastlink else "/DEBUG",
+ "%{msvc_cl_path}": cl_path,
+ "%{msvc_cxx_builtin_include_directories}": " " + ",\n ".join(escaped_cxx_include_directories),
+ "%{msvc_env_include}": escaped_include_paths,
+ "%{msvc_env_lib}": escaped_lib_paths,
+ "%{msvc_env_path}": escaped_paths,
+ "%{msvc_env_tmp}": escaped_tmp_dir,
+ "%{msvc_lib_path}": lib_path,
+ "%{msvc_link_path}": link_path,
+ "%{msvc_ml_path}": msvc_ml_path,
+ }
+ return msvc_vars
+
+def _get_clang_cl_vars(repository_ctx, paths, msvc_vars):
+ """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}"] == "vc_installation_error.bat":
+ error_script = "vc_installation_error.bat"
+ elif not llvm_path:
+ repository_ctx.template(
+ "clang_installation_error.bat",
+ paths["@rules_cc//cc/private/toolchain: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["@rules_cc//cc/private/toolchain: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_cl_path}": error_script,
+ "%{clang_cl_cxx_builtin_include_directories}": "",
+ "%{clang_cl_dbg_mode_debug_flag}": "/DEBUG",
+ "%{clang_cl_env_include}": "clang_cl_not_found",
+ "%{clang_cl_env_lib}": "clang_cl_not_found",
+ "%{clang_cl_env_path}": "clang_cl_not_found",
+ "%{clang_cl_env_tmp}": "clang_cl_not_found",
+ "%{clang_cl_fastbuild_mode_debug_flag}": "/DEBUG",
+ "%{clang_cl_lib_path}": error_script,
+ "%{clang_cl_link_path}": error_script,
+ "%{clang_cl_ml_path}": error_script,
+ }
+ 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}"] + (",\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_cl_path}": clang_cl_path,
+ "%{clang_cl_cxx_builtin_include_directories}": clang_cl_include_directories,
+ # LLVM's lld-link.exe doesn't support /DEBUG:FASTLINK.
+ "%{clang_cl_dbg_mode_debug_flag}": "/DEBUG",
+ "%{clang_cl_env_include}": msvc_vars["%{msvc_env_include}"] + ";" + clang_include_path,
+ "%{clang_cl_env_lib}": msvc_vars["%{msvc_env_lib}"] + ";" + clang_lib_path,
+ "%{clang_cl_env_path}": msvc_vars["%{msvc_env_path}"],
+ "%{clang_cl_env_tmp}": msvc_vars["%{msvc_env_tmp}"],
+ "%{clang_cl_fastbuild_mode_debug_flag}": "/DEBUG",
+ "%{clang_cl_lib_path}": llvm_lib_path,
+ "%{clang_cl_link_path}": lld_link_path,
+ "%{clang_cl_ml_path}": msvc_vars["%{msvc_ml_path}"],
+ }
+ return clang_cl_vars
+
+def configure_windows_toolchain(repository_ctx):
+ """Configure C++ toolchain on Windows.
+
+ Args:
+ repository_ctx: The repository context.
+ """
+ paths = resolve_labels(repository_ctx, [
+ "@rules_cc//cc/private/toolchain:BUILD.windows.tpl",
+ "@rules_cc//cc/private/toolchain:windows_cc_toolchain_config.bzl",
+ "@rules_cc//cc/private/toolchain:armeabi_cc_toolchain_config.bzl",
+ "@rules_cc//cc/private/toolchain:vc_installation_error.bat.tpl",
+ "@rules_cc//cc/private/toolchain:msys_gcc_installation_error.bat",
+ "@rules_cc//cc/private/toolchain:clang_installation_error.bat.tpl",
+ ])
+
+ repository_ctx.symlink(
+ paths["@rules_cc//cc/private/toolchain:windows_cc_toolchain_config.bzl"],
+ "windows_cc_toolchain_config.bzl",
+ )
+ repository_ctx.symlink(
+ paths["@rules_cc//cc/private/toolchain:armeabi_cc_toolchain_config.bzl"],
+ "armeabi_cc_toolchain_config.bzl",
+ )
+ repository_ctx.symlink(
+ paths["@rules_cc//cc/private/toolchain:msys_gcc_installation_error.bat"],
+ "msys_gcc_installation_error.bat",
+ )
+
+ template_vars = dict()
+ msvc_vars = _get_msvc_vars(repository_ctx, paths)
+ template_vars.update(msvc_vars)
+ template_vars.update(_get_clang_cl_vars(repository_ctx, paths, msvc_vars))
+ template_vars.update(_get_msys_mingw_vars(repository_ctx))
+
+ repository_ctx.template(
+ "BUILD",
+ paths["@rules_cc//cc/private/toolchain:BUILD.windows.tpl"],
+ template_vars,
+ )