mirror of https://github.com/bazelbuild/rules_cc
C++: Move tools/cpp from bazel_tools to rules_cc
Here we are duplicating bazel_tools/tools/cpp. The goal is for the BUILD files in bazel_tools/tools/cpp to have an alias that point to rules_cc. Then later on with the incompatible flag these aliases will no longer be valid. Working towards #8743 RELNOTES:none PiperOrigin-RevId: 264604076 Change-Id: I389702793a1a95b0990dce93577de2b7182e2e6b
This commit is contained in:
parent
624b5d59df
commit
4a1c578fb0
12
WORKSPACE
12
WORKSPACE
|
@ -24,3 +24,15 @@ rules_cc_internal_deps()
|
|||
|
||||
load("//:internal_setup.bzl", "rules_cc_internal_setup")
|
||||
rules_cc_internal_setup()
|
||||
|
||||
# We're pinning to a commit because this project does not have a recent release.
|
||||
# Nothing special about this commit, though.
|
||||
http_archive(
|
||||
name = "com_google_googletest",
|
||||
sha256 = "0fb00ff413f6b9b80ccee44a374ca7a18af7315aea72a43c62f2acd1ca74e9b5",
|
||||
strip_prefix = "googletest-f13bbe2992d188e834339abe6f715b2b2f840a77",
|
||||
urls = [
|
||||
"https://mirror.bazel.build/github.com/google/googletest/archive/f13bbe2992d188e834339abe6f715b2b2f840a77.tar.gz",
|
||||
"https://github.com/google/googletest/archive/f13bbe2992d188e834339abe6f715b2b2f840a77.tar.gz",
|
||||
],
|
||||
)
|
||||
|
|
40
cc/BUILD
40
cc/BUILD
|
@ -1,8 +1,46 @@
|
|||
# Copyright 2018 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.
|
||||
|
||||
package(default_visibility = ["//visibility:public"])
|
||||
|
||||
licenses(["notice"]) # Apache 2.0
|
||||
|
||||
filegroup(
|
||||
name = "all_files_for_testing",
|
||||
srcs = glob(["**"]) + [
|
||||
"//cc/private/rules_impl:srcs",
|
||||
"//cc/private/toolchain:srcs",
|
||||
],
|
||||
)
|
||||
|
||||
exports_files([
|
||||
"defs.bzl",
|
||||
"action_names.bzl",
|
||||
])
|
||||
|
||||
# The toolchain type used to distinguish cc toolchains.
|
||||
alias(
|
||||
name = "toolchain_type",
|
||||
actual = "@bazel_tools//tools/cpp:toolchain_type",
|
||||
)
|
||||
|
||||
exports_files(["defs.bzl"])
|
||||
filegroup(
|
||||
name = "action_names_test_files",
|
||||
testonly = True,
|
||||
srcs = [
|
||||
"BUILD",
|
||||
"action_names.bzl",
|
||||
],
|
||||
visibility = ["//visibility:public"],
|
||||
)
|
||||
|
|
|
@ -0,0 +1,122 @@
|
|||
# Copyright 2018 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.
|
||||
"""Constants for action names used for C++ rules."""
|
||||
|
||||
# Name for the C compilation action.
|
||||
C_COMPILE_ACTION_NAME = "c-compile"
|
||||
|
||||
# Name of the C++ compilation action.
|
||||
CPP_COMPILE_ACTION_NAME = "c++-compile"
|
||||
|
||||
# Name of the linkstamp-compile action.
|
||||
LINKSTAMP_COMPILE_ACTION_NAME = "linkstamp-compile"
|
||||
|
||||
# Name of the action used to compute CC_FLAGS make variable.
|
||||
CC_FLAGS_MAKE_VARIABLE_ACTION_NAME = "cc-flags-make-variable"
|
||||
|
||||
# Name of the C++ module codegen action.
|
||||
CPP_MODULE_CODEGEN_ACTION_NAME = "c++-module-codegen"
|
||||
|
||||
# Name of the C++ header parsing action.
|
||||
CPP_HEADER_PARSING_ACTION_NAME = "c++-header-parsing"
|
||||
|
||||
# Name of the C++ module compile action.
|
||||
CPP_MODULE_COMPILE_ACTION_NAME = "c++-module-compile"
|
||||
|
||||
# Name of the assembler action.
|
||||
ASSEMBLE_ACTION_NAME = "assemble"
|
||||
|
||||
# Name of the assembly preprocessing action.
|
||||
PREPROCESS_ASSEMBLE_ACTION_NAME = "preprocess-assemble"
|
||||
|
||||
# Name of the action producing ThinLto index.
|
||||
LTO_INDEXING_ACTION_NAME = "lto-indexing"
|
||||
|
||||
# Name of the action producing ThinLto index for executable.
|
||||
LTO_INDEX_FOR_EXECUTABLE_ACTION_NAME = "lto-index-for-executable"
|
||||
|
||||
# Name of the action producing ThinLto index for dynamic library.
|
||||
LTO_INDEX_FOR_DYNAMIC_LIBRARY_ACTION_NAME = "lto-index-for-dynamic-library"
|
||||
|
||||
# Name of the action producing ThinLto index for nodeps dynamic library.
|
||||
LTO_INDEX_FOR_NODEPS_DYNAMIC_LIBRARY_ACTION_NAME = "lto-index-for-nodeps-dynamic-library"
|
||||
|
||||
# Name of the action compiling lto bitcodes into native objects.
|
||||
LTO_BACKEND_ACTION_NAME = "lto-backend"
|
||||
|
||||
# Name of the link action producing executable binary.
|
||||
CPP_LINK_EXECUTABLE_ACTION_NAME = "c++-link-executable"
|
||||
|
||||
# Name of the link action producing dynamic library.
|
||||
CPP_LINK_DYNAMIC_LIBRARY_ACTION_NAME = "c++-link-dynamic-library"
|
||||
|
||||
# Name of the link action producing dynamic library that doesn't include it's
|
||||
# transitive dependencies.
|
||||
CPP_LINK_NODEPS_DYNAMIC_LIBRARY_ACTION_NAME = "c++-link-nodeps-dynamic-library"
|
||||
|
||||
# Name of the archiving action producing static library.
|
||||
CPP_LINK_STATIC_LIBRARY_ACTION_NAME = "c++-link-static-library"
|
||||
|
||||
# Name of the action stripping the binary.
|
||||
STRIP_ACTION_NAME = "strip"
|
||||
|
||||
# A string constant for the objc archive action.
|
||||
OBJC_ARCHIVE_ACTION_NAME = "objc-archive"
|
||||
|
||||
# A string constant for the objc compilation action.
|
||||
OBJC_COMPILE_ACTION_NAME = "objc-compile"
|
||||
|
||||
# A string constant for the objc++ compile action.
|
||||
OBJCPP_COMPILE_ACTION_NAME = "objc++-compile"
|
||||
|
||||
# A string constant for the objc executable link action.
|
||||
OBJC_EXECUTABLE_ACTION_NAME = "objc-executable"
|
||||
|
||||
# A string constant for the objc++ executable link action.
|
||||
OBJCPP_EXECUTABLE_ACTION_NAME = "objc++-executable"
|
||||
|
||||
# A string constant for the objc fully-link link action.
|
||||
OBJC_FULLY_LINK_ACTION_NAME = "objc-fully-link"
|
||||
|
||||
# A string constant for the clif actions.
|
||||
CLIF_MATCH_ACTION_NAME = "clif-match"
|
||||
|
||||
ACTION_NAMES = struct(
|
||||
c_compile = C_COMPILE_ACTION_NAME,
|
||||
cpp_compile = CPP_COMPILE_ACTION_NAME,
|
||||
linkstamp_compile = LINKSTAMP_COMPILE_ACTION_NAME,
|
||||
cc_flags_make_variable = CC_FLAGS_MAKE_VARIABLE_ACTION_NAME,
|
||||
cpp_module_codegen = CPP_MODULE_CODEGEN_ACTION_NAME,
|
||||
cpp_header_parsing = CPP_HEADER_PARSING_ACTION_NAME,
|
||||
cpp_module_compile = CPP_MODULE_COMPILE_ACTION_NAME,
|
||||
assemble = ASSEMBLE_ACTION_NAME,
|
||||
preprocess_assemble = PREPROCESS_ASSEMBLE_ACTION_NAME,
|
||||
lto_indexing = LTO_INDEXING_ACTION_NAME,
|
||||
lto_backend = LTO_BACKEND_ACTION_NAME,
|
||||
lto_index_for_executable = LTO_INDEX_FOR_EXECUTABLE_ACTION_NAME,
|
||||
lto_index_for_dynamic_library = LTO_INDEX_FOR_DYNAMIC_LIBRARY_ACTION_NAME,
|
||||
lto_index_for_nodeps_dynamic_library = LTO_INDEX_FOR_NODEPS_DYNAMIC_LIBRARY_ACTION_NAME,
|
||||
cpp_link_executable = CPP_LINK_EXECUTABLE_ACTION_NAME,
|
||||
cpp_link_dynamic_library = CPP_LINK_DYNAMIC_LIBRARY_ACTION_NAME,
|
||||
cpp_link_nodeps_dynamic_library = CPP_LINK_NODEPS_DYNAMIC_LIBRARY_ACTION_NAME,
|
||||
cpp_link_static_library = CPP_LINK_STATIC_LIBRARY_ACTION_NAME,
|
||||
strip = STRIP_ACTION_NAME,
|
||||
objc_archive = OBJC_ARCHIVE_ACTION_NAME,
|
||||
objc_compile = OBJC_COMPILE_ACTION_NAME,
|
||||
objc_executable = OBJC_EXECUTABLE_ACTION_NAME,
|
||||
objc_fully_link = OBJC_FULLY_LINK_ACTION_NAME,
|
||||
objcpp_compile = OBJCPP_COMPILE_ACTION_NAME,
|
||||
objcpp_executable = OBJCPP_EXECUTABLE_ACTION_NAME,
|
||||
clif_match = CLIF_MATCH_ACTION_NAME,
|
||||
)
|
|
@ -14,8 +14,8 @@
|
|||
|
||||
"""Starlark rules for building C++ projects."""
|
||||
|
||||
load("@bazel_tools//tools/cpp:cc_flags_supplier.bzl", _cc_flags_supplier = "cc_flags_supplier")
|
||||
load("@bazel_tools//tools/cpp:compiler_flag.bzl", _compiler_flag = "compiler_flag")
|
||||
load("@rules_cc//cc/private/rules_impl:cc_flags_supplier.bzl", _cc_flags_supplier = "cc_flags_supplier")
|
||||
load("@rules_cc//cc/private/rules_impl:compiler_flag.bzl", _compiler_flag = "compiler_flag")
|
||||
|
||||
_MIGRATION_TAG = "__CC_RULES_MIGRATION_DO_NOT_USE_WILL_BREAK__"
|
||||
|
||||
|
|
|
@ -24,7 +24,7 @@ Returns the current `CcToolchainInfo`.
|
|||
foo = rule(
|
||||
implementation = _foo_impl,
|
||||
attrs = {
|
||||
"_cc_toolchain": attr.label(default = Label("@bazel_tools//tools/cpp:current_cc_toolchain")),
|
||||
"_cc_toolchain": attr.label(default = Label("@rules_cc//cc/private/toolchain:current_cc_toolchain")),
|
||||
},
|
||||
)
|
||||
* When https://github.com/bazelbuild/bazel/issues/7260 **is** flipped, current
|
||||
|
|
|
@ -0,0 +1,14 @@
|
|||
package(default_visibility = ["//visibility:public"])
|
||||
|
||||
licenses(["notice"]) # Apache 2.0
|
||||
|
||||
filegroup(
|
||||
name = "srcs",
|
||||
srcs = glob(
|
||||
["**"],
|
||||
exclude = [
|
||||
".*",
|
||||
"*~",
|
||||
],
|
||||
),
|
||||
)
|
|
@ -0,0 +1,35 @@
|
|||
# Copyright 2018 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.
|
||||
"""Rule that provides the CC_FLAGS Make variable."""
|
||||
|
||||
load("//cc:action_names.bzl", "CC_FLAGS_MAKE_VARIABLE_ACTION_NAME")
|
||||
load("//cc/private/rules_impl:cc_flags_supplier_lib.bzl", "build_cc_flags")
|
||||
load("//cc:toolchain_utils.bzl", "find_cpp_toolchain")
|
||||
|
||||
def _cc_flags_supplier_impl(ctx):
|
||||
cc_toolchain = find_cpp_toolchain(ctx)
|
||||
cc_flags = build_cc_flags(ctx, cc_toolchain, CC_FLAGS_MAKE_VARIABLE_ACTION_NAME)
|
||||
variables = platform_common.TemplateVariableInfo({
|
||||
"CC_FLAGS": cc_flags,
|
||||
})
|
||||
return [variables]
|
||||
|
||||
cc_flags_supplier = rule(
|
||||
implementation = _cc_flags_supplier_impl,
|
||||
attrs = {
|
||||
"_cc_toolchain": attr.label(default = Label("@rules_cc//cc/private/toolchain:current_cc_toolchain")),
|
||||
},
|
||||
toolchains = ["@rules_cc//cc:toolchain_type"],
|
||||
fragments = ["cpp"],
|
||||
)
|
|
@ -0,0 +1,71 @@
|
|||
# Copyright 2018 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.
|
||||
"""Library of functions that provide the CC_FLAGS Make variable."""
|
||||
|
||||
# This should match the logic in CcCommon.computeCcFlags:
|
||||
def build_cc_flags(ctx, cc_toolchain, action_name):
|
||||
"""Determine the value for CC_FLAGS based on the given toolchain."""
|
||||
|
||||
# Get default cc flags from toolchain's make_variables.
|
||||
legacy_cc_flags = cc_common.legacy_cc_flags_make_variable_do_not_use(
|
||||
cc_toolchain = cc_toolchain,
|
||||
)
|
||||
|
||||
# Determine the sysroot flag.
|
||||
sysroot_cc_flags = _from_sysroot(cc_toolchain)
|
||||
|
||||
# Flags from feature config.
|
||||
feature_config_cc_flags = _from_features(ctx, cc_toolchain, action_name)
|
||||
|
||||
# Combine the different sources, but only add the sysroot flag if nothing
|
||||
# else adds sysroot.
|
||||
# If added, it must appear before the feature config flags.
|
||||
cc_flags = []
|
||||
if legacy_cc_flags:
|
||||
cc_flags.append(legacy_cc_flags)
|
||||
if sysroot_cc_flags and not _contains_sysroot(feature_config_cc_flags):
|
||||
cc_flags.append(sysroot_cc_flags)
|
||||
cc_flags.extend(feature_config_cc_flags)
|
||||
|
||||
return " ".join(cc_flags)
|
||||
|
||||
def _contains_sysroot(flags):
|
||||
for flag in flags:
|
||||
if "--sysroot=" in flag:
|
||||
return True
|
||||
return False
|
||||
|
||||
def _from_sysroot(cc_toolchain):
|
||||
sysroot = cc_toolchain.sysroot
|
||||
if sysroot:
|
||||
return "--sysroot=%s" % sysroot
|
||||
else:
|
||||
return None
|
||||
|
||||
def _from_features(ctx, cc_toolchain, action_name):
|
||||
feature_configuration = cc_common.configure_features(
|
||||
ctx = ctx,
|
||||
cc_toolchain = cc_toolchain,
|
||||
requested_features = ctx.features,
|
||||
unsupported_features = ctx.disabled_features,
|
||||
)
|
||||
|
||||
variables = cc_common.empty_variables()
|
||||
|
||||
cc_flags = cc_common.get_memory_inefficient_command_line(
|
||||
feature_configuration = feature_configuration,
|
||||
action_name = action_name,
|
||||
variables = variables,
|
||||
)
|
||||
return cc_flags
|
|
@ -0,0 +1,29 @@
|
|||
# Copyright 2018 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.
|
||||
|
||||
"""Rule that allows select() to differentiate between compilers."""
|
||||
|
||||
load("@rules_cc//cc:toolchain_utils.bzl", "find_cpp_toolchain")
|
||||
|
||||
def _compiler_flag_impl(ctx):
|
||||
toolchain = find_cpp_toolchain(ctx)
|
||||
return [config_common.FeatureFlagInfo(value = toolchain.compiler)]
|
||||
|
||||
compiler_flag = rule(
|
||||
implementation = _compiler_flag_impl,
|
||||
attrs = {
|
||||
"_cc_toolchain": attr.label(default = Label("@rules_cc//cc/private/toolchain:current_cc_toolchain")),
|
||||
},
|
||||
toolchains = ["@rules_cc//cc:toolchain_type"],
|
||||
)
|
|
@ -0,0 +1,124 @@
|
|||
# Copyright 2018 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.
|
||||
#
|
||||
package(default_visibility = ["//visibility:public"])
|
||||
|
||||
licenses(["notice"]) # Apache 2.0
|
||||
|
||||
load("//cc:defs.bzl", "cc_flags_supplier", "cc_library", "compiler_flag")
|
||||
|
||||
# It is frequently necessary to constrain platforms based on the cc compiler type.
|
||||
constraint_setting(name = "cc_compiler")
|
||||
|
||||
constraint_value(
|
||||
name = "clang",
|
||||
constraint_setting = ":cc_compiler",
|
||||
)
|
||||
|
||||
constraint_value(
|
||||
name = "gcc",
|
||||
constraint_setting = ":cc_compiler",
|
||||
)
|
||||
|
||||
constraint_value(
|
||||
name = "msvc",
|
||||
constraint_setting = ":cc_compiler",
|
||||
)
|
||||
|
||||
constraint_value(
|
||||
name = "clang-cl",
|
||||
constraint_setting = ":cc_compiler",
|
||||
)
|
||||
|
||||
constraint_value(
|
||||
name = "mingw",
|
||||
constraint_setting = ":cc_compiler",
|
||||
)
|
||||
|
||||
constraint_value(
|
||||
name = "msys",
|
||||
constraint_setting = ":cc_compiler",
|
||||
)
|
||||
|
||||
cc_toolchain_alias(name = "current_cc_toolchain")
|
||||
|
||||
cc_host_toolchain_alias(name = "current_cc_host_toolchain")
|
||||
|
||||
cc_libc_top_alias(name = "current_libc_top")
|
||||
|
||||
cc_library(
|
||||
name = "malloc",
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "grep-includes",
|
||||
srcs = ["grep-includes.sh"],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "empty",
|
||||
srcs = [],
|
||||
)
|
||||
|
||||
# This is the entry point for --crosstool_top. Toolchains are found
|
||||
# by lopping off the name of --crosstool_top and searching for
|
||||
# "cc-compiler-${CPU}" in this BUILD file, where CPU is the target CPU
|
||||
# specified in --cpu.
|
||||
#
|
||||
# This file group should include
|
||||
# * all cc_toolchain targets supported
|
||||
# * all file groups that said cc_toolchain might refer to
|
||||
alias(
|
||||
name = "toolchain",
|
||||
actual = "//external:cc_toolchain",
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "srcs",
|
||||
srcs = glob(["**"]) + [
|
||||
"//cc/private/toolchain/runfiles:srcs",
|
||||
],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "embedded_tools",
|
||||
srcs = glob(["**"]) + [
|
||||
"//cc:action_names.bzl",
|
||||
"//cc/private/toolchain/runfiles:embedded_tools",
|
||||
],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "interface_library_builder",
|
||||
srcs = ["build_interface_so"],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "osx_wrapper",
|
||||
srcs = ["osx_cc_wrapper.sh"],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "link_dynamic_library",
|
||||
srcs = ["link_dynamic_library.sh"],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "lib_cc_configure",
|
||||
srcs = ["lib_cc_configure.bzl"],
|
||||
)
|
||||
|
||||
compiler_flag(name = "compiler")
|
||||
|
||||
cc_flags_supplier(name = "cc_flags")
|
|
@ -0,0 +1,50 @@
|
|||
# Copyright 2018 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.
|
||||
|
||||
package(default_visibility = ["//visibility:public"])
|
||||
|
||||
load(":cc_toolchain_config.bzl", "cc_toolchain_config")
|
||||
|
||||
cc_library(
|
||||
name = "malloc",
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "empty",
|
||||
srcs = [],
|
||||
)
|
||||
|
||||
cc_toolchain_suite(
|
||||
name = "toolchain",
|
||||
toolchains = {
|
||||
"local|local": ":local",
|
||||
"local": ":local",
|
||||
},
|
||||
)
|
||||
|
||||
cc_toolchain(
|
||||
name = "local",
|
||||
toolchain_identifier = "local",
|
||||
toolchain_config = ":local_config",
|
||||
all_files = ":empty",
|
||||
ar_files = ":empty",
|
||||
as_files = ":empty",
|
||||
compiler_files = ":empty",
|
||||
dwp_files = ":empty",
|
||||
linker_files = ":empty",
|
||||
objcopy_files = ":empty",
|
||||
strip_files = ":empty",
|
||||
)
|
||||
|
||||
cc_toolchain_config(name = "local_config")
|
|
@ -0,0 +1,112 @@
|
|||
# Copyright 2018 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.
|
||||
|
||||
# This becomes the BUILD file for @local_config_cc// under FreeBSD.
|
||||
|
||||
package(default_visibility = ["//visibility:public"])
|
||||
|
||||
load(":cc_toolchain_config.bzl", "cc_toolchain_config")
|
||||
load("@rules_cc//cc:defs.bzl", "cc_toolchain_suite", "cc_toolchain", "cc_library")
|
||||
|
||||
cc_library(
|
||||
name = "malloc",
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "empty",
|
||||
srcs = [],
|
||||
)
|
||||
|
||||
# Hardcoded toolchain, legacy behaviour.
|
||||
cc_toolchain_suite(
|
||||
name = "toolchain",
|
||||
toolchains = {
|
||||
"armeabi-v7a|compiler": ":cc-compiler-armeabi-v7a",
|
||||
"freebsd|compiler": ":cc-compiler-freebsd",
|
||||
"armeabi-v7a": ":cc-compiler-armeabi-v7a",
|
||||
"freebsd": ":cc-compiler-freebsd",
|
||||
},
|
||||
)
|
||||
|
||||
cc_toolchain(
|
||||
name = "cc-compiler-freebsd",
|
||||
toolchain_identifier = "local_freebsd",
|
||||
toolchain_config = ":local_freebsd",
|
||||
all_files = ":empty",
|
||||
ar_files = ":empty",
|
||||
as_files = ":empty",
|
||||
compiler_files = ":empty",
|
||||
dwp_files = ":empty",
|
||||
linker_files = ":empty",
|
||||
objcopy_files = ":empty",
|
||||
strip_files = ":empty",
|
||||
supports_param_files = 0,
|
||||
)
|
||||
|
||||
cc_toolchain_config(
|
||||
name = "local_freebsd",
|
||||
cpu = "freebsd",
|
||||
)
|
||||
|
||||
toolchain(
|
||||
name = "cc-toolchain-freebsd",
|
||||
exec_compatible_with = [
|
||||
"@platforms//cpu:x86_64",
|
||||
"@platforms//os:freebsd",
|
||||
],
|
||||
target_compatible_with = [
|
||||
"@platforms//cpu:x86_64",
|
||||
"@platforms//os:freebsd",
|
||||
],
|
||||
toolchain = ":cc-compiler-freebsd",
|
||||
toolchain_type = "@rules_cc//cc:toolchain_type",
|
||||
)
|
||||
|
||||
cc_toolchain(
|
||||
name = "cc-compiler-armeabi-v7a",
|
||||
toolchain_identifier = "stub_armeabi-v7a",
|
||||
toolchain_config = ":stub_armeabi-v7a",
|
||||
all_files = ":empty",
|
||||
ar_files = ":empty",
|
||||
as_files = ":empty",
|
||||
compiler_files = ":empty",
|
||||
dwp_files = ":empty",
|
||||
linker_files = ":empty",
|
||||
objcopy_files = ":empty",
|
||||
strip_files = ":empty",
|
||||
supports_param_files = 0,
|
||||
)
|
||||
|
||||
cc_toolchain_config(
|
||||
name = "stub_armeabi-v7a",
|
||||
cpu = "armeabi-v7a",
|
||||
)
|
||||
|
||||
toolchain(
|
||||
name = "cc-toolchain-armeabi-v7a",
|
||||
exec_compatible_with = [
|
||||
"@platforms//cpu:arm",
|
||||
],
|
||||
target_compatible_with = [
|
||||
"@platforms//cpu:arm",
|
||||
"@platforms//os:android",
|
||||
],
|
||||
toolchain = ":cc-compiler-armeabi-v7a",
|
||||
toolchain_type = "@rules_cc//cc:toolchain_type",
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "link_dynamic_library",
|
||||
srcs = ["link_dynamic_library.sh"],
|
||||
)
|
|
@ -0,0 +1,19 @@
|
|||
load("@local_config_platform//:constraints.bzl", "HOST_CONSTRAINTS")
|
||||
toolchain(
|
||||
name = "cc-toolchain-%{name}",
|
||||
exec_compatible_with = HOST_CONSTRAINTS,
|
||||
target_compatible_with = HOST_CONSTRAINTS,
|
||||
toolchain = "@local_config_cc//:cc-compiler-%{name}",
|
||||
toolchain_type = "@rules_cc//cc:toolchain_type",
|
||||
)
|
||||
|
||||
toolchain(
|
||||
name = "cc-toolchain-armeabi-v7a",
|
||||
exec_compatible_with = HOST_CONSTRAINTS,
|
||||
target_compatible_with = [
|
||||
"@platforms//cpu:arm",
|
||||
"@platforms//os:android",
|
||||
],
|
||||
toolchain = "@local_config_cc//:cc-compiler-armeabi-v7a",
|
||||
toolchain_type = "@rules_cc//cc:toolchain_type",
|
||||
)
|
|
@ -0,0 +1,113 @@
|
|||
# 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.
|
||||
|
||||
# This becomes the BUILD file for @local_config_cc// under non-FreeBSD unixes.
|
||||
|
||||
package(default_visibility = ["//visibility:public"])
|
||||
|
||||
load(":cc_toolchain_config.bzl", "cc_toolchain_config")
|
||||
load(":armeabi_cc_toolchain_config.bzl", "armeabi_cc_toolchain_config")
|
||||
load("@rules_cc//cc:defs.bzl", "cc_toolchain", "cc_toolchain_suite")
|
||||
|
||||
licenses(["notice"]) # Apache 2.0
|
||||
|
||||
cc_library(
|
||||
name = "malloc",
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "empty",
|
||||
srcs = [],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "cc_wrapper",
|
||||
srcs = ["cc_wrapper.sh"],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "compiler_deps",
|
||||
srcs = glob(["extra_tools/**"], allow_empty = True) + ["%{cc_compiler_deps}"],
|
||||
)
|
||||
|
||||
# This is the entry point for --crosstool_top. Toolchains are found
|
||||
# by lopping off the name of --crosstool_top and searching for
|
||||
# the "${CPU}" entry in the toolchains attribute.
|
||||
cc_toolchain_suite(
|
||||
name = "toolchain",
|
||||
toolchains = {
|
||||
"%{name}|%{compiler}": ":cc-compiler-%{name}",
|
||||
"%{name}": ":cc-compiler-%{name}",
|
||||
"armeabi-v7a|compiler": ":cc-compiler-armeabi-v7a",
|
||||
"armeabi-v7a": ":cc-compiler-armeabi-v7a",
|
||||
},
|
||||
)
|
||||
|
||||
cc_toolchain(
|
||||
name = "cc-compiler-%{name}",
|
||||
toolchain_identifier = "%{cc_toolchain_identifier}",
|
||||
toolchain_config = ":%{cc_toolchain_identifier}",
|
||||
all_files = ":compiler_deps",
|
||||
ar_files = ":compiler_deps",
|
||||
as_files = ":compiler_deps",
|
||||
compiler_files = ":compiler_deps",
|
||||
dwp_files = ":empty",
|
||||
linker_files = ":compiler_deps",
|
||||
objcopy_files = ":empty",
|
||||
strip_files = ":empty",
|
||||
supports_param_files = %{supports_param_files},
|
||||
)
|
||||
|
||||
cc_toolchain_config(
|
||||
name = "%{cc_toolchain_identifier}",
|
||||
cpu = "%{target_cpu}",
|
||||
compiler = "%{compiler}",
|
||||
toolchain_identifier = "%{cc_toolchain_identifier}",
|
||||
host_system_name = "%{host_system_name}",
|
||||
target_system_name = "%{target_system_name}",
|
||||
target_libc = "%{target_libc}",
|
||||
abi_version = "%{abi_version}",
|
||||
abi_libc_version = "%{abi_libc_version}",
|
||||
cxx_builtin_include_directories = [%{cxx_builtin_include_directories}],
|
||||
tool_paths = {%{tool_paths}},
|
||||
compile_flags = [%{compile_flags}],
|
||||
opt_compile_flags = [%{opt_compile_flags}],
|
||||
dbg_compile_flags = [%{dbg_compile_flags}],
|
||||
cxx_flags = [%{cxx_flags}],
|
||||
link_flags = [%{link_flags}],
|
||||
link_libs = [%{link_libs}],
|
||||
opt_link_flags = [%{opt_link_flags}],
|
||||
unfiltered_compile_flags = [%{unfiltered_compile_flags}],
|
||||
coverage_compile_flags = [%{coverage_compile_flags}],
|
||||
coverage_link_flags = [%{coverage_link_flags}],
|
||||
supports_start_end_lib = %{supports_start_end_lib},
|
||||
)
|
||||
|
||||
# Android tooling requires a default toolchain for the armeabi-v7a cpu.
|
||||
cc_toolchain(
|
||||
name = "cc-compiler-armeabi-v7a",
|
||||
toolchain_identifier = "stub_armeabi-v7a",
|
||||
toolchain_config = ":stub_armeabi-v7a",
|
||||
all_files = ":empty",
|
||||
ar_files = ":empty",
|
||||
as_files = ":empty",
|
||||
compiler_files = ":empty",
|
||||
dwp_files = ":empty",
|
||||
linker_files = ":empty",
|
||||
objcopy_files = ":empty",
|
||||
strip_files = ":empty",
|
||||
supports_param_files = 1,
|
||||
)
|
||||
|
||||
armeabi_cc_toolchain_config(name = "stub_armeabi-v7a")
|
|
@ -0,0 +1,301 @@
|
|||
# Copyright 2018 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.
|
||||
|
||||
# This becomes the BUILD file for @local_config_cc// under Windows.
|
||||
|
||||
package(default_visibility = ["//visibility:public"])
|
||||
|
||||
load("@rules_cc//cc:defs.bzl", "cc_toolchain", "cc_toolchain_suite", "cc_library")
|
||||
load(":windows_cc_toolchain_config.bzl", "cc_toolchain_config")
|
||||
load(":armeabi_cc_toolchain_config.bzl", "armeabi_cc_toolchain_config")
|
||||
cc_library(
|
||||
name = "malloc",
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "empty",
|
||||
srcs = [],
|
||||
)
|
||||
|
||||
# Hardcoded toolchain, legacy behaviour.
|
||||
cc_toolchain_suite(
|
||||
name = "toolchain",
|
||||
toolchains = {
|
||||
"armeabi-v7a|compiler": ":cc-compiler-armeabi-v7a",
|
||||
"x64_windows|msvc-cl": ":cc-compiler-x64_windows",
|
||||
"x64_windows|msys-gcc": ":cc-compiler-x64_windows_msys",
|
||||
"x64_windows|mingw-gcc": ":cc-compiler-x64_windows_mingw",
|
||||
"x64_windows|clang-cl": ":cc-compiler-x64_windows-clang-cl",
|
||||
"x64_windows_msys": ":cc-compiler-x64_windows_msys",
|
||||
"x64_windows": ":cc-compiler-x64_windows",
|
||||
"armeabi-v7a": ":cc-compiler-armeabi-v7a",
|
||||
},
|
||||
)
|
||||
|
||||
cc_toolchain(
|
||||
name = "cc-compiler-x64_windows_msys",
|
||||
toolchain_identifier = "msys_x64",
|
||||
toolchain_config = ":msys_x64",
|
||||
all_files = ":empty",
|
||||
ar_files = ":empty",
|
||||
as_files = ":empty",
|
||||
compiler_files = ":empty",
|
||||
dwp_files = ":empty",
|
||||
linker_files = ":empty",
|
||||
objcopy_files = ":empty",
|
||||
strip_files = ":empty",
|
||||
supports_param_files = 1,
|
||||
)
|
||||
|
||||
cc_toolchain_config(
|
||||
name = "msys_x64",
|
||||
cpu = "x64_windows",
|
||||
compiler = "msys-gcc",
|
||||
host_system_name = "local",
|
||||
target_system_name = "local",
|
||||
target_libc = "msys",
|
||||
abi_version = "local",
|
||||
abi_libc_version = "local",
|
||||
cxx_builtin_include_directories = [%{cxx_builtin_include_directories}],
|
||||
tool_paths = {%{tool_paths}},
|
||||
tool_bin_path = "%{tool_bin_path}",
|
||||
dbg_mode_debug_flag = "%{dbg_mode_debug_flag}",
|
||||
fastbuild_mode_debug_flag = "%{fastbuild_mode_debug_flag}",
|
||||
)
|
||||
|
||||
toolchain(
|
||||
name = "cc-toolchain-x64_windows_msys",
|
||||
exec_compatible_with = [
|
||||
"@platforms//cpu:x86_64",
|
||||
"@platforms//os:windows",
|
||||
"@rules_cc//cc/private/toolchain:msys",
|
||||
],
|
||||
target_compatible_with = [
|
||||
"@platforms//cpu:x86_64",
|
||||
"@platforms//os:windows",
|
||||
],
|
||||
toolchain = ":cc-compiler-x64_windows_msys",
|
||||
toolchain_type = "@rules_cc//cc:toolchain_type",
|
||||
)
|
||||
|
||||
cc_toolchain(
|
||||
name = "cc-compiler-x64_windows_mingw",
|
||||
toolchain_identifier = "msys_x64_mingw",
|
||||
toolchain_config = ":msys_x64_mingw",
|
||||
all_files = ":empty",
|
||||
ar_files = ":empty",
|
||||
as_files = ":empty",
|
||||
compiler_files = ":empty",
|
||||
dwp_files = ":empty",
|
||||
linker_files = ":empty",
|
||||
objcopy_files = ":empty",
|
||||
strip_files = ":empty",
|
||||
supports_param_files = 0,
|
||||
)
|
||||
|
||||
cc_toolchain_config(
|
||||
name = "msys_x64_mingw",
|
||||
cpu = "x64_windows",
|
||||
compiler = "mingw-gcc",
|
||||
host_system_name = "local",
|
||||
target_system_name = "local",
|
||||
target_libc = "mingw",
|
||||
abi_version = "local",
|
||||
abi_libc_version = "local",
|
||||
tool_bin_path = "%{mingw_tool_bin_path}",
|
||||
cxx_builtin_include_directories = [%{mingw_cxx_builtin_include_directories}],
|
||||
tool_paths = {%{mingw_tool_paths}},
|
||||
dbg_mode_debug_flag = "%{dbg_mode_debug_flag}",
|
||||
fastbuild_mode_debug_flag = "%{fastbuild_mode_debug_flag}",
|
||||
)
|
||||
|
||||
toolchain(
|
||||
name = "cc-toolchain-x64_windows_mingw",
|
||||
exec_compatible_with = [
|
||||
"@platforms//cpu:x86_64",
|
||||
"@platforms//os:windows",
|
||||
"@rules_cc//cc/private/toolchain:mingw",
|
||||
],
|
||||
target_compatible_with = [
|
||||
"@platforms//cpu:x86_64",
|
||||
"@platforms//os:windows",
|
||||
],
|
||||
toolchain = ":cc-compiler-x64_windows_mingw",
|
||||
toolchain_type = "@rules_cc//cc:toolchain_type",
|
||||
)
|
||||
|
||||
cc_toolchain(
|
||||
name = "cc-compiler-x64_windows",
|
||||
toolchain_identifier = "msvc_x64",
|
||||
toolchain_config = ":msvc_x64",
|
||||
all_files = ":empty",
|
||||
ar_files = ":empty",
|
||||
as_files = ":empty",
|
||||
compiler_files = ":empty",
|
||||
dwp_files = ":empty",
|
||||
linker_files = ":empty",
|
||||
objcopy_files = ":empty",
|
||||
strip_files = ":empty",
|
||||
supports_param_files = 1,
|
||||
)
|
||||
|
||||
cc_toolchain_config(
|
||||
name = "msvc_x64",
|
||||
cpu = "x64_windows",
|
||||
compiler = "msvc-cl",
|
||||
host_system_name = "local",
|
||||
target_system_name = "local",
|
||||
target_libc = "msvcrt",
|
||||
abi_version = "local",
|
||||
abi_libc_version = "local",
|
||||
toolchain_identifier = "msvc_x64",
|
||||
msvc_env_tmp = "%{msvc_env_tmp}",
|
||||
msvc_env_path = "%{msvc_env_path}",
|
||||
msvc_env_include = "%{msvc_env_include}",
|
||||
msvc_env_lib = "%{msvc_env_lib}",
|
||||
msvc_cl_path = "%{msvc_cl_path}",
|
||||
msvc_ml_path = "%{msvc_ml_path}",
|
||||
msvc_link_path = "%{msvc_link_path}",
|
||||
msvc_lib_path = "%{msvc_lib_path}",
|
||||
cxx_builtin_include_directories = [%{msvc_cxx_builtin_include_directories}],
|
||||
tool_paths = {
|
||||
"ar": "%{msvc_lib_path}",
|
||||
"ml": "%{msvc_ml_path}",
|
||||
"cpp": "%{msvc_cl_path}",
|
||||
"gcc": "%{msvc_cl_path}",
|
||||
"gcov": "wrapper/bin/msvc_nop.bat",
|
||||
"ld": "%{msvc_link_path}",
|
||||
"nm": "wrapper/bin/msvc_nop.bat",
|
||||
"objcopy": "wrapper/bin/msvc_nop.bat",
|
||||
"objdump": "wrapper/bin/msvc_nop.bat",
|
||||
"strip": "wrapper/bin/msvc_nop.bat",
|
||||
},
|
||||
default_link_flags = ["/MACHINE:X64"],
|
||||
dbg_mode_debug_flag = "%{dbg_mode_debug_flag}",
|
||||
fastbuild_mode_debug_flag = "%{fastbuild_mode_debug_flag}",
|
||||
)
|
||||
|
||||
toolchain(
|
||||
name = "cc-toolchain-x64_windows",
|
||||
exec_compatible_with = [
|
||||
"@platforms//cpu:x86_64",
|
||||
"@platforms//os:windows",
|
||||
],
|
||||
target_compatible_with = [
|
||||
"@platforms//cpu:x86_64",
|
||||
"@platforms//os:windows",
|
||||
],
|
||||
toolchain = ":cc-compiler-x64_windows",
|
||||
toolchain_type = "@rules_cc//cc:toolchain_type",
|
||||
)
|
||||
|
||||
cc_toolchain(
|
||||
name = "cc-compiler-x64_windows-clang-cl",
|
||||
toolchain_identifier = "clang_cl_x64",
|
||||
toolchain_config = ":clang_cl_x64",
|
||||
all_files = ":empty",
|
||||
ar_files = ":empty",
|
||||
as_files = ":empty",
|
||||
compiler_files = ":empty",
|
||||
dwp_files = ":empty",
|
||||
linker_files = ":empty",
|
||||
objcopy_files = ":empty",
|
||||
strip_files = ":empty",
|
||||
supports_param_files = 1,
|
||||
)
|
||||
|
||||
cc_toolchain_config(
|
||||
name = "clang_cl_x64",
|
||||
cpu = "x64_windows",
|
||||
compiler = "clang-cl",
|
||||
host_system_name = "local",
|
||||
target_system_name = "local",
|
||||
target_libc = "msvcrt",
|
||||
abi_version = "local",
|
||||
abi_libc_version = "local",
|
||||
toolchain_identifier = "clang_cl_x64",
|
||||
msvc_env_tmp = "%{clang_cl_env_tmp}",
|
||||
msvc_env_path = "%{clang_cl_env_path}",
|
||||
msvc_env_include = "%{clang_cl_env_include}",
|
||||
msvc_env_lib = "%{clang_cl_env_lib}",
|
||||
msvc_cl_path = "%{clang_cl_cl_path}",
|
||||
msvc_ml_path = "%{clang_cl_ml_path}",
|
||||
msvc_link_path = "%{clang_cl_link_path}",
|
||||
msvc_lib_path = "%{clang_cl_lib_path}",
|
||||
cxx_builtin_include_directories = [%{clang_cl_cxx_builtin_include_directories}],
|
||||
tool_paths = {
|
||||
"ar": "%{clang_cl_lib_path}",
|
||||
"ml": "%{clang_cl_ml_path}",
|
||||
"cpp": "%{clang_cl_cl_path}",
|
||||
"gcc": "%{clang_cl_cl_path}",
|
||||
"gcov": "wrapper/bin/msvc_nop.bat",
|
||||
"ld": "%{clang_cl_link_path}",
|
||||
"nm": "wrapper/bin/msvc_nop.bat",
|
||||
"objcopy": "wrapper/bin/msvc_nop.bat",
|
||||
"objdump": "wrapper/bin/msvc_nop.bat",
|
||||
"strip": "wrapper/bin/msvc_nop.bat",
|
||||
},
|
||||
default_link_flags = ["/MACHINE:X64", "/DEFAULTLIB:clang_rt.builtins-x86_64.lib"],
|
||||
dbg_mode_debug_flag = "%{clang_cl_dbg_mode_debug_flag}",
|
||||
fastbuild_mode_debug_flag = "%{clang_cl_fastbuild_mode_debug_flag}",
|
||||
)
|
||||
|
||||
toolchain(
|
||||
name = "cc-toolchain-x64_windows-clang-cl",
|
||||
exec_compatible_with = [
|
||||
"@platforms//cpu:x86_64",
|
||||
"@platforms//os:windows",
|
||||
"@rules_cc//cc/private/toolchain:clang-cl",
|
||||
],
|
||||
target_compatible_with = [
|
||||
"@platforms//cpu:x86_64",
|
||||
"@platforms//os:windows",
|
||||
],
|
||||
toolchain = ":cc-compiler-x64_windows-clang-cl",
|
||||
toolchain_type = "@rules_cc//cc:toolchain_type",
|
||||
)
|
||||
|
||||
cc_toolchain(
|
||||
name = "cc-compiler-armeabi-v7a",
|
||||
toolchain_identifier = "stub_armeabi-v7a",
|
||||
toolchain_config = ":stub_armeabi-v7a",
|
||||
all_files = ":empty",
|
||||
ar_files = ":empty",
|
||||
as_files = ":empty",
|
||||
compiler_files = ":empty",
|
||||
dwp_files = ":empty",
|
||||
linker_files = ":empty",
|
||||
objcopy_files = ":empty",
|
||||
strip_files = ":empty",
|
||||
supports_param_files = 1,
|
||||
)
|
||||
|
||||
armeabi_cc_toolchain_config(name = "stub_armeabi-v7a")
|
||||
|
||||
toolchain(
|
||||
name = "cc-toolchain-armeabi-v7a",
|
||||
exec_compatible_with = [
|
||||
],
|
||||
target_compatible_with = [
|
||||
"@platforms//cpu:arm",
|
||||
"@platforms//os:android",
|
||||
],
|
||||
toolchain = ":cc-compiler-armeabi-v7a",
|
||||
toolchain_type = "@rules_cc//cc:toolchain_type",
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "link_dynamic_library",
|
||||
srcs = ["link_dynamic_library.sh"],
|
||||
)
|
|
@ -0,0 +1,82 @@
|
|||
# Copyright 2019 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.
|
||||
|
||||
"""A Starlark cc_toolchain configuration rule"""
|
||||
|
||||
load(
|
||||
"@rules_cc//cc/private/toolchain:cc_toolchain_config_lib.bzl",
|
||||
"feature",
|
||||
"tool_path",
|
||||
)
|
||||
|
||||
def _impl(ctx):
|
||||
toolchain_identifier = "stub_armeabi-v7a"
|
||||
host_system_name = "armeabi-v7a"
|
||||
target_system_name = "armeabi-v7a"
|
||||
target_cpu = "armeabi-v7a"
|
||||
target_libc = "armeabi-v7a"
|
||||
compiler = "compiler"
|
||||
abi_version = "armeabi-v7a"
|
||||
abi_libc_version = "armeabi-v7a"
|
||||
cc_target_os = None
|
||||
builtin_sysroot = None
|
||||
action_configs = []
|
||||
|
||||
supports_pic_feature = feature(name = "supports_pic", enabled = True)
|
||||
supports_dynamic_linker_feature = feature(name = "supports_dynamic_linker", enabled = True)
|
||||
features = [supports_dynamic_linker_feature, supports_pic_feature]
|
||||
|
||||
cxx_builtin_include_directories = []
|
||||
artifact_name_patterns = []
|
||||
make_variables = []
|
||||
|
||||
tool_paths = [
|
||||
tool_path(name = "ar", path = "/bin/false"),
|
||||
tool_path(name = "compat-ld", path = "/bin/false"),
|
||||
tool_path(name = "cpp", path = "/bin/false"),
|
||||
tool_path(name = "dwp", path = "/bin/false"),
|
||||
tool_path(name = "gcc", path = "/bin/false"),
|
||||
tool_path(name = "gcov", path = "/bin/false"),
|
||||
tool_path(name = "ld", path = "/bin/false"),
|
||||
tool_path(name = "nm", path = "/bin/false"),
|
||||
tool_path(name = "objcopy", path = "/bin/false"),
|
||||
tool_path(name = "objdump", path = "/bin/false"),
|
||||
tool_path(name = "strip", path = "/bin/false"),
|
||||
]
|
||||
|
||||
return cc_common.create_cc_toolchain_config_info(
|
||||
ctx = ctx,
|
||||
features = features,
|
||||
action_configs = action_configs,
|
||||
artifact_name_patterns = artifact_name_patterns,
|
||||
cxx_builtin_include_directories = cxx_builtin_include_directories,
|
||||
toolchain_identifier = toolchain_identifier,
|
||||
host_system_name = host_system_name,
|
||||
target_system_name = target_system_name,
|
||||
target_cpu = target_cpu,
|
||||
target_libc = target_libc,
|
||||
compiler = compiler,
|
||||
abi_version = abi_version,
|
||||
abi_libc_version = abi_libc_version,
|
||||
tool_paths = tool_paths,
|
||||
make_variables = make_variables,
|
||||
builtin_sysroot = builtin_sysroot,
|
||||
cc_target_os = cc_target_os,
|
||||
)
|
||||
|
||||
armeabi_cc_toolchain_config = rule(
|
||||
implementation = _impl,
|
||||
attrs = {},
|
||||
provides = [CcToolchainConfigInfo],
|
||||
)
|
|
@ -0,0 +1,8 @@
|
|||
#!/bin/bash
|
||||
|
||||
if [[ $# != 2 ]]; then
|
||||
echo "Usage: $0 <so> <interface so>" 1>&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
exec cp $1 $2
|
|
@ -0,0 +1,181 @@
|
|||
# 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.
|
||||
"""Rules for configuring the C++ toolchain (experimental)."""
|
||||
|
||||
load("@rules_cc//cc/private/toolchain:windows_cc_configure.bzl", "configure_windows_toolchain")
|
||||
load("@rules_cc//cc/private/toolchain:osx_cc_configure.bzl", "configure_osx_toolchain")
|
||||
load("@rules_cc//cc/private/toolchain:unix_cc_configure.bzl", "configure_unix_toolchain")
|
||||
load(
|
||||
"@rules_cc//cc/private/toolchain:lib_cc_configure.bzl",
|
||||
"get_cpu_value",
|
||||
"resolve_labels",
|
||||
)
|
||||
load("@bazel_tools//tools/osx:xcode_configure.bzl", "run_xcode_locator")
|
||||
|
||||
def _generate_cpp_only_build_file(repository_ctx, cpu_value, paths):
|
||||
repository_ctx.template(
|
||||
"BUILD",
|
||||
paths["@rules_cc//cc/private/toolchain:BUILD.toolchains.tpl"],
|
||||
{"%{name}": cpu_value},
|
||||
)
|
||||
|
||||
def cc_autoconf_toolchains_impl(repository_ctx):
|
||||
"""Generate BUILD file with 'toolchain' targets for the local host C++ toolchain.
|
||||
|
||||
Args:
|
||||
repository_ctx: repository context
|
||||
"""
|
||||
paths = resolve_labels(repository_ctx, [
|
||||
"@rules_cc//cc/private/toolchain:BUILD.toolchains.tpl",
|
||||
"@bazel_tools//tools/osx/crosstool:BUILD.toolchains",
|
||||
"@bazel_tools//tools/osx/crosstool:osx_archs.bzl",
|
||||
"@bazel_tools//tools/osx:xcode_locator.m",
|
||||
])
|
||||
env = repository_ctx.os.environ
|
||||
cpu_value = get_cpu_value(repository_ctx)
|
||||
|
||||
# Should we try to find C++ toolchain at all? If not, we don't have to generate toolchains for C++ at all.
|
||||
should_detect_cpp_toolchain = "BAZEL_DO_NOT_DETECT_CPP_TOOLCHAIN" not in env or env["BAZEL_DO_NOT_DETECT_CPP_TOOLCHAIN"] != "1"
|
||||
|
||||
# Should we unconditionally *not* use xcode? If so, we don't have to run Xcode locator ever.
|
||||
should_use_cpp_only_toolchain = "BAZEL_USE_CPP_ONLY_TOOLCHAIN" in env and env["BAZEL_USE_CPP_ONLY_TOOLCHAIN"] == "1"
|
||||
|
||||
# Should we unconditionally use xcode? If so, we don't have to run Xcode locator now.
|
||||
should_use_xcode = "BAZEL_USE_XCODE_TOOLCHAIN" in env and env["BAZEL_USE_XCODE_TOOLCHAIN"] == "1"
|
||||
|
||||
if not should_detect_cpp_toolchain:
|
||||
repository_ctx.file("BUILD", "# C++ toolchain autoconfiguration was disabled by BAZEL_DO_NOT_DETECT_CPP_TOOLCHAIN env variable.")
|
||||
elif cpu_value == "darwin" and not should_use_cpp_only_toolchain:
|
||||
xcode_toolchains = []
|
||||
|
||||
# Only detect xcode if the user didn't tell us it will be there.
|
||||
if not should_use_xcode:
|
||||
# TODO(#6926): Unify C++ and ObjC toolchains so we don't have to run xcode locator to generate toolchain targets.
|
||||
# And also so we don't have to keep this code in sync with @rules_cc//cc/private/toolchain:osx_cc_configure.bzl.
|
||||
(xcode_toolchains, _xcodeloc_err) = run_xcode_locator(
|
||||
repository_ctx,
|
||||
paths["@bazel_tools//tools/osx:xcode_locator.m"],
|
||||
)
|
||||
|
||||
if should_use_xcode or xcode_toolchains:
|
||||
repository_ctx.symlink(paths["@bazel_tools//tools/osx/crosstool:BUILD.toolchains"], "BUILD")
|
||||
repository_ctx.symlink(paths["@bazel_tools//tools/osx/crosstool:osx_archs.bzl"], "osx_archs.bzl")
|
||||
else:
|
||||
_generate_cpp_only_build_file(repository_ctx, cpu_value, paths)
|
||||
else:
|
||||
_generate_cpp_only_build_file(repository_ctx, cpu_value, paths)
|
||||
|
||||
cc_autoconf_toolchains = repository_rule(
|
||||
environ = [
|
||||
"BAZEL_USE_CPP_ONLY_TOOLCHAIN",
|
||||
"BAZEL_DO_NOT_DETECT_CPP_TOOLCHAIN",
|
||||
],
|
||||
implementation = cc_autoconf_toolchains_impl,
|
||||
)
|
||||
|
||||
def cc_autoconf_impl(repository_ctx, overriden_tools = dict()):
|
||||
"""Generate BUILD file with 'cc_toolchain' targets for the local host C++ toolchain.
|
||||
|
||||
Args:
|
||||
repository_ctx: repository context
|
||||
overriden_tools: dict of tool paths to use instead of autoconfigured tools
|
||||
"""
|
||||
|
||||
env = repository_ctx.os.environ
|
||||
cpu_value = get_cpu_value(repository_ctx)
|
||||
if "BAZEL_DO_NOT_DETECT_CPP_TOOLCHAIN" in env and env["BAZEL_DO_NOT_DETECT_CPP_TOOLCHAIN"] == "1":
|
||||
paths = resolve_labels(repository_ctx, [
|
||||
"@rules_cc//cc/private/toolchain:BUILD.empty",
|
||||
"@rules_cc//cc/private/toolchain:empty_cc_toolchain_config.bzl",
|
||||
])
|
||||
repository_ctx.symlink(paths["@rules_cc//cc/private/toolchain:empty_cc_toolchain_config.bzl"], "cc_toolchain_config.bzl")
|
||||
repository_ctx.symlink(paths("@rules_cc//cc/private/toolchain:BUILD.empty"), "BUILD")
|
||||
elif cpu_value == "freebsd":
|
||||
paths = resolve_labels(repository_ctx, [
|
||||
"@rules_cc//cc/private/toolchain:BUILD.static.freebsd",
|
||||
"@rules_cc//cc/private/toolchain:freebsd_cc_toolchain_config.bzl",
|
||||
])
|
||||
|
||||
# This is defaulting to a static crosstool, we should eventually
|
||||
# autoconfigure this platform too. Theorically, FreeBSD should be
|
||||
# straightforward to add but we cannot run it in a docker container so
|
||||
# skipping until we have proper tests for FreeBSD.
|
||||
repository_ctx.symlink(paths["@rules_cc//cc/private/toolchain:freebsd_cc_toolchain_config.bzl"], "cc_toolchain_config.bzl")
|
||||
repository_ctx.symlink(paths["@rules_cc//cc/private/toolchain:BUILD.static.freebsd"], "BUILD")
|
||||
elif cpu_value == "x64_windows":
|
||||
# TODO(ibiryukov): overriden_tools are only supported in configure_unix_toolchain.
|
||||
# We might want to add that to Windows too(at least for msys toolchain).
|
||||
configure_windows_toolchain(repository_ctx)
|
||||
elif (cpu_value == "darwin" and
|
||||
("BAZEL_USE_CPP_ONLY_TOOLCHAIN" not in env or env["BAZEL_USE_CPP_ONLY_TOOLCHAIN"] != "1")):
|
||||
configure_osx_toolchain(repository_ctx, overriden_tools)
|
||||
else:
|
||||
configure_unix_toolchain(repository_ctx, cpu_value, overriden_tools)
|
||||
|
||||
MSVC_ENVVARS = [
|
||||
"BAZEL_VC",
|
||||
"BAZEL_VC_FULL_VERSION",
|
||||
"BAZEL_VS",
|
||||
"BAZEL_WINSDK_FULL_VERSION",
|
||||
"VS90COMNTOOLS",
|
||||
"VS100COMNTOOLS",
|
||||
"VS110COMNTOOLS",
|
||||
"VS120COMNTOOLS",
|
||||
"VS140COMNTOOLS",
|
||||
"VS150COMNTOOLS",
|
||||
"VS160COMNTOOLS",
|
||||
"TMP",
|
||||
"TEMP",
|
||||
]
|
||||
|
||||
cc_autoconf = repository_rule(
|
||||
environ = [
|
||||
"ABI_LIBC_VERSION",
|
||||
"ABI_VERSION",
|
||||
"BAZEL_COMPILER",
|
||||
"BAZEL_HOST_SYSTEM",
|
||||
"BAZEL_CXXOPTS",
|
||||
"BAZEL_LINKOPTS",
|
||||
"BAZEL_LINKLIBS",
|
||||
"BAZEL_PYTHON",
|
||||
"BAZEL_SH",
|
||||
"BAZEL_TARGET_CPU",
|
||||
"BAZEL_TARGET_LIBC",
|
||||
"BAZEL_TARGET_SYSTEM",
|
||||
"BAZEL_USE_CPP_ONLY_TOOLCHAIN",
|
||||
"BAZEL_USE_XCODE_TOOLCHAIN",
|
||||
"BAZEL_DO_NOT_DETECT_CPP_TOOLCHAIN",
|
||||
"BAZEL_USE_LLVM_NATIVE_COVERAGE",
|
||||
"BAZEL_LLVM",
|
||||
"USE_CLANG_CL",
|
||||
"CC",
|
||||
"CC_CONFIGURE_DEBUG",
|
||||
"CC_TOOLCHAIN_NAME",
|
||||
"CPLUS_INCLUDE_PATH",
|
||||
"GCOV",
|
||||
"HOMEBREW_RUBY_PATH",
|
||||
"SYSTEMROOT",
|
||||
] + MSVC_ENVVARS,
|
||||
implementation = cc_autoconf_impl,
|
||||
)
|
||||
|
||||
def cc_configure():
|
||||
"""A C++ configuration rules that generate the crosstool file."""
|
||||
cc_autoconf_toolchains(name = "local_config_cc_toolchains")
|
||||
cc_autoconf(name = "local_config_cc")
|
||||
native.bind(name = "cc_toolchain", actual = "@local_config_cc//:toolchain")
|
||||
native.register_toolchains(
|
||||
# Use register_toolchain's target pattern expansion to register all toolchains in the package.
|
||||
"@local_config_cc_toolchains//:all",
|
||||
)
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,542 @@
|
|||
# Copyright 2018 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.
|
||||
|
||||
""" A library of functions creating structs for CcToolchainConfigInfo."""
|
||||
|
||||
def _check_is_none_or_right_type(obj, obj_of_right_type, parameter_name, method_name):
|
||||
if obj != None:
|
||||
_check_right_type(obj, obj_of_right_type, parameter_name, method_name)
|
||||
|
||||
def _check_right_type(obj, obj_of_right_type, parameter_name, method_name):
|
||||
if type(obj) != type(obj_of_right_type):
|
||||
fail("{} parameter of {} should be a {}, found {}."
|
||||
.format(parameter_name, method_name, type(obj_of_right_type), type(obj)))
|
||||
|
||||
def _check_is_nonempty_string(obj, parameter_name, method_name):
|
||||
_check_right_type(obj, "", parameter_name, method_name)
|
||||
if obj == "":
|
||||
fail("{} parameter of {} must be a nonempty string."
|
||||
.format(parameter_name, method_name))
|
||||
|
||||
def _check_is_nonempty_list(obj, parameter_name, method_name):
|
||||
_check_right_type(obj, [], parameter_name, method_name)
|
||||
if len(obj) == 0:
|
||||
fail("{} parameter of {} must be a nonempty list."
|
||||
.format(parameter_name, method_name))
|
||||
|
||||
EnvEntryInfo = provider(fields = ["key", "value", "type_name"])
|
||||
|
||||
def env_entry(key, value):
|
||||
""" A key/value pair to be added as an environment variable.
|
||||
|
||||
The returned EnvEntry provider finds its use in EnvSet creation through
|
||||
the env_entries parameter of env_set(); EnvSet groups environment variables
|
||||
that need to be expanded for specific actions.
|
||||
The value of this pair is expanded in the same way as is described in
|
||||
flag_group. The key remains an unexpanded string literal.
|
||||
|
||||
Args:
|
||||
key: a string literal representing the name of the variable.
|
||||
value: the value to be expanded.
|
||||
|
||||
Returns:
|
||||
An EnvEntryInfo provider.
|
||||
"""
|
||||
_check_is_nonempty_string(key, "key", "env_entry")
|
||||
_check_is_nonempty_string(value, "value", "env_entry")
|
||||
return EnvEntryInfo(key = key, value = value, type_name = "env_entry")
|
||||
|
||||
VariableWithValueInfo = provider(fields = ["name", "value", "type_name"])
|
||||
|
||||
def variable_with_value(name, value):
|
||||
""" Represents equality check between a variable and a certain value.
|
||||
|
||||
The returned provider finds its use through flag_group.expand_if_equal,
|
||||
making the expansion of the flag_group conditional on the value of the
|
||||
variable.
|
||||
|
||||
Args:
|
||||
name: name of the variable.
|
||||
value: the value the variable should be compared against.
|
||||
|
||||
Returns:
|
||||
A VariableWithValueInfo provider.
|
||||
"""
|
||||
_check_is_nonempty_string(name, "name", "variable_with_value")
|
||||
_check_is_nonempty_string(value, "value", "variable_with_value")
|
||||
return VariableWithValueInfo(
|
||||
name = name,
|
||||
value = value,
|
||||
type_name = "variable_with_value",
|
||||
)
|
||||
|
||||
MakeVariableInfo = provider(fields = ["name", "value", "type_name"])
|
||||
|
||||
def make_variable(name, value):
|
||||
""" A make variable that is made accessible to rules."""
|
||||
_check_is_nonempty_string(name, "name", "make_variable")
|
||||
_check_is_nonempty_string(value, "value", "make_variable")
|
||||
return MakeVariableInfo(
|
||||
name = name,
|
||||
value = value,
|
||||
type_name = "make_variable",
|
||||
)
|
||||
|
||||
FeatureSetInfo = provider(fields = ["features", "type_name"])
|
||||
|
||||
def feature_set(features = []):
|
||||
""" A set of features.
|
||||
|
||||
Used to support logical 'and' when specifying feature requirements in a
|
||||
feature.
|
||||
|
||||
Args:
|
||||
features: A list of unordered feature names.
|
||||
|
||||
Returns:
|
||||
A FeatureSetInfo provider.
|
||||
"""
|
||||
_check_right_type(features, [], "features", "feature_set")
|
||||
return FeatureSetInfo(features = features, type_name = "feature_set")
|
||||
|
||||
WithFeatureSetInfo = provider(fields = ["features", "not_features", "type_name"])
|
||||
|
||||
def with_feature_set(features = [], not_features = []):
|
||||
""" A set of positive and negative features.
|
||||
|
||||
This stanza will evaluate to true when every 'feature' is enabled, and
|
||||
every 'not_feature' is not enabled.
|
||||
|
||||
Args:
|
||||
features: A list of feature names that need to be enabled.
|
||||
not_features: A list of feature names that need to not be enabled.
|
||||
|
||||
Returns:
|
||||
A WithFeatureSetInfo provider.
|
||||
"""
|
||||
_check_right_type(features, [], "features", "with_feature_set")
|
||||
_check_right_type(not_features, [], "not_features", "with_feature_set")
|
||||
return WithFeatureSetInfo(
|
||||
features = features,
|
||||
not_features = not_features,
|
||||
type_name = "with_feature_set",
|
||||
)
|
||||
|
||||
EnvSetInfo = provider(fields = ["actions", "env_entries", "with_features", "type_name"])
|
||||
|
||||
def env_set(actions, env_entries = [], with_features = []):
|
||||
""" Groups a set of environment variables to apply for certain actions.
|
||||
|
||||
EnvSet providers are passed to feature() and action_config(), to be applied to
|
||||
the actions they are specified for.
|
||||
|
||||
Args:
|
||||
actions: A list of actions this env set applies to; each env set must
|
||||
specify at least one action.
|
||||
env_entries: A list of EnvEntry - the environment variables applied
|
||||
via this env set.
|
||||
with_features: A list of feature sets defining when this env set gets
|
||||
applied. The env set will be applied when any one of the feature
|
||||
sets evaluate to true. (That is, when when every 'feature' is
|
||||
enabled, and every 'not_feature' is not enabled.)
|
||||
If 'with_features' is omitted, the env set will be applied
|
||||
unconditionally for every action specified.
|
||||
|
||||
Returns:
|
||||
An EnvSetInfo provider.
|
||||
"""
|
||||
_check_is_nonempty_list(actions, "actions", "env_set")
|
||||
_check_right_type(env_entries, [], "env_entries", "env_set")
|
||||
_check_right_type(with_features, [], "with_features", "env_set")
|
||||
return EnvSetInfo(
|
||||
actions = actions,
|
||||
env_entries = env_entries,
|
||||
with_features = with_features,
|
||||
type_name = "env_set",
|
||||
)
|
||||
|
||||
FlagGroupInfo = provider(fields = [
|
||||
"flags",
|
||||
"flag_groups",
|
||||
"iterate_over",
|
||||
"expand_if_available",
|
||||
"expand_if_not_available",
|
||||
"expand_if_true",
|
||||
"expand_if_false",
|
||||
"expand_if_equal",
|
||||
"type_name",
|
||||
])
|
||||
|
||||
def flag_group(
|
||||
flags = [],
|
||||
flag_groups = [],
|
||||
iterate_over = None,
|
||||
expand_if_available = None,
|
||||
expand_if_not_available = None,
|
||||
expand_if_true = None,
|
||||
expand_if_false = None,
|
||||
expand_if_equal = None):
|
||||
""" A group of flags. Supports parametrization via variable expansion.
|
||||
|
||||
To expand a variable of list type, flag_group has to be annotated with
|
||||
`iterate_over` message. Then all nested flags or flag_groups will be
|
||||
expanded repeatedly for each element of the list.
|
||||
For example:
|
||||
flag_group(
|
||||
iterate_over = 'include_path',
|
||||
flags = ['-I', '%{include_path}'],
|
||||
)
|
||||
... will get expanded to -I /to/path1 -I /to/path2 ... for each
|
||||
include_path /to/pathN.
|
||||
|
||||
To expand a variable of structure type, use dot-notation, e.g.:
|
||||
flag_group(
|
||||
iterate_over = "libraries_to_link",
|
||||
flag_groups = [
|
||||
flag_group(
|
||||
iterate_over = "libraries_to_link.libraries",
|
||||
flags = ["-L%{libraries_to_link.libraries.directory}"],
|
||||
)
|
||||
]
|
||||
)
|
||||
|
||||
Flag groups can be nested; if they are, the flag group must only contain
|
||||
other flag groups (no flags) so the order is unambiguously specified.
|
||||
In order to expand a variable of nested lists, 'iterate_over' can be used.
|
||||
For example:
|
||||
flag_group (
|
||||
iterate_over = 'object_files',
|
||||
flag_groups = [
|
||||
flag_group (
|
||||
flags = ['--start-lib'],
|
||||
),
|
||||
flag_group (
|
||||
iterate_over = 'object_files',
|
||||
flags = ['%{object_files}'],
|
||||
),
|
||||
flag_group (
|
||||
flags = ['--end-lib'],
|
||||
)
|
||||
]
|
||||
)
|
||||
... will get expanded to
|
||||
--start-lib a1.o a2.o ... --end-lib --start-lib b1.o b2.o .. --end-lib
|
||||
with %{object_files} being a variable of nested list type
|
||||
[['a1.o', 'a2.o', ...], ['b1.o', 'b2.o', ...], ...].
|
||||
|
||||
Args:
|
||||
flags: a string list, representing flags. Only one of flags and
|
||||
flag_groups can be set, as to avoid ambiguity.
|
||||
flag_groups: a list of FlagGroup entries. Only one of flags and
|
||||
flag_groups can be set, as to avoid ambiguity.
|
||||
iterate_over: a string, representing a variable of list type.
|
||||
expand_if_available: A build variable that needs to be available
|
||||
in order to expand the flag_group.
|
||||
expand_if_not_available: A build variable that needs to be
|
||||
unavailable in order for this flag_group to be expanded.
|
||||
expand_if_true: if set, this variable needs to evaluate to True in
|
||||
order for the flag_group to be expanded.
|
||||
expand_if_false: if set, this variable needs to evalate to False in
|
||||
order for the flag_group to be expanded.
|
||||
expand_if_equal: a VariableWithValue, the flag_group is expanded in
|
||||
case of equality.
|
||||
|
||||
Returns:
|
||||
A FlagGroupInfo provider.
|
||||
"""
|
||||
|
||||
_check_right_type(flags, [], "flags", "flag_group")
|
||||
_check_right_type(flag_groups, [], "flag_groups", "flag_group")
|
||||
if len(flags) > 0 and len(flag_groups) > 0:
|
||||
fail("flag_group must not contain both a flag and another flag_group.")
|
||||
if len(flags) == 0 and len(flag_groups) == 0:
|
||||
fail("flag_group must contain either a list of flags or a list of flag_groups.")
|
||||
_check_is_none_or_right_type(expand_if_true, "string", "expand_if_true", "flag_group")
|
||||
_check_is_none_or_right_type(expand_if_false, "string", "expand_if_false", "flag_group")
|
||||
_check_is_none_or_right_type(expand_if_available, "string", "expand_if_available", "flag_group")
|
||||
_check_is_none_or_right_type(
|
||||
expand_if_not_available,
|
||||
"string",
|
||||
"expand_if_not_available",
|
||||
"flag_group",
|
||||
)
|
||||
_check_is_none_or_right_type(iterate_over, "string", "iterate_over", "flag_group")
|
||||
|
||||
return FlagGroupInfo(
|
||||
flags = flags,
|
||||
flag_groups = flag_groups,
|
||||
iterate_over = iterate_over,
|
||||
expand_if_available = expand_if_available,
|
||||
expand_if_not_available = expand_if_not_available,
|
||||
expand_if_true = expand_if_true,
|
||||
expand_if_false = expand_if_false,
|
||||
expand_if_equal = expand_if_equal,
|
||||
type_name = "flag_group",
|
||||
)
|
||||
|
||||
FlagSetInfo = provider(fields = [
|
||||
"actions",
|
||||
"with_features",
|
||||
"flag_groups",
|
||||
"type_name",
|
||||
])
|
||||
|
||||
def flag_set(
|
||||
actions = [],
|
||||
with_features = [],
|
||||
flag_groups = []):
|
||||
""" A set of flags to be expanded in the command line for specific actions.
|
||||
|
||||
Args:
|
||||
actions: The actions this flag set applies to; each flag set must
|
||||
specify at least one action.
|
||||
with_features: A list of feature sets defining when this flag set gets
|
||||
applied. The flag set will be applied when any one of the feature
|
||||
sets evaluate to true. (That is, when when every 'feature' is
|
||||
enabled, and every 'not_feature' is not enabled.)
|
||||
If 'with_feature' is omitted, the flag set will be applied
|
||||
unconditionally for every action specified.
|
||||
flag_groups: A FlagGroup list - the flags applied via this flag set.
|
||||
|
||||
Returns:
|
||||
A FlagSetInfo provider.
|
||||
"""
|
||||
_check_right_type(actions, [], "actions", "flag_set")
|
||||
_check_right_type(with_features, [], "with_features", "flag_set")
|
||||
_check_right_type(flag_groups, [], "flag_groups", "flag_set")
|
||||
return FlagSetInfo(
|
||||
actions = actions,
|
||||
with_features = with_features,
|
||||
flag_groups = flag_groups,
|
||||
type_name = "flag_set",
|
||||
)
|
||||
|
||||
FeatureInfo = provider(fields = [
|
||||
"name",
|
||||
"enabled",
|
||||
"flag_sets",
|
||||
"env_sets",
|
||||
"requires",
|
||||
"implies",
|
||||
"provides",
|
||||
"type_name",
|
||||
])
|
||||
|
||||
def feature(
|
||||
name,
|
||||
enabled = False,
|
||||
flag_sets = [],
|
||||
env_sets = [],
|
||||
requires = [],
|
||||
implies = [],
|
||||
provides = []):
|
||||
""" Contains all flag specifications for one feature.
|
||||
|
||||
Args:
|
||||
name: The feature's name. It is possible to introduce a feature without
|
||||
a change to Bazel by adding a 'feature' section to the toolchain
|
||||
and adding the corresponding string as feature in the BUILD file.
|
||||
enabled: If 'True', this feature is enabled unless a rule type
|
||||
explicitly marks it as unsupported.
|
||||
flag_sets: A FlagSet list - If the given feature is enabled, the flag
|
||||
sets will be applied for the actions are specified for.
|
||||
env_sets: an EnvSet list - If the given feature is enabled, the env
|
||||
sets will be applied for the actions they are specified for.
|
||||
requires: A list of feature sets defining when this feature is
|
||||
supported by the toolchain. The feature is supported if any of the
|
||||
feature sets fully apply, that is, when all features of a feature
|
||||
set are enabled.
|
||||
If 'requires' is omitted, the feature is supported independently of
|
||||
which other features are enabled.
|
||||
Use this for example to filter flags depending on the build mode
|
||||
enabled (opt / fastbuild / dbg).
|
||||
implies: A string list of features or action configs that are
|
||||
automatically enabled when this feature is enabled. If any of the
|
||||
implied features or action configs cannot be enabled, this feature
|
||||
will (silently) not be enabled either.
|
||||
provides: A list of names this feature conflicts with.
|
||||
A feature cannot be enabled if:
|
||||
- 'provides' contains the name of a different feature or action
|
||||
config that we want to enable.
|
||||
- 'provides' contains the same value as a 'provides' in a
|
||||
different feature or action config that we want to enable.
|
||||
Use this in order to ensure that incompatible features cannot be
|
||||
accidentally activated at the same time, leading to hard to
|
||||
diagnose compiler errors.
|
||||
|
||||
Returns:
|
||||
A FeatureInfo provider.
|
||||
"""
|
||||
_check_right_type(enabled, True, "enabled", "feature")
|
||||
_check_right_type(flag_sets, [], "flag_sets", "feature")
|
||||
_check_right_type(env_sets, [], "env_sets", "feature")
|
||||
_check_right_type(requires, [], "requires", "feature")
|
||||
_check_right_type(provides, [], "provides", "feature")
|
||||
_check_right_type(implies, [], "implies", "feature")
|
||||
return FeatureInfo(
|
||||
name = name,
|
||||
enabled = enabled,
|
||||
flag_sets = flag_sets,
|
||||
env_sets = env_sets,
|
||||
requires = requires,
|
||||
implies = implies,
|
||||
provides = provides,
|
||||
type_name = "feature",
|
||||
)
|
||||
|
||||
ToolPathInfo = provider(fields = ["name", "path", "type_name"])
|
||||
|
||||
def tool_path(name, path):
|
||||
""" Tool locations.
|
||||
|
||||
Args:
|
||||
name: Name of the tool.
|
||||
path: Location of the tool; Can be absolute path (in case of non hermetic
|
||||
toolchain), or path relative to the cc_toolchain's package.
|
||||
|
||||
Returns:
|
||||
A ToolPathInfo provider.
|
||||
|
||||
Deprecated:
|
||||
Prefer specifying an ActionConfig for the action that needs the tool.
|
||||
TODO(b/27903698) migrate to ActionConfig.
|
||||
"""
|
||||
_check_is_nonempty_string(name, "name", "tool_path")
|
||||
_check_is_nonempty_string(path, "path", "tool_path")
|
||||
return ToolPathInfo(name = name, path = path, type_name = "tool_path")
|
||||
|
||||
ToolInfo = provider(fields = ["path", "with_features", "execution_requirements", "type_name"])
|
||||
|
||||
def tool(path, with_features = [], execution_requirements = []):
|
||||
""" Describes a tool associated with a crosstool action config.
|
||||
|
||||
Args:
|
||||
path: Location of the tool; Can be absolute path (in case of non hermetic
|
||||
toolchain), or path relative to the cc_toolchain's package.
|
||||
with_features: A list of feature sets defining when this tool is
|
||||
applicable. The tool will used when any one of the feature sets
|
||||
evaluate to true. (That is, when when every 'feature' is enabled,
|
||||
and every 'not_feature' is not enabled.)
|
||||
If 'with_feature' is omitted, the tool will apply for any feature
|
||||
configuration.
|
||||
execution_requirements: Requirements on the execution environment for
|
||||
the execution of this tool, to be passed as out-of-band "hints" to
|
||||
the execution backend.
|
||||
Ex. "requires-darwin"
|
||||
|
||||
Returns:
|
||||
A ToolInfo provider.
|
||||
"""
|
||||
_check_is_nonempty_string(path, "path", "tool")
|
||||
_check_right_type(with_features, [], "with_features", "tool")
|
||||
_check_right_type(execution_requirements, [], "execution_requirements", "tool")
|
||||
return ToolInfo(
|
||||
path = path,
|
||||
with_features = with_features,
|
||||
execution_requirements = execution_requirements,
|
||||
type_name = "tool",
|
||||
)
|
||||
|
||||
ActionConfigInfo = provider(fields = [
|
||||
"config_name",
|
||||
"action_name",
|
||||
"enabled",
|
||||
"tools",
|
||||
"flag_sets",
|
||||
"implies",
|
||||
"type_name",
|
||||
])
|
||||
|
||||
def action_config(
|
||||
action_name,
|
||||
enabled = False,
|
||||
tools = [],
|
||||
flag_sets = [],
|
||||
implies = []):
|
||||
""" Configuration of a Bazel action.
|
||||
|
||||
An action config corresponds to a Bazel action, and allows selection of
|
||||
a tool based on activated features.
|
||||
Action config activation occurs by the same semantics as features: a
|
||||
feature can 'require' or 'imply' an action config in the same way that it
|
||||
would another feature.
|
||||
|
||||
Args:
|
||||
action_name: The name of the Bazel action that this config applies to,
|
||||
ex. 'c-compile' or 'c-module-compile'.
|
||||
enabled: If 'True', this action is enabled unless a rule type
|
||||
explicitly marks it as unsupported.
|
||||
tools: The tool applied to the action will be the first Tool with a
|
||||
feature set that matches the feature configuration. An error will
|
||||
be thrown if no tool matches a provided feature configuration - for
|
||||
that reason, it's a good idea to provide a default tool with an
|
||||
empty feature set.
|
||||
flag_sets: If the given action config is enabled, the flag sets will be
|
||||
applied to the corresponding action.
|
||||
implies: A list of features or action configs that are automatically
|
||||
enabled when this action config is enabled. If any of the implied
|
||||
features or action configs cannot be enabled, this action config
|
||||
will (silently) not be enabled either.
|
||||
|
||||
Returns:
|
||||
An ActionConfigInfo provider.
|
||||
"""
|
||||
_check_is_nonempty_string(action_name, "name", "action_config")
|
||||
_check_right_type(enabled, True, "enabled", "action_config")
|
||||
_check_right_type(tools, [], "tools", "action_config")
|
||||
_check_right_type(flag_sets, [], "flag_sets", "action_config")
|
||||
_check_right_type(implies, [], "implies", "action_config")
|
||||
return ActionConfigInfo(
|
||||
action_name = action_name,
|
||||
enabled = enabled,
|
||||
tools = tools,
|
||||
flag_sets = flag_sets,
|
||||
implies = implies,
|
||||
type_name = "action_config",
|
||||
)
|
||||
|
||||
ArtifactNamePatternInfo = provider(fields = [
|
||||
"category_name",
|
||||
"prefix",
|
||||
"extension",
|
||||
"type_name",
|
||||
])
|
||||
|
||||
def artifact_name_pattern(category_name, prefix, extension):
|
||||
""" The name for an artifact of a given category of input or output artifacts to an action.
|
||||
|
||||
Args:
|
||||
category_name: The category of artifacts that this selection applies
|
||||
to. This field is compared against a list of categories defined
|
||||
in bazel. Example categories include "linked_output" or
|
||||
"debug_symbols". An error is thrown if no category is matched.
|
||||
prefix: The prefix for creating the artifact for this selection.
|
||||
Together with the extension it is used to create an artifact name
|
||||
based on the target name.
|
||||
extension: The extension for creating the artifact for this selection.
|
||||
Together with the prefix it is used to create an artifact name
|
||||
based on the target name.
|
||||
|
||||
Returns:
|
||||
An ArtifactNamePatternInfo provider
|
||||
"""
|
||||
_check_is_nonempty_string(category_name, "category_name", "artifact_name_pattern")
|
||||
_check_is_none_or_right_type(prefix, "", "prefix", "artifact_name_pattern")
|
||||
_check_is_none_or_right_type(extension, "", "extension", "artifact_name_pattern")
|
||||
return ArtifactNamePatternInfo(
|
||||
category_name = category_name,
|
||||
prefix = prefix,
|
||||
extension = extension,
|
||||
type_name = "artifact_name_pattern",
|
||||
)
|
|
@ -0,0 +1,24 @@
|
|||
:: Copyright 2019 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.
|
||||
|
||||
@echo OFF
|
||||
|
||||
echo. 1>&2
|
||||
echo The target you are compiling requires the Clang compiler. 1>&2
|
||||
echo Bazel couldn't find a valid Clang installation on your machine. 1>&2
|
||||
%{clang_error_message}
|
||||
echo Please check your installation following https://docs.bazel.build/versions/master/windows.html#using 1>&2
|
||||
echo. 1>&2
|
||||
|
||||
exit /b 1
|
|
@ -0,0 +1,15 @@
|
|||
// Copyright 2017 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.
|
||||
|
||||
int main() {}
|
|
@ -0,0 +1,42 @@
|
|||
# Copyright 2019 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.
|
||||
|
||||
"""A fake C++ toolchain configuration rule"""
|
||||
|
||||
def _impl(ctx):
|
||||
out = ctx.actions.declare_file(ctx.label.name)
|
||||
ctx.actions.write(out, "Fake executable")
|
||||
return [
|
||||
cc_common.create_cc_toolchain_config_info(
|
||||
ctx = ctx,
|
||||
toolchain_identifier = "local_linux",
|
||||
host_system_name = "local",
|
||||
target_system_name = "local",
|
||||
target_cpu = "local",
|
||||
target_libc = "local",
|
||||
compiler = "compiler",
|
||||
abi_version = "local",
|
||||
abi_libc_version = "local",
|
||||
),
|
||||
DefaultInfo(
|
||||
executable = out,
|
||||
),
|
||||
]
|
||||
|
||||
cc_toolchain_config = rule(
|
||||
implementation = _impl,
|
||||
attrs = {},
|
||||
provides = [CcToolchainConfigInfo],
|
||||
executable = True,
|
||||
)
|
|
@ -0,0 +1,307 @@
|
|||
# Copyright 2019 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.
|
||||
|
||||
"""A Starlark cc_toolchain configuration rule for freebsd."""
|
||||
|
||||
load(
|
||||
"@rules_cc//cc/private/toolchain:cc_toolchain_config_lib.bzl",
|
||||
"action_config",
|
||||
"feature",
|
||||
"flag_group",
|
||||
"flag_set",
|
||||
"tool",
|
||||
"tool_path",
|
||||
"with_feature_set",
|
||||
)
|
||||
load("@rules_cc//cc:action_names.bzl", "ACTION_NAMES")
|
||||
|
||||
all_compile_actions = [
|
||||
ACTION_NAMES.c_compile,
|
||||
ACTION_NAMES.cpp_compile,
|
||||
ACTION_NAMES.linkstamp_compile,
|
||||
ACTION_NAMES.assemble,
|
||||
ACTION_NAMES.preprocess_assemble,
|
||||
ACTION_NAMES.cpp_header_parsing,
|
||||
ACTION_NAMES.cpp_module_compile,
|
||||
ACTION_NAMES.cpp_module_codegen,
|
||||
ACTION_NAMES.clif_match,
|
||||
ACTION_NAMES.lto_backend,
|
||||
]
|
||||
|
||||
all_cpp_compile_actions = [
|
||||
ACTION_NAMES.cpp_compile,
|
||||
ACTION_NAMES.linkstamp_compile,
|
||||
ACTION_NAMES.cpp_header_parsing,
|
||||
ACTION_NAMES.cpp_module_compile,
|
||||
ACTION_NAMES.cpp_module_codegen,
|
||||
ACTION_NAMES.clif_match,
|
||||
]
|
||||
|
||||
all_link_actions = [
|
||||
ACTION_NAMES.cpp_link_executable,
|
||||
ACTION_NAMES.cpp_link_dynamic_library,
|
||||
ACTION_NAMES.cpp_link_nodeps_dynamic_library,
|
||||
]
|
||||
|
||||
def _impl(ctx):
|
||||
cpu = ctx.attr.cpu
|
||||
compiler = "compiler"
|
||||
toolchain_identifier = "local_freebsd" if cpu == "freebsd" else "stub_armeabi-v7a"
|
||||
host_system_name = "local" if cpu == "freebsd" else "armeabi-v7a"
|
||||
target_system_name = "local" if cpu == "freebsd" else "armeabi-v7a"
|
||||
target_libc = "local" if cpu == "freebsd" else "armeabi-v7a"
|
||||
abi_version = "local" if cpu == "freebsd" else "armeabi-v7a"
|
||||
abi_libc_version = "local" if cpu == "freebsd" else "armeabi-v7a"
|
||||
|
||||
objcopy_embed_data_action = action_config(
|
||||
action_name = "objcopy_embed_data",
|
||||
enabled = True,
|
||||
tools = [tool(path = "/usr/bin/objcopy")],
|
||||
)
|
||||
|
||||
action_configs = [objcopy_embed_data_action] if cpu == "freebsd" else []
|
||||
|
||||
default_link_flags_feature = feature(
|
||||
name = "default_link_flags",
|
||||
enabled = True,
|
||||
flag_sets = [
|
||||
flag_set(
|
||||
actions = all_link_actions,
|
||||
flag_groups = [
|
||||
flag_group(
|
||||
flags = [
|
||||
"-lstdc++",
|
||||
"-Wl,-z,relro,-z,now",
|
||||
"-no-canonical-prefixes",
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
flag_set(
|
||||
actions = all_link_actions,
|
||||
flag_groups = [flag_group(flags = ["-Wl,--gc-sections"])],
|
||||
with_features = [with_feature_set(features = ["opt"])],
|
||||
),
|
||||
],
|
||||
)
|
||||
|
||||
unfiltered_compile_flags_feature = feature(
|
||||
name = "unfiltered_compile_flags",
|
||||
enabled = True,
|
||||
flag_sets = [
|
||||
flag_set(
|
||||
actions = all_compile_actions,
|
||||
flag_groups = [
|
||||
flag_group(
|
||||
flags = [
|
||||
"-no-canonical-prefixes",
|
||||
"-Wno-builtin-macro-redefined",
|
||||
"-D__DATE__=\"redacted\"",
|
||||
"-D__TIMESTAMP__=\"redacted\"",
|
||||
"-D__TIME__=\"redacted\"",
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
)
|
||||
|
||||
supports_pic_feature = feature(name = "supports_pic", enabled = True)
|
||||
|
||||
default_compile_flags_feature = feature(
|
||||
name = "default_compile_flags",
|
||||
enabled = True,
|
||||
flag_sets = [
|
||||
flag_set(
|
||||
actions = all_compile_actions,
|
||||
flag_groups = [
|
||||
flag_group(
|
||||
flags = [
|
||||
"-U_FORTIFY_SOURCE",
|
||||
"-D_FORTIFY_SOURCE=1",
|
||||
"-fstack-protector",
|
||||
"-Wall",
|
||||
"-fno-omit-frame-pointer",
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
flag_set(
|
||||
actions = all_compile_actions,
|
||||
flag_groups = [flag_group(flags = ["-g"])],
|
||||
with_features = [with_feature_set(features = ["dbg"])],
|
||||
),
|
||||
flag_set(
|
||||
actions = all_compile_actions,
|
||||
flag_groups = [
|
||||
flag_group(
|
||||
flags = [
|
||||
"-g0",
|
||||
"-O2",
|
||||
"-DNDEBUG",
|
||||
"-ffunction-sections",
|
||||
"-fdata-sections",
|
||||
],
|
||||
),
|
||||
],
|
||||
with_features = [with_feature_set(features = ["opt"])],
|
||||
),
|
||||
flag_set(
|
||||
actions = all_cpp_compile_actions + [ACTION_NAMES.lto_backend],
|
||||
flag_groups = [flag_group(flags = ["-std=c++0x"])],
|
||||
),
|
||||
],
|
||||
)
|
||||
|
||||
opt_feature = feature(name = "opt")
|
||||
|
||||
supports_dynamic_linker_feature = feature(name = "supports_dynamic_linker", enabled = True)
|
||||
|
||||
objcopy_embed_flags_feature = feature(
|
||||
name = "objcopy_embed_flags",
|
||||
enabled = True,
|
||||
flag_sets = [
|
||||
flag_set(
|
||||
actions = ["objcopy_embed_data"],
|
||||
flag_groups = [flag_group(flags = ["-I", "binary"])],
|
||||
),
|
||||
],
|
||||
)
|
||||
|
||||
dbg_feature = feature(name = "dbg")
|
||||
|
||||
user_compile_flags_feature = feature(
|
||||
name = "user_compile_flags",
|
||||
enabled = True,
|
||||
flag_sets = [
|
||||
flag_set(
|
||||
actions = all_compile_actions,
|
||||
flag_groups = [
|
||||
flag_group(
|
||||
flags = ["%{user_compile_flags}"],
|
||||
iterate_over = "user_compile_flags",
|
||||
expand_if_available = "user_compile_flags",
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
)
|
||||
|
||||
sysroot_feature = feature(
|
||||
name = "sysroot",
|
||||
enabled = True,
|
||||
flag_sets = [
|
||||
flag_set(
|
||||
actions = [
|
||||
ACTION_NAMES.c_compile,
|
||||
ACTION_NAMES.cpp_compile,
|
||||
ACTION_NAMES.linkstamp_compile,
|
||||
ACTION_NAMES.preprocess_assemble,
|
||||
ACTION_NAMES.cpp_header_parsing,
|
||||
ACTION_NAMES.cpp_module_compile,
|
||||
ACTION_NAMES.cpp_module_codegen,
|
||||
ACTION_NAMES.clif_match,
|
||||
ACTION_NAMES.lto_backend,
|
||||
] + all_link_actions,
|
||||
flag_groups = [
|
||||
flag_group(
|
||||
flags = ["--sysroot=%{sysroot}"],
|
||||
expand_if_available = "sysroot",
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
)
|
||||
|
||||
if cpu == "freebsd":
|
||||
features = [
|
||||
default_compile_flags_feature,
|
||||
default_link_flags_feature,
|
||||
supports_dynamic_linker_feature,
|
||||
supports_pic_feature,
|
||||
objcopy_embed_flags_feature,
|
||||
opt_feature,
|
||||
dbg_feature,
|
||||
user_compile_flags_feature,
|
||||
sysroot_feature,
|
||||
unfiltered_compile_flags_feature,
|
||||
]
|
||||
else:
|
||||
features = [supports_dynamic_linker_feature, supports_pic_feature]
|
||||
|
||||
if (cpu == "freebsd"):
|
||||
cxx_builtin_include_directories = ["/usr/lib/clang", "/usr/local/include", "/usr/include"]
|
||||
else:
|
||||
cxx_builtin_include_directories = []
|
||||
|
||||
if cpu == "freebsd":
|
||||
tool_paths = [
|
||||
tool_path(name = "ar", path = "/usr/bin/ar"),
|
||||
tool_path(name = "compat-ld", path = "/usr/bin/ld"),
|
||||
tool_path(name = "cpp", path = "/usr/bin/cpp"),
|
||||
tool_path(name = "dwp", path = "/usr/bin/dwp"),
|
||||
tool_path(name = "gcc", path = "/usr/bin/clang"),
|
||||
tool_path(name = "gcov", path = "/usr/bin/gcov"),
|
||||
tool_path(name = "ld", path = "/usr/bin/ld"),
|
||||
tool_path(name = "nm", path = "/usr/bin/nm"),
|
||||
tool_path(name = "objcopy", path = "/usr/bin/objcopy"),
|
||||
tool_path(name = "objdump", path = "/usr/bin/objdump"),
|
||||
tool_path(name = "strip", path = "/usr/bin/strip"),
|
||||
]
|
||||
else:
|
||||
tool_paths = [
|
||||
tool_path(name = "ar", path = "/bin/false"),
|
||||
tool_path(name = "compat-ld", path = "/bin/false"),
|
||||
tool_path(name = "cpp", path = "/bin/false"),
|
||||
tool_path(name = "dwp", path = "/bin/false"),
|
||||
tool_path(name = "gcc", path = "/bin/false"),
|
||||
tool_path(name = "gcov", path = "/bin/false"),
|
||||
tool_path(name = "ld", path = "/bin/false"),
|
||||
tool_path(name = "nm", path = "/bin/false"),
|
||||
tool_path(name = "objcopy", path = "/bin/false"),
|
||||
tool_path(name = "objdump", path = "/bin/false"),
|
||||
tool_path(name = "strip", path = "/bin/false"),
|
||||
]
|
||||
|
||||
out = ctx.actions.declare_file(ctx.label.name)
|
||||
ctx.actions.write(out, "Fake executable")
|
||||
return [
|
||||
cc_common.create_cc_toolchain_config_info(
|
||||
ctx = ctx,
|
||||
features = features,
|
||||
action_configs = action_configs,
|
||||
cxx_builtin_include_directories = cxx_builtin_include_directories,
|
||||
toolchain_identifier = toolchain_identifier,
|
||||
host_system_name = host_system_name,
|
||||
target_system_name = target_system_name,
|
||||
target_cpu = cpu,
|
||||
target_libc = target_libc,
|
||||
compiler = compiler,
|
||||
abi_version = abi_version,
|
||||
abi_libc_version = abi_libc_version,
|
||||
tool_paths = tool_paths,
|
||||
),
|
||||
DefaultInfo(
|
||||
executable = out,
|
||||
),
|
||||
]
|
||||
|
||||
cc_toolchain_config = rule(
|
||||
implementation = _impl,
|
||||
attrs = {
|
||||
"cpu": attr.string(mandatory = True),
|
||||
},
|
||||
provides = [CcToolchainConfigInfo],
|
||||
executable = True,
|
||||
)
|
|
@ -0,0 +1,19 @@
|
|||
#!/bin/bash
|
||||
#
|
||||
# Copyright 2018 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.
|
||||
#
|
||||
# TODO(bazel-team): Support include scanning and grep-includes in Bazel
|
||||
echo "grep-includes is not supported by Bazel"
|
||||
exit 1
|
|
@ -0,0 +1,219 @@
|
|||
# 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."""
|
||||
|
||||
def resolve_labels(repository_ctx, labels):
|
||||
"""Resolves a collection of labels to their paths.
|
||||
|
||||
Label resolution can cause the evaluation of Skylark 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" ]
|
||||
|
||||
Delimeter 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 Skylark 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"
|
||||
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!"""
|
||||
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)
|
||||
|
||||
def which(repository_ctx, cmd, default = None):
|
||||
"""A wrapper around repository_ctx.which() to provide a fallback value. Doesn't %-escape the value!"""
|
||||
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!"""
|
||||
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):
|
||||
"""Execute a command, return stdout if succeed and throw an error if it fails. Doesn't %-escape the result!"""
|
||||
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 not stripped_stdout:
|
||||
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!"""
|
||||
os_name = repository_ctx.os.name.lower()
|
||||
if os_name.startswith("mac os"):
|
||||
return "darwin"
|
||||
if os_name.find("freebsd") != -1:
|
||||
return "freebsd"
|
||||
if os_name.find("windows") != -1:
|
||||
return "x64_windows"
|
||||
|
||||
# Use uname to figure out whether we are on x86_32 or x86_64
|
||||
result = repository_ctx.execute(["uname", "-m"])
|
||||
if result.stdout.strip() in ["power", "ppc64le", "ppc", "ppc64"]:
|
||||
return "ppc"
|
||||
if result.stdout.strip() in ["s390x"]:
|
||||
return "s390x"
|
||||
if result.stdout.strip() in ["arm", "armv7l"]:
|
||||
return "arm"
|
||||
if result.stdout.strip() in ["aarch64"]:
|
||||
return "aarch64"
|
||||
return "k8" if result.stdout.strip() 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):
|
||||
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)
|
|
@ -0,0 +1,113 @@
|
|||
#!/bin/bash
|
||||
#
|
||||
# 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.
|
||||
|
||||
# This script handles interface library generation for dynamic library
|
||||
# link action.
|
||||
#
|
||||
# Bazel can be configured to generate external interface library script
|
||||
# to generate interface libraries in CppLinkAction for dynamic libraries.
|
||||
# This is not needed on Windows (as the "interface" libraries are
|
||||
# generated by default). This script therefore handles the cases when
|
||||
# external script is provided, or when no script should be used.
|
||||
|
||||
set -eu
|
||||
|
||||
E_LINKER_COMMAND_NOT_FOUND=12
|
||||
E_INTERFACE_BUILDER_NOT_FOUND=13
|
||||
|
||||
|
||||
SUFFIX=".rewritten"
|
||||
|
||||
other_args=""
|
||||
|
||||
if [[ "$#" -eq 1 ]]; then
|
||||
if [[ "$1" != @* ]]; then
|
||||
echo "Parameter file must start with @" 1>&2;
|
||||
exit "$E_LINKER_COMMAND_NOT_FOUND"
|
||||
fi
|
||||
|
||||
filename=$(echo "$1" | cut -c2-)
|
||||
first_five_lines=$(head -n 5 $filename)
|
||||
|
||||
# Should generate interface library switch (<yes|no>); if the value is "no",
|
||||
# following 3 args are ignored (but must be present)
|
||||
GENERATE_INTERFACE_LIBRARY=$(echo "$first_five_lines" | head -n1 | tail -n1)
|
||||
# Tool which can generate interface library from dynamic library file
|
||||
INTERFACE_LIBRARY_BUILDER=$(echo "$first_five_lines" | head -n2 | tail -n1)
|
||||
# Dynamic library from which we want to generate interface library
|
||||
DYNAMIC_LIBRARY=$(echo "$first_five_lines" | head -n3 | tail -n1)
|
||||
# Resulting interface library
|
||||
INTERFACE_LIBRARY=$(echo "$first_five_lines" | head -n4 | tail -n1)
|
||||
# The command used to generate the dynamic library
|
||||
LINKER_COMMAND=$(echo "$first_five_lines" | head -n5 | tail -n1)
|
||||
|
||||
rest_of_lines=$(tail -n +6 $filename)
|
||||
new_param_file="${filename}${SUFFIX}"
|
||||
echo "$rest_of_lines" > $new_param_file
|
||||
other_args="@$new_param_file"
|
||||
|
||||
if [[ ! -e "$LINKER_COMMAND" ]]; then
|
||||
echo "Linker command ($LINKER_COMMAND) not found." 1>&2;
|
||||
exit "$E_LINKER_COMMAND_NOT_FOUND"
|
||||
fi
|
||||
|
||||
if [[ "no" == "$GENERATE_INTERFACE_LIBRARY" ]]; then
|
||||
INTERFACE_GENERATION=:
|
||||
else
|
||||
if [[ ! -e "$INTERFACE_LIBRARY_BUILDER" ]]; then
|
||||
echo "Interface library builder ($INTERFACE_LIBRARY_BUILDER)
|
||||
not found." 1>&2;
|
||||
exit "$E_INTERFACE_BUILDER_NOT_FOUND"
|
||||
fi
|
||||
INTERFACE_GENERATION="${INTERFACE_LIBRARY_BUILDER} ${DYNAMIC_LIBRARY}
|
||||
${INTERFACE_LIBRARY}"
|
||||
fi
|
||||
|
||||
${LINKER_COMMAND} "$other_args" && ${INTERFACE_GENERATION}
|
||||
else
|
||||
# TODO(b/113358321): Remove this branch once projects are migrated to not
|
||||
# splitting the linking command line.
|
||||
# Should generate interface library switch (<yes|no>); if the value is "no",
|
||||
# following 3 args are ignored (but must be present)
|
||||
GENERATE_INTERFACE_LIBRARY="$1"
|
||||
# Tool which can generate interface library from dynamic library file
|
||||
INTERFACE_LIBRARY_BUILDER="$2"
|
||||
# Dynamic library from which we want to generate interface library
|
||||
DYNAMIC_LIBRARY="$3"
|
||||
# Resulting interface library
|
||||
INTERFACE_LIBRARY="$4"
|
||||
# The command used to generate the dynamic library
|
||||
LINKER_COMMAND="$5"
|
||||
shift 5
|
||||
if [[ ! -e "$LINKER_COMMAND" ]]; then
|
||||
echo "Linker command ($LINKER_COMMAND) not found." 1>&2;
|
||||
exit "$E_LINKER_COMMAND_NOT_FOUND"
|
||||
fi
|
||||
|
||||
if [[ "no" == "$GENERATE_INTERFACE_LIBRARY" ]]; then
|
||||
INTERFACE_GENERATION=:
|
||||
else
|
||||
if [[ ! -e "$INTERFACE_LIBRARY_BUILDER" ]]; then
|
||||
echo "Interface library builder ($INTERFACE_LIBRARY_BUILDER)
|
||||
not found." 1>&2;
|
||||
exit "$E_INTERFACE_BUILDER_NOT_FOUND"
|
||||
fi
|
||||
INTERFACE_GENERATION="${INTERFACE_LIBRARY_BUILDER} ${DYNAMIC_LIBRARY}
|
||||
${INTERFACE_LIBRARY}"
|
||||
fi
|
||||
|
||||
${LINKER_COMMAND} "$@" && ${INTERFACE_GENERATION}
|
||||
fi
|
|
@ -0,0 +1,25 @@
|
|||
#!/bin/bash
|
||||
#
|
||||
# Copyright 2015 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.
|
||||
#
|
||||
# Ship the environment to the C++ action
|
||||
#
|
||||
set -eu
|
||||
|
||||
# Set-up the environment
|
||||
%{env}
|
||||
|
||||
# Call the C++ compiler
|
||||
%{cc} "$@"
|
|
@ -0,0 +1,23 @@
|
|||
:: Copyright 2018 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.
|
||||
|
||||
@echo OFF
|
||||
|
||||
echo. 1>&2
|
||||
echo The target you are compiling requires MSYS gcc / MINGW gcc. 1>&2
|
||||
echo Bazel couldn't find gcc installation on your machine. 1>&2
|
||||
echo Please install MSYS gcc / MINGW gcc and set BAZEL_SH environment variable 1>&2
|
||||
echo. 1>&2
|
||||
|
||||
exit /b 1
|
|
@ -0,0 +1,148 @@
|
|||
# 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 macOS."""
|
||||
|
||||
load("@bazel_tools//tools/osx:xcode_configure.bzl", "run_xcode_locator")
|
||||
load(
|
||||
"@rules_cc//cc/private/toolchain:lib_cc_configure.bzl",
|
||||
"escape_string",
|
||||
"resolve_labels",
|
||||
)
|
||||
load(
|
||||
"@rules_cc//cc/private/toolchain:unix_cc_configure.bzl",
|
||||
"configure_unix_toolchain",
|
||||
"find_cc",
|
||||
"get_env",
|
||||
"get_escaped_cxx_inc_directories",
|
||||
)
|
||||
|
||||
def _get_escaped_xcode_cxx_inc_directories(repository_ctx, cc, xcode_toolchains):
|
||||
"""Compute the list of default C++ include paths on Xcode-enabled darwin.
|
||||
|
||||
Args:
|
||||
repository_ctx: The repository context.
|
||||
cc: The default C++ compiler on the local system.
|
||||
xcode_toolchains: A list containing the xcode toolchains available
|
||||
Returns:
|
||||
include_paths: A list of builtin include paths.
|
||||
"""
|
||||
|
||||
# TODO(cparsons): Falling back to the default C++ compiler builtin include
|
||||
# paths shouldn't be unnecessary once all actions are using xcrun.
|
||||
include_dirs = get_escaped_cxx_inc_directories(repository_ctx, cc, "-xc++")
|
||||
for toolchain in xcode_toolchains:
|
||||
include_dirs.append(escape_string(toolchain.developer_dir))
|
||||
|
||||
# Assume that all paths that point to /Applications/ are built in include paths
|
||||
include_dirs.append("/Applications/")
|
||||
return include_dirs
|
||||
|
||||
def configure_osx_toolchain(repository_ctx, overriden_tools):
|
||||
"""Configure C++ toolchain on macOS."""
|
||||
paths = resolve_labels(repository_ctx, [
|
||||
"@rules_cc//cc/private/toolchain:osx_cc_wrapper.sh.tpl",
|
||||
"@bazel_tools//tools/objc:libtool.sh",
|
||||
"@bazel_tools//tools/objc:make_hashed_objlist.py",
|
||||
"@bazel_tools//tools/objc:xcrunwrapper.sh",
|
||||
"@bazel_tools//tools/osx/crosstool:BUILD.tpl",
|
||||
"@bazel_tools//tools/osx/crosstool:cc_toolchain_config.bzl",
|
||||
"@bazel_tools//tools/osx/crosstool:wrapped_ar.tpl",
|
||||
"@bazel_tools//tools/osx/crosstool:wrapped_clang.cc",
|
||||
"@bazel_tools//tools/osx:xcode_locator.m",
|
||||
])
|
||||
|
||||
env = repository_ctx.os.environ
|
||||
should_use_xcode = "BAZEL_USE_XCODE_TOOLCHAIN" in env and env["BAZEL_USE_XCODE_TOOLCHAIN"] == "1"
|
||||
xcode_toolchains = []
|
||||
|
||||
# Make the following logic in sync with @rules_cc//cc/private/toolchain:cc_configure.bzl#cc_autoconf_toolchains_impl
|
||||
(xcode_toolchains, xcodeloc_err) = run_xcode_locator(
|
||||
repository_ctx,
|
||||
paths["@bazel_tools//tools/osx:xcode_locator.m"],
|
||||
)
|
||||
if should_use_xcode and not xcode_toolchains:
|
||||
fail("BAZEL_USE_XCODE_TOOLCHAIN is set to 1 but Bazel couldn't find Xcode installed on the " +
|
||||
"system. Verify that 'xcode-select -p' is correct.")
|
||||
if xcode_toolchains:
|
||||
cc = find_cc(repository_ctx, overriden_tools = {})
|
||||
repository_ctx.template(
|
||||
"cc_wrapper.sh",
|
||||
paths["@rules_cc//cc/private/toolchain:osx_cc_wrapper.sh.tpl"],
|
||||
{
|
||||
"%{cc}": escape_string(str(cc)),
|
||||
"%{env}": escape_string(get_env(repository_ctx)),
|
||||
},
|
||||
)
|
||||
repository_ctx.symlink(
|
||||
paths["@bazel_tools//tools/objc:xcrunwrapper.sh"],
|
||||
"xcrunwrapper.sh",
|
||||
)
|
||||
repository_ctx.symlink(
|
||||
paths["@bazel_tools//tools/objc:libtool.sh"],
|
||||
"libtool",
|
||||
)
|
||||
repository_ctx.symlink(
|
||||
paths["@bazel_tools//tools/objc:make_hashed_objlist.py"],
|
||||
"make_hashed_objlist.py",
|
||||
)
|
||||
repository_ctx.symlink(
|
||||
paths["@bazel_tools//tools/osx/crosstool:wrapped_ar.tpl"],
|
||||
"wrapped_ar",
|
||||
)
|
||||
repository_ctx.symlink(
|
||||
paths["@bazel_tools//tools/osx/crosstool:cc_toolchain_config.bzl"],
|
||||
"cc_toolchain_config.bzl",
|
||||
)
|
||||
wrapped_clang_src_path = str(repository_ctx.path(
|
||||
paths["@bazel_tools//tools/osx/crosstool:wrapped_clang.cc"],
|
||||
))
|
||||
xcrun_result = repository_ctx.execute([
|
||||
"env",
|
||||
"-i",
|
||||
"xcrun",
|
||||
"clang",
|
||||
"-std=c++11",
|
||||
"-lc++",
|
||||
"-o",
|
||||
"wrapped_clang",
|
||||
wrapped_clang_src_path,
|
||||
], 30)
|
||||
if (xcrun_result.return_code == 0):
|
||||
repository_ctx.symlink("wrapped_clang", "wrapped_clang_pp")
|
||||
else:
|
||||
error_msg = (
|
||||
"return code {code}, stderr: {err}, stdout: {out}"
|
||||
).format(
|
||||
code = xcrun_result.return_code,
|
||||
err = xcrun_result.stderr,
|
||||
out = xcrun_result.stdout,
|
||||
)
|
||||
fail("wrapped_clang failed to generate. Please file an issue at " +
|
||||
"https://github.com/bazelbuild/bazel/issues with the following:\n" +
|
||||
error_msg)
|
||||
|
||||
escaped_include_paths = _get_escaped_xcode_cxx_inc_directories(repository_ctx, cc, xcode_toolchains)
|
||||
escaped_cxx_include_directories = []
|
||||
for path in escaped_include_paths:
|
||||
escaped_cxx_include_directories.append((" \"%s\"," % path))
|
||||
if xcodeloc_err:
|
||||
escaped_cxx_include_directories.append("# Error: " + xcodeloc_err + "\n")
|
||||
repository_ctx.template(
|
||||
"BUILD",
|
||||
paths["@bazel_tools//tools/osx/crosstool:BUILD.tpl"],
|
||||
{"%{cxx_builtin_include_directories}": "\n".join(escaped_cxx_include_directories)},
|
||||
)
|
||||
else:
|
||||
configure_unix_toolchain(repository_ctx, cpu_value = "darwin", overriden_tools = overriden_tools)
|
|
@ -0,0 +1,104 @@
|
|||
#!/bin/bash
|
||||
#
|
||||
# Copyright 2015 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.
|
||||
#
|
||||
# OS X relpath is not really working. This is a wrapper script around gcc
|
||||
# to simulate relpath behavior.
|
||||
#
|
||||
# This wrapper uses install_name_tool to replace all paths in the binary
|
||||
# (bazel-out/.../path/to/original/library.so) by the paths relative to
|
||||
# the binary. It parses the command line to behave as rpath is supposed
|
||||
# to work.
|
||||
#
|
||||
# See https://blogs.oracle.com/dipol/entry/dynamic_libraries_rpath_and_mac
|
||||
# on how to set those paths for Mach-O binaries.
|
||||
#
|
||||
set -eu
|
||||
|
||||
GCC=/usr/bin/gcc
|
||||
INSTALL_NAME_TOOL="/usr/bin/install_name_tool"
|
||||
|
||||
LIBS=
|
||||
LIB_DIRS=
|
||||
RPATHS=
|
||||
OUTPUT=
|
||||
# let parse the option list
|
||||
for i in "$@"; do
|
||||
if [[ "${OUTPUT}" = "1" ]]; then
|
||||
OUTPUT=$i
|
||||
elif [[ "$i" =~ ^-l(.*)$ ]]; then
|
||||
LIBS="${BASH_REMATCH[1]} $LIBS"
|
||||
elif [[ "$i" =~ ^-L(.*)$ ]]; then
|
||||
LIB_DIRS="${BASH_REMATCH[1]} $LIB_DIRS"
|
||||
elif [[ "$i" =~ ^-Wl,-rpath,\@loader_path/(.*)$ ]]; then
|
||||
RPATHS="${BASH_REMATCH[1]} ${RPATHS}"
|
||||
elif [[ "$i" = "-o" ]]; then
|
||||
# output is coming
|
||||
OUTPUT=1
|
||||
fi
|
||||
done
|
||||
|
||||
# Call gcc
|
||||
${GCC} "$@"
|
||||
|
||||
function get_library_path() {
|
||||
for libdir in ${LIB_DIRS}; do
|
||||
if [ -f ${libdir}/lib$1.so ]; then
|
||||
echo "${libdir}/lib$1.so"
|
||||
elif [ -f ${libdir}/lib$1.dylib ]; then
|
||||
echo "${libdir}/lib$1.dylib"
|
||||
fi
|
||||
done
|
||||
}
|
||||
|
||||
# A convenient method to return the actual path even for non symlinks
|
||||
# and multi-level symlinks.
|
||||
function get_realpath() {
|
||||
local previous="$1"
|
||||
local next=$(readlink "${previous}")
|
||||
while [ -n "${next}" ]; do
|
||||
previous="${next}"
|
||||
next=$(readlink "${previous}")
|
||||
done
|
||||
echo "${previous}"
|
||||
}
|
||||
|
||||
# Get the path of a lib inside a tool
|
||||
function get_otool_path() {
|
||||
# the lib path is the path of the original lib relative to the workspace
|
||||
get_realpath $1 | sed 's|^.*/bazel-out/|bazel-out/|'
|
||||
}
|
||||
|
||||
# Do replacements in the output
|
||||
for rpath in ${RPATHS}; do
|
||||
for lib in ${LIBS}; do
|
||||
unset libname
|
||||
if [ -f "$(dirname ${OUTPUT})/${rpath}/lib${lib}.so" ]; then
|
||||
libname="lib${lib}.so"
|
||||
elif [ -f "$(dirname ${OUTPUT})/${rpath}/lib${lib}.dylib" ]; then
|
||||
libname="lib${lib}.dylib"
|
||||
fi
|
||||
# ${libname-} --> return $libname if defined, or undefined otherwise. This is to make
|
||||
# this set -e friendly
|
||||
if [[ -n "${libname-}" ]]; then
|
||||
libpath=$(get_library_path ${lib})
|
||||
if [ -n "${libpath}" ]; then
|
||||
${INSTALL_NAME_TOOL} -change $(get_otool_path "${libpath}") \
|
||||
"@loader_path/${rpath}/${libname}" "${OUTPUT}"
|
||||
fi
|
||||
fi
|
||||
done
|
||||
done
|
||||
|
|
@ -0,0 +1,106 @@
|
|||
#!/bin/bash
|
||||
#
|
||||
# Copyright 2015 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.
|
||||
#
|
||||
# OS X relpath is not really working. This is a wrapper script around gcc
|
||||
# to simulate relpath behavior.
|
||||
#
|
||||
# This wrapper uses install_name_tool to replace all paths in the binary
|
||||
# (bazel-out/.../path/to/original/library.so) by the paths relative to
|
||||
# the binary. It parses the command line to behave as rpath is supposed
|
||||
# to work.
|
||||
#
|
||||
# See https://blogs.oracle.com/dipol/entry/dynamic_libraries_rpath_and_mac
|
||||
# on how to set those paths for Mach-O binaries.
|
||||
#
|
||||
set -eu
|
||||
|
||||
INSTALL_NAME_TOOL="/usr/bin/install_name_tool"
|
||||
|
||||
LIBS=
|
||||
LIB_DIRS=
|
||||
RPATHS=
|
||||
OUTPUT=
|
||||
# let parse the option list
|
||||
for i in "$@"; do
|
||||
if [[ "${OUTPUT}" = "1" ]]; then
|
||||
OUTPUT=$i
|
||||
elif [[ "$i" =~ ^-l(.*)$ ]]; then
|
||||
LIBS="${BASH_REMATCH[1]} $LIBS"
|
||||
elif [[ "$i" =~ ^-L(.*)$ ]]; then
|
||||
LIB_DIRS="${BASH_REMATCH[1]} $LIB_DIRS"
|
||||
elif [[ "$i" =~ ^-Wl,-rpath,\@loader_path/(.*)$ ]]; then
|
||||
RPATHS="${BASH_REMATCH[1]} ${RPATHS}"
|
||||
elif [[ "$i" = "-o" ]]; then
|
||||
# output is coming
|
||||
OUTPUT=1
|
||||
fi
|
||||
done
|
||||
|
||||
# Set-up the environment
|
||||
%{env}
|
||||
|
||||
# Call the C++ compiler
|
||||
%{cc} "$@"
|
||||
|
||||
function get_library_path() {
|
||||
for libdir in ${LIB_DIRS}; do
|
||||
if [ -f ${libdir}/lib$1.so ]; then
|
||||
echo "${libdir}/lib$1.so"
|
||||
elif [ -f ${libdir}/lib$1.dylib ]; then
|
||||
echo "${libdir}/lib$1.dylib"
|
||||
fi
|
||||
done
|
||||
}
|
||||
|
||||
# A convenient method to return the actual path even for non symlinks
|
||||
# and multi-level symlinks.
|
||||
function get_realpath() {
|
||||
local previous="$1"
|
||||
local next=$(readlink "${previous}")
|
||||
while [ -n "${next}" ]; do
|
||||
previous="${next}"
|
||||
next=$(readlink "${previous}")
|
||||
done
|
||||
echo "${previous}"
|
||||
}
|
||||
|
||||
# Get the path of a lib inside a tool
|
||||
function get_otool_path() {
|
||||
# the lib path is the path of the original lib relative to the workspace
|
||||
get_realpath $1 | sed 's|^.*/bazel-out/|bazel-out/|'
|
||||
}
|
||||
|
||||
# Do replacements in the output
|
||||
for rpath in ${RPATHS}; do
|
||||
for lib in ${LIBS}; do
|
||||
unset libname
|
||||
if [ -f "$(dirname ${OUTPUT})/${rpath}/lib${lib}.so" ]; then
|
||||
libname="lib${lib}.so"
|
||||
elif [ -f "$(dirname ${OUTPUT})/${rpath}/lib${lib}.dylib" ]; then
|
||||
libname="lib${lib}.dylib"
|
||||
fi
|
||||
# ${libname-} --> return $libname if defined, or undefined otherwise. This is to make
|
||||
# this set -e friendly
|
||||
if [[ -n "${libname-}" ]]; then
|
||||
libpath=$(get_library_path ${lib})
|
||||
if [ -n "${libpath}" ]; then
|
||||
${INSTALL_NAME_TOOL} -change $(get_otool_path "${libpath}") \
|
||||
"@loader_path/${rpath}/${libname}" "${OUTPUT}"
|
||||
fi
|
||||
fi
|
||||
done
|
||||
done
|
||||
|
|
@ -0,0 +1,84 @@
|
|||
package(default_visibility = ["//visibility:private"])
|
||||
|
||||
load("@rules_cc//cc:defs.bzl", "cc_library", "cc_test")
|
||||
|
||||
filegroup(
|
||||
name = "srcs",
|
||||
srcs = glob(
|
||||
["**"],
|
||||
exclude = [
|
||||
".*",
|
||||
"*~",
|
||||
],
|
||||
),
|
||||
visibility = ["//cc/private/toolchain:__pkg__"],
|
||||
)
|
||||
|
||||
filegroup(
|
||||
name = "embedded_tools",
|
||||
srcs = [
|
||||
"BUILD.tools",
|
||||
":srcs_for_embedded_tools",
|
||||
],
|
||||
visibility = ["//cc/private/toolchain:__pkg__"],
|
||||
)
|
||||
|
||||
# Rewrite the include path for runfiles.h in runfiles_src.cc, and create
|
||||
# "generated_runfiles.{h,cc}". These files are renamed to "runfiles.{h,cc}" as
|
||||
# part of creating the embedded tools of Bazel.
|
||||
#
|
||||
# We cannot just check in runfiles_src.{h,cc} as runfiles.{h,cc}, because it'd
|
||||
# cause a header check failure on Windows when building targets in the Bazel
|
||||
# source tree, if those targets depend on @rules_cc//cc/private/toolchain/runfiles,
|
||||
# because due to lack of sandboxing they would accidentally pick up runfiles.h
|
||||
# from @rules_cc//cc/private/toolchain/runfiles.
|
||||
genrule(
|
||||
name = "srcs_for_embedded_tools",
|
||||
srcs = [
|
||||
"runfiles_src.cc",
|
||||
"runfiles_src.h",
|
||||
],
|
||||
outs = [
|
||||
"generated_runfiles.cc",
|
||||
"generated_runfiles.h",
|
||||
],
|
||||
# Keep this transformation logic in sync with the
|
||||
# //scripts/bootstrap/compile.sh
|
||||
cmd = ("sed " +
|
||||
" 's|^#include.*/runfiles_src.h.*|#include \"tools/cpp/runfiles/runfiles.h\"|' " +
|
||||
" $(location runfiles_src.cc) > $(location generated_runfiles.cc) && " +
|
||||
"cp $(location runfiles_src.h) $(location generated_runfiles.h)"),
|
||||
)
|
||||
|
||||
cc_library(
|
||||
name = "runfiles",
|
||||
testonly = 1,
|
||||
srcs = ["runfiles_src.cc"],
|
||||
hdrs = ["runfiles_src.h"],
|
||||
)
|
||||
|
||||
cc_test(
|
||||
name = "runfiles_test",
|
||||
srcs = ["runfiles_test.cc"],
|
||||
visibility = ["//visibility:public"],
|
||||
deps = [
|
||||
":runfiles",
|
||||
"@com_google_googletest//:gtest_main",
|
||||
],
|
||||
)
|
||||
|
||||
test_suite(
|
||||
name = "windows_tests",
|
||||
tags = [
|
||||
"-no_windows",
|
||||
"-slow",
|
||||
],
|
||||
)
|
||||
|
||||
test_suite(
|
||||
name = "all_windows_tests",
|
||||
tests = [
|
||||
":windows_tests",
|
||||
],
|
||||
visibility = ["//tools:__pkg__"],
|
||||
)
|
|
@ -0,0 +1,8 @@
|
|||
# This package will host the C++ runfiles library when it's finally released.
|
||||
|
||||
cc_library(
|
||||
name = "runfiles",
|
||||
srcs = ["runfiles.cc"],
|
||||
hdrs = ["runfiles.h"],
|
||||
visibility = ["//visibility:public"],
|
||||
)
|
|
@ -0,0 +1,318 @@
|
|||
// Copyright 2018 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.
|
||||
|
||||
// The "srcs_for_embedded_tools" rule in the same package sets the line below to
|
||||
// include runfiles.h from the correct path. Do not modify the line below.
|
||||
#include "cc/private/toolchain/runfiles/runfiles_src.h"
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <windows.h>
|
||||
#else // not _WIN32
|
||||
#include <stdlib.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
#endif // _WIN32
|
||||
|
||||
#include <fstream>
|
||||
#include <functional>
|
||||
#include <map>
|
||||
#include <sstream>
|
||||
#include <vector>
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <memory>
|
||||
#endif // _WIN32
|
||||
|
||||
namespace bazel {
|
||||
namespace tools {
|
||||
namespace cpp {
|
||||
namespace runfiles {
|
||||
|
||||
using std::function;
|
||||
using std::map;
|
||||
using std::pair;
|
||||
using std::string;
|
||||
using std::vector;
|
||||
|
||||
namespace {
|
||||
|
||||
bool starts_with(const string& s, const char* prefix) {
|
||||
if (!prefix || !*prefix) {
|
||||
return true;
|
||||
}
|
||||
if (s.empty()) {
|
||||
return false;
|
||||
}
|
||||
return s.find(prefix) == 0;
|
||||
}
|
||||
|
||||
bool contains(const string& s, const char* substr) {
|
||||
if (!substr || !*substr) {
|
||||
return true;
|
||||
}
|
||||
if (s.empty()) {
|
||||
return false;
|
||||
}
|
||||
return s.find(substr) != string::npos;
|
||||
}
|
||||
|
||||
bool ends_with(const string& s, const string& suffix) {
|
||||
if (suffix.empty()) {
|
||||
return true;
|
||||
}
|
||||
if (s.empty()) {
|
||||
return false;
|
||||
}
|
||||
return s.rfind(suffix) == s.size() - suffix.size();
|
||||
}
|
||||
|
||||
bool IsReadableFile(const string& path) {
|
||||
return std::ifstream(path).is_open();
|
||||
}
|
||||
|
||||
bool IsDirectory(const string& path) {
|
||||
#ifdef _WIN32
|
||||
DWORD attrs = GetFileAttributesA(path.c_str());
|
||||
return (attrs != INVALID_FILE_ATTRIBUTES) &&
|
||||
(attrs & FILE_ATTRIBUTE_DIRECTORY);
|
||||
#else
|
||||
struct stat buf;
|
||||
return stat(path.c_str(), &buf) == 0 && S_ISDIR(buf.st_mode);
|
||||
#endif
|
||||
}
|
||||
|
||||
bool PathsFrom(const std::string& argv0, std::string runfiles_manifest_file,
|
||||
std::string runfiles_dir, std::string* out_manifest,
|
||||
std::string* out_directory);
|
||||
|
||||
bool PathsFrom(const std::string& argv0, std::string runfiles_manifest_file,
|
||||
std::string runfiles_dir,
|
||||
std::function<bool(const std::string&)> is_runfiles_manifest,
|
||||
std::function<bool(const std::string&)> is_runfiles_directory,
|
||||
std::string* out_manifest, std::string* out_directory);
|
||||
|
||||
bool ParseManifest(const string& path, map<string, string>* result,
|
||||
string* error);
|
||||
|
||||
} // namespace
|
||||
|
||||
Runfiles* Runfiles::Create(const string& argv0,
|
||||
const string& runfiles_manifest_file,
|
||||
const string& runfiles_dir, string* error) {
|
||||
string manifest, directory;
|
||||
if (!PathsFrom(argv0, runfiles_manifest_file, runfiles_dir, &manifest,
|
||||
&directory)) {
|
||||
if (error) {
|
||||
std::ostringstream err;
|
||||
err << "ERROR: " << __FILE__ << "(" << __LINE__
|
||||
<< "): cannot find runfiles (argv0=\"" << argv0 << "\")";
|
||||
*error = err.str();
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
const vector<pair<string, string> > envvars = {
|
||||
{"RUNFILES_MANIFEST_FILE", manifest},
|
||||
{"RUNFILES_DIR", directory},
|
||||
// TODO(laszlocsomor): remove JAVA_RUNFILES once the Java launcher can
|
||||
// pick up RUNFILES_DIR.
|
||||
{"JAVA_RUNFILES", directory}};
|
||||
|
||||
map<string, string> runfiles;
|
||||
if (!manifest.empty()) {
|
||||
if (!ParseManifest(manifest, &runfiles, error)) {
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
return new Runfiles(std::move(runfiles), std::move(directory),
|
||||
std::move(envvars));
|
||||
}
|
||||
|
||||
bool IsAbsolute(const string& path) {
|
||||
if (path.empty()) {
|
||||
return false;
|
||||
}
|
||||
char c = path.front();
|
||||
return (c == '/' && (path.size() < 2 || path[1] != '/')) ||
|
||||
(path.size() >= 3 &&
|
||||
((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z')) &&
|
||||
path[1] == ':' && (path[2] == '\\' || path[2] == '/'));
|
||||
}
|
||||
|
||||
string GetEnv(const string& key) {
|
||||
#ifdef _WIN32
|
||||
DWORD size = ::GetEnvironmentVariableA(key.c_str(), NULL, 0);
|
||||
if (size == 0) {
|
||||
return string(); // unset or empty envvar
|
||||
}
|
||||
std::unique_ptr<char[]> value(new char[size]);
|
||||
::GetEnvironmentVariableA(key.c_str(), value.get(), size);
|
||||
return value.get();
|
||||
#else
|
||||
char* result = getenv(key.c_str());
|
||||
return (result == NULL) ? string() : string(result);
|
||||
#endif
|
||||
}
|
||||
|
||||
string Runfiles::Rlocation(const string& path) const {
|
||||
if (path.empty() || starts_with(path, "../") || contains(path, "/..") ||
|
||||
starts_with(path, "./") || contains(path, "/./") ||
|
||||
ends_with(path, "/.") || contains(path, "//")) {
|
||||
return string();
|
||||
}
|
||||
if (IsAbsolute(path)) {
|
||||
return path;
|
||||
}
|
||||
const auto value = runfiles_map_.find(path);
|
||||
if (value != runfiles_map_.end()) {
|
||||
return value->second;
|
||||
}
|
||||
if (!directory_.empty()) {
|
||||
return directory_ + "/" + path;
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
bool ParseManifest(const string& path, map<string, string>* result,
|
||||
string* error) {
|
||||
std::ifstream stm(path);
|
||||
if (!stm.is_open()) {
|
||||
if (error) {
|
||||
std::ostringstream err;
|
||||
err << "ERROR: " << __FILE__ << "(" << __LINE__
|
||||
<< "): cannot open runfiles manifest \"" << path << "\"";
|
||||
*error = err.str();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
string line;
|
||||
std::getline(stm, line);
|
||||
size_t line_count = 1;
|
||||
while (!line.empty()) {
|
||||
string::size_type idx = line.find_first_of(' ');
|
||||
if (idx == string::npos) {
|
||||
if (error) {
|
||||
std::ostringstream err;
|
||||
err << "ERROR: " << __FILE__ << "(" << __LINE__
|
||||
<< "): bad runfiles manifest entry in \"" << path << "\" line #"
|
||||
<< line_count << ": \"" << line << "\"";
|
||||
*error = err.str();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
(*result)[line.substr(0, idx)] = line.substr(idx + 1);
|
||||
std::getline(stm, line);
|
||||
++line_count;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
namespace testing {
|
||||
|
||||
bool TestOnly_PathsFrom(const string& argv0, string mf, string dir,
|
||||
function<bool(const string&)> is_runfiles_manifest,
|
||||
function<bool(const string&)> is_runfiles_directory,
|
||||
string* out_manifest, string* out_directory) {
|
||||
return PathsFrom(argv0, mf, dir, is_runfiles_manifest, is_runfiles_directory,
|
||||
out_manifest, out_directory);
|
||||
}
|
||||
|
||||
bool TestOnly_IsAbsolute(const string& path) { return IsAbsolute(path); }
|
||||
|
||||
} // namespace testing
|
||||
|
||||
Runfiles* Runfiles::Create(const string& argv0, string* error) {
|
||||
return Runfiles::Create(argv0, GetEnv("RUNFILES_MANIFEST_FILE"),
|
||||
GetEnv("RUNFILES_DIR"), error);
|
||||
}
|
||||
|
||||
Runfiles* Runfiles::CreateForTest(std::string* error) {
|
||||
return Runfiles::Create(std::string(), GetEnv("RUNFILES_MANIFEST_FILE"),
|
||||
GetEnv("TEST_SRCDIR"), error);
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
bool PathsFrom(const string& argv0, string mf, string dir, string* out_manifest,
|
||||
string* out_directory) {
|
||||
return PathsFrom(
|
||||
argv0, mf, dir, [](const string& path) { return IsReadableFile(path); },
|
||||
[](const string& path) { return IsDirectory(path); }, out_manifest,
|
||||
out_directory);
|
||||
}
|
||||
|
||||
bool PathsFrom(const string& argv0, string mf, string dir,
|
||||
function<bool(const string&)> is_runfiles_manifest,
|
||||
function<bool(const string&)> is_runfiles_directory,
|
||||
string* out_manifest, string* out_directory) {
|
||||
out_manifest->clear();
|
||||
out_directory->clear();
|
||||
|
||||
bool mfValid = is_runfiles_manifest(mf);
|
||||
bool dirValid = is_runfiles_directory(dir);
|
||||
|
||||
if (!argv0.empty() && !mfValid && !dirValid) {
|
||||
mf = argv0 + ".runfiles/MANIFEST";
|
||||
dir = argv0 + ".runfiles";
|
||||
mfValid = is_runfiles_manifest(mf);
|
||||
dirValid = is_runfiles_directory(dir);
|
||||
if (!mfValid) {
|
||||
mf = argv0 + ".runfiles_manifest";
|
||||
mfValid = is_runfiles_manifest(mf);
|
||||
}
|
||||
}
|
||||
|
||||
if (!mfValid && !dirValid) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!mfValid) {
|
||||
mf = dir + "/MANIFEST";
|
||||
mfValid = is_runfiles_manifest(mf);
|
||||
if (!mfValid) {
|
||||
mf = dir + "_manifest";
|
||||
mfValid = is_runfiles_manifest(mf);
|
||||
}
|
||||
}
|
||||
|
||||
if (!dirValid &&
|
||||
(ends_with(mf, ".runfiles_manifest") || ends_with(mf, "/MANIFEST"))) {
|
||||
static const size_t kSubstrLen = 9; // "_manifest" or "/MANIFEST"
|
||||
dir = mf.substr(0, mf.size() - kSubstrLen);
|
||||
dirValid = is_runfiles_directory(dir);
|
||||
}
|
||||
|
||||
if (mfValid) {
|
||||
*out_manifest = mf;
|
||||
}
|
||||
|
||||
if (dirValid) {
|
||||
*out_directory = dir;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
} // namespace runfiles
|
||||
} // namespace cpp
|
||||
} // namespace tools
|
||||
} // namespace bazel
|
|
@ -0,0 +1,222 @@
|
|||
// Copyright 2018 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.
|
||||
|
||||
// Runfiles lookup library for Bazel-built C++ binaries and tests.
|
||||
//
|
||||
// USAGE:
|
||||
// 1. Depend on this runfiles library from your build rule:
|
||||
//
|
||||
// cc_binary(
|
||||
// name = "my_binary",
|
||||
// ...
|
||||
// deps = ["@rules_cc//cc/private/toolchain/runfiles"],
|
||||
// )
|
||||
//
|
||||
// 2. Include the runfiles library.
|
||||
//
|
||||
// #include "tools/cpp/runfiles/runfiles.h"
|
||||
//
|
||||
// using bazel::tools::cpp::runfiles::Runfiles;
|
||||
//
|
||||
// 3. Create a Runfiles object and use rlocation to look up runfile paths:
|
||||
//
|
||||
// int main(int argc, char** argv) {
|
||||
// std::string error;
|
||||
// std::unique_ptr<Runfiles> runfiles(
|
||||
// Runfiles::Create(argv[0], &error));
|
||||
//
|
||||
// // Important:
|
||||
// // If this is a test, use Runfiles::CreateForTest(&error).
|
||||
// // Otherwise, if you don't have the value for argv[0] for whatever
|
||||
// // reason, then use Runfiles::Create(&error).
|
||||
//
|
||||
// if (runfiles == nullptr) {
|
||||
// ... // error handling
|
||||
// }
|
||||
// std::string path =
|
||||
// runfiles->Rlocation("my_workspace/path/to/my/data.txt");
|
||||
// ...
|
||||
//
|
||||
// The code above creates a Runfiles object and retrieves a runfile path.
|
||||
//
|
||||
// The Runfiles::Create function uses the runfiles manifest and the
|
||||
// runfiles directory from the RUNFILES_MANIFEST_FILE and RUNFILES_DIR
|
||||
// environment variables. If not present, the function looks for the
|
||||
// manifest and directory near argv[0], the path of the main program.
|
||||
//
|
||||
// To start child processes that also need runfiles, you need to set the right
|
||||
// environment variables for them:
|
||||
//
|
||||
// std::unique_ptr<Runfiles> runfiles(Runfiles::Create(argv[0], &error));
|
||||
//
|
||||
// std::string path = runfiles->Rlocation("path/to/binary"));
|
||||
// if (!path.empty()) {
|
||||
// ... // create "args" argument vector for execv
|
||||
// const auto envvars = runfiles->EnvVars();
|
||||
// pid_t child = fork();
|
||||
// if (child) {
|
||||
// int status;
|
||||
// waitpid(child, &status, 0);
|
||||
// } else {
|
||||
// for (const auto i : envvars) {
|
||||
// setenv(i.first.c_str(), i.second.c_str(), 1);
|
||||
// }
|
||||
// execv(args[0], args);
|
||||
// }
|
||||
|
||||
#ifndef TOOLS_CPP_RUNFILES_RUNFILES_H_
|
||||
#define TOOLS_CPP_RUNFILES_RUNFILES_H_ 1
|
||||
|
||||
#include <functional>
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace bazel {
|
||||
namespace tools {
|
||||
namespace cpp {
|
||||
namespace runfiles {
|
||||
|
||||
class Runfiles {
|
||||
public:
|
||||
virtual ~Runfiles() {}
|
||||
|
||||
// Returns a new `Runfiles` instance.
|
||||
//
|
||||
// Use this from within `cc_test` rules.
|
||||
//
|
||||
// Returns nullptr on error. If `error` is provided, the method prints an
|
||||
// error message into it.
|
||||
//
|
||||
// This method looks at the RUNFILES_MANIFEST_FILE and TEST_SRCDIR
|
||||
// environment variables.
|
||||
static Runfiles* CreateForTest(std::string* error = nullptr);
|
||||
|
||||
// Returns a new `Runfiles` instance.
|
||||
//
|
||||
// Use this from `cc_binary` or `cc_library` rules. You may pass an empty
|
||||
// `argv0` if `argv[0]` from the `main` method is unknown.
|
||||
//
|
||||
// Returns nullptr on error. If `error` is provided, the method prints an
|
||||
// error message into it.
|
||||
//
|
||||
// This method looks at the RUNFILES_MANIFEST_FILE and RUNFILES_DIR
|
||||
// environment variables. If either is empty, the method looks for the
|
||||
// manifest or directory using the other environment variable, or using argv0
|
||||
// (unless it's empty).
|
||||
static Runfiles* Create(const std::string& argv0,
|
||||
std::string* error = nullptr);
|
||||
|
||||
// Returns a new `Runfiles` instance.
|
||||
//
|
||||
// Use this from any `cc_*` rule if you want to manually specify the paths to
|
||||
// the runfiles manifest and/or runfiles directory. You may pass an empty
|
||||
// `argv0` if `argv[0]` from the `main` method is unknown.
|
||||
//
|
||||
// This method is the same as `Create(argv0, error)`, except it uses
|
||||
// `runfiles_manifest_file` and `runfiles_dir` as the corresponding
|
||||
// environment variable values, instead of looking up the actual environment
|
||||
// variables.
|
||||
static Runfiles* Create(const std::string& argv0,
|
||||
const std::string& runfiles_manifest_file,
|
||||
const std::string& runfiles_dir,
|
||||
std::string* error = nullptr);
|
||||
|
||||
// Returns the runtime path of a runfile.
|
||||
//
|
||||
// Runfiles are data-dependencies of Bazel-built binaries and tests.
|
||||
//
|
||||
// The returned path may not exist. The caller should verify the path's
|
||||
// existence.
|
||||
//
|
||||
// The function may return an empty string if it cannot find a runfile.
|
||||
//
|
||||
// Args:
|
||||
// path: runfiles-root-relative path of the runfile; must not be empty and
|
||||
// must not contain uplevel references.
|
||||
// Returns:
|
||||
// the path to the runfile, which the caller should check for existence, or
|
||||
// an empty string if the method doesn't know about this runfile
|
||||
std::string Rlocation(const std::string& path) const;
|
||||
|
||||
// Returns environment variables for subprocesses.
|
||||
//
|
||||
// The caller should set the returned key-value pairs in the environment of
|
||||
// subprocesses, so that those subprocesses can also access runfiles (in case
|
||||
// they are also Bazel-built binaries).
|
||||
const std::vector<std::pair<std::string, std::string> >& EnvVars() const {
|
||||
return envvars_;
|
||||
}
|
||||
|
||||
private:
|
||||
Runfiles(const std::map<std::string, std::string>&& runfiles_map,
|
||||
const std::string&& directory,
|
||||
const std::vector<std::pair<std::string, std::string> >&& envvars)
|
||||
: runfiles_map_(std::move(runfiles_map)),
|
||||
directory_(std::move(directory)),
|
||||
envvars_(std::move(envvars)) {}
|
||||
Runfiles(const Runfiles&) = delete;
|
||||
Runfiles(Runfiles&&) = delete;
|
||||
Runfiles& operator=(const Runfiles&) = delete;
|
||||
Runfiles& operator=(Runfiles&&) = delete;
|
||||
|
||||
const std::map<std::string, std::string> runfiles_map_;
|
||||
const std::string directory_;
|
||||
const std::vector<std::pair<std::string, std::string> > envvars_;
|
||||
};
|
||||
|
||||
// The "testing" namespace contains functions that allow unit testing the code.
|
||||
// Do not use these outside of runfiles_test.cc, they are only part of the
|
||||
// public API for the benefit of the tests.
|
||||
// These functions and their interface may change without notice.
|
||||
namespace testing {
|
||||
|
||||
// For testing only.
|
||||
//
|
||||
// Computes the path of the runfiles manifest and the runfiles directory.
|
||||
//
|
||||
// If the method finds both a valid manifest and valid directory according to
|
||||
// `is_runfiles_manifest` and `is_runfiles_directory`, then the method sets
|
||||
// the corresponding values to `out_manifest` and `out_directory` and returns
|
||||
// true.
|
||||
//
|
||||
// If the method only finds a valid manifest or a valid directory, but not
|
||||
// both, then it sets the corresponding output variable (`out_manifest` or
|
||||
// `out_directory`) to the value while clearing the other output variable. The
|
||||
// method still returns true in this case.
|
||||
//
|
||||
// If the method cannot find either a valid manifest or valid directory, it
|
||||
// clears both output variables and returns false.
|
||||
bool TestOnly_PathsFrom(
|
||||
const std::string& argv0, std::string runfiles_manifest_file,
|
||||
std::string runfiles_dir,
|
||||
std::function<bool(const std::string&)> is_runfiles_manifest,
|
||||
std::function<bool(const std::string&)> is_runfiles_directory,
|
||||
std::string* out_manifest, std::string* out_directory);
|
||||
|
||||
// For testing only.
|
||||
// Returns true if `path` is an absolute Unix or Windows path.
|
||||
// For Windows paths, this function does not regard drive-less absolute paths
|
||||
// (i.e. absolute-on-current-drive, e.g. "\foo\bar") as absolute and returns
|
||||
// false for these.
|
||||
bool TestOnly_IsAbsolute(const std::string& path);
|
||||
|
||||
} // namespace testing
|
||||
} // namespace runfiles
|
||||
} // namespace cpp
|
||||
} // namespace tools
|
||||
} // namespace bazel
|
||||
|
||||
#endif // TOOLS_CPP_RUNFILES_RUNFILES_H_
|
|
@ -0,0 +1,582 @@
|
|||
// Copyright 2018 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.
|
||||
|
||||
#include "cc/private/toolchain/runfiles/runfiles_src.h"
|
||||
#ifdef _WIN32
|
||||
#include <windows.h>
|
||||
#endif // _WIN32
|
||||
|
||||
#include <fstream>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "gtest/gtest.h"
|
||||
|
||||
#define RUNFILES_TEST_TOSTRING_HELPER(x) #x
|
||||
#define RUNFILES_TEST_TOSTRING(x) RUNFILES_TEST_TOSTRING_HELPER(x)
|
||||
#define LINE_AS_STRING() RUNFILES_TEST_TOSTRING(__LINE__)
|
||||
|
||||
namespace bazel {
|
||||
namespace tools {
|
||||
namespace cpp {
|
||||
namespace runfiles {
|
||||
namespace {
|
||||
|
||||
using bazel::tools::cpp::runfiles::testing::TestOnly_IsAbsolute;
|
||||
using bazel::tools::cpp::runfiles::testing::TestOnly_PathsFrom;
|
||||
using std::cerr;
|
||||
using std::endl;
|
||||
using std::function;
|
||||
using std::pair;
|
||||
using std::string;
|
||||
using std::unique_ptr;
|
||||
using std::vector;
|
||||
|
||||
class RunfilesTest : public ::testing::Test {
|
||||
protected:
|
||||
// Create a temporary file that is deleted with the destructor.
|
||||
class MockFile {
|
||||
public:
|
||||
// Create an empty file with the given name under $TEST_TMPDIR.
|
||||
static MockFile* Create(const string& name);
|
||||
|
||||
// Create a file with the given name and contents under $TEST_TMPDIR.
|
||||
// The method ensures to create all parent directories, so `name` is allowed
|
||||
// to contain directory components.
|
||||
static MockFile* Create(const string& name, const vector<string>& lines);
|
||||
|
||||
~MockFile();
|
||||
const string& Path() const { return path_; }
|
||||
|
||||
string DirName() const {
|
||||
string::size_type pos = path_.find_last_of('/');
|
||||
return pos == string::npos ? "" : path_.substr(0, pos);
|
||||
}
|
||||
|
||||
private:
|
||||
MockFile(const string& path) : path_(path) {}
|
||||
MockFile(const MockFile&) = delete;
|
||||
MockFile(MockFile&&) = delete;
|
||||
MockFile& operator=(const MockFile&) = delete;
|
||||
MockFile& operator=(MockFile&&) = delete;
|
||||
|
||||
const string path_;
|
||||
};
|
||||
|
||||
void AssertEnvvars(const Runfiles& runfiles,
|
||||
const string& expected_manifest_file,
|
||||
const string& expected_directory);
|
||||
|
||||
static string GetTemp();
|
||||
};
|
||||
|
||||
void RunfilesTest::AssertEnvvars(const Runfiles& runfiles,
|
||||
const string& expected_manifest_file,
|
||||
const string& expected_directory) {
|
||||
vector<pair<string, string> > expected = {
|
||||
{"RUNFILES_MANIFEST_FILE", expected_manifest_file},
|
||||
{"RUNFILES_DIR", expected_directory},
|
||||
{"JAVA_RUNFILES", expected_directory}};
|
||||
ASSERT_EQ(runfiles.EnvVars(), expected);
|
||||
}
|
||||
|
||||
string RunfilesTest::GetTemp() {
|
||||
#ifdef _WIN32
|
||||
DWORD size = ::GetEnvironmentVariableA("TEST_TMPDIR", NULL, 0);
|
||||
if (size == 0) {
|
||||
return string(); // unset or empty envvar
|
||||
}
|
||||
unique_ptr<char[]> value(new char[size]);
|
||||
::GetEnvironmentVariableA("TEST_TMPDIR", value.get(), size);
|
||||
return value.get();
|
||||
#else
|
||||
char* result = getenv("TEST_TMPDIR");
|
||||
return result != NULL ? string(result) : string();
|
||||
#endif
|
||||
}
|
||||
|
||||
RunfilesTest::MockFile* RunfilesTest::MockFile::Create(const string& name) {
|
||||
return Create(name, vector<string>());
|
||||
}
|
||||
|
||||
RunfilesTest::MockFile* RunfilesTest::MockFile::Create(
|
||||
const string& name, const vector<string>& lines) {
|
||||
if (name.find("..") != string::npos || TestOnly_IsAbsolute(name)) {
|
||||
cerr << "WARNING: " << __FILE__ << "(" << __LINE__ << "): bad name: \""
|
||||
<< name << "\"" << endl;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
string tmp(RunfilesTest::GetTemp());
|
||||
if (tmp.empty()) {
|
||||
cerr << "WARNING: " << __FILE__ << "(" << __LINE__
|
||||
<< "): $TEST_TMPDIR is empty" << endl;
|
||||
return nullptr;
|
||||
}
|
||||
string path(tmp + "/" + name);
|
||||
|
||||
string::size_type i = 0;
|
||||
#ifdef _WIN32
|
||||
while ((i = name.find_first_of("/\\", i + 1)) != string::npos) {
|
||||
string d = tmp + "\\" + name.substr(0, i);
|
||||
if (!CreateDirectoryA(d.c_str(), NULL)) {
|
||||
cerr << "ERROR: " << __FILE__ << "(" << __LINE__
|
||||
<< "): failed to create directory \"" << d << "\"" << endl;
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
#else
|
||||
while ((i = name.find_first_of('/', i + 1)) != string::npos) {
|
||||
string d = tmp + "/" + name.substr(0, i);
|
||||
if (mkdir(d.c_str(), 0777)) {
|
||||
cerr << "ERROR: " << __FILE__ << "(" << __LINE__
|
||||
<< "): failed to create directory \"" << d << "\"" << endl;
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
std::ofstream stm(path);
|
||||
for (auto i : lines) {
|
||||
stm << i << std::endl;
|
||||
}
|
||||
return new MockFile(path);
|
||||
}
|
||||
|
||||
RunfilesTest::MockFile::~MockFile() { std::remove(path_.c_str()); }
|
||||
|
||||
TEST_F(RunfilesTest, CreatesManifestBasedRunfilesFromManifestNextToBinary) {
|
||||
unique_ptr<MockFile> mf(MockFile::Create(
|
||||
"foo" LINE_AS_STRING() ".runfiles_manifest", {"a/b c/d"}));
|
||||
EXPECT_TRUE(mf != nullptr);
|
||||
string argv0(mf->Path().substr(
|
||||
0, mf->Path().size() - string(".runfiles_manifest").size()));
|
||||
|
||||
string error;
|
||||
unique_ptr<Runfiles> r(Runfiles::Create(argv0, "", "", &error));
|
||||
ASSERT_NE(r, nullptr);
|
||||
EXPECT_TRUE(error.empty());
|
||||
EXPECT_EQ(r->Rlocation("a/b"), "c/d");
|
||||
// We know it's manifest-based because it returns empty string for unknown
|
||||
// paths.
|
||||
EXPECT_EQ(r->Rlocation("unknown"), "");
|
||||
AssertEnvvars(*r, mf->Path(), "");
|
||||
}
|
||||
|
||||
TEST_F(RunfilesTest,
|
||||
CreatesManifestBasedRunfilesFromManifestInRunfilesDirectory) {
|
||||
unique_ptr<MockFile> mf(MockFile::Create(
|
||||
"foo" LINE_AS_STRING() ".runfiles/MANIFEST", {"a/b c/d"}));
|
||||
EXPECT_TRUE(mf != nullptr);
|
||||
string argv0(mf->Path().substr(
|
||||
0, mf->Path().size() - string(".runfiles/MANIFEST").size()));
|
||||
|
||||
string error;
|
||||
unique_ptr<Runfiles> r(Runfiles::Create(argv0, "", "", &error));
|
||||
ASSERT_NE(r, nullptr);
|
||||
EXPECT_TRUE(error.empty());
|
||||
EXPECT_EQ(r->Rlocation("a/b"), "c/d");
|
||||
EXPECT_EQ(r->Rlocation("foo"), argv0 + ".runfiles/foo");
|
||||
AssertEnvvars(*r, mf->Path(), argv0 + ".runfiles");
|
||||
}
|
||||
|
||||
TEST_F(RunfilesTest, CreatesManifestBasedRunfilesFromEnvvar) {
|
||||
unique_ptr<MockFile> mf(MockFile::Create(
|
||||
"foo" LINE_AS_STRING() ".runfiles_manifest", {"a/b c/d"}));
|
||||
EXPECT_TRUE(mf != nullptr);
|
||||
|
||||
string error;
|
||||
unique_ptr<Runfiles> r(Runfiles::Create("ignore-argv0", mf->Path(),
|
||||
"non-existent-runfiles_dir", &error));
|
||||
ASSERT_NE(r, nullptr);
|
||||
EXPECT_TRUE(error.empty());
|
||||
EXPECT_EQ(r->Rlocation("a/b"), "c/d");
|
||||
// We know it's manifest-based because it returns empty string for unknown
|
||||
// paths.
|
||||
EXPECT_EQ(r->Rlocation("unknown"), "");
|
||||
AssertEnvvars(*r, mf->Path(), "");
|
||||
}
|
||||
|
||||
TEST_F(RunfilesTest, CannotCreateManifestBasedRunfilesDueToBadManifest) {
|
||||
unique_ptr<MockFile> mf(MockFile::Create(
|
||||
"foo" LINE_AS_STRING() ".runfiles_manifest", {"a b", "nospace"}));
|
||||
EXPECT_TRUE(mf != nullptr);
|
||||
|
||||
string error;
|
||||
unique_ptr<Runfiles> r(
|
||||
Runfiles::Create("ignore-argv0", mf->Path(), "", &error));
|
||||
ASSERT_EQ(r, nullptr);
|
||||
EXPECT_NE(error.find("bad runfiles manifest entry"), string::npos);
|
||||
EXPECT_NE(error.find("line #2: \"nospace\""), string::npos);
|
||||
}
|
||||
|
||||
TEST_F(RunfilesTest, ManifestBasedRunfilesRlocationAndEnvVars) {
|
||||
unique_ptr<MockFile> mf(MockFile::Create(
|
||||
"foo" LINE_AS_STRING() ".runfiles_manifest", {"a/b c/d"}));
|
||||
EXPECT_TRUE(mf != nullptr);
|
||||
|
||||
string error;
|
||||
unique_ptr<Runfiles> r(
|
||||
Runfiles::Create("ignore-argv0", mf->Path(), "", &error));
|
||||
|
||||
ASSERT_NE(r, nullptr);
|
||||
EXPECT_TRUE(error.empty());
|
||||
EXPECT_EQ(r->Rlocation("a/b"), "c/d");
|
||||
EXPECT_EQ(r->Rlocation("c/d"), "");
|
||||
EXPECT_EQ(r->Rlocation(""), "");
|
||||
EXPECT_EQ(r->Rlocation("foo"), "");
|
||||
EXPECT_EQ(r->Rlocation("foo/"), "");
|
||||
EXPECT_EQ(r->Rlocation("foo/bar"), "");
|
||||
EXPECT_EQ(r->Rlocation("../foo"), "");
|
||||
EXPECT_EQ(r->Rlocation("foo/.."), "");
|
||||
EXPECT_EQ(r->Rlocation("foo/../bar"), "");
|
||||
EXPECT_EQ(r->Rlocation("./foo"), "");
|
||||
EXPECT_EQ(r->Rlocation("foo/."), "");
|
||||
EXPECT_EQ(r->Rlocation("foo/./bar"), "");
|
||||
EXPECT_EQ(r->Rlocation("//foo"), "");
|
||||
EXPECT_EQ(r->Rlocation("foo//"), "");
|
||||
EXPECT_EQ(r->Rlocation("foo//bar"), "");
|
||||
EXPECT_EQ(r->Rlocation("/Foo"), "/Foo");
|
||||
EXPECT_EQ(r->Rlocation("c:/Foo"), "c:/Foo");
|
||||
EXPECT_EQ(r->Rlocation("c:\\Foo"), "c:\\Foo");
|
||||
}
|
||||
|
||||
TEST_F(RunfilesTest, DirectoryBasedRunfilesRlocationAndEnvVars) {
|
||||
unique_ptr<MockFile> dummy(
|
||||
MockFile::Create("foo" LINE_AS_STRING() ".runfiles/dummy", {"a/b c/d"}));
|
||||
EXPECT_TRUE(dummy != nullptr);
|
||||
string dir = dummy->DirName();
|
||||
|
||||
string error;
|
||||
unique_ptr<Runfiles> r(Runfiles::Create("ignore-argv0", "", dir, &error));
|
||||
ASSERT_NE(r, nullptr);
|
||||
EXPECT_TRUE(error.empty());
|
||||
|
||||
EXPECT_EQ(r->Rlocation("a/b"), dir + "/a/b");
|
||||
EXPECT_EQ(r->Rlocation("c/d"), dir + "/c/d");
|
||||
EXPECT_EQ(r->Rlocation(""), "");
|
||||
EXPECT_EQ(r->Rlocation("foo"), dir + "/foo");
|
||||
EXPECT_EQ(r->Rlocation("foo/"), dir + "/foo/");
|
||||
EXPECT_EQ(r->Rlocation("foo/bar"), dir + "/foo/bar");
|
||||
EXPECT_EQ(r->Rlocation("../foo"), "");
|
||||
EXPECT_EQ(r->Rlocation("foo/.."), "");
|
||||
EXPECT_EQ(r->Rlocation("foo/../bar"), "");
|
||||
EXPECT_EQ(r->Rlocation("./foo"), "");
|
||||
EXPECT_EQ(r->Rlocation("foo/."), "");
|
||||
EXPECT_EQ(r->Rlocation("foo/./bar"), "");
|
||||
EXPECT_EQ(r->Rlocation("//foo"), "");
|
||||
EXPECT_EQ(r->Rlocation("foo//"), "");
|
||||
EXPECT_EQ(r->Rlocation("foo//bar"), "");
|
||||
EXPECT_EQ(r->Rlocation("/Foo"), "/Foo");
|
||||
EXPECT_EQ(r->Rlocation("c:/Foo"), "c:/Foo");
|
||||
EXPECT_EQ(r->Rlocation("c:\\Foo"), "c:\\Foo");
|
||||
AssertEnvvars(*r, "", dir);
|
||||
}
|
||||
|
||||
TEST_F(RunfilesTest, ManifestAndDirectoryBasedRunfilesRlocationAndEnvVars) {
|
||||
unique_ptr<MockFile> mf(MockFile::Create(
|
||||
"foo" LINE_AS_STRING() ".runfiles/MANIFEST", {"a/b c/d"}));
|
||||
EXPECT_TRUE(mf != nullptr);
|
||||
string dir = mf->DirName();
|
||||
|
||||
string error;
|
||||
unique_ptr<Runfiles> r(
|
||||
Runfiles::Create("ignore-argv0", mf->Path(), "", &error));
|
||||
|
||||
ASSERT_NE(r, nullptr);
|
||||
EXPECT_TRUE(error.empty());
|
||||
EXPECT_EQ(r->Rlocation("a/b"), "c/d");
|
||||
EXPECT_EQ(r->Rlocation("c/d"), dir + "/c/d");
|
||||
EXPECT_EQ(r->Rlocation(""), "");
|
||||
EXPECT_EQ(r->Rlocation("foo"), dir + "/foo");
|
||||
EXPECT_EQ(r->Rlocation("foo/"), dir + "/foo/");
|
||||
EXPECT_EQ(r->Rlocation("foo/bar"), dir + "/foo/bar");
|
||||
EXPECT_EQ(r->Rlocation("../foo"), "");
|
||||
EXPECT_EQ(r->Rlocation("foo/.."), "");
|
||||
EXPECT_EQ(r->Rlocation("foo/../bar"), "");
|
||||
EXPECT_EQ(r->Rlocation("./foo"), "");
|
||||
EXPECT_EQ(r->Rlocation("foo/."), "");
|
||||
EXPECT_EQ(r->Rlocation("foo/./bar"), "");
|
||||
EXPECT_EQ(r->Rlocation("//foo"), "");
|
||||
EXPECT_EQ(r->Rlocation("foo//"), "");
|
||||
EXPECT_EQ(r->Rlocation("foo//bar"), "");
|
||||
EXPECT_EQ(r->Rlocation("/Foo"), "/Foo");
|
||||
EXPECT_EQ(r->Rlocation("c:/Foo"), "c:/Foo");
|
||||
EXPECT_EQ(r->Rlocation("c:\\Foo"), "c:\\Foo");
|
||||
AssertEnvvars(*r, mf->Path(), dir);
|
||||
}
|
||||
|
||||
TEST_F(RunfilesTest, ManifestBasedRunfilesEnvVars) {
|
||||
unique_ptr<MockFile> mf(
|
||||
MockFile::Create(string("foo" LINE_AS_STRING() ".runfiles_manifest")));
|
||||
EXPECT_TRUE(mf != nullptr);
|
||||
|
||||
string error;
|
||||
unique_ptr<Runfiles> r(
|
||||
Runfiles::Create("ignore-argv0", mf->Path(), "", &error));
|
||||
ASSERT_NE(r, nullptr);
|
||||
EXPECT_TRUE(error.empty());
|
||||
|
||||
AssertEnvvars(*r, mf->Path(), "");
|
||||
}
|
||||
|
||||
TEST_F(RunfilesTest, CreatesDirectoryBasedRunfilesFromDirectoryNextToBinary) {
|
||||
// We create a directory as a side-effect of creating a mock file.
|
||||
unique_ptr<MockFile> mf(
|
||||
MockFile::Create(string("foo" LINE_AS_STRING() ".runfiles/dummy")));
|
||||
string argv0(mf->Path().substr(
|
||||
0, mf->Path().size() - string(".runfiles/dummy").size()));
|
||||
|
||||
string error;
|
||||
unique_ptr<Runfiles> r(Runfiles::Create(argv0, "", "", &error));
|
||||
ASSERT_NE(r, nullptr);
|
||||
EXPECT_TRUE(error.empty());
|
||||
|
||||
EXPECT_EQ(r->Rlocation("a/b"), argv0 + ".runfiles/a/b");
|
||||
// We know it's directory-based because it returns some result for unknown
|
||||
// paths.
|
||||
EXPECT_EQ(r->Rlocation("unknown"), argv0 + ".runfiles/unknown");
|
||||
AssertEnvvars(*r, "", argv0 + ".runfiles");
|
||||
}
|
||||
|
||||
TEST_F(RunfilesTest, CreatesDirectoryBasedRunfilesFromEnvvar) {
|
||||
// We create a directory as a side-effect of creating a mock file.
|
||||
unique_ptr<MockFile> mf(
|
||||
MockFile::Create(string("foo" LINE_AS_STRING() ".runfiles/dummy")));
|
||||
string dir = mf->DirName();
|
||||
|
||||
string error;
|
||||
unique_ptr<Runfiles> r(Runfiles::Create("ignore-argv0", "", dir, &error));
|
||||
ASSERT_NE(r, nullptr);
|
||||
EXPECT_TRUE(error.empty());
|
||||
|
||||
EXPECT_EQ(r->Rlocation("a/b"), dir + "/a/b");
|
||||
EXPECT_EQ(r->Rlocation("foo"), dir + "/foo");
|
||||
EXPECT_EQ(r->Rlocation("/Foo"), "/Foo");
|
||||
EXPECT_EQ(r->Rlocation("c:/Foo"), "c:/Foo");
|
||||
EXPECT_EQ(r->Rlocation("c:\\Foo"), "c:\\Foo");
|
||||
AssertEnvvars(*r, "", dir);
|
||||
}
|
||||
|
||||
TEST_F(RunfilesTest, FailsToCreateAnyRunfilesBecauseEnvvarsAreNotDefined) {
|
||||
unique_ptr<MockFile> mf(
|
||||
MockFile::Create(string("foo" LINE_AS_STRING() ".runfiles/MANIFEST")));
|
||||
EXPECT_TRUE(mf != nullptr);
|
||||
|
||||
string error;
|
||||
unique_ptr<Runfiles> r(
|
||||
Runfiles::Create("ignore-argv0", mf->Path(), "whatever", &error));
|
||||
ASSERT_NE(r, nullptr);
|
||||
EXPECT_TRUE(error.empty());
|
||||
|
||||
// We create a directory as a side-effect of creating a mock file.
|
||||
mf.reset(MockFile::Create(string("foo" LINE_AS_STRING() ".runfiles/dummy")));
|
||||
r.reset(Runfiles::Create("ignore-argv0", "", mf->DirName(), &error));
|
||||
ASSERT_NE(r, nullptr);
|
||||
EXPECT_TRUE(error.empty());
|
||||
|
||||
r.reset(Runfiles::Create("ignore-argv0", "", "", &error));
|
||||
ASSERT_EQ(r, nullptr);
|
||||
EXPECT_NE(error.find("cannot find runfiles"), string::npos);
|
||||
}
|
||||
|
||||
TEST_F(RunfilesTest, MockFileTest) {
|
||||
{
|
||||
unique_ptr<MockFile> mf(
|
||||
MockFile::Create(string("foo" LINE_AS_STRING() "/..")));
|
||||
EXPECT_TRUE(mf == nullptr);
|
||||
}
|
||||
|
||||
{
|
||||
unique_ptr<MockFile> mf(MockFile::Create(string("/Foo" LINE_AS_STRING())));
|
||||
EXPECT_TRUE(mf == nullptr);
|
||||
}
|
||||
|
||||
{
|
||||
unique_ptr<MockFile> mf(
|
||||
MockFile::Create(string("C:/Foo" LINE_AS_STRING())));
|
||||
EXPECT_TRUE(mf == nullptr);
|
||||
}
|
||||
|
||||
string path;
|
||||
{
|
||||
unique_ptr<MockFile> mf(
|
||||
MockFile::Create(string("foo" LINE_AS_STRING() "/bar1/qux")));
|
||||
EXPECT_TRUE(mf != nullptr);
|
||||
path = mf->Path();
|
||||
|
||||
std::ifstream stm(path);
|
||||
EXPECT_TRUE(stm.good());
|
||||
string actual;
|
||||
stm >> actual;
|
||||
EXPECT_TRUE(actual.empty());
|
||||
}
|
||||
{
|
||||
std::ifstream stm(path);
|
||||
EXPECT_FALSE(stm.good());
|
||||
}
|
||||
|
||||
{
|
||||
unique_ptr<MockFile> mf(MockFile::Create(
|
||||
string("foo" LINE_AS_STRING() "/bar2/qux"), vector<string>()));
|
||||
EXPECT_TRUE(mf != nullptr);
|
||||
path = mf->Path();
|
||||
|
||||
std::ifstream stm(path);
|
||||
EXPECT_TRUE(stm.good());
|
||||
string actual;
|
||||
stm >> actual;
|
||||
EXPECT_TRUE(actual.empty());
|
||||
}
|
||||
{
|
||||
std::ifstream stm(path);
|
||||
EXPECT_FALSE(stm.good());
|
||||
}
|
||||
|
||||
{
|
||||
unique_ptr<MockFile> mf(
|
||||
MockFile::Create(string("foo" LINE_AS_STRING() "/bar3/qux"),
|
||||
{"hello world", "you are beautiful"}));
|
||||
EXPECT_TRUE(mf != nullptr);
|
||||
path = mf->Path();
|
||||
|
||||
std::ifstream stm(path);
|
||||
EXPECT_TRUE(stm.good());
|
||||
string actual;
|
||||
std::getline(stm, actual);
|
||||
EXPECT_EQ("hello world", actual);
|
||||
std::getline(stm, actual);
|
||||
EXPECT_EQ("you are beautiful", actual);
|
||||
std::getline(stm, actual);
|
||||
EXPECT_EQ("", actual);
|
||||
}
|
||||
{
|
||||
std::ifstream stm(path);
|
||||
EXPECT_FALSE(stm.good());
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(RunfilesTest, IsAbsolute) {
|
||||
EXPECT_FALSE(TestOnly_IsAbsolute("foo"));
|
||||
EXPECT_FALSE(TestOnly_IsAbsolute("foo/bar"));
|
||||
EXPECT_FALSE(TestOnly_IsAbsolute("\\foo"));
|
||||
EXPECT_TRUE(TestOnly_IsAbsolute("c:\\foo"));
|
||||
EXPECT_TRUE(TestOnly_IsAbsolute("c:/foo"));
|
||||
EXPECT_TRUE(TestOnly_IsAbsolute("/foo"));
|
||||
EXPECT_TRUE(TestOnly_IsAbsolute("x:\\foo"));
|
||||
EXPECT_FALSE(TestOnly_IsAbsolute("::\\foo"));
|
||||
EXPECT_FALSE(TestOnly_IsAbsolute("x\\foo"));
|
||||
EXPECT_FALSE(TestOnly_IsAbsolute("x:"));
|
||||
EXPECT_TRUE(TestOnly_IsAbsolute("x:\\"));
|
||||
}
|
||||
|
||||
TEST_F(RunfilesTest, PathsFromEnvVars) {
|
||||
string mf, dir;
|
||||
|
||||
// Both envvars have a valid value.
|
||||
EXPECT_TRUE(TestOnly_PathsFrom(
|
||||
"argv0", "mock1/MANIFEST", "mock2",
|
||||
[](const string& path) { return path == "mock1/MANIFEST"; },
|
||||
[](const string& path) { return path == "mock2"; }, &mf, &dir));
|
||||
EXPECT_EQ(mf, "mock1/MANIFEST");
|
||||
EXPECT_EQ(dir, "mock2");
|
||||
|
||||
// RUNFILES_MANIFEST_FILE is invalid but RUNFILES_DIR is good and there's a
|
||||
// runfiles manifest in the runfiles directory.
|
||||
EXPECT_TRUE(TestOnly_PathsFrom(
|
||||
"argv0", "mock1/MANIFEST", "mock2",
|
||||
[](const string& path) { return path == "mock2/MANIFEST"; },
|
||||
[](const string& path) { return path == "mock2"; }, &mf, &dir));
|
||||
EXPECT_EQ(mf, "mock2/MANIFEST");
|
||||
EXPECT_EQ(dir, "mock2");
|
||||
|
||||
// RUNFILES_MANIFEST_FILE is invalid but RUNFILES_DIR is good, but there's no
|
||||
// runfiles manifest in the runfiles directory.
|
||||
EXPECT_TRUE(TestOnly_PathsFrom(
|
||||
"argv0", "mock1/MANIFEST", "mock2",
|
||||
[](const string& path) { return false; },
|
||||
[](const string& path) { return path == "mock2"; }, &mf, &dir));
|
||||
EXPECT_EQ(mf, "");
|
||||
EXPECT_EQ(dir, "mock2");
|
||||
|
||||
// RUNFILES_DIR is invalid but RUNFILES_MANIFEST_FILE is good, and it is in
|
||||
// a valid-looking runfiles directory.
|
||||
EXPECT_TRUE(TestOnly_PathsFrom(
|
||||
"argv0", "mock1/MANIFEST", "mock2",
|
||||
[](const string& path) { return path == "mock1/MANIFEST"; },
|
||||
[](const string& path) { return path == "mock1"; }, &mf, &dir));
|
||||
EXPECT_EQ(mf, "mock1/MANIFEST");
|
||||
EXPECT_EQ(dir, "mock1");
|
||||
|
||||
// RUNFILES_DIR is invalid but RUNFILES_MANIFEST_FILE is good, but it is not
|
||||
// in any valid-looking runfiles directory.
|
||||
EXPECT_TRUE(TestOnly_PathsFrom(
|
||||
"argv0", "mock1/MANIFEST", "mock2",
|
||||
[](const string& path) { return path == "mock1/MANIFEST"; },
|
||||
[](const string& path) { return false; }, &mf, &dir));
|
||||
EXPECT_EQ(mf, "mock1/MANIFEST");
|
||||
EXPECT_EQ(dir, "");
|
||||
|
||||
// Both envvars are invalid, but there's a manifest in a runfiles directory
|
||||
// next to argv0, however there's no other content in the runfiles directory.
|
||||
EXPECT_TRUE(TestOnly_PathsFrom(
|
||||
"argv0", "mock1/MANIFEST", "mock2",
|
||||
[](const string& path) { return path == "argv0.runfiles/MANIFEST"; },
|
||||
[](const string& path) { return false; }, &mf, &dir));
|
||||
EXPECT_EQ(mf, "argv0.runfiles/MANIFEST");
|
||||
EXPECT_EQ(dir, "");
|
||||
|
||||
// Both envvars are invalid, but there's a manifest next to argv0. There's
|
||||
// no runfiles tree anywhere.
|
||||
EXPECT_TRUE(TestOnly_PathsFrom(
|
||||
"argv0", "mock1/MANIFEST", "mock2",
|
||||
[](const string& path) { return path == "argv0.runfiles_manifest"; },
|
||||
[](const string& path) { return false; }, &mf, &dir));
|
||||
EXPECT_EQ(mf, "argv0.runfiles_manifest");
|
||||
EXPECT_EQ(dir, "");
|
||||
|
||||
// Both envvars are invalid, but there's a valid manifest next to argv0, and a
|
||||
// valid runfiles directory (without a manifest in it).
|
||||
EXPECT_TRUE(TestOnly_PathsFrom(
|
||||
"argv0", "mock1/MANIFEST", "mock2",
|
||||
[](const string& path) { return path == "argv0.runfiles_manifest"; },
|
||||
[](const string& path) { return path == "argv0.runfiles"; }, &mf, &dir));
|
||||
EXPECT_EQ(mf, "argv0.runfiles_manifest");
|
||||
EXPECT_EQ(dir, "argv0.runfiles");
|
||||
|
||||
// Both envvars are invalid, but there's a valid runfiles directory next to
|
||||
// argv0, though no manifest in it.
|
||||
EXPECT_TRUE(TestOnly_PathsFrom(
|
||||
"argv0", "mock1/MANIFEST", "mock2",
|
||||
[](const string& path) { return false; },
|
||||
[](const string& path) { return path == "argv0.runfiles"; }, &mf, &dir));
|
||||
EXPECT_EQ(mf, "");
|
||||
EXPECT_EQ(dir, "argv0.runfiles");
|
||||
|
||||
// Both envvars are invalid, but there's a valid runfiles directory next to
|
||||
// argv0 with a valid manifest in it.
|
||||
EXPECT_TRUE(TestOnly_PathsFrom(
|
||||
"argv0", "mock1/MANIFEST", "mock2",
|
||||
[](const string& path) { return path == "argv0.runfiles/MANIFEST"; },
|
||||
[](const string& path) { return path == "argv0.runfiles"; }, &mf, &dir));
|
||||
EXPECT_EQ(mf, "argv0.runfiles/MANIFEST");
|
||||
EXPECT_EQ(dir, "argv0.runfiles");
|
||||
}
|
||||
|
||||
} // namespace
|
||||
} // namespace runfiles
|
||||
} // namespace cpp
|
||||
} // namespace tools
|
||||
} // namespace bazel
|
|
@ -0,0 +1,567 @@
|
|||
# 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 Unix platforms."""
|
||||
|
||||
load(
|
||||
"@rules_cc//cc/private/toolchain:lib_cc_configure.bzl",
|
||||
"auto_configure_fail",
|
||||
"auto_configure_warning",
|
||||
"auto_configure_warning_maybe",
|
||||
"escape_string",
|
||||
"get_env_var",
|
||||
"get_starlark_list",
|
||||
"resolve_labels",
|
||||
"split_escaped",
|
||||
"which",
|
||||
)
|
||||
|
||||
def _field(name, value):
|
||||
"""Returns properly indented top level crosstool field."""
|
||||
if type(value) == "list":
|
||||
return "\n".join([" " + name + ": '" + v + "'" for v in value])
|
||||
elif type(value) == "string":
|
||||
return " " + name + ": '" + value + "'"
|
||||
else:
|
||||
auto_configure_fail("Unexpected field type: " + type(value))
|
||||
return ""
|
||||
|
||||
def _uniq(iterable):
|
||||
"""Remove duplicates from a list."""
|
||||
|
||||
unique_elements = {element: None for element in iterable}
|
||||
return unique_elements.keys()
|
||||
|
||||
def _prepare_include_path(repo_ctx, path):
|
||||
"""Resolve and sanitize include path before outputting it into the crosstool.
|
||||
|
||||
Args:
|
||||
repo_ctx: repository_ctx object.
|
||||
path: an include path to be sanitized.
|
||||
|
||||
Returns:
|
||||
Sanitized include path that can be written to the crosstoot. Resulting path
|
||||
is absolute if it is outside the repository and relative otherwise.
|
||||
"""
|
||||
|
||||
repo_root = str(repo_ctx.path("."))
|
||||
|
||||
# We're on UNIX, so the path delimiter is '/'.
|
||||
repo_root += "/"
|
||||
path = str(repo_ctx.path(path))
|
||||
if path.startswith(repo_root):
|
||||
return escape_string(path[len(repo_root):])
|
||||
return escape_string(path)
|
||||
|
||||
def _get_value(it):
|
||||
"""Convert `it` in serialized protobuf format."""
|
||||
if type(it) == "int":
|
||||
return str(it)
|
||||
elif type(it) == "bool":
|
||||
return "true" if it else "false"
|
||||
else:
|
||||
return "\"%s\"" % it
|
||||
|
||||
def _find_tool(repository_ctx, tool, overriden_tools):
|
||||
"""Find a tool for repository, taking overriden tools into account."""
|
||||
if tool in overriden_tools:
|
||||
return overriden_tools[tool]
|
||||
return which(repository_ctx, tool, "/usr/bin/" + tool)
|
||||
|
||||
def _get_tool_paths(repository_ctx, overriden_tools):
|
||||
"""Compute the %-escaped path to the various tools"""
|
||||
return dict({
|
||||
k: escape_string(_find_tool(repository_ctx, k, overriden_tools))
|
||||
for k in [
|
||||
"ar",
|
||||
"ld",
|
||||
"cpp",
|
||||
"gcc",
|
||||
"dwp",
|
||||
"gcov",
|
||||
"nm",
|
||||
"objcopy",
|
||||
"objdump",
|
||||
"strip",
|
||||
]
|
||||
}.items())
|
||||
|
||||
def _escaped_cplus_include_paths(repository_ctx):
|
||||
"""Use ${CPLUS_INCLUDE_PATH} to compute the %-escaped list of flags for cxxflag."""
|
||||
if "CPLUS_INCLUDE_PATH" in repository_ctx.os.environ:
|
||||
result = []
|
||||
for p in repository_ctx.os.environ["CPLUS_INCLUDE_PATH"].split(":"):
|
||||
p = escape_string(str(repository_ctx.path(p))) # Normalize the path
|
||||
result.append("-I" + p)
|
||||
return result
|
||||
else:
|
||||
return []
|
||||
|
||||
_INC_DIR_MARKER_BEGIN = "#include <...>"
|
||||
|
||||
# OSX add " (framework directory)" at the end of line, strip it.
|
||||
_OSX_FRAMEWORK_SUFFIX = " (framework directory)"
|
||||
_OSX_FRAMEWORK_SUFFIX_LEN = len(_OSX_FRAMEWORK_SUFFIX)
|
||||
|
||||
def _cxx_inc_convert(path):
|
||||
"""Convert path returned by cc -E xc++ in a complete path. Doesn't %-escape the path!"""
|
||||
path = path.strip()
|
||||
if path.endswith(_OSX_FRAMEWORK_SUFFIX):
|
||||
path = path[:-_OSX_FRAMEWORK_SUFFIX_LEN].strip()
|
||||
return path
|
||||
|
||||
def get_escaped_cxx_inc_directories(repository_ctx, cc, lang_flag, additional_flags = []):
|
||||
"""Compute the list of default %-escaped C++ include directories."""
|
||||
result = repository_ctx.execute([cc, "-E", lang_flag, "-", "-v"] + additional_flags)
|
||||
index1 = result.stderr.find(_INC_DIR_MARKER_BEGIN)
|
||||
if index1 == -1:
|
||||
return []
|
||||
index1 = result.stderr.find("\n", index1)
|
||||
if index1 == -1:
|
||||
return []
|
||||
index2 = result.stderr.rfind("\n ")
|
||||
if index2 == -1 or index2 < index1:
|
||||
return []
|
||||
index2 = result.stderr.find("\n", index2 + 1)
|
||||
if index2 == -1:
|
||||
inc_dirs = result.stderr[index1 + 1:]
|
||||
else:
|
||||
inc_dirs = result.stderr[index1 + 1:index2].strip()
|
||||
|
||||
return [
|
||||
_prepare_include_path(repository_ctx, _cxx_inc_convert(p))
|
||||
for p in inc_dirs.split("\n")
|
||||
]
|
||||
|
||||
def _is_compiler_option_supported(repository_ctx, cc, option):
|
||||
"""Checks that `option` is supported by the C compiler. Doesn't %-escape the option."""
|
||||
result = repository_ctx.execute([
|
||||
cc,
|
||||
option,
|
||||
"-o",
|
||||
"/dev/null",
|
||||
"-c",
|
||||
str(repository_ctx.path("tools/cpp/empty.cc")),
|
||||
])
|
||||
return result.stderr.find(option) == -1
|
||||
|
||||
def _is_linker_option_supported(repository_ctx, cc, option, pattern):
|
||||
"""Checks that `option` is supported by the C linker. Doesn't %-escape the option."""
|
||||
result = repository_ctx.execute([
|
||||
cc,
|
||||
option,
|
||||
"-o",
|
||||
"/dev/null",
|
||||
str(repository_ctx.path("tools/cpp/empty.cc")),
|
||||
])
|
||||
return result.stderr.find(pattern) == -1
|
||||
|
||||
def _find_gold_linker_path(repository_ctx, cc):
|
||||
"""Checks if `gold` is supported by the C compiler.
|
||||
|
||||
Args:
|
||||
repository_ctx: repository_ctx.
|
||||
cc: path to the C compiler.
|
||||
|
||||
Returns:
|
||||
String to put as value to -fuse-ld= flag, or None if gold couldn't be found.
|
||||
"""
|
||||
result = repository_ctx.execute([
|
||||
cc,
|
||||
str(repository_ctx.path("tools/cpp/empty.cc")),
|
||||
"-o",
|
||||
"/dev/null",
|
||||
# Some macos clang versions don't fail when setting -fuse-ld=gold, adding
|
||||
# these lines to force it to. This also means that we will not detect
|
||||
# gold when only a very old (year 2010 and older) is present.
|
||||
"-Wl,--start-lib",
|
||||
"-Wl,--end-lib",
|
||||
"-fuse-ld=gold",
|
||||
"-v",
|
||||
])
|
||||
if result.return_code != 0:
|
||||
return None
|
||||
|
||||
for line in result.stderr.splitlines():
|
||||
if line.find("gold") == -1:
|
||||
continue
|
||||
for flag in line.split(" "):
|
||||
if flag.find("gold") == -1:
|
||||
continue
|
||||
|
||||
# flag is '-fuse-ld=gold' for GCC or "/usr/lib/ld.gold" for Clang
|
||||
# strip space, single quote, and double quotes
|
||||
flag = flag.strip(" \"'")
|
||||
|
||||
# remove -fuse-ld= from GCC output so we have only the flag value part
|
||||
flag = flag.replace("-fuse-ld=", "")
|
||||
return flag
|
||||
auto_configure_warning(
|
||||
"CC with -fuse-ld=gold returned 0, but its -v output " +
|
||||
"didn't contain 'gold', falling back to the default linker.",
|
||||
)
|
||||
return None
|
||||
|
||||
def _add_compiler_option_if_supported(repository_ctx, cc, option):
|
||||
"""Returns `[option]` if supported, `[]` otherwise. Doesn't %-escape the option."""
|
||||
return [option] if _is_compiler_option_supported(repository_ctx, cc, option) else []
|
||||
|
||||
def _add_linker_option_if_supported(repository_ctx, cc, option, pattern):
|
||||
"""Returns `[option]` if supported, `[]` otherwise. Doesn't %-escape the option."""
|
||||
return [option] if _is_linker_option_supported(repository_ctx, cc, option, pattern) else []
|
||||
|
||||
def _get_no_canonical_prefixes_opt(repository_ctx, cc):
|
||||
# If the compiler sometimes rewrites paths in the .d files without symlinks
|
||||
# (ie when they're shorter), it confuses Bazel's logic for verifying all
|
||||
# #included header files are listed as inputs to the action.
|
||||
|
||||
# The '-fno-canonical-system-headers' should be enough, but clang does not
|
||||
# support it, so we also try '-no-canonical-prefixes' if first option does
|
||||
# not work.
|
||||
opt = _add_compiler_option_if_supported(
|
||||
repository_ctx,
|
||||
cc,
|
||||
"-fno-canonical-system-headers",
|
||||
)
|
||||
if len(opt) == 0:
|
||||
return _add_compiler_option_if_supported(
|
||||
repository_ctx,
|
||||
cc,
|
||||
"-no-canonical-prefixes",
|
||||
)
|
||||
return opt
|
||||
|
||||
def get_env(repository_ctx):
|
||||
"""Convert the environment in a list of export if in Homebrew. Doesn't %-escape the result!"""
|
||||
env = repository_ctx.os.environ
|
||||
if "HOMEBREW_RUBY_PATH" in env:
|
||||
return "\n".join([
|
||||
"export %s='%s'" % (k, env[k].replace("'", "'\\''"))
|
||||
for k in env
|
||||
if k != "_" and k.find(".") == -1
|
||||
])
|
||||
else:
|
||||
return ""
|
||||
|
||||
def _coverage_flags(repository_ctx, darwin):
|
||||
use_llvm_cov = "1" == get_env_var(
|
||||
repository_ctx,
|
||||
"BAZEL_USE_LLVM_NATIVE_COVERAGE",
|
||||
default = "0",
|
||||
enable_warning = False,
|
||||
)
|
||||
if darwin or use_llvm_cov:
|
||||
compile_flags = '"-fprofile-instr-generate", "-fcoverage-mapping"'
|
||||
link_flags = '"-fprofile-instr-generate"'
|
||||
else:
|
||||
# gcc requires --coverage being passed for compilation and linking
|
||||
# https://gcc.gnu.org/onlinedocs/gcc/Instrumentation-Options.html#Instrumentation-Options
|
||||
compile_flags = '"--coverage"'
|
||||
link_flags = '"--coverage"'
|
||||
return compile_flags, link_flags
|
||||
|
||||
def _find_generic(repository_ctx, name, env_name, overriden_tools, warn = False, silent = False):
|
||||
"""Find a generic C++ toolchain tool. Doesn't %-escape the result."""
|
||||
|
||||
if name in overriden_tools:
|
||||
return overriden_tools[name]
|
||||
|
||||
result = name
|
||||
env_value = repository_ctx.os.environ.get(env_name)
|
||||
env_value_with_paren = ""
|
||||
if env_value != None:
|
||||
env_value = env_value.strip()
|
||||
if env_value:
|
||||
result = env_value
|
||||
env_value_with_paren = " (%s)" % env_value
|
||||
if result.startswith("/"):
|
||||
# Absolute path, maybe we should make this suported by our which function.
|
||||
return result
|
||||
result = repository_ctx.which(result)
|
||||
if result == None:
|
||||
msg = ("Cannot find %s or %s%s; either correct your path or set the %s" +
|
||||
" environment variable") % (name, env_name, env_value_with_paren, env_name)
|
||||
if warn:
|
||||
if not silent:
|
||||
auto_configure_warning(msg)
|
||||
else:
|
||||
auto_configure_fail(msg)
|
||||
return result
|
||||
|
||||
def find_cc(repository_ctx, overriden_tools):
|
||||
return _find_generic(repository_ctx, "gcc", "CC", overriden_tools)
|
||||
|
||||
def configure_unix_toolchain(repository_ctx, cpu_value, overriden_tools):
|
||||
"""Configure C++ toolchain on Unix platforms."""
|
||||
paths = resolve_labels(repository_ctx, [
|
||||
"@rules_cc//cc/private/toolchain:BUILD.tpl",
|
||||
"@rules_cc//cc/private/toolchain:armeabi_cc_toolchain_config.bzl",
|
||||
"@rules_cc//cc/private/toolchain:unix_cc_toolchain_config.bzl",
|
||||
"@rules_cc//cc/private/toolchain:linux_cc_wrapper.sh.tpl",
|
||||
"@rules_cc//cc/private/toolchain:osx_cc_wrapper.sh.tpl",
|
||||
])
|
||||
|
||||
repository_ctx.symlink(
|
||||
paths["@rules_cc//cc/private/toolchain:unix_cc_toolchain_config.bzl"],
|
||||
"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.file("tools/cpp/empty.cc", "int main() {}")
|
||||
darwin = cpu_value == "darwin"
|
||||
|
||||
cc = _find_generic(repository_ctx, "gcc", "CC", overriden_tools)
|
||||
overriden_tools = dict(overriden_tools)
|
||||
overriden_tools["gcc"] = cc
|
||||
overriden_tools["gcov"] = _find_generic(
|
||||
repository_ctx,
|
||||
"gcov",
|
||||
"GCOV",
|
||||
overriden_tools,
|
||||
warn = True,
|
||||
silent = True,
|
||||
)
|
||||
if darwin:
|
||||
overriden_tools["gcc"] = "cc_wrapper.sh"
|
||||
overriden_tools["ar"] = "/usr/bin/libtool"
|
||||
auto_configure_warning_maybe(repository_ctx, "CC used: " + str(cc))
|
||||
tool_paths = _get_tool_paths(repository_ctx, overriden_tools)
|
||||
cc_toolchain_identifier = escape_string(get_env_var(
|
||||
repository_ctx,
|
||||
"CC_TOOLCHAIN_NAME",
|
||||
"local",
|
||||
False,
|
||||
))
|
||||
|
||||
cc_wrapper_src = (
|
||||
"@rules_cc//cc/private/toolchain:osx_cc_wrapper.sh.tpl" if darwin else "@rules_cc//cc/private/toolchain:linux_cc_wrapper.sh.tpl"
|
||||
)
|
||||
repository_ctx.template(
|
||||
"cc_wrapper.sh",
|
||||
paths[cc_wrapper_src],
|
||||
{
|
||||
"%{cc}": escape_string(str(cc)),
|
||||
"%{env}": escape_string(get_env(repository_ctx)),
|
||||
},
|
||||
)
|
||||
|
||||
cxx_opts = split_escaped(get_env_var(
|
||||
repository_ctx,
|
||||
"BAZEL_CXXOPTS",
|
||||
"-std=c++0x",
|
||||
False,
|
||||
), ":")
|
||||
link_opts = split_escaped(get_env_var(
|
||||
repository_ctx,
|
||||
"BAZEL_LINKOPTS",
|
||||
"-lstdc++:-lm",
|
||||
False,
|
||||
), ":")
|
||||
link_libs = split_escaped(get_env_var(
|
||||
repository_ctx,
|
||||
"BAZEL_LINKLIBS",
|
||||
"",
|
||||
False,
|
||||
), ":")
|
||||
gold_linker_path = _find_gold_linker_path(repository_ctx, cc)
|
||||
cc_path = repository_ctx.path(cc)
|
||||
if not str(cc_path).startswith(str(repository_ctx.path(".")) + "/"):
|
||||
# cc is outside the repository, set -B
|
||||
bin_search_flag = ["-B" + escape_string(str(cc_path.dirname))]
|
||||
else:
|
||||
# cc is inside the repository, don't set -B.
|
||||
bin_search_flag = []
|
||||
|
||||
coverage_compile_flags, coverage_link_flags = _coverage_flags(repository_ctx, darwin)
|
||||
|
||||
repository_ctx.template(
|
||||
"BUILD",
|
||||
paths["@rules_cc//cc/private/toolchain:BUILD.tpl"],
|
||||
{
|
||||
"%{cc_toolchain_identifier}": cc_toolchain_identifier,
|
||||
"%{name}": cpu_value,
|
||||
"%{supports_param_files}": "0" if darwin else "1",
|
||||
"%{cc_compiler_deps}": ":cc_wrapper" if darwin else ":empty",
|
||||
"%{compiler}": escape_string(get_env_var(
|
||||
repository_ctx,
|
||||
"BAZEL_COMPILER",
|
||||
"compiler",
|
||||
False,
|
||||
)),
|
||||
"%{abi_version}": escape_string(get_env_var(
|
||||
repository_ctx,
|
||||
"ABI_VERSION",
|
||||
"local",
|
||||
False,
|
||||
)),
|
||||
"%{abi_libc_version}": escape_string(get_env_var(
|
||||
repository_ctx,
|
||||
"ABI_LIBC_VERSION",
|
||||
"local",
|
||||
False,
|
||||
)),
|
||||
"%{host_system_name}": escape_string(get_env_var(
|
||||
repository_ctx,
|
||||
"BAZEL_HOST_SYSTEM",
|
||||
"local",
|
||||
False,
|
||||
)),
|
||||
"%{target_libc}": "macosx" if darwin else escape_string(get_env_var(
|
||||
repository_ctx,
|
||||
"BAZEL_TARGET_LIBC",
|
||||
"local",
|
||||
False,
|
||||
)),
|
||||
"%{target_cpu}": escape_string(get_env_var(
|
||||
repository_ctx,
|
||||
"BAZEL_TARGET_CPU",
|
||||
cpu_value,
|
||||
False,
|
||||
)),
|
||||
"%{target_system_name}": escape_string(get_env_var(
|
||||
repository_ctx,
|
||||
"BAZEL_TARGET_SYSTEM",
|
||||
"local",
|
||||
False,
|
||||
)),
|
||||
"%{tool_paths}": ",\n ".join(
|
||||
['"%s": "%s"' % (k, v) for k, v in tool_paths.items()],
|
||||
),
|
||||
"%{cxx_builtin_include_directories}": get_starlark_list(
|
||||
_uniq(
|
||||
get_escaped_cxx_inc_directories(repository_ctx, cc, "-xc") +
|
||||
get_escaped_cxx_inc_directories(repository_ctx, cc, "-xc++", cxx_opts) +
|
||||
get_escaped_cxx_inc_directories(
|
||||
repository_ctx,
|
||||
cc,
|
||||
"-xc",
|
||||
_get_no_canonical_prefixes_opt(repository_ctx, cc),
|
||||
) +
|
||||
get_escaped_cxx_inc_directories(
|
||||
repository_ctx,
|
||||
cc,
|
||||
"-xc++",
|
||||
cxx_opts + _get_no_canonical_prefixes_opt(repository_ctx, cc),
|
||||
),
|
||||
),
|
||||
),
|
||||
"%{compile_flags}": get_starlark_list(
|
||||
[
|
||||
# Security hardening requires optimization.
|
||||
# We need to undef it as some distributions now have it enabled by default.
|
||||
"-U_FORTIFY_SOURCE",
|
||||
"-fstack-protector",
|
||||
# All warnings are enabled. Maybe enable -Werror as well?
|
||||
"-Wall",
|
||||
# Enable a few more warnings that aren't part of -Wall.
|
||||
] + ((
|
||||
_add_compiler_option_if_supported(repository_ctx, cc, "-Wthread-safety") +
|
||||
_add_compiler_option_if_supported(repository_ctx, cc, "-Wself-assign")
|
||||
)) + (
|
||||
# Disable problematic warnings.
|
||||
_add_compiler_option_if_supported(repository_ctx, cc, "-Wunused-but-set-parameter") +
|
||||
# has false positives
|
||||
_add_compiler_option_if_supported(repository_ctx, cc, "-Wno-free-nonheap-object") +
|
||||
# Enable coloring even if there's no attached terminal. Bazel removes the
|
||||
# escape sequences if --nocolor is specified.
|
||||
_add_compiler_option_if_supported(repository_ctx, cc, "-fcolor-diagnostics")
|
||||
) + [
|
||||
# Keep stack frames for debugging, even in opt mode.
|
||||
"-fno-omit-frame-pointer",
|
||||
],
|
||||
),
|
||||
"%{cxx_flags}": get_starlark_list(cxx_opts + _escaped_cplus_include_paths(repository_ctx)),
|
||||
"%{link_flags}": get_starlark_list((
|
||||
["-fuse-ld=" + gold_linker_path] if gold_linker_path else []
|
||||
) + _add_linker_option_if_supported(
|
||||
repository_ctx,
|
||||
cc,
|
||||
"-Wl,-no-as-needed",
|
||||
"-no-as-needed",
|
||||
) + _add_linker_option_if_supported(
|
||||
repository_ctx,
|
||||
cc,
|
||||
"-Wl,-z,relro,-z,now",
|
||||
"-z",
|
||||
) + (
|
||||
[
|
||||
"-undefined",
|
||||
"dynamic_lookup",
|
||||
"-headerpad_max_install_names",
|
||||
] if darwin else bin_search_flag + [
|
||||
# Gold linker only? Can we enable this by default?
|
||||
# "-Wl,--warn-execstack",
|
||||
# "-Wl,--detect-odr-violations"
|
||||
] + _add_compiler_option_if_supported(
|
||||
# Have gcc return the exit code from ld.
|
||||
repository_ctx,
|
||||
cc,
|
||||
"-pass-exit-codes",
|
||||
)
|
||||
) + link_opts),
|
||||
"%{link_libs}": get_starlark_list(link_libs),
|
||||
"%{opt_compile_flags}": get_starlark_list(
|
||||
[
|
||||
# No debug symbols.
|
||||
# Maybe we should enable https://gcc.gnu.org/wiki/DebugFission for opt or
|
||||
# even generally? However, that can't happen here, as it requires special
|
||||
# handling in Bazel.
|
||||
"-g0",
|
||||
|
||||
# Conservative choice for -O
|
||||
# -O3 can increase binary size and even slow down the resulting binaries.
|
||||
# Profile first and / or use FDO if you need better performance than this.
|
||||
"-O2",
|
||||
|
||||
# Security hardening on by default.
|
||||
# Conservative choice; -D_FORTIFY_SOURCE=2 may be unsafe in some cases.
|
||||
"-D_FORTIFY_SOURCE=1",
|
||||
|
||||
# Disable assertions
|
||||
"-DNDEBUG",
|
||||
|
||||
# Removal of unused code and data at link time (can this increase binary
|
||||
# size in some cases?).
|
||||
"-ffunction-sections",
|
||||
"-fdata-sections",
|
||||
],
|
||||
),
|
||||
"%{opt_link_flags}": get_starlark_list(
|
||||
[] if darwin else _add_linker_option_if_supported(
|
||||
repository_ctx,
|
||||
cc,
|
||||
"-Wl,--gc-sections",
|
||||
"-gc-sections",
|
||||
),
|
||||
),
|
||||
"%{unfiltered_compile_flags}": get_starlark_list(
|
||||
_get_no_canonical_prefixes_opt(repository_ctx, cc) + [
|
||||
# Make C++ compilation deterministic. Use linkstamping instead of these
|
||||
# compiler symbols.
|
||||
"-Wno-builtin-macro-redefined",
|
||||
"-D__DATE__=\\\"redacted\\\"",
|
||||
"-D__TIMESTAMP__=\\\"redacted\\\"",
|
||||
"-D__TIME__=\\\"redacted\\\"",
|
||||
],
|
||||
),
|
||||
"%{dbg_compile_flags}": get_starlark_list(["-g"]),
|
||||
"%{coverage_compile_flags}": coverage_compile_flags,
|
||||
"%{coverage_link_flags}": coverage_link_flags,
|
||||
"%{supports_start_end_lib}": "True" if gold_linker_path else "False",
|
||||
},
|
||||
)
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,24 @@
|
|||
:: Copyright 2017 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.
|
||||
|
||||
@echo OFF
|
||||
|
||||
echo. 1>&2
|
||||
echo The target you are compiling requires Visual C++ build tools. 1>&2
|
||||
echo Bazel couldn't find a valid Visual C++ build tools installation on your machine. 1>&2
|
||||
%{vc_error_message}
|
||||
echo Please check your installation following https://docs.bazel.build/versions/master/windows.html#using 1>&2
|
||||
echo. 1>&2
|
||||
|
||||
exit /b 1
|
|
@ -0,0 +1,692 @@
|
|||
# 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(
|
||||
"@rules_cc//cc/private/toolchain:lib_cc_configure.bzl",
|
||||
"auto_configure_fail",
|
||||
"auto_configure_warning",
|
||||
"auto_configure_warning_maybe",
|
||||
"escape_string",
|
||||
"execute",
|
||||
"resolve_labels",
|
||||
)
|
||||
|
||||
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.strip().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)
|
||||
msys_mingw_vars = {
|
||||
"%{cxx_builtin_include_directories}": inc_dir_msys,
|
||||
"%{mingw_cxx_builtin_include_directories}": inc_dir_mingw,
|
||||
"%{tool_paths}": tool_paths,
|
||||
"%{mingw_tool_paths}": tool_paths_mingw,
|
||||
"%{tool_bin_path}": tool_bin_path,
|
||||
"%{mingw_tool_bin_path}": tool_bin_path_mingw,
|
||||
}
|
||||
return msys_mingw_vars
|
||||
|
||||
def _get_msvc_vars(repository_ctx, paths):
|
||||
"""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:
|
||||
msvc_vars = {
|
||||
"%{msvc_env_tmp}": "msvc_not_found",
|
||||
"%{msvc_env_path}": "msvc_not_found",
|
||||
"%{msvc_env_include}": "msvc_not_found",
|
||||
"%{msvc_env_lib}": "msvc_not_found",
|
||||
"%{msvc_cl_path}": "vc_installation_error.bat",
|
||||
"%{msvc_ml_path}": "vc_installation_error.bat",
|
||||
"%{msvc_link_path}": "vc_installation_error.bat",
|
||||
"%{msvc_lib_path}": "vc_installation_error.bat",
|
||||
"%{dbg_mode_debug_flag}": "/DEBUG",
|
||||
"%{fastbuild_mode_debug_flag}": "/DEBUG",
|
||||
"%{msvc_cxx_builtin_include_directories}": "",
|
||||
}
|
||||
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)
|
||||
|
||||
msvc_vars = {
|
||||
"%{msvc_env_tmp}": escaped_tmp_dir,
|
||||
"%{msvc_env_path}": escaped_paths,
|
||||
"%{msvc_env_include}": escaped_include_paths,
|
||||
"%{msvc_env_lib}": escaped_lib_paths,
|
||||
"%{msvc_cl_path}": cl_path,
|
||||
"%{msvc_ml_path}": msvc_ml_path,
|
||||
"%{msvc_link_path}": link_path,
|
||||
"%{msvc_lib_path}": lib_path,
|
||||
"%{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_cxx_builtin_include_directories}": " " + ",\n ".join(escaped_cxx_include_directories),
|
||||
}
|
||||
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:
|
||||
clang_cl_vars = {
|
||||
"%{clang_cl_env_tmp}": "clang_cl_not_found",
|
||||
"%{clang_cl_env_path}": "clang_cl_not_found",
|
||||
"%{clang_cl_env_include}": "clang_cl_not_found",
|
||||
"%{clang_cl_env_lib}": "clang_cl_not_found",
|
||||
"%{clang_cl_cl_path}": error_script,
|
||||
"%{clang_cl_link_path}": error_script,
|
||||
"%{clang_cl_lib_path}": error_script,
|
||||
"%{clang_cl_ml_path}": error_script,
|
||||
"%{clang_cl_dbg_mode_debug_flag}": "/DEBUG",
|
||||
"%{clang_cl_fastbuild_mode_debug_flag}": "/DEBUG",
|
||||
"%{clang_cl_cxx_builtin_include_directories}": "",
|
||||
}
|
||||
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_vars = {
|
||||
"%{clang_cl_env_tmp}": msvc_vars["%{msvc_env_tmp}"],
|
||||
"%{clang_cl_env_path}": msvc_vars["%{msvc_env_path}"],
|
||||
"%{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_cxx_builtin_include_directories}": msvc_vars["%{msvc_cxx_builtin_include_directories}"] + (",\n \"%s\"" % clang_include_path),
|
||||
"%{clang_cl_cl_path}": clang_cl_path,
|
||||
"%{clang_cl_link_path}": lld_link_path,
|
||||
"%{clang_cl_lib_path}": llvm_lib_path,
|
||||
"%{clang_cl_ml_path}": msvc_vars["%{msvc_ml_path}"],
|
||||
# LLVM's lld-link.exe doesn't support /DEBUG:FASTLINK.
|
||||
"%{clang_cl_dbg_mode_debug_flag}": "/DEBUG",
|
||||
"%{clang_cl_fastbuild_mode_debug_flag}": "/DEBUG",
|
||||
}
|
||||
return clang_cl_vars
|
||||
|
||||
def configure_windows_toolchain(repository_ctx):
|
||||
"""Configure C++ toolchain on Windows."""
|
||||
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,
|
||||
)
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,48 @@
|
|||
# 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.
|
||||
|
||||
"""
|
||||
Finds the c++ toolchain.
|
||||
|
||||
Returns the toolchain if enabled, and falls back to a toolchain constructed from
|
||||
the CppConfiguration.
|
||||
"""
|
||||
|
||||
def find_cpp_toolchain(ctx):
|
||||
"""
|
||||
Finds the c++ toolchain.
|
||||
|
||||
If the c++ toolchain is in use, returns it. Otherwise, returns a c++
|
||||
toolchain derived from legacy toolchain selection.
|
||||
|
||||
Args:
|
||||
ctx: The rule context for which to find a toolchain.
|
||||
|
||||
Returns:
|
||||
A CcToolchainProvider.
|
||||
"""
|
||||
|
||||
# Check the incompatible flag for toolchain resolution.
|
||||
if hasattr(cc_common, "is_cc_toolchain_resolution_enabled_do_not_use") and cc_common.is_cc_toolchain_resolution_enabled_do_not_use(ctx = ctx):
|
||||
if "@rules_cc//cc:toolchain_type" in ctx.toolchains:
|
||||
return ctx.toolchains["@rules_cc//cc:toolchain_type"]
|
||||
fail("In order to use find_cpp_toolchain, you must include the '@rules_cc//cc:toolchain_type' in the toolchains argument to your rule.")
|
||||
|
||||
# Fall back to the legacy implicit attribute lookup.
|
||||
if hasattr(ctx.attr, "_cc_toolchain"):
|
||||
return ctx.attr._cc_toolchain[cc_common.CcToolchainInfo]
|
||||
|
||||
# We didn't find anything.
|
||||
fail("In order to use find_cpp_toolchain, you must define the '_cc_toolchain' attribute on your rule or aspect.")
|
|
@ -14,7 +14,7 @@
|
|||
|
||||
"""Example showing how to create a rule that rules_cc can depend on."""
|
||||
|
||||
load("@bazel_tools//tools/cpp:toolchain_utils.bzl", "find_cpp_toolchain")
|
||||
load("@rules_cc//cc:toolchain_utils.bzl", "find_cpp_toolchain")
|
||||
load("@bazel_tools//tools/build_defs/cc:action_names.bzl", "CPP_LINK_STATIC_LIBRARY_ACTION_NAME")
|
||||
load("//examples/my_c_compile:my_c_compile.bzl", "MyCCompileInfo")
|
||||
|
||||
|
|
|
@ -14,7 +14,7 @@
|
|||
|
||||
"""Example showing how to create a rule that just compiles C sources."""
|
||||
|
||||
load("@bazel_tools//tools/cpp:toolchain_utils.bzl", "find_cpp_toolchain")
|
||||
load("@rules_cc//cc:toolchain_utils.bzl", "find_cpp_toolchain")
|
||||
load("@bazel_tools//tools/build_defs/cc:action_names.bzl", "C_COMPILE_ACTION_NAME")
|
||||
|
||||
MyCCompileInfo = provider(doc = "", fields = ["object"])
|
||||
|
|
|
@ -14,7 +14,7 @@
|
|||
|
||||
"""Example showing how to get CcToolchainInfo in a custom rule."""
|
||||
|
||||
load("@bazel_tools//tools/cpp:toolchain_utils.bzl", "find_cpp_toolchain")
|
||||
load("@rules_cc//cc:toolchain_utils.bzl", "find_cpp_toolchain")
|
||||
|
||||
def _write_cc_toolchain_cpu_impl(ctx):
|
||||
cc_toolchain = find_cpp_toolchain(ctx)
|
||||
|
|
Loading…
Reference in New Issue