SERVER-104386: Define the custom windows toolchain cc config. (#35485)
GitOrigin-RevId: ad55457bf3ffdf588e747ea7ed3cad6c36638d66
This commit is contained in:
committed by
MongoDB Bot
parent
4f931e4b71
commit
8f05820834
@@ -180,3 +180,8 @@ setup_local_host_values(name = "local_host_values")
|
||||
setup_evergreen_variables = use_repo_rule("//bazel/repository_rules:evergreen_variables.bzl", "setup_evergreen_variables")
|
||||
|
||||
setup_evergreen_variables(name = "evergreen_variables")
|
||||
|
||||
setup_mongo_windows_toolchains_extension = use_extension("//bazel/toolchains/cc/mongo_windows:mongo_toolchain.bzl", "setup_mongo_windows_toolchain_extension")
|
||||
use_repo(setup_mongo_windows_toolchains_extension, "mongo_windows_toolchain")
|
||||
|
||||
register_toolchains("@mongo_windows_toolchain//...")
|
||||
|
||||
@@ -60,6 +60,13 @@ constraint_setting(name = "distro")
|
||||
]
|
||||
]
|
||||
|
||||
constraint_setting(name = "mongo_windows_toolchain_config")
|
||||
|
||||
constraint_value(
|
||||
name = "use_mongo_windows_toolchain_config",
|
||||
constraint_setting = ":mongo_windows_toolchain_config",
|
||||
)
|
||||
|
||||
platform(
|
||||
name = "windows_amd64",
|
||||
constraint_values = [
|
||||
|
||||
@@ -70,6 +70,11 @@ def _setup_local_config_platform(ctx):
|
||||
constraints_str += ',\n "@//bazel/platforms:%s"' % (distro)
|
||||
result = {"DISTRO": distro}
|
||||
exec_props = ""
|
||||
#elif os == "windows":
|
||||
#constraints_str += ',\n "@//bazel/platforms:use_mongo_windows_toolchain_config"'
|
||||
#result = {"USE_NATIVE_TOOLCHAIN": "1"}
|
||||
#exec_props = ""
|
||||
|
||||
else:
|
||||
result = {"USE_NATIVE_TOOLCHAIN": "1"}
|
||||
exec_props = ""
|
||||
|
||||
308
bazel/toolchains/cc/mongo_windows/lib_cc_configure.bzl
Normal file
308
bazel/toolchains/cc/mongo_windows/lib_cc_configure.bzl
Normal file
@@ -0,0 +1,308 @@
|
||||
# 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.
|
||||
"""Base library for configuring the C++ toolchain."""
|
||||
|
||||
###
|
||||
# This file was retrieved from the following location:
|
||||
# https://github.com/bazelbuild/rules_cc/blob/b1c049c65c7ffa4dfa175e29b6af75d5e08486d5/cc/private/toolchain/lib_cc_configure.bzl
|
||||
###
|
||||
|
||||
def resolve_labels(repository_ctx, labels):
|
||||
"""Resolves a collection of labels to their paths.
|
||||
|
||||
Label resolution can cause the evaluation of Starlark functions to restart.
|
||||
For functions with side-effects (like the auto-configuration functions, which
|
||||
inspect the system and touch the file system), such restarts are costly.
|
||||
We cannot avoid the restarts, but we can minimize their penalty by resolving
|
||||
all labels upfront.
|
||||
|
||||
Among other things, doing less work on restarts can cut analysis times by
|
||||
several seconds and may also prevent tickling kernel conditions that cause
|
||||
build failures. See https://github.com/bazelbuild/bazel/issues/5196 for
|
||||
more details.
|
||||
|
||||
Args:
|
||||
repository_ctx: The context with which to resolve the labels.
|
||||
labels: Labels to be resolved expressed as a list of strings.
|
||||
|
||||
Returns:
|
||||
A dictionary with the labels as keys and their paths as values.
|
||||
"""
|
||||
return dict([(label, repository_ctx.path(Label(label))) for label in labels])
|
||||
|
||||
def escape_string(arg):
|
||||
"""Escape percent sign (%) in the string so it can appear in the Crosstool."""
|
||||
if arg != None:
|
||||
return str(arg).replace("%", "%%")
|
||||
else:
|
||||
return None
|
||||
|
||||
def split_escaped(string, delimiter):
|
||||
"""Split string on the delimiter unless %-escaped.
|
||||
|
||||
Examples:
|
||||
Basic usage:
|
||||
split_escaped("a:b:c", ":") -> [ "a", "b", "c" ]
|
||||
|
||||
Delimiter that is not supposed to be splitten on has to be %-escaped:
|
||||
split_escaped("a%:b", ":") -> [ "a:b" ]
|
||||
|
||||
Literal % can be represented by escaping it as %%:
|
||||
split_escaped("a%%b", ":") -> [ "a%b" ]
|
||||
|
||||
Consecutive delimiters produce empty strings:
|
||||
split_escaped("a::b", ":") -> [ "a", "", "", "b" ]
|
||||
|
||||
Args:
|
||||
string: The string to be split.
|
||||
delimiter: Non-empty string not containing %-sign to be used as a
|
||||
delimiter.
|
||||
|
||||
Returns:
|
||||
A list of substrings.
|
||||
"""
|
||||
if delimiter == "":
|
||||
fail("Delimiter cannot be empty")
|
||||
if delimiter.find("%") != -1:
|
||||
fail("Delimiter cannot contain %-sign")
|
||||
|
||||
i = 0
|
||||
result = []
|
||||
accumulator = []
|
||||
length = len(string)
|
||||
delimiter_length = len(delimiter)
|
||||
|
||||
if not string:
|
||||
return []
|
||||
|
||||
# Iterate over the length of string since Starlark doesn't have while loops
|
||||
for _ in range(length):
|
||||
if i >= length:
|
||||
break
|
||||
if i + 2 <= length and string[i:i + 2] == "%%":
|
||||
accumulator.append("%")
|
||||
i += 2
|
||||
elif (i + 1 + delimiter_length <= length and
|
||||
string[i:i + 1 + delimiter_length] == "%" + delimiter):
|
||||
accumulator.append(delimiter)
|
||||
i += 1 + delimiter_length
|
||||
elif i + delimiter_length <= length and string[i:i + delimiter_length] == delimiter:
|
||||
result.append("".join(accumulator))
|
||||
accumulator = []
|
||||
i += delimiter_length
|
||||
else:
|
||||
accumulator.append(string[i])
|
||||
i += 1
|
||||
|
||||
# Append the last group still in accumulator
|
||||
result.append("".join(accumulator))
|
||||
return result
|
||||
|
||||
def auto_configure_fail(msg):
|
||||
"""Output failure message when auto configuration fails."""
|
||||
red = "\033[0;31m"
|
||||
no_color = "\033[0m"
|
||||
fail("\n%sAuto-Configuration Error:%s %s\n" % (red, no_color, msg))
|
||||
|
||||
def auto_configure_warning(msg):
|
||||
"""Output warning message during auto configuration."""
|
||||
yellow = "\033[1;33m"
|
||||
no_color = "\033[0m"
|
||||
|
||||
# buildifier: disable=print
|
||||
print("\n%sAuto-Configuration Warning:%s %s\n" % (yellow, no_color, msg))
|
||||
|
||||
def get_env_var(repository_ctx, name, default = None, enable_warning = True):
|
||||
"""Find an environment variable in system path. Doesn't %-escape the value!
|
||||
|
||||
Args:
|
||||
repository_ctx: The repository context.
|
||||
name: Name of the environment variable.
|
||||
default: Default value to be used when such environment variable is not present.
|
||||
enable_warning: Show warning if the variable is not present.
|
||||
Returns:
|
||||
value of the environment variable or default.
|
||||
"""
|
||||
|
||||
if name in repository_ctx.os.environ:
|
||||
return repository_ctx.os.environ[name]
|
||||
if default != None:
|
||||
if enable_warning:
|
||||
auto_configure_warning("'%s' environment variable is not set, using '%s' as default" % (name, default))
|
||||
return default
|
||||
auto_configure_fail("'%s' environment variable is not set" % name)
|
||||
return None
|
||||
|
||||
def which(repository_ctx, cmd, default = None):
|
||||
"""A wrapper around repository_ctx.which() to provide a fallback value. Doesn't %-escape the value!
|
||||
|
||||
Args:
|
||||
repository_ctx: The repository context.
|
||||
cmd: name of the executable to resolve.
|
||||
default: Value to be returned when such executable couldn't be found.
|
||||
Returns:
|
||||
absolute path to the cmd or default when not found.
|
||||
"""
|
||||
result = repository_ctx.which(cmd)
|
||||
return default if result == None else str(result)
|
||||
|
||||
def which_cmd(repository_ctx, cmd, default = None):
|
||||
"""Find cmd in PATH using repository_ctx.which() and fail if cannot find it. Doesn't %-escape the cmd!
|
||||
|
||||
Args:
|
||||
repository_ctx: The repository context.
|
||||
cmd: name of the executable to resolve.
|
||||
default: Value to be returned when such executable couldn't be found.
|
||||
Returns:
|
||||
absolute path to the cmd or default when not found.
|
||||
"""
|
||||
result = repository_ctx.which(cmd)
|
||||
if result != None:
|
||||
return str(result)
|
||||
path = get_env_var(repository_ctx, "PATH")
|
||||
if default != None:
|
||||
auto_configure_warning("Cannot find %s in PATH, using '%s' as default.\nPATH=%s" % (cmd, default, path))
|
||||
return default
|
||||
auto_configure_fail("Cannot find %s in PATH, please make sure %s is installed and add its directory in PATH.\nPATH=%s" % (cmd, cmd, path))
|
||||
return str(result)
|
||||
|
||||
def execute(
|
||||
repository_ctx,
|
||||
command,
|
||||
environment = None,
|
||||
expect_failure = False,
|
||||
expect_empty_output = False):
|
||||
"""Execute a command, return stdout if succeed and throw an error if it fails. Doesn't %-escape the result!
|
||||
|
||||
Args:
|
||||
repository_ctx: The repository context.
|
||||
command: command to execute.
|
||||
environment: dictionary with environment variables to set for the command.
|
||||
expect_failure: True if the command is expected to fail.
|
||||
expect_empty_output: True if the command is expected to produce no output.
|
||||
Returns:
|
||||
stdout of the executed command.
|
||||
"""
|
||||
if environment:
|
||||
result = repository_ctx.execute(command, environment = environment)
|
||||
else:
|
||||
result = repository_ctx.execute(command)
|
||||
if expect_failure != (result.return_code != 0):
|
||||
if expect_failure:
|
||||
auto_configure_fail(
|
||||
"expected failure, command %s, stderr: (%s)" % (
|
||||
command,
|
||||
result.stderr,
|
||||
),
|
||||
)
|
||||
else:
|
||||
auto_configure_fail(
|
||||
"non-zero exit code: %d, command %s, stderr: (%s)" % (
|
||||
result.return_code,
|
||||
command,
|
||||
result.stderr,
|
||||
),
|
||||
)
|
||||
stripped_stdout = result.stdout.strip()
|
||||
if expect_empty_output != (not stripped_stdout):
|
||||
if expect_empty_output:
|
||||
auto_configure_fail(
|
||||
"non-empty output from command %s, stdout: (%s), stderr: (%s)" % (command, result.stdout, result.stderr),
|
||||
)
|
||||
else:
|
||||
auto_configure_fail(
|
||||
"empty output from command %s, stderr: (%s)" % (command, result.stderr),
|
||||
)
|
||||
return stripped_stdout
|
||||
|
||||
def get_cpu_value(repository_ctx):
|
||||
"""Compute the cpu_value based on the OS name. Doesn't %-escape the result!
|
||||
|
||||
Args:
|
||||
repository_ctx: The repository context.
|
||||
Returns:
|
||||
One of (darwin, freebsd, x64_windows, ppc, s390x, arm, aarch64, k8, piii)
|
||||
"""
|
||||
os_name = repository_ctx.os.name
|
||||
arch = repository_ctx.os.arch
|
||||
if os_name.startswith("mac os"):
|
||||
# Check if we are on x86_64 or arm64 and return the corresponding cpu value.
|
||||
return "darwin_" + ("arm64" if arch == "aarch64" else "x86_64")
|
||||
if os_name.find("freebsd") != -1:
|
||||
return "freebsd"
|
||||
if os_name.find("openbsd") != -1:
|
||||
return "openbsd"
|
||||
if os_name.find("windows") != -1:
|
||||
if arch == "aarch64":
|
||||
return "arm64_windows"
|
||||
else:
|
||||
return "x64_windows"
|
||||
|
||||
if arch in ["power", "ppc64le", "ppc", "ppc64"]:
|
||||
return "ppc"
|
||||
if arch in ["s390x"]:
|
||||
return "s390x"
|
||||
if arch in ["mips64"]:
|
||||
return "mips64"
|
||||
if arch in ["riscv64"]:
|
||||
return "riscv64"
|
||||
if arch in ["arm", "armv7l"]:
|
||||
return "arm"
|
||||
if arch in ["aarch64"]:
|
||||
return "aarch64"
|
||||
return "k8" if arch in ["amd64", "x86_64", "x64"] else "piii"
|
||||
|
||||
def is_cc_configure_debug(repository_ctx):
|
||||
"""Returns True if CC_CONFIGURE_DEBUG is set to 1."""
|
||||
env = repository_ctx.os.environ
|
||||
return "CC_CONFIGURE_DEBUG" in env and env["CC_CONFIGURE_DEBUG"] == "1"
|
||||
|
||||
def build_flags(flags):
|
||||
"""Convert `flags` to a string of flag fields."""
|
||||
return "\n".join([" flag: '" + flag + "'" for flag in flags])
|
||||
|
||||
def get_starlark_list(values):
|
||||
"""Convert a list of string into a string that can be passed to a rule attribute."""
|
||||
if not values:
|
||||
return ""
|
||||
return "\"" + "\",\n \"".join(values) + "\""
|
||||
|
||||
def auto_configure_warning_maybe(repository_ctx, msg):
|
||||
"""Output warning message when CC_CONFIGURE_DEBUG is enabled."""
|
||||
if is_cc_configure_debug(repository_ctx):
|
||||
auto_configure_warning(msg)
|
||||
|
||||
def write_builtin_include_directory_paths(repository_ctx, cc, directories, file_suffix = ""):
|
||||
"""Generate output file named 'builtin_include_directory_paths' in the root of the repository."""
|
||||
if get_env_var(repository_ctx, "BAZEL_IGNORE_SYSTEM_HEADERS_VERSIONS", "0", False) == "1":
|
||||
repository_ctx.file(
|
||||
"builtin_include_directory_paths" + file_suffix,
|
||||
"""This file is generated by cc_configure and normally contains builtin include directories
|
||||
that C++ compiler reported. But because BAZEL_IGNORE_SYSTEM_HEADERS_VERSIONS was set to 1,
|
||||
header include directory paths are intentionally not put there.
|
||||
""",
|
||||
)
|
||||
else:
|
||||
repository_ctx.file(
|
||||
"builtin_include_directory_paths" + file_suffix,
|
||||
"""This file is generated by cc_configure and contains builtin include directories
|
||||
that %s reported. This file is a dependency of every compilation action and
|
||||
changes to it will be reflected in the action cache key. When some of these
|
||||
paths change, Bazel will make sure to rerun the action, even though none of
|
||||
declared action inputs or the action commandline changes.
|
||||
|
||||
%s
|
||||
""" % (cc, "\n".join(directories)),
|
||||
)
|
||||
73
bazel/toolchains/cc/mongo_windows/mongo_toolchain.BUILD.tmpl
Normal file
73
bazel/toolchains/cc/mongo_windows/mongo_toolchain.BUILD.tmpl
Normal file
@@ -0,0 +1,73 @@
|
||||
load("@//bazel/toolchains/cc/mongo_windows:mongo_windows_cc_toolchain_config.bzl", "mongo_windows_cc_toolchain_config")
|
||||
|
||||
mongo_windows_cc_toolchain_config(
|
||||
name = "cc_msvc_toolchain_config",
|
||||
abi_libc_version = "local",
|
||||
abi_version = "local",
|
||||
compiler = "msvc-cl",
|
||||
cpu = "x64_windows",
|
||||
cxx_builtin_include_directories = "{include_dirs}".split(";"),
|
||||
dbg_mode_debug_flag = "/DEBUG:FULL",
|
||||
default_compile_flags = ["/nologo"],
|
||||
default_link_flags = ["/MACHINE:X64", "/NODEFAULTLIB:library"],
|
||||
archiver_flags = ["/MACHINE:X64"],
|
||||
fastbuild_mode_debug_flag = "/DEBUG:FASTLINK",
|
||||
host_system_name = "local",
|
||||
msvc_cl_path = "{cl}",
|
||||
msvc_env_include = "{include_dirs}",
|
||||
msvc_env_lib = "{lib_dirs}",
|
||||
msvc_env_path = "{env_path}",
|
||||
msvc_env_tmp = "{tmp_dir}",
|
||||
msvc_lib_path = "{ar}",
|
||||
msvc_link_path = "{ld}",
|
||||
msvc_ml_path = "{ml}",
|
||||
target_libc = "msvcrt",
|
||||
target_system_name = "local",
|
||||
tool_paths = {
|
||||
"ar": "{ar}",
|
||||
"ml": "{ml}",
|
||||
"cpp": "{cl}",
|
||||
"gcc": "{cl}",
|
||||
"gcov": "wrapper/bin/msvc_nop.bat",
|
||||
"ld": "{ld}",
|
||||
"nm": "wrapper/bin/msvc_nop.bat",
|
||||
"objcopy": "wrapper/bin/msvc_nop.bat",
|
||||
"objdump": "wrapper/bin/msvc_nop.bat",
|
||||
"strip": "wrapper/bin/msvc_nop.bat",
|
||||
},
|
||||
toolchain_identifier = "msvc_x64",
|
||||
)
|
||||
|
||||
cc_toolchain(
|
||||
name = "mongo_win_cc_toolchain",
|
||||
all_files = ":all_files",
|
||||
ar_files = ":all_files",
|
||||
compiler_files = ":all_files",
|
||||
dwp_files = ":all_files",
|
||||
linker_files = ":all_files",
|
||||
objcopy_files = ":all_files",
|
||||
strip_files = ":all_files",
|
||||
toolchain_config = "cc_msvc_toolchain_config",
|
||||
)
|
||||
|
||||
toolchain(
|
||||
name = "windows_cc_toolchain",
|
||||
exec_compatible_with = [
|
||||
"@platforms//os:windows",
|
||||
"@platforms//cpu:x86_64",
|
||||
"@//bazel/platforms:use_mongo_windows_toolchain_config",
|
||||
],
|
||||
target_compatible_with = [
|
||||
"@platforms//os:windows",
|
||||
"@platforms//cpu:x86_64",
|
||||
"@//bazel/platforms:use_mongo_windows_toolchain_config",
|
||||
],
|
||||
toolchain = ":mongo_win_cc_toolchain",
|
||||
toolchain_type = "@bazel_tools//tools/cpp:toolchain_type",
|
||||
)
|
||||
|
||||
# Helper target for the toolchain (see below):
|
||||
filegroup(
|
||||
name = "all_files",
|
||||
srcs = glob(["**/*"]),
|
||||
)
|
||||
88
bazel/toolchains/cc/mongo_windows/mongo_toolchain.bzl
Normal file
88
bazel/toolchains/cc/mongo_windows/mongo_toolchain.bzl
Normal file
@@ -0,0 +1,88 @@
|
||||
load("//bazel/toolchains/cc/mongo_windows:lib_cc_configure.bzl", "auto_configure_fail")
|
||||
load(
|
||||
":windows_cc_configure.bzl",
|
||||
"find_msvc_tool",
|
||||
"find_vc_path",
|
||||
"get_tmp_dir",
|
||||
"setup_vc_env_vars",
|
||||
)
|
||||
|
||||
def _impl_gen_windows_toolchain_build_file(ctx):
|
||||
if "windows" not in ctx.os.name:
|
||||
ctx.file(
|
||||
"BUILD.bazel",
|
||||
"# {} not supported on this platform",
|
||||
)
|
||||
return None
|
||||
|
||||
ctx.report_progress("Generating the required cc environment variables")
|
||||
vc_path = find_vc_path(ctx)
|
||||
if vc_path == None:
|
||||
auto_configure_fail("require vc path before continuing")
|
||||
|
||||
vars = setup_vc_env_vars(ctx, vc_path)
|
||||
|
||||
include_dirs = vars["INCLUDE"]
|
||||
if include_dirs == None:
|
||||
auto_configure_fail("failed to generate a list of cc include directories")
|
||||
|
||||
lib_dirs = vars["LIB"]
|
||||
if lib_dirs == None:
|
||||
auto_configure_fail("failed to generate a list of cc library directories")
|
||||
|
||||
env_path = vars["PATH"]
|
||||
if env_path == None:
|
||||
auto_configure_fail("failed to generate the cc environment paths")
|
||||
|
||||
tmp_dir = get_tmp_dir(ctx)
|
||||
if tmp_dir == None:
|
||||
auto_configure_fail("temporary directory does not exist")
|
||||
|
||||
substitutions = {
|
||||
"{tmp_dir}": tmp_dir,
|
||||
"{include_dirs}": include_dirs,
|
||||
"{lib_dirs}": lib_dirs,
|
||||
"{env_path}": env_path,
|
||||
}
|
||||
|
||||
ctx.report_progress("Locating cc tooling in the filesystem")
|
||||
tools_subs = {
|
||||
"cl.exe": "{cl}",
|
||||
"lib.exe": "{ar}",
|
||||
"link.exe": "{ld}",
|
||||
"ml64.exe": "{ml}",
|
||||
}
|
||||
for tool_name in tools_subs:
|
||||
sub = tools_subs[tool_name]
|
||||
tool_path = find_msvc_tool(ctx, vc_path, tool_name)
|
||||
if tool_path == None:
|
||||
auto_configure_fail("locating the full path for tool %s was not found" % tool_name)
|
||||
substitutions[sub] = tool_path
|
||||
|
||||
ctx.report_progress("Generating toolchain build file")
|
||||
ctx.template(
|
||||
"BUILD.bazel",
|
||||
ctx.attr.build_tpl,
|
||||
substitutions,
|
||||
)
|
||||
|
||||
return None
|
||||
|
||||
generate_windows_toolchain_build_file = repository_rule(
|
||||
implementation = _impl_gen_windows_toolchain_build_file,
|
||||
attrs = {
|
||||
"build_tpl": attr.label(
|
||||
default = "//bazel/toolchains/cc/mongo_windows:mongo_toolchain.BUILD.tmpl",
|
||||
doc = "Label denoting the BUILD file template that gets installed in the repo.",
|
||||
),
|
||||
},
|
||||
)
|
||||
|
||||
def setup_mongo_windows_toolchain():
|
||||
generate_windows_toolchain_build_file(
|
||||
name = "mongo_windows_toolchain",
|
||||
)
|
||||
|
||||
setup_mongo_windows_toolchain_extension = module_extension(
|
||||
implementation = lambda ctx: setup_mongo_windows_toolchain(),
|
||||
)
|
||||
File diff suppressed because it is too large
Load Diff
911
bazel/toolchains/cc/mongo_windows/windows_cc_configure.bzl
Normal file
911
bazel/toolchains/cc/mongo_windows/windows_cc_configure.bzl
Normal file
@@ -0,0 +1,911 @@
|
||||
# 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."""
|
||||
|
||||
###
|
||||
# This file was retrieved from the following location:
|
||||
# https://github.com/bazelbuild/rules_cc/blob/b1c049c65c7ffa4dfa175e29b6af75d5e08486d5/cc/private/toolchain/windows_cc_configure.bzl
|
||||
###
|
||||
|
||||
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",
|
||||
)
|
||||
|
||||
_targets_archs = {"arm": "amd64_arm", "arm64": "amd64_arm64", "x64": "amd64", "x86": "amd64_x86"}
|
||||
_targets_lib_folder = {"arm": "arm", "arm64": "arm64", "x86": ""}
|
||||
|
||||
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.
|
||||
|
||||
Args:
|
||||
repository_ctx: The repository context.
|
||||
|
||||
Returns:
|
||||
The path to the Visual C++ build tools installation.
|
||||
"""
|
||||
|
||||
# 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\\%s\\%s\\VC" % (year, edition)
|
||||
for year in (2022, 2019, 2017)
|
||||
for edition in ("Preview", "BuildTools", "Community", "Professional", "Enterprise")
|
||||
] + [
|
||||
"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_newer(repository_ctx, vc_path):
|
||||
"""Check if the installed VS version is Visual Studio 2017 or newer."""
|
||||
|
||||
# For VS 2017 and later, a `Tools` directory should exist under `BAZEL_VC`
|
||||
return repository_ctx.path(vc_path).get_child("Tools").exists
|
||||
|
||||
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_newer(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_newer(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_newer(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_newer(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.
|
||||
|
||||
Args:
|
||||
repository_ctx: The repository context.
|
||||
vc_path: Visual C++ root directory.
|
||||
tool: The name of the tool to find.
|
||||
target_arch: The target architecture (default is "x64").
|
||||
|
||||
Returns:
|
||||
The exact path of the specified build tool in MSVC, or None if not found.
|
||||
"""
|
||||
tool_path = None
|
||||
if _is_vs_2017_or_newer(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 = {
|
||||
"arm": {"CL": "cl.exe", "DUMPBIN": "dumpbin.exe", "LIB": "lib.exe", "LINK": "link.exe"},
|
||||
"arm64": {"CL": "cl.exe", "DUMPBIN": "dumpbin.exe", "LIB": "lib.exe", "LINK": "link.exe"},
|
||||
"x64": {"CL": "cl.exe", "DUMPBIN": "dumpbin.exe", "LIB": "lib.exe", "LINK": "link.exe", "ML": "ml64.exe"},
|
||||
"x86": {"CL": "cl.exe", "DUMPBIN": "dumpbin.exe", "LIB": "lib.exe", "LINK": "link.exe", "ML": "ml.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 _is_support_parse_showincludes(repository_ctx, cl, env):
|
||||
repository_ctx.file(
|
||||
"main.cpp",
|
||||
"#include \"bazel_showincludes.h\"\nint main(){}\n",
|
||||
)
|
||||
repository_ctx.file(
|
||||
"bazel_showincludes.h",
|
||||
"\n",
|
||||
)
|
||||
result = execute(
|
||||
repository_ctx,
|
||||
[cl, "/nologo", "/showIncludes", "/c", "main.cpp", "/out", "main.exe", "/Fo", "main.obj"],
|
||||
# Attempt to force English language. This may fail if the language pack isn't installed.
|
||||
environment = env | {"VSLANG": "1033"},
|
||||
)
|
||||
for file in ["main.cpp", "bazel_showincludes.h", "main.exe", "main.obj"]:
|
||||
execute(repository_ctx, ["cmd", "/C", "del", file], expect_empty_output = True)
|
||||
return any([
|
||||
line.startswith("Note: including file:") and line.endswith("bazel_showincludes.h")
|
||||
for line in result.split("\n")
|
||||
])
|
||||
|
||||
def find_llvm_path(repository_ctx):
|
||||
"""Find LLVM install path.
|
||||
|
||||
Args:
|
||||
repository_ctx: The repository context.
|
||||
|
||||
Returns:
|
||||
The path to the LLVM installation, or None if not found.
|
||||
"""
|
||||
|
||||
# 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.
|
||||
|
||||
Args:
|
||||
repository_ctx: The repository context.
|
||||
llvm_path: The path to the LLVM installation.
|
||||
tool: The name of the tool to find.
|
||||
|
||||
Returns:
|
||||
The exact path of the specified build tool in LLVM, or None if not found.
|
||||
"""
|
||||
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_clang_dir(repository_ctx, llvm_path, clang_version):
|
||||
"""Get the clang installation directory."""
|
||||
|
||||
# The clang_version string format is "X.X.X"
|
||||
clang_dir = llvm_path + "\\lib\\clang\\" + clang_version
|
||||
if repository_ctx.path(clang_dir).exists:
|
||||
return clang_dir
|
||||
|
||||
# Clang 16 changed the install path to use just the major number.
|
||||
clang_major_version = clang_version.split(".")[0]
|
||||
return llvm_path + "\\lib\\clang\\" + clang_major_version
|
||||
|
||||
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, target_arch = "x64", msvc_vars_x64 = None):
|
||||
"""Get the variables we need to populate the MSVC toolchains."""
|
||||
vc_path = find_vc_path(repository_ctx)
|
||||
missing_tools = None
|
||||
|
||||
if not vc_path:
|
||||
repository_ctx.template(
|
||||
"vc_installation_error_" + target_arch + ".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, 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["@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 = {
|
||||
"%{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",
|
||||
"%{msvc_parse_showincludes_" + target_arch + "}": repr(False),
|
||||
}
|
||||
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 = _get_clang_dir(repository_ctx, llvm_path, 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")
|
||||
|
||||
support_parse_showincludes = _is_support_parse_showincludes(repository_ctx, build_tools["CL"], env)
|
||||
if not support_parse_showincludes:
|
||||
auto_configure_warning("""
|
||||
Header pruning has been disabled since Bazel failed to recognize the output of /showIncludes.
|
||||
This can result in unnecessary recompilation.
|
||||
Fix this by installing the English language pack for the Visual Studio installation at {} and run 'bazel sync --configure'.""".format(vc_path))
|
||||
|
||||
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"],
|
||||
"%{msvc_dumpbin_path_" + target_arch + "}": build_tools["DUMPBIN"],
|
||||
"%{msvc_parse_showincludes_" + target_arch + "}": repr(support_parse_showincludes),
|
||||
"%{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["@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_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 + "}": "",
|
||||
"%{clang_cl_parse_showincludes_" + target_arch + "}": repr(False),
|
||||
}
|
||||
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 = _get_clang_dir(repository_ctx, llvm_path, 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",
|
||||
# clang-cl always emits the English language version of the /showIncludes prefix.
|
||||
"%{clang_cl_parse_showincludes_" + target_arch + "}": repr(True),
|
||||
}
|
||||
return clang_cl_vars
|
||||
|
||||
def _get_msvc_deps_scanner_vars(repository_ctx, paths, template_vars, target_arch = "x64"):
|
||||
repository_ctx.template(
|
||||
"msvc_deps_scanner_wrapper_" + target_arch + ".bat",
|
||||
paths["@rules_cc//cc/private/toolchain:msvc_deps_scanner_wrapper.bat.tpl"],
|
||||
{
|
||||
"%{cc}": template_vars["%{msvc_cl_path_" + target_arch + "}"],
|
||||
},
|
||||
)
|
||||
|
||||
return {
|
||||
"%{msvc_deps_scanner_wrapper_path_" + target_arch + "}": "msvc_deps_scanner_wrapper_" + target_arch + ".bat",
|
||||
}
|
||||
|
||||
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",
|
||||
"@rules_cc//cc/private/toolchain:msvc_deps_scanner_wrapper.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_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"))
|
||||
|
||||
template_vars.update(_get_msvc_deps_scanner_vars(repository_ctx, paths, template_vars, "x64"))
|
||||
template_vars.update(_get_msvc_deps_scanner_vars(repository_ctx, paths, template_vars, "x86"))
|
||||
template_vars.update(_get_msvc_deps_scanner_vars(repository_ctx, paths, template_vars, "arm"))
|
||||
template_vars.update(_get_msvc_deps_scanner_vars(repository_ctx, paths, template_vars, "arm64"))
|
||||
repository_ctx.template(
|
||||
"BUILD",
|
||||
paths["@rules_cc//cc/private/toolchain:BUILD.windows.tpl"],
|
||||
template_vars,
|
||||
)
|
||||
|
||||
###
|
||||
# mongodb customization
|
||||
def get_tmp_dir(repository_ctx):
|
||||
return escape_string(_get_temp_env(repository_ctx).replace("\\", "\\\\"))
|
||||
|
||||
###
|
||||
Reference in New Issue
Block a user