From f364500ba834894e8dd9d1d4f3e332901a49b1be Mon Sep 17 00:00:00 2001 From: Googler Date: Wed, 2 Oct 2024 19:55:47 -0700 Subject: [PATCH 1/2] Create a concept of a tool capability. This should make the concept of "sentinel features" work correctly with known_features and enabled_features, rather than enabling them directly in features. PiperOrigin-RevId: 681688437 Change-Id: I29184a2079ccfd0eb3a275439508a66ca61109af --- cc/toolchains/capabilities/BUILD | 19 +++++ cc/toolchains/cc_toolchain_info.bzl | 10 +++ cc/toolchains/features/BUILD | 28 ------ cc/toolchains/impl/collect.bzl | 1 + cc/toolchains/impl/documented_api.bzl | 3 + cc/toolchains/impl/legacy_converter.bzl | 29 +++++-- cc/toolchains/impl/toolchain_config_info.bzl | 9 +- cc/toolchains/tool.bzl | 12 ++- cc/toolchains/tool_capability.bzl | 85 +++++++++++++++++++ cc/toolchains/toolchain_api.md | 46 +++++++++- .../rule_based_toolchain/generate_factory.bzl | 2 +- tests/rule_based_toolchain/subjects.bzl | 11 +++ tests/rule_based_toolchain/tool/BUILD | 1 + .../toolchain_config/BUILD | 1 + .../toolchain_config_test.bzl | 5 ++ 15 files changed, 221 insertions(+), 41 deletions(-) create mode 100644 cc/toolchains/capabilities/BUILD create mode 100644 cc/toolchains/tool_capability.bzl diff --git a/cc/toolchains/capabilities/BUILD b/cc/toolchains/capabilities/BUILD new file mode 100644 index 0000000..8c55804 --- /dev/null +++ b/cc/toolchains/capabilities/BUILD @@ -0,0 +1,19 @@ +load("//cc/toolchains:tool_capability.bzl", "cc_tool_capability") + +package(default_visibility = ["//visibility:public"]) + +cc_tool_capability( + name = "supports_start_end_lib", +) + +cc_tool_capability( + name = "supports_interface_shared_libraries", +) + +cc_tool_capability( + name = "supports_dynamic_linker", +) + +cc_tool_capability( + name = "supports_pic", +) diff --git a/cc/toolchains/cc_toolchain_info.bzl b/cc/toolchains/cc_toolchain_info.bzl index 2325ddb..17881a8 100644 --- a/cc/toolchains/cc_toolchain_info.bzl +++ b/cc/toolchains/cc_toolchain_info.bzl @@ -156,6 +156,16 @@ ToolInfo = provider( "runfiles": "(runfiles) The files required to run the tool", "execution_requirements": "(Sequence[str]) A set of execution requirements of the tool", "allowlist_include_directories": "(depset[DirectoryInfo]) Built-in include directories implied by this tool that should be allowlisted in Bazel's include checker", + "capabilities": "(Sequence[ToolCapabilityInfo]) Capabilities supported by the tool.", + }, +) + +ToolCapabilityInfo = provider( + doc = "A capability associated with a tool (eg. supports_pic).", + # @unsorted-dict-items + fields = { + "label": "(Label) The label defining this provider. Place in error messages to simplify debugging", + "feature": "(FeatureInfo) The feature this capability defines", }, ) diff --git a/cc/toolchains/features/BUILD b/cc/toolchains/features/BUILD index 6c6088b..22c3519 100644 --- a/cc/toolchains/features/BUILD +++ b/cc/toolchains/features/BUILD @@ -41,36 +41,12 @@ cc_external_feature( overridable = True, ) -cc_external_feature( - name = "supports_start_end_lib", - feature_name = "supports_start_end_lib", - overridable = True, -) - -cc_external_feature( - name = "supports_interface_shared_libraries", - feature_name = "supports_interface_shared_libraries", - overridable = True, -) - -cc_external_feature( - name = "supports_dynamic_linker", - feature_name = "supports_dynamic_linker", - overridable = True, -) - cc_external_feature( name = "static_link_cpp_runtimes", feature_name = "static_link_cpp_runtimes", overridable = True, ) -cc_external_feature( - name = "supports_pic", - feature_name = "supports_pic", - overridable = True, -) - cc_feature_set( name = "all_non_legacy_builtin_features", all_of = [ @@ -80,11 +56,7 @@ cc_feature_set( ":static_linking_mode", ":dynamic_linking_mode", ":per_object_debug_info", - ":supports_start_end_lib", - ":supports_interface_shared_libraries", - ":supports_dynamic_linker", ":static_link_cpp_runtimes", - ":supports_pic", ], visibility = ["//visibility:private"], ) diff --git a/cc/toolchains/impl/collect.bzl b/cc/toolchains/impl/collect.bzl index f41aa7d..e242d91 100644 --- a/cc/toolchains/impl/collect.bzl +++ b/cc/toolchains/impl/collect.bzl @@ -107,6 +107,7 @@ def collect_tools(ctx, targets, fail = fail): runfiles = collect_data(ctx, [target]), execution_requirements = tuple(), allowlist_include_directories = depset(), + capabilities = tuple(), )) else: fail("Expected %s to be a cc_tool or a binary rule" % target.label) diff --git a/cc/toolchains/impl/documented_api.bzl b/cc/toolchains/impl/documented_api.bzl index a863290..f1f634e 100644 --- a/cc/toolchains/impl/documented_api.bzl +++ b/cc/toolchains/impl/documented_api.bzl @@ -22,12 +22,14 @@ load("//cc/toolchains:feature_set.bzl", _cc_feature_set = "cc_feature_set") load("//cc/toolchains:mutually_exclusive_category.bzl", _cc_mutually_exclusive_category = "cc_mutually_exclusive_category") load("//cc/toolchains:nested_args.bzl", _cc_nested_args = "cc_nested_args") load("//cc/toolchains:tool.bzl", _cc_tool = "cc_tool") +load("//cc/toolchains:tool_capability.bzl", _cc_tool_capability = "cc_tool_capability") load("//cc/toolchains:tool_map.bzl", _cc_tool_map = "cc_tool_map") load("//cc/toolchains/impl:external_feature.bzl", _cc_external_feature = "cc_external_feature") load("//cc/toolchains/impl:variables.bzl", _cc_variable = "cc_variable") cc_tool_map = _cc_tool_map cc_tool = _cc_tool +cc_tool_capability = _cc_tool_capability cc_args = _cc_args cc_nested_args = _cc_nested_args cc_args_list = _cc_args_list @@ -46,6 +48,7 @@ cc_external_feature = _cc_external_feature DOCUMENTED_TOOLCHAIN_RULES = [ "cc_tool_map", "cc_tool", + "cc_tool_capability", "cc_args", "cc_nested_args", "cc_args_list", diff --git a/cc/toolchains/impl/legacy_converter.bzl b/cc/toolchains/impl/legacy_converter.bzl index 7197716..64fea95 100644 --- a/cc/toolchains/impl/legacy_converter.bzl +++ b/cc/toolchains/impl/legacy_converter.bzl @@ -131,16 +131,30 @@ def convert_tool(tool): with_features = [], ) +def convert_capability(capability): + return legacy_feature( + name = capability.name, + enabled = False, + ) + def _convert_tool_map(tool_map): - return [ - legacy_action_config( + action_configs = [] + caps = {} + for action_type, tool in tool_map.configs.items(): + action_configs.append(legacy_action_config( action_name = action_type.name, enabled = True, - tools = [convert_tool(tool_map.configs[action_type])], - implies = [], - ) - for action_type in tool_map.configs.keys() + tools = [convert_tool(tool)], + implies = [cap.feature.name for cap in tool.capabilities], + )) + for cap in tool.capabilities: + caps[cap] = None + + cap_features = [ + legacy_feature(name = cap.feature.name, enabled = False) + for cap in caps ] + return action_configs, cap_features def convert_toolchain(toolchain): """Converts a rule-based toolchain into the legacy providers. @@ -155,6 +169,8 @@ def convert_toolchain(toolchain): convert_feature(feature, enabled = feature in toolchain.enabled_features) for feature in toolchain.features ] + action_configs, cap_features = _convert_tool_map(toolchain.tool_map) + features.extend(cap_features) features.append(convert_feature(FeatureInfo( # We reserve names starting with implied_by. This ensures we don't # conflict with the name of a feature the user creates. @@ -167,7 +183,6 @@ def convert_toolchain(toolchain): external = False, allowlist_include_directories = depset(), ))) - action_configs = _convert_tool_map(toolchain.tool_map) cxx_builtin_include_directories = [ d.path diff --git a/cc/toolchains/impl/toolchain_config_info.bzl b/cc/toolchains/impl/toolchain_config_info.bzl index 7e68b15..0fa499d 100644 --- a/cc/toolchains/impl/toolchain_config_info.bzl +++ b/cc/toolchains/impl/toolchain_config_info.bzl @@ -54,9 +54,9 @@ def _feature_key(feature): # This should be sufficiently unique. return (feature.label, feature.name) -def _get_known_features(features, fail): +def _get_known_features(features, capability_features, fail): feature_names = {} - for ft in features: + for ft in capability_features + features: if ft.name in feature_names: other = feature_names[ft.name] if other.overrides != ft and ft.overrides != other: @@ -113,7 +113,10 @@ def _validate_feature(self, known_features, fail): _validate_implies(self, known_features, fail = fail) def _validate_toolchain(self, fail = fail): - known_features = _get_known_features(self.features, fail = fail) + capabilities = [] + for tool in self.tool_map.configs.values(): + capabilities.extend([cap.feature for cap in tool.capabilities]) + known_features = _get_known_features(self.features, capabilities, fail = fail) for feature in self.features: _validate_feature(feature, known_features, fail = fail) diff --git a/cc/toolchains/tool.bzl b/cc/toolchains/tool.bzl index 0dc309d..a3536cf 100644 --- a/cc/toolchains/tool.bzl +++ b/cc/toolchains/tool.bzl @@ -14,9 +14,10 @@ """Implementation of cc_tool""" load("@bazel_skylib//rules/directory:providers.bzl", "DirectoryInfo") -load("//cc/toolchains/impl:collect.bzl", "collect_data") +load("//cc/toolchains/impl:collect.bzl", "collect_data", "collect_provider") load( ":cc_toolchain_info.bzl", + "ToolCapabilityInfo", "ToolInfo", ) @@ -38,6 +39,7 @@ def _cc_tool_impl(ctx): allowlist_include_directories = depset( direct = [d[DirectoryInfo] for d in ctx.attr.allowlist_include_directories], ), + capabilities = tuple(collect_provider(ctx.attr.capabilities, ToolCapabilityInfo)), ) link = ctx.actions.declare_file(ctx.label.name) @@ -94,6 +96,13 @@ and/or `-fno-canonical-system-headers` arguments. This can help work around errors like: `the source file 'main.c' includes the following non-builtin files with absolute paths (if these are builtin files, make sure these paths are in your toolchain)`. +""", + ), + "capabilities": attr.label_list( + providers = [ToolCapabilityInfo], + doc = """Declares that a tool is capable of doing something. + +For example, `//cc/toolchains/capabilities:supports_pic`. """, ), }, @@ -120,6 +129,7 @@ cc_tool( # Suppose clang needs libc to run. data = ["@llvm_toolchain//:lib/x86_64-linux-gnu/libc.so.6"] tags = ["requires-network"], + capabilities = ["//cc/toolchains/capabilities:supports_pic"], ) ``` """, diff --git a/cc/toolchains/tool_capability.bzl b/cc/toolchains/tool_capability.bzl new file mode 100644 index 0000000..60b0f59 --- /dev/null +++ b/cc/toolchains/tool_capability.bzl @@ -0,0 +1,85 @@ +# Copyright 2024 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. +"""Implementation of the cc_tool_capability rule.""" + +load( + ":cc_toolchain_info.bzl", + "ArgsListInfo", + "FeatureConstraintInfo", + "FeatureInfo", + "ToolCapabilityInfo", +) + +def _cc_tool_capability_impl(ctx): + ft = FeatureInfo( + name = ctx.attr.feature_name or ctx.label.name, + label = ctx.label, + enabled = False, + args = ArgsListInfo( + label = ctx.label, + args = (), + files = depset(), + by_action = (), + allowlist_include_directories = depset(), + ), + implies = depset(), + requires_any_of = (), + mutually_exclusive = (), + # Mark it as external so that it doesn't complain if we say + # "requires" on a constraint that was never referenced elsewhere + # in the toolchain. + external = True, + overridable = True, + overrides = None, + allowlist_include_directories = depset(), + ) + return [ + ToolCapabilityInfo(label = ctx.label, feature = ft), + # Only give it a feature constraint info and not a feature info. + # This way you can't imply it - you can only require it. + FeatureConstraintInfo(label = ctx.label, all_of = depset([ft])), + ] + +cc_tool_capability = rule( + implementation = _cc_tool_capability_impl, + provides = [ToolCapabilityInfo, FeatureConstraintInfo], + doc = """A capability is an optional feature that a tool supports. + +For example, not all compilers support PIC, so to handle this, we write: + +``` +cc_tool( + name = "clang", + src = "@host_tools/bin/clang", + capabilities = [ + "//cc/toolchains/capabilities:supports_pic", + ], +) + +cc_args( + name = "pic", + requires = [ + "//cc/toolchains/capabilities:supports_pic" + ], + args = ["-fPIC"], +) +``` + +This ensures that `-fPIC` is added to the command-line only when we are using a +tool that supports PIC. +""", + attrs = { + "feature_name": attr.string(doc = "The name of the feature to generate for this capability"), + }, +) diff --git a/cc/toolchains/toolchain_api.md b/cc/toolchains/toolchain_api.md index 418ef52..d5b3be1 100644 --- a/cc/toolchains/toolchain_api.md +++ b/cc/toolchains/toolchain_api.md @@ -380,7 +380,7 @@ cc_feature( ## cc_tool
-cc_tool(name, src, data, allowlist_include_directories)
+cc_tool(name, src, data, allowlist_include_directories, capabilities)
 
Declares a tool for use by toolchain actions. @@ -405,6 +405,7 @@ cc_tool( # Suppose clang needs libc to run. data = ["@llvm_toolchain//:lib/x86_64-linux-gnu/libc.so.6"] tags = ["requires-network"], + capabilities = ["@rules_cc//cc/toolchains/capabilities:supports_pic"], ) ``` @@ -417,6 +418,49 @@ cc_tool( | src | The underlying binary that this tool represents.

Usually just a single prebuilt (eg. @toolchain//:bin/clang), but may be any executable label. | Label | optional | `None` | | data | Additional files that are required for this tool to run.

Frequently, clang and gcc require additional files to execute as they often shell out to other binaries (e.g. `cc1`). | List of labels | optional | `[]` | | allowlist_include_directories | Include paths implied by using this tool.

Compilers may include a set of built-in headers that are implicitly available unless flags like `-nostdinc` are provided. Bazel checks that all included headers are properly provided by a dependency or allowlisted through this mechanism.

As a rule of thumb, only use this if Bazel is complaining about absolute paths in your toolchain and you've ensured that the toolchain is compiling with the `-no-canonical-prefixes` and/or `-fno-canonical-system-headers` arguments.

This can help work around errors like: `the source file 'main.c' includes the following non-builtin files with absolute paths (if these are builtin files, make sure these paths are in your toolchain)`. | List of labels | optional | `[]` | +| capabilities | Declares that a tool is capable of doing something.

For example, `@rules_cc//cc/toolchains/capabilities:supports_pic`. | List of labels | optional | `[]` | + + + + +## cc_tool_capability + +
+cc_tool_capability(name, feature_name)
+
+ +A capability is an optional feature that a tool supports. + +For example, not all compilers support PIC, so to handle this, we write: + +``` +cc_tool( + name = "clang", + src = "@host_tools/bin/clang", + capabilities = [ + "@rules_cc//cc/toolchains/capabilities:supports_pic", + ], +) + +cc_args( + name = "pic", + requires = [ + "@rules_cc//cc/toolchains/capabilities:supports_pic" + ], + args = ["-fPIC"], +) +``` + +This ensures that `-fPIC` is added to the command-line only when we are using a +tool that supports PIC. + +**ATTRIBUTES** + + +| Name | Description | Type | Mandatory | Default | +| :------------- | :------------- | :------------- | :------------- | :------------- | +| name | A unique name for this target. | Name | required | | +| feature_name | The name of the feature to generate for this capability | String | optional | `""` | diff --git a/tests/rule_based_toolchain/generate_factory.bzl b/tests/rule_based_toolchain/generate_factory.bzl index c58bb51..ea9dc58 100644 --- a/tests/rule_based_toolchain/generate_factory.bzl +++ b/tests/rule_based_toolchain/generate_factory.bzl @@ -67,7 +67,7 @@ def generate_factory(type, name, attrs): meta.add_failure("Wanted a %s but got" % name, value) got_keys = sorted(structs.to_dict(value).keys()) subjects.collection(got_keys, meta = meta.derive(details = [ - "Value was not a %s - it has a different set of fields" % name, + "Value %r was not a %s - it has a different set of fields" % (value, name), ])).contains_exactly(want_keys).in_order() def type_factory(value, *, meta): diff --git a/tests/rule_based_toolchain/subjects.bzl b/tests/rule_based_toolchain/subjects.bzl index e741d67..be36b1c 100644 --- a/tests/rule_based_toolchain/subjects.bzl +++ b/tests/rule_based_toolchain/subjects.bzl @@ -26,6 +26,7 @@ load( "FeatureSetInfo", "MutuallyExclusiveCategoryInfo", "NestedArgsInfo", + "ToolCapabilityInfo", "ToolConfigInfo", "ToolInfo", "ToolchainConfigInfo", @@ -178,6 +179,15 @@ _FeatureFactory = generate_factory( ), ) +# buildifier: disable=name-conventions +_ToolCapabilityFactory = generate_factory( + ToolCapabilityInfo, + "ToolCapabilityInfo", + dict( + name = _subjects.str, + ), +) + # buildifier: disable=name-conventions _ToolFactory = generate_factory( ToolInfo, @@ -187,6 +197,7 @@ _ToolFactory = generate_factory( runfiles = runfiles_subject, execution_requirements = _subjects.collection, allowlist_include_directories = _FakeDirectoryDepset, + capabilities = ProviderSequence(_ToolCapabilityFactory), ), ) diff --git a/tests/rule_based_toolchain/tool/BUILD b/tests/rule_based_toolchain/tool/BUILD index 67ce625..daa617a 100644 --- a/tests/rule_based_toolchain/tool/BUILD +++ b/tests/rule_based_toolchain/tool/BUILD @@ -6,6 +6,7 @@ load(":tool_test.bzl", "TARGETS", "TESTS") cc_tool( name = "tool", src = "//tests/rule_based_toolchain/testdata:bin_wrapper.sh", + capabilities = ["//cc/toolchains/capabilities:supports_pic"], data = ["//tests/rule_based_toolchain/testdata:bin"], tags = ["requires-network"], ) diff --git a/tests/rule_based_toolchain/toolchain_config/BUILD b/tests/rule_based_toolchain/toolchain_config/BUILD index b002eff..6d894a9 100644 --- a/tests/rule_based_toolchain/toolchain_config/BUILD +++ b/tests/rule_based_toolchain/toolchain_config/BUILD @@ -47,6 +47,7 @@ cc_tool( name = "c_compile_tool", src = "//tests/rule_based_toolchain/testdata:bin_wrapper", allowlist_include_directories = ["//tests/rule_based_toolchain/testdata:subdirectory_3"], + capabilities = ["//cc/toolchains/capabilities:supports_pic"], ) cc_sysroot( diff --git a/tests/rule_based_toolchain/toolchain_config/toolchain_config_test.bzl b/tests/rule_based_toolchain/toolchain_config/toolchain_config_test.bzl index 71a05cf..f54fb52 100644 --- a/tests/rule_based_toolchain/toolchain_config/toolchain_config_test.bzl +++ b/tests/rule_based_toolchain/toolchain_config/toolchain_config_test.bzl @@ -207,6 +207,10 @@ def _toolchain_collects_files_test(env, targets): ], )], ), + legacy_feature( + name = "supports_pic", + enabled = False, + ), legacy_feature( name = "implied_by_always_enabled", enabled = True, @@ -252,6 +256,7 @@ def _toolchain_collects_files_test(env, targets): action_name = "c_compile", enabled = True, tools = [legacy_tool(tool = exe)], + implies = ["supports_pic"], ), legacy_action_config( action_name = "cpp_compile", From c2549f6eb07ce00e529b84f9b9f1b31135a9ff77 Mon Sep 17 00:00:00 2001 From: Googler Date: Thu, 3 Oct 2024 09:31:57 -0700 Subject: [PATCH 2/2] Sync cc toolchain from Bazel's tools/cpp - @bazel_tools//tools/cpp:toolchain_type is not moved. - Added cc/toolchains/toolchain_config_utils.bzl for exposing util functions for cc toolchain configuration. Closes https://github.com/bazelbuild/rules_cc/pull/247 Working towards https://github.com/bazelbuild/bazel/issues/23809 PiperOrigin-RevId: 681913803 Change-Id: I16ff456a212ab0e579c137bd74344255f4e49bd8 --- .gitignore | 3 +- MODULE.bazel | 4 +- cc/BUILD | 5 + cc/action_names.bzl | 19 +- cc/compiler/BUILD | 16 +- cc/extensions.bzl | 7 +- .../{BUILD.empty => BUILD.empty.tpl} | 9 +- ...{BUILD.static.freebsd => BUILD.static.bsd} | 70 +- cc/private/toolchain/BUILD.toolchains.tpl | 6 +- cc/private/toolchain/BUILD.tpl | 39 +- cc/private/toolchain/BUILD.windows.tpl | 502 +++++++- .../toolchain/armeabi_cc_toolchain_config.bzl | 1 + ...config.bzl => bsd_cc_toolchain_config.bzl} | 27 +- cc/private/toolchain/cc_configure.bzl | 35 +- .../clang_deps_scanner_wrapper.sh.tpl | 11 + .../clang_installation_error.bat.tpl | 2 +- .../toolchain/gcc_deps_scanner_wrapper.sh.tpl | 12 + .../toolchain/generate_system_module_map.sh | 35 + cc/private/toolchain/lib_cc_configure.bzl | 51 +- cc/private/toolchain/linux_cc_wrapper.sh.tpl | 29 + .../msvc_deps_scanner_wrapper.bat.tpl | 16 + cc/private/toolchain/osx_cc_wrapper.sh.tpl | 33 +- cc/private/toolchain/unix_cc_configure.bzl | 426 +++++-- .../toolchain/unix_cc_toolchain_config.bzl | 1112 ++++++++++++++--- .../toolchain/validate_static_library.sh.tpl | 44 + .../toolchain/vc_installation_error.bat.tpl | 2 +- cc/private/toolchain/windows_cc_configure.bzl | 506 +++++--- .../toolchain/windows_cc_toolchain_config.bzl | 496 ++++++-- cc/toolchains/actions/BUILD | 32 +- cc/toolchains/cc_flags_supplier.bzl | 2 +- cc/toolchains/compiler_flag.bzl | 2 +- cc/toolchains/toolchain_config_utils.bzl | 29 + .../custom_toolchain/toolchain_config.bzl | 2 +- examples/my_c_archive/my_c_archive.bzl | 6 +- examples/my_c_compile/my_c_compile.bzl | 6 +- .../write_cc_toolchain_cpu.bzl | 6 +- tools/migration/crosstool_to_starlark_lib.go | 4 +- .../crosstool_to_starlark_lib_test.go | 4 +- 38 files changed, 2914 insertions(+), 697 deletions(-) rename cc/private/toolchain/{BUILD.empty => BUILD.empty.tpl} (92%) rename cc/private/toolchain/{BUILD.static.freebsd => BUILD.static.bsd} (63%) rename cc/private/toolchain/{freebsd_cc_toolchain_config.bzl => bsd_cc_toolchain_config.bzl} (93%) create mode 100644 cc/private/toolchain/clang_deps_scanner_wrapper.sh.tpl create mode 100644 cc/private/toolchain/gcc_deps_scanner_wrapper.sh.tpl create mode 100755 cc/private/toolchain/generate_system_module_map.sh create mode 100644 cc/private/toolchain/msvc_deps_scanner_wrapper.bat.tpl create mode 100755 cc/private/toolchain/validate_static_library.sh.tpl create mode 100644 cc/toolchains/toolchain_config_utils.bzl diff --git a/.gitignore b/.gitignore index 65e8edc..7f69f3a 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,2 @@ -/bazel-* \ No newline at end of file +/bazel-* +MODULE.bazel.lock diff --git a/MODULE.bazel b/MODULE.bazel index 91092b0..5fa70e9 100644 --- a/MODULE.bazel +++ b/MODULE.bazel @@ -8,8 +8,8 @@ bazel_dep(name = "bazel_skylib", version = "1.7.1") bazel_dep(name = "platforms", version = "0.0.10") bazel_dep(name = "stardoc", version = "0.7.0") -cc_configure = use_extension("@bazel_tools//tools/cpp:cc_configure.bzl", "cc_configure_extension") -use_repo(cc_configure, "local_config_cc_toolchains") +cc_configure = use_extension("//cc:extensions.bzl", "cc_configure_extension") +use_repo(cc_configure, "local_config_cc", "local_config_cc_toolchains") register_toolchains("@local_config_cc_toolchains//:all") diff --git a/cc/BUILD b/cc/BUILD index d0db658..0fb5da3 100644 --- a/cc/BUILD +++ b/cc/BUILD @@ -102,4 +102,9 @@ bzl_library( cc_toolchain_alias(name = "current_cc_toolchain") +cc_toolchain_alias( + name = "optional_current_cc_toolchain", + mandatory = False, +) + cc_libc_top_alias(name = "current_libc_top") diff --git a/cc/action_names.bzl b/cc/action_names.bzl index 6735d82..31a5967 100644 --- a/cc/action_names.bzl +++ b/cc/action_names.bzl @@ -33,6 +33,13 @@ 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++ deps scanning action. +CPP_MODULE_DEPS_SCANNING_ACTION_NAME = "c++-module-deps-scanning" + +# Name of the C++ module compile action. +CPP20_MODULE_COMPILE_ACTION_NAME = "c++20-module-compile" +CPP20_MODULE_CODEGEN_ACTION_NAME = "c++20-module-codegen" + # Name of the C++ module compile action. CPP_MODULE_COMPILE_ACTION_NAME = "c++-module-compile" @@ -42,6 +49,8 @@ ASSEMBLE_ACTION_NAME = "assemble" # Name of the assembly preprocessing action. PREPROCESS_ASSEMBLE_ACTION_NAME = "preprocess-assemble" +LLVM_COV = "llvm-cov" + # Name of the action producing ThinLto index. LTO_INDEXING_ACTION_NAME = "lto-indexing" @@ -85,12 +94,15 @@ OBJC_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 action. +# A string constant for the clif actions. CLIF_MATCH_ACTION_NAME = "clif-match" # A string constant for the obj copy actions. OBJ_COPY_ACTION_NAME = "objcopy_embed_data" +# A string constant for the validation action for cc_static_library. +VALIDATE_STATIC_LIBRARY = "validate-static-library" + ACTION_NAMES = struct( c_compile = C_COMPILE_ACTION_NAME, cpp_compile = CPP_COMPILE_ACTION_NAME, @@ -98,9 +110,13 @@ ACTION_NAMES = struct( 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_deps_scanning = CPP_MODULE_DEPS_SCANNING_ACTION_NAME, + cpp20_module_compile = CPP20_MODULE_COMPILE_ACTION_NAME, + cpp20_module_codegen = CPP20_MODULE_CODEGEN_ACTION_NAME, cpp_module_compile = CPP_MODULE_COMPILE_ACTION_NAME, assemble = ASSEMBLE_ACTION_NAME, preprocess_assemble = PREPROCESS_ASSEMBLE_ACTION_NAME, + llvm_cov = LLVM_COV, lto_indexing = LTO_INDEXING_ACTION_NAME, lto_backend = LTO_BACKEND_ACTION_NAME, lto_index_for_executable = LTO_INDEX_FOR_EXECUTABLE_ACTION_NAME, @@ -117,6 +133,7 @@ ACTION_NAMES = struct( objcpp_compile = OBJCPP_COMPILE_ACTION_NAME, clif_match = CLIF_MATCH_ACTION_NAME, objcopy_embed_data = OBJ_COPY_ACTION_NAME, + validate_static_library = VALIDATE_STATIC_LIBRARY, ) # Names of actions that parse or compile C++ code. diff --git a/cc/compiler/BUILD b/cc/compiler/BUILD index 41f00e4..eecccaa 100644 --- a/cc/compiler/BUILD +++ b/cc/compiler/BUILD @@ -29,9 +29,9 @@ Example: name = "foo", srcs = ["foo.cc"], copts = select({ - "@rules_cc//cc/compiler:gcc": [...], - "@rules_cc//cc/compiler:clang": [...], - "@rules_cc//cc/compiler:msvc-cl": [...], + "//cc/compiler:gcc": [...], + "//cc/compiler:clang": [...], + "//cc/compiler:msvc-cl": [...], # Fallback case for an undetected compiler. "//conditions:default": [...], }), @@ -47,25 +47,25 @@ licenses(["notice"]) config_setting( name = "clang", - flag_values = {"@bazel_tools//tools/cpp:compiler": "clang"}, + flag_values = {"@rules_cc//cc/private/toolchain:compiler": "clang"}, ) config_setting( name = "clang-cl", - flag_values = {"@bazel_tools//tools/cpp:compiler": "clang-cl"}, + flag_values = {"@rules_cc//cc/private/toolchain:compiler": "clang-cl"}, ) config_setting( name = "gcc", - flag_values = {"@bazel_tools//tools/cpp:compiler": "gcc"}, + flag_values = {"@rules_cc//cc/private/toolchain:compiler": "gcc"}, ) config_setting( name = "mingw-gcc", - flag_values = {"@bazel_tools//tools/cpp:compiler": "mingw-gcc"}, + flag_values = {"@rules_cc//cc/private/toolchain:compiler": "mingw-gcc"}, ) config_setting( name = "msvc-cl", - flag_values = {"@bazel_tools//tools/cpp:compiler": "msvc-cl"}, + flag_values = {"@rules_cc//cc/private/toolchain:compiler": "msvc-cl"}, ) diff --git a/cc/extensions.bzl b/cc/extensions.bzl index 72b2dca..1ac80dc 100644 --- a/cc/extensions.bzl +++ b/cc/extensions.bzl @@ -13,12 +13,11 @@ # limitations under the License. """Module extension for cc auto configuration.""" -load("@bazel_tools//tools/osx:xcode_configure.bzl", "xcode_configure") load("//cc/private/toolchain:cc_configure.bzl", "cc_autoconf", "cc_autoconf_toolchains") -def _cc_configure_impl(_): +def _cc_configure_extension_impl(ctx): cc_autoconf_toolchains(name = "local_config_cc_toolchains") cc_autoconf(name = "local_config_cc") - xcode_configure("@bazel_tools//tools/osx:xcode_locator.m") + return ctx.extension_metadata(reproducible = True) -cc_configure = module_extension(implementation = _cc_configure_impl) +cc_configure_extension = module_extension(implementation = _cc_configure_extension_impl) diff --git a/cc/private/toolchain/BUILD.empty b/cc/private/toolchain/BUILD.empty.tpl similarity index 92% rename from cc/private/toolchain/BUILD.empty rename to cc/private/toolchain/BUILD.empty.tpl index a873d0c..6e2d202 100644 --- a/cc/private/toolchain/BUILD.empty +++ b/cc/private/toolchain/BUILD.empty.tpl @@ -13,10 +13,13 @@ # limitations under the License. load("@rules_cc//cc:defs.bzl", "cc_library", "cc_toolchain", "cc_toolchain_suite") +load(":cc_toolchain_config.bzl", "cc_toolchain_config") package(default_visibility = ["//visibility:public"]) -load(":cc_toolchain_config.bzl", "cc_toolchain_config") +cc_library( + name = "link_extra_lib", +) cc_library( name = "malloc", @@ -30,8 +33,8 @@ filegroup( cc_toolchain_suite( name = "toolchain", toolchains = { - "local": ":local", - "local|local": ":local", + "%{cpu}|local": ":local", + "%{cpu}": ":local", }, ) diff --git a/cc/private/toolchain/BUILD.static.freebsd b/cc/private/toolchain/BUILD.static.bsd similarity index 63% rename from cc/private/toolchain/BUILD.static.freebsd rename to cc/private/toolchain/BUILD.static.bsd index d8a7b2d..b0d52e6 100644 --- a/cc/private/toolchain/BUILD.static.freebsd +++ b/cc/private/toolchain/BUILD.static.bsd @@ -12,12 +12,30 @@ # 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. +# This becomes the BUILD file for @local_config_cc// under FreeBSD and OpenBSD. + +load(":cc_toolchain_config.bzl", "cc_toolchain_config") +load("@rules_cc//cc:defs.bzl", "cc_library", "cc_toolchain", "cc_toolchain_suite") package(default_visibility = ["//visibility:public"]) -load("@rules_cc//cc:defs.bzl", "cc_library", "cc_toolchain", "cc_toolchain_suite") -load(":cc_toolchain_config.bzl", "cc_toolchain_config") +cc_library(name = "empty_lib") + +# Label flag for extra libraries to be linked into every binary. +# TODO(bazel-team): Support passing flag multiple times to build a list. +label_flag( + name = "link_extra_libs", + build_setting_default = ":empty_lib", +) + +# The final extra library to be linked into every binary target. This collects +# the above flag, but may also include more libraries depending on config. +cc_library( + name = "link_extra_lib", + deps = [ + ":link_extra_libs", + ], +) cc_library( name = "malloc", @@ -32,10 +50,12 @@ filegroup( cc_toolchain_suite( name = "toolchain", toolchains = { - "armeabi-v7a": ":cc-compiler-armeabi-v7a", "armeabi-v7a|compiler": ":cc-compiler-armeabi-v7a", - "freebsd": ":cc-compiler-freebsd", "freebsd|compiler": ":cc-compiler-freebsd", + "openbsd|compiler": ":cc-compiler-openbsd", + "armeabi-v7a": ":cc-compiler-armeabi-v7a", + "freebsd": ":cc-compiler-freebsd", + "openbsd": ":cc-compiler-openbsd", }, ) @@ -70,7 +90,41 @@ toolchain( "@platforms//os:freebsd", ], toolchain = ":cc-compiler-freebsd", - toolchain_type = "@rules_cc//cc:toolchain_type", + toolchain_type = "@bazel_tools//tools/cpp:toolchain_type", +) + +cc_toolchain( + name = "cc-compiler-openbsd", + 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, + toolchain_config = ":local_openbsd", + toolchain_identifier = "local_openbsd", +) + +cc_toolchain_config( + name = "local_openbsd", + cpu = "openbsd", +) + +toolchain( + name = "cc-toolchain-openbsd", + exec_compatible_with = [ + "@platforms//cpu:x86_64", + "@platforms//os:openbsd", + ], + target_compatible_with = [ + "@platforms//cpu:x86_64", + "@platforms//os:openbsd", + ], + toolchain = ":cc-compiler-openbsd", + toolchain_type = "@bazel_tools//tools/cpp:toolchain_type", ) cc_toolchain( @@ -99,11 +153,11 @@ toolchain( "@platforms//cpu:arm", ], target_compatible_with = [ - "@platforms//cpu:arm", + "@platforms//cpu:armv7", "@platforms//os:android", ], toolchain = ":cc-compiler-armeabi-v7a", - toolchain_type = "@rules_cc//cc:toolchain_type", + toolchain_type = "@bazel_tools//tools/cpp:toolchain_type", ) filegroup( diff --git a/cc/private/toolchain/BUILD.toolchains.tpl b/cc/private/toolchain/BUILD.toolchains.tpl index 3fee112..7d3d6d6 100644 --- a/cc/private/toolchain/BUILD.toolchains.tpl +++ b/cc/private/toolchain/BUILD.toolchains.tpl @@ -5,16 +5,16 @@ toolchain( 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_type = "@bazel_tools//tools/cpp:toolchain_type", ) toolchain( name = "cc-toolchain-armeabi-v7a", exec_compatible_with = HOST_CONSTRAINTS, target_compatible_with = [ - "@platforms//cpu:arm", + "@platforms//cpu:armv7", "@platforms//os:android", ], toolchain = "@local_config_cc//:cc-compiler-armeabi-v7a", - toolchain_type = "@rules_cc//cc:toolchain_type", + toolchain_type = "@bazel_tools//tools/cpp:toolchain_type", ) diff --git a/cc/private/toolchain/BUILD.tpl b/cc/private/toolchain/BUILD.tpl index 9241326..99896dc 100644 --- a/cc/private/toolchain/BUILD.tpl +++ b/cc/private/toolchain/BUILD.tpl @@ -12,16 +12,34 @@ # 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"]) +# This becomes the BUILD file for @local_config_cc// under non-BSD unixes. 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") +package(default_visibility = ["//visibility:public"]) + licenses(["notice"]) # Apache 2.0 +cc_library(name = "empty_lib") + +# Label flag for extra libraries to be linked into every binary. +# TODO(bazel-team): Support passing flag multiple times to build a list. +label_flag( + name = "link_extra_libs", + build_setting_default = ":empty_lib", +) + +# The final extra library to be linked into every binary target. This collects +# the above flag, but may also include more libraries depending on config. +cc_library( + name = "link_extra_lib", + deps = [ + ":link_extra_libs", + ], +) + cc_library( name = "malloc", ) @@ -36,6 +54,15 @@ filegroup( srcs = ["cc_wrapper.sh"], ) +filegroup( + name = "validate_static_library", + srcs = ["validate_static_library.sh"], +) + +filegroup( + name = "deps_scanner_wrapper", + srcs = ["deps_scanner_wrapper.sh"], +) filegroup( name = "compiler_deps", srcs = glob(["extra_tools/**"], allow_empty = True) + [%{cc_compiler_deps}], @@ -66,7 +93,9 @@ cc_toolchain( linker_files = ":compiler_deps", objcopy_files = ":empty", strip_files = ":empty", - supports_param_files = %{supports_param_files}, + supports_header_parsing = 1, + supports_param_files = 1, + module_map = %{modulemap}, ) cc_toolchain_config( @@ -84,6 +113,7 @@ cc_toolchain_config( compile_flags = [%{compile_flags}], opt_compile_flags = [%{opt_compile_flags}], dbg_compile_flags = [%{dbg_compile_flags}], + conly_flags = [%{conly_flags}], cxx_flags = [%{cxx_flags}], link_flags = [%{link_flags}], link_libs = [%{link_libs}], @@ -92,6 +122,7 @@ cc_toolchain_config( coverage_compile_flags = [%{coverage_compile_flags}], coverage_link_flags = [%{coverage_link_flags}], supports_start_end_lib = %{supports_start_end_lib}, + extra_flags_per_feature = %{extra_flags_per_feature}, ) # Android tooling requires a default toolchain for the armeabi-v7a cpu. diff --git a/cc/private/toolchain/BUILD.windows.tpl b/cc/private/toolchain/BUILD.windows.tpl index 66dbafd..d554869 100644 --- a/cc/private/toolchain/BUILD.windows.tpl +++ b/cc/private/toolchain/BUILD.windows.tpl @@ -14,11 +14,30 @@ # 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") + +package(default_visibility = ["//visibility:public"]) + +cc_library(name = "empty_lib") + +# Label flag for extra libraries to be linked into every binary. +# TODO(bazel-team): Support passing flag multiple times to build a list. +label_flag( + name = "link_extra_libs", + build_setting_default = ":empty_lib", +) + +# The final extra library to be linked into every binary target. This collects +# the above flag, but may also include more libraries depending on config. +cc_library( + name = "link_extra_lib", + deps = [ + ":link_extra_libs", + ], +) + cc_library( name = "malloc", ) @@ -40,7 +59,13 @@ filegroup( filegroup( name = "msvc_compiler_files", - srcs = [":builtin_include_directory_paths_msvc"] + srcs = [ + ":builtin_include_directory_paths_msvc", + "%{msvc_deps_scanner_wrapper_path_x86}", + "%{msvc_deps_scanner_wrapper_path_x64}", + "%{msvc_deps_scanner_wrapper_path_arm}", + "%{msvc_deps_scanner_wrapper_path_arm64}", + ] ) # Hardcoded toolchain, legacy behaviour. @@ -49,11 +74,23 @@ cc_toolchain_suite( toolchains = { "armeabi-v7a|compiler": ":cc-compiler-armeabi-v7a", "x64_windows|msvc-cl": ":cc-compiler-x64_windows", + "x64_x86_windows|msvc-cl": ":cc-compiler-x64_x86_windows", + "x64_arm_windows|msvc-cl": ":cc-compiler-x64_arm_windows", + "x64_arm64_windows|msvc-cl": ":cc-compiler-arm64_windows", + "arm64_windows|msvc-cl": ":cc-compiler-arm64_windows", "x64_windows|msys-gcc": ":cc-compiler-x64_windows_msys", + "x64_x86_windows|msys-gcc": ":cc-compiler-x64_x86_windows_msys", "x64_windows|mingw-gcc": ":cc-compiler-x64_windows_mingw", + "x64_x86_windows|mingw-gcc": ":cc-compiler-x64_x86_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", + "x64_x86_windows": ":cc-compiler-x64_x86_windows", + "x64_arm_windows": ":cc-compiler-x64_arm_windows", + "x64_arm64_windows": ":cc-compiler-arm64_windows", + "arm64_windows": ":cc-compiler-arm64_windows", + "x64_arm64_windows|clang-cl": ":cc-compiler-arm64_windows-clang-cl", + "arm64_windows|clang-cl": ":cc-compiler-arm64_windows-clang-cl", "armeabi-v7a": ":cc-compiler-armeabi-v7a", }, ) @@ -85,8 +122,6 @@ cc_toolchain_config( 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( @@ -101,7 +136,53 @@ toolchain( "@platforms//os:windows", ], toolchain = ":cc-compiler-x64_windows_msys", - toolchain_type = "@rules_cc//cc:toolchain_type", + toolchain_type = "@bazel_tools//tools/cpp:toolchain_type", +) + +cc_toolchain( + name = "cc-compiler-x64_x86_windows_msys", + toolchain_identifier = "msys_x64_x86", + toolchain_config = ":msys_x64_x86", + all_files = ":empty", + ar_files = ":empty", + as_files = ":mingw_compiler_files", + compiler_files = ":mingw_compiler_files", + dwp_files = ":empty", + linker_files = ":empty", + objcopy_files = ":empty", + strip_files = ":empty", + supports_param_files = 1, +) + +cc_toolchain_config( + name = "msys_x64_x86", + cpu = "x64_x86_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}", + default_compile_flags = ["-m32"], + default_link_flags = ["-m32"], +) + +toolchain( + name = "cc-toolchain-x64_x86_windows_msys", + exec_compatible_with = [ + "@platforms//cpu:x86_64", + "@platforms//os:windows", + "@rules_cc//cc/private/toolchain:msys", + ], + target_compatible_with = [ + "@platforms//cpu:x86_32", + "@platforms//os:windows", + ], + toolchain = ":cc-compiler-x64_x86_windows_msys", + toolchain_type = "@bazel_tools//tools/cpp:toolchain_type", ) cc_toolchain( @@ -131,8 +212,6 @@ cc_toolchain_config( 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( @@ -147,7 +226,53 @@ toolchain( "@platforms//os:windows", ], toolchain = ":cc-compiler-x64_windows_mingw", - toolchain_type = "@rules_cc//cc:toolchain_type", + toolchain_type = "@bazel_tools//tools/cpp:toolchain_type", +) + +cc_toolchain( + name = "cc-compiler-x64_x86_windows_mingw", + toolchain_identifier = "msys_x64_x86_mingw", + toolchain_config = ":msys_x64_x86_mingw", + all_files = ":empty", + ar_files = ":empty", + as_files = ":mingw_compiler_files", + compiler_files = ":mingw_compiler_files", + dwp_files = ":empty", + linker_files = ":empty", + objcopy_files = ":empty", + strip_files = ":empty", + supports_param_files = 0, +) + +cc_toolchain_config( + name = "msys_x64_x86_mingw", + cpu = "x64_x86_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}}, + default_compile_flags = ["-m32"], + default_link_flags = ["-m32"], +) + +toolchain( + name = "cc-toolchain-x64_x86_windows_mingw", + exec_compatible_with = [ + "@platforms//cpu:x86_64", + "@platforms//os:windows", + "@rules_cc//cc/private/toolchain:mingw", + ], + target_compatible_with = [ + "@platforms//cpu:x86_32", + "@platforms//os:windows", + ], + toolchain = ":cc-compiler-x64_x86_windows_mingw", + toolchain_type = "@bazel_tools//tools/cpp:toolchain_type", ) cc_toolchain( @@ -175,30 +300,34 @@ cc_toolchain_config( 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}], + msvc_env_tmp = "%{msvc_env_tmp_x64}", + msvc_env_path = "%{msvc_env_path_x64}", + msvc_env_include = "%{msvc_env_include_x64}", + msvc_env_lib = "%{msvc_env_lib_x64}", + msvc_cl_path = "%{msvc_cl_path_x64}", + msvc_ml_path = "%{msvc_ml_path_x64}", + msvc_link_path = "%{msvc_link_path_x64}", + msvc_lib_path = "%{msvc_lib_path_x64}", + cxx_builtin_include_directories = [%{msvc_cxx_builtin_include_directories_x64}], tool_paths = { - "ar": "%{msvc_lib_path}", - "ml": "%{msvc_ml_path}", - "cpp": "%{msvc_cl_path}", - "gcc": "%{msvc_cl_path}", + "ar": "%{msvc_lib_path_x64}", + "ml": "%{msvc_ml_path_x64}", + "cpp": "%{msvc_cl_path_x64}", + "gcc": "%{msvc_cl_path_x64}", "gcov": "wrapper/bin/msvc_nop.bat", - "ld": "%{msvc_link_path}", + "ld": "%{msvc_link_path_x64}", "nm": "wrapper/bin/msvc_nop.bat", "objcopy": "wrapper/bin/msvc_nop.bat", "objdump": "wrapper/bin/msvc_nop.bat", "strip": "wrapper/bin/msvc_nop.bat", + "dumpbin": "%{msvc_dumpbin_path_x64}", + "cpp-module-deps-scanner": "%{msvc_deps_scanner_wrapper_path_x64}", }, + archiver_flags = ["/MACHINE:X64"], default_link_flags = ["/MACHINE:X64"], - dbg_mode_debug_flag = "%{dbg_mode_debug_flag}", - fastbuild_mode_debug_flag = "%{fastbuild_mode_debug_flag}", + dbg_mode_debug_flag = "%{dbg_mode_debug_flag_x64}", + fastbuild_mode_debug_flag = "%{fastbuild_mode_debug_flag_x64}", + supports_parse_showincludes = %{msvc_parse_showincludes_x64}, ) toolchain( @@ -212,9 +341,216 @@ toolchain( "@platforms//os:windows", ], toolchain = ":cc-compiler-x64_windows", - toolchain_type = "@rules_cc//cc:toolchain_type", + toolchain_type = "@bazel_tools//tools/cpp:toolchain_type", ) +cc_toolchain( + name = "cc-compiler-x64_x86_windows", + toolchain_identifier = "msvc_x64_x86", + toolchain_config = ":msvc_x64_x86", + all_files = ":empty", + ar_files = ":empty", + as_files = ":msvc_compiler_files", + compiler_files = ":msvc_compiler_files", + dwp_files = ":empty", + linker_files = ":empty", + objcopy_files = ":empty", + strip_files = ":empty", + supports_param_files = 1, +) + +cc_toolchain_config( + name = "msvc_x64_x86", + 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_x86", + msvc_env_tmp = "%{msvc_env_tmp_x86}", + msvc_env_path = "%{msvc_env_path_x86}", + msvc_env_include = "%{msvc_env_include_x86}", + msvc_env_lib = "%{msvc_env_lib_x86}", + msvc_cl_path = "%{msvc_cl_path_x86}", + msvc_ml_path = "%{msvc_ml_path_x86}", + msvc_link_path = "%{msvc_link_path_x86}", + msvc_lib_path = "%{msvc_lib_path_x86}", + cxx_builtin_include_directories = [%{msvc_cxx_builtin_include_directories_x86}], + tool_paths = { + "ar": "%{msvc_lib_path_x86}", + "ml": "%{msvc_ml_path_x86}", + "cpp": "%{msvc_cl_path_x86}", + "gcc": "%{msvc_cl_path_x86}", + "gcov": "wrapper/bin/msvc_nop.bat", + "ld": "%{msvc_link_path_x86}", + "nm": "wrapper/bin/msvc_nop.bat", + "objcopy": "wrapper/bin/msvc_nop.bat", + "objdump": "wrapper/bin/msvc_nop.bat", + "strip": "wrapper/bin/msvc_nop.bat", + "dumpbin": "%{msvc_dumpbin_path_x86}", + "cpp-module-deps-scanner": "%{msvc_deps_scanner_wrapper_path_x86}", + }, + archiver_flags = ["/MACHINE:X86"], + default_link_flags = ["/MACHINE:X86"], + dbg_mode_debug_flag = "%{dbg_mode_debug_flag_x86}", + fastbuild_mode_debug_flag = "%{fastbuild_mode_debug_flag_x86}", + supports_parse_showincludes = %{msvc_parse_showincludes_x86}, +) + +toolchain( + name = "cc-toolchain-x64_x86_windows", + exec_compatible_with = [ + "@platforms//cpu:x86_64", + "@platforms//os:windows", + ], + target_compatible_with = [ + "@platforms//cpu:x86_32", + "@platforms//os:windows", + ], + toolchain = ":cc-compiler-x64_x86_windows", + toolchain_type = "@bazel_tools//tools/cpp:toolchain_type", +) + +cc_toolchain( + name = "cc-compiler-x64_arm_windows", + toolchain_identifier = "msvc_x64_arm", + toolchain_config = ":msvc_x64_arm", + all_files = ":empty", + ar_files = ":empty", + as_files = ":msvc_compiler_files", + compiler_files = ":msvc_compiler_files", + dwp_files = ":empty", + linker_files = ":empty", + objcopy_files = ":empty", + strip_files = ":empty", + supports_param_files = 1, +) + +cc_toolchain_config( + name = "msvc_x64_arm", + 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_arm", + msvc_env_tmp = "%{msvc_env_tmp_arm}", + msvc_env_path = "%{msvc_env_path_arm}", + msvc_env_include = "%{msvc_env_include_arm}", + msvc_env_lib = "%{msvc_env_lib_arm}", + msvc_cl_path = "%{msvc_cl_path_arm}", + msvc_ml_path = "%{msvc_ml_path_arm}", + msvc_link_path = "%{msvc_link_path_arm}", + msvc_lib_path = "%{msvc_lib_path_arm}", + cxx_builtin_include_directories = [%{msvc_cxx_builtin_include_directories_arm}], + tool_paths = { + "ar": "%{msvc_lib_path_arm}", + "ml": "%{msvc_ml_path_arm}", + "cpp": "%{msvc_cl_path_arm}", + "gcc": "%{msvc_cl_path_arm}", + "gcov": "wrapper/bin/msvc_nop.bat", + "ld": "%{msvc_link_path_arm}", + "nm": "wrapper/bin/msvc_nop.bat", + "objcopy": "wrapper/bin/msvc_nop.bat", + "objdump": "wrapper/bin/msvc_nop.bat", + "strip": "wrapper/bin/msvc_nop.bat", + "dumpbin": "%{msvc_dumpbin_path_arm}", + "cpp-module-deps-scanner": "%{msvc_deps_scanner_wrapper_path_arm}", + }, + archiver_flags = ["/MACHINE:ARM"], + default_link_flags = ["/MACHINE:ARM"], + dbg_mode_debug_flag = "%{dbg_mode_debug_flag_arm}", + fastbuild_mode_debug_flag = "%{fastbuild_mode_debug_flag_arm}", + supports_parse_showincludes = %{msvc_parse_showincludes_arm}, +) + +toolchain( + name = "cc-toolchain-x64_arm_windows", + exec_compatible_with = [ + "@platforms//cpu:x86_64", + "@platforms//os:windows", + ], + target_compatible_with = [ + "@platforms//cpu:arm", + "@platforms//os:windows", + ], + toolchain = ":cc-compiler-x64_arm_windows", + toolchain_type = "@bazel_tools//tools/cpp:toolchain_type", +) + +cc_toolchain( + name = "cc-compiler-arm64_windows", + toolchain_identifier = "msvc_arm64", + toolchain_config = ":msvc_arm64", + all_files = ":empty", + ar_files = ":empty", + as_files = ":msvc_compiler_files", + compiler_files = ":msvc_compiler_files", + dwp_files = ":empty", + linker_files = ":empty", + objcopy_files = ":empty", + strip_files = ":empty", + supports_param_files = 1, +) + +cc_toolchain_config( + name = "msvc_arm64", + 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_arm64", + msvc_env_tmp = "%{msvc_env_tmp_arm64}", + msvc_env_path = "%{msvc_env_path_arm64}", + msvc_env_include = "%{msvc_env_include_arm64}", + msvc_env_lib = "%{msvc_env_lib_arm64}", + msvc_cl_path = "%{msvc_cl_path_arm64}", + msvc_ml_path = "%{msvc_ml_path_arm64}", + msvc_link_path = "%{msvc_link_path_arm64}", + msvc_lib_path = "%{msvc_lib_path_arm64}", + cxx_builtin_include_directories = [%{msvc_cxx_builtin_include_directories_arm64}], + tool_paths = { + "ar": "%{msvc_lib_path_arm64}", + "ml": "%{msvc_ml_path_arm64}", + "cpp": "%{msvc_cl_path_arm64}", + "gcc": "%{msvc_cl_path_arm64}", + "gcov": "wrapper/bin/msvc_nop.bat", + "ld": "%{msvc_link_path_arm64}", + "nm": "wrapper/bin/msvc_nop.bat", + "objcopy": "wrapper/bin/msvc_nop.bat", + "objdump": "wrapper/bin/msvc_nop.bat", + "strip": "wrapper/bin/msvc_nop.bat", + "dumpbin": "%{msvc_dumpbin_path_arm64}", + "cpp-module-deps-scanner": "%{msvc_deps_scanner_wrapper_path_arm64}", + }, + archiver_flags = ["/MACHINE:ARM64"], + default_link_flags = ["/MACHINE:ARM64"], + dbg_mode_debug_flag = "%{dbg_mode_debug_flag_arm64}", + fastbuild_mode_debug_flag = "%{fastbuild_mode_debug_flag_arm64}", + supports_parse_showincludes = %{msvc_parse_showincludes_arm64}, +) + +toolchain( + name = "cc-toolchain-arm64_windows", + exec_compatible_with = [ + "@platforms//os:windows", + ], + target_compatible_with = [ + "@platforms//cpu:arm64", + "@platforms//os:windows", + ], + toolchain = ":cc-compiler-arm64_windows", + toolchain_type = "@bazel_tools//tools/cpp:toolchain_type", +) + + cc_toolchain( name = "cc-compiler-x64_windows-clang-cl", toolchain_identifier = "clang_cl_x64", @@ -240,30 +576,32 @@ cc_toolchain_config( 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}], + msvc_env_tmp = "%{clang_cl_env_tmp_x64}", + msvc_env_path = "%{clang_cl_env_path_x64}", + msvc_env_include = "%{clang_cl_env_include_x64}", + msvc_env_lib = "%{clang_cl_env_lib_x64}", + msvc_cl_path = "%{clang_cl_cl_path_x64}", + msvc_ml_path = "%{clang_cl_ml_path_x64}", + msvc_link_path = "%{clang_cl_link_path_x64}", + msvc_lib_path = "%{clang_cl_lib_path_x64}", + cxx_builtin_include_directories = [%{clang_cl_cxx_builtin_include_directories_x64}], tool_paths = { - "ar": "%{clang_cl_lib_path}", - "ml": "%{clang_cl_ml_path}", - "cpp": "%{clang_cl_cl_path}", - "gcc": "%{clang_cl_cl_path}", + "ar": "%{clang_cl_lib_path_x64}", + "ml": "%{clang_cl_ml_path_x64}", + "cpp": "%{clang_cl_cl_path_x64}", + "gcc": "%{clang_cl_cl_path_x64}", "gcov": "wrapper/bin/msvc_nop.bat", - "ld": "%{clang_cl_link_path}", + "ld": "%{clang_cl_link_path_x64}", "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}", + archiver_flags = ["/MACHINE:X64"], + default_link_flags = ["/MACHINE:X64"], + dbg_mode_debug_flag = "%{clang_cl_dbg_mode_debug_flag_x64}", + fastbuild_mode_debug_flag = "%{clang_cl_fastbuild_mode_debug_flag_x64}", + supports_parse_showincludes = %{clang_cl_parse_showincludes_x64}, ) toolchain( @@ -278,7 +616,74 @@ toolchain( "@platforms//os:windows", ], toolchain = ":cc-compiler-x64_windows-clang-cl", - toolchain_type = "@rules_cc//cc:toolchain_type", + toolchain_type = "@bazel_tools//tools/cpp:toolchain_type", +) + +cc_toolchain( + name = "cc-compiler-arm64_windows-clang-cl", + toolchain_identifier = "clang_cl_arm64", + toolchain_config = ":clang_cl_arm64", + all_files = ":empty", + ar_files = ":empty", + as_files = ":clangcl_compiler_files", + compiler_files = ":clangcl_compiler_files", + dwp_files = ":empty", + linker_files = ":empty", + objcopy_files = ":empty", + strip_files = ":empty", + supports_param_files = 1, +) + +cc_toolchain_config( + name = "clang_cl_arm64", + cpu = "arm64_windows", + compiler = "clang-cl", + host_system_name = "local", + target_system_name = "aarch64-pc-windows-msvc", + target_libc = "msvcrt", + abi_version = "local", + abi_libc_version = "local", + toolchain_identifier = "clang_cl_arm64", + msvc_env_tmp = "%{clang_cl_env_tmp_arm64}", + msvc_env_path = "%{clang_cl_env_path_arm64}", + msvc_env_include = "%{clang_cl_env_include_arm64}", + msvc_env_lib = "%{clang_cl_env_lib_arm64}", + msvc_cl_path = "%{clang_cl_cl_path_arm64}", + msvc_ml_path = "%{clang_cl_ml_path_arm64}", + msvc_link_path = "%{clang_cl_link_path_arm64}", + msvc_lib_path = "%{clang_cl_lib_path_arm64}", + cxx_builtin_include_directories = [%{clang_cl_cxx_builtin_include_directories_arm64}], + tool_paths = { + "ar": "%{clang_cl_lib_path_arm64}", + "ml": "%{clang_cl_ml_path_arm64}", + "cpp": "%{clang_cl_cl_path_arm64}", + "gcc": "%{clang_cl_cl_path_arm64}", + "gcov": "wrapper/bin/msvc_nop.bat", + "ld": "%{clang_cl_link_path_arm64}", + "nm": "wrapper/bin/msvc_nop.bat", + "objcopy": "wrapper/bin/msvc_nop.bat", + "objdump": "wrapper/bin/msvc_nop.bat", + "strip": "wrapper/bin/msvc_nop.bat", + }, + archiver_flags = ["/MACHINE:ARM64"], + default_link_flags = ["/MACHINE:ARM64"], + dbg_mode_debug_flag = "%{clang_cl_dbg_mode_debug_flag_arm64}", + fastbuild_mode_debug_flag = "%{clang_cl_fastbuild_mode_debug_flag_arm64}", + supports_parse_showincludes = %{clang_cl_parse_showincludes_arm64}, +) + +toolchain( + name = "cc-toolchain-arm64_windows-clang-cl", + exec_compatible_with = [ + "@platforms//os:windows", + "@rules_cc//cc/private/toolchain:clang-cl", + ], + target_compatible_with = [ + "@platforms//cpu:arm64", + "@platforms//os:windows", + ], + toolchain = ":cc-compiler-arm64_windows-clang-cl", + toolchain_type = "@bazel_tools//tools/cpp:toolchain_type", ) cc_toolchain( @@ -303,14 +708,9 @@ toolchain( exec_compatible_with = [ ], target_compatible_with = [ - "@platforms//cpu:arm", + "@platforms//cpu:armv7", "@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"], + toolchain_type = "@bazel_tools//tools/cpp:toolchain_type", ) diff --git a/cc/private/toolchain/armeabi_cc_toolchain_config.bzl b/cc/private/toolchain/armeabi_cc_toolchain_config.bzl index 66c5752..7d4baad 100644 --- a/cc/private/toolchain/armeabi_cc_toolchain_config.bzl +++ b/cc/private/toolchain/armeabi_cc_toolchain_config.bzl @@ -49,6 +49,7 @@ def _impl(ctx): tool_path(name = "gcc", path = "/bin/false"), tool_path(name = "gcov", path = "/bin/false"), tool_path(name = "ld", path = "/bin/false"), + tool_path(name = "llvm-profdata", path = "/bin/false"), tool_path(name = "nm", path = "/bin/false"), tool_path(name = "objcopy", path = "/bin/false"), tool_path(name = "objdump", path = "/bin/false"), diff --git a/cc/private/toolchain/freebsd_cc_toolchain_config.bzl b/cc/private/toolchain/bsd_cc_toolchain_config.bzl similarity index 93% rename from cc/private/toolchain/freebsd_cc_toolchain_config.bzl rename to cc/private/toolchain/bsd_cc_toolchain_config.bzl index 3521d92..3ad8d1f 100644 --- a/cc/private/toolchain/freebsd_cc_toolchain_config.bzl +++ b/cc/private/toolchain/bsd_cc_toolchain_config.bzl @@ -12,7 +12,7 @@ # See the License for the specific language governing permissions and # limitations under the License. -"""A Starlark cc_toolchain configuration rule for freebsd.""" +"""A Starlark cc_toolchain configuration rule for FreeBSD and OpenBSD.""" load("@rules_cc//cc:action_names.bzl", "ACTION_NAMES") load( @@ -24,7 +24,7 @@ load( "tool", "tool_path", "with_feature_set", -) +) # buildifier: disable=deprecated-function all_compile_actions = [ ACTION_NAMES.c_compile, @@ -56,13 +56,14 @@ all_link_actions = [ def _impl(ctx): cpu = ctx.attr.cpu + is_bsd = cpu == "freebsd" or cpu == "openbsd" 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" + toolchain_identifier = "local_{}".format(cpu) if is_bsd else "stub_armeabi-v7a" + host_system_name = "local" if is_bsd else "armeabi-v7a" + target_system_name = "local" if is_bsd else "armeabi-v7a" + target_libc = "local" if is_bsd else "armeabi-v7a" + abi_version = "local" if is_bsd else "armeabi-v7a" + abi_libc_version = "local" if is_bsd else "armeabi-v7a" objcopy_embed_data_action = action_config( action_name = "objcopy_embed_data", @@ -70,7 +71,7 @@ def _impl(ctx): tools = [tool(path = "/usr/bin/objcopy")], ) - action_configs = [objcopy_embed_data_action] if cpu == "freebsd" else [] + action_configs = [objcopy_embed_data_action] if is_bsd else [] default_link_flags_feature = feature( name = "default_link_flags", @@ -159,7 +160,7 @@ def _impl(ctx): ), flag_set( actions = all_cpp_compile_actions + [ACTION_NAMES.lto_backend], - flag_groups = [flag_group(flags = ["-std=c++0x"])], + flag_groups = [flag_group(flags = ["-std=c++17"])], ), ], ) @@ -224,7 +225,7 @@ def _impl(ctx): ], ) - if cpu == "freebsd": + if is_bsd: features = [ default_compile_flags_feature, default_link_flags_feature, @@ -240,12 +241,12 @@ def _impl(ctx): else: features = [supports_dynamic_linker_feature, supports_pic_feature] - if (cpu == "freebsd"): + if (is_bsd): cxx_builtin_include_directories = ["/usr/lib/clang", "/usr/local/include", "/usr/include"] else: cxx_builtin_include_directories = [] - if cpu == "freebsd": + if is_bsd: tool_paths = [ tool_path(name = "ar", path = "/usr/bin/ar"), tool_path(name = "compat-ld", path = "/usr/bin/ld"), diff --git a/cc/private/toolchain/cc_configure.bzl b/cc/private/toolchain/cc_configure.bzl index c7b19de..ce0dac5 100644 --- a/cc/private/toolchain/cc_configure.bzl +++ b/cc/private/toolchain/cc_configure.bzl @@ -46,7 +46,6 @@ def cc_autoconf_toolchains_impl(repository_ctx): cc_autoconf_toolchains = repository_rule( environ = [ - "BAZEL_USE_CPP_ONLY_TOOLCHAIN", "BAZEL_DO_NOT_DETECT_CPP_TOOLCHAIN", ], implementation = cc_autoconf_toolchains_impl, @@ -65,24 +64,26 @@ def cc_autoconf_impl(repository_ctx, overriden_tools = dict()): 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:BUILD.empty.tpl", "@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": + repository_ctx.template("BUILD", paths["@rules_cc//cc/private/toolchain:BUILD.empty.tpl"], { + "%{cpu}": get_cpu_value(repository_ctx), + }) + elif cpu_value == "freebsd" or cpu_value == "openbsd": paths = resolve_labels(repository_ctx, [ - "@rules_cc//cc/private/toolchain:BUILD.static.freebsd", - "@rules_cc//cc/private/toolchain:freebsd_cc_toolchain_config.bzl", + "@rules_cc//cc/private/toolchain:BUILD.static.bsd", + "@rules_cc//cc/private/toolchain:bsd_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": + # This is defaulting to a static crosstool. We should eventually + # autoconfigure this platform too. Theoretically, FreeBSD and OpenBSD + # should be straightforward to add but we cannot run them in a Docker + # container so skipping until we have proper tests for these platforms. + repository_ctx.symlink(paths["@rules_cc//cc/private/toolchain:bsd_cc_toolchain_config.bzl"], "cc_toolchain_config.bzl") + repository_ctx.symlink(paths["@rules_cc//cc/private/toolchain:BUILD.static.bsd"], "BUILD") + elif cpu_value in ["x64_windows", "arm64_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) @@ -111,16 +112,17 @@ cc_autoconf = repository_rule( "ABI_VERSION", "BAZEL_COMPILER", "BAZEL_HOST_SYSTEM", + "BAZEL_CONLYOPTS", "BAZEL_CXXOPTS", "BAZEL_LINKOPTS", "BAZEL_LINKLIBS", + "BAZEL_LLVM_COV", + "BAZEL_LLVM_PROFDATA", "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", @@ -130,9 +132,12 @@ cc_autoconf = repository_rule( "CC_CONFIGURE_DEBUG", "CC_TOOLCHAIN_NAME", "CPLUS_INCLUDE_PATH", + "DEVELOPER_DIR", "GCOV", + "LIBTOOL", "HOMEBREW_RUBY_PATH", "SYSTEMROOT", + "USER", ] + MSVC_ENVVARS, implementation = cc_autoconf_impl, configure = True, diff --git a/cc/private/toolchain/clang_deps_scanner_wrapper.sh.tpl b/cc/private/toolchain/clang_deps_scanner_wrapper.sh.tpl new file mode 100644 index 0000000..0bff014 --- /dev/null +++ b/cc/private/toolchain/clang_deps_scanner_wrapper.sh.tpl @@ -0,0 +1,11 @@ +#!/usr/bin/env bash +# +# Ship the environment to the C++ action +# +set -eu + +# Set-up the environment +%{env} + +# Call the C++ compiler +%{deps_scanner} -format=p1689 -- %{cc} "$@" >"$DEPS_SCANNER_OUTPUT_FILE" diff --git a/cc/private/toolchain/clang_installation_error.bat.tpl b/cc/private/toolchain/clang_installation_error.bat.tpl index e3a61a4..13668ae 100644 --- a/cc/private/toolchain/clang_installation_error.bat.tpl +++ b/cc/private/toolchain/clang_installation_error.bat.tpl @@ -18,7 +18,7 @@ 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/main/windows.html#using 1>&2 +echo Please check your installation following https://bazel.build/docs/windows#using 1>&2 echo. 1>&2 exit /b 1 diff --git a/cc/private/toolchain/gcc_deps_scanner_wrapper.sh.tpl b/cc/private/toolchain/gcc_deps_scanner_wrapper.sh.tpl new file mode 100644 index 0000000..9436493 --- /dev/null +++ b/cc/private/toolchain/gcc_deps_scanner_wrapper.sh.tpl @@ -0,0 +1,12 @@ +#!/bin/bash +# +# Ship the environment to the C++ action +# +set -eu + +# Set-up the environment +%{env} + +# Call the C++ compiler + +%{cc} -E -x c++ -fmodules-ts -fdeps-file=out.tmp -fdeps-format=p1689r5 "$@" >"$DEPS_SCANNER_OUTPUT_FILE" diff --git a/cc/private/toolchain/generate_system_module_map.sh b/cc/private/toolchain/generate_system_module_map.sh new file mode 100755 index 0000000..deb52c2 --- /dev/null +++ b/cc/private/toolchain/generate_system_module_map.sh @@ -0,0 +1,35 @@ +#!/bin/bash +# Copyright 2020 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. + +set -eu + +echo 'module "crosstool" [system] {' + +if [[ "$OSTYPE" == darwin* ]]; then + for dir in $@; do + find "$dir" -type f \( -name "*.h" -o -name "*.def" -o -path "*/c++/*" \) \ + | LANG=C sort -u | while read -r header; do + echo " textual header \"${header}\"" + done + done +else + for dir in $@; do + find -L "${dir}" -type f 2>/dev/null | LANG=C sort -u | while read -r header; do + echo " textual header \"${header}\"" + done + done +fi + +echo "}" diff --git a/cc/private/toolchain/lib_cc_configure.bzl b/cc/private/toolchain/lib_cc_configure.bzl index bcd9013..975dd44 100644 --- a/cc/private/toolchain/lib_cc_configure.bzl +++ b/cc/private/toolchain/lib_cc_configure.bzl @@ -51,7 +51,7 @@ def split_escaped(string, delimiter): Basic usage: split_escaped("a:b:c", ":") -> [ "a", "b", "c" ] - Delimeter that is not supposed to be splitten on has to be %-escaped: + Delimiter that is not supposed to be splitten on has to be %-escaped: split_escaped("a%:b", ":") -> [ "a:b" ] Literal % can be represented by escaping it as %%: @@ -137,7 +137,8 @@ def get_env_var(repository_ctx, name, default = None, enable_warning = True): if enable_warning: auto_configure_warning("'%s' environment variable is not set, using '%s' as default" % (name, default)) return default - return auto_configure_fail("'%s' environment variable is not set" % name) + auto_configure_fail("'%s' environment variable is not set" % name) + return None def which(repository_ctx, cmd, default = None): """A wrapper around repository_ctx.which() to provide a fallback value. Doesn't %-escape the value! @@ -176,7 +177,8 @@ def execute( repository_ctx, command, environment = None, - expect_failure = False): + expect_failure = False, + expect_empty_output = False): """Execute a command, return stdout if succeed and throw an error if it fails. Doesn't %-escape the result! Args: @@ -184,6 +186,7 @@ def execute( command: command to execute. environment: dictionary with environment variables to set for the command. expect_failure: True if the command is expected to fail. + expect_empty_output: True if the command is expected to produce no output. Returns: stdout of the executed command. """ @@ -208,10 +211,15 @@ def execute( ), ) stripped_stdout = result.stdout.strip() - if not stripped_stdout: - auto_configure_fail( - "empty output from command %s, stderr: (%s)" % (command, result.stderr), - ) + if expect_empty_output != (not stripped_stdout): + if expect_empty_output: + auto_configure_fail( + "non-empty output from command %s, stdout: (%s), stderr: (%s)" % (command, result.stdout, result.stderr), + ) + else: + auto_configure_fail( + "empty output from command %s, stderr: (%s)" % (command, result.stderr), + ) return stripped_stdout def get_cpu_value(repository_ctx): @@ -222,25 +230,34 @@ def get_cpu_value(repository_ctx): Returns: One of (darwin, freebsd, x64_windows, ppc, s390x, arm, aarch64, k8, piii) """ - os_name = repository_ctx.os.name.lower() + os_name = repository_ctx.os.name + arch = repository_ctx.os.arch if os_name.startswith("mac os"): - return "darwin" + # Check if we are on x86_64 or arm64 and return the corresponding cpu value. + return "darwin_" + ("arm64" if arch == "aarch64" else "x86_64") if os_name.find("freebsd") != -1: return "freebsd" + if os_name.find("openbsd") != -1: + return "openbsd" if os_name.find("windows") != -1: - return "x64_windows" + if arch == "aarch64": + return "arm64_windows" + else: + 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"]: + if arch in ["power", "ppc64le", "ppc", "ppc64"]: return "ppc" - if result.stdout.strip() in ["s390x"]: + if arch in ["s390x"]: return "s390x" - if result.stdout.strip() in ["arm", "armv7l"]: + if arch in ["mips64"]: + return "mips64" + if arch in ["riscv64"]: + return "riscv64" + if arch in ["arm", "armv7l"]: return "arm" - if result.stdout.strip() in ["aarch64"]: + if arch in ["aarch64"]: return "aarch64" - return "k8" if result.stdout.strip() in ["amd64", "x86_64", "x64"] else "piii" + return "k8" if arch in ["amd64", "x86_64", "x64"] else "piii" def is_cc_configure_debug(repository_ctx): """Returns True if CC_CONFIGURE_DEBUG is set to 1.""" diff --git a/cc/private/toolchain/linux_cc_wrapper.sh.tpl b/cc/private/toolchain/linux_cc_wrapper.sh.tpl index a83be50..629741e 100644 --- a/cc/private/toolchain/linux_cc_wrapper.sh.tpl +++ b/cc/private/toolchain/linux_cc_wrapper.sh.tpl @@ -18,8 +18,37 @@ # set -eu +OUTPUT= + +function parse_option() { + local -r opt="$1" + if [[ "${OUTPUT}" = "1" ]]; then + OUTPUT=$opt + elif [[ "$opt" = "-o" ]]; then + # output is coming + OUTPUT=1 + fi +} + +# let parse the option list +for i in "$@"; do + if [[ "$i" = @* && -r "${i:1}" ]]; then + while IFS= read -r opt + do + parse_option "$opt" + done < "${i:1}" || exit 1 + else + parse_option "$i" + fi +done + # Set-up the environment %{env} # Call the C++ compiler %{cc} "$@" + +# Generate an empty file if header processing succeeded. +if [[ "${OUTPUT}" == *.h.processed ]]; then + echo -n > "${OUTPUT}" +fi diff --git a/cc/private/toolchain/msvc_deps_scanner_wrapper.bat.tpl b/cc/private/toolchain/msvc_deps_scanner_wrapper.bat.tpl new file mode 100644 index 0000000..2c6200f --- /dev/null +++ b/cc/private/toolchain/msvc_deps_scanner_wrapper.bat.tpl @@ -0,0 +1,16 @@ +:: Copyright 2024 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 +"%{cc}" /scanDependencies- /TP %* >%DEPS_SCANNER_OUTPUT_FILE% diff --git a/cc/private/toolchain/osx_cc_wrapper.sh.tpl b/cc/private/toolchain/osx_cc_wrapper.sh.tpl index 28bd47b..e40a98b 100644 --- a/cc/private/toolchain/osx_cc_wrapper.sh.tpl +++ b/cc/private/toolchain/osx_cc_wrapper.sh.tpl @@ -27,9 +27,8 @@ # set -eu -INSTALL_NAME_TOOL="/usr/bin/install_name_tool" - LIBS= +LIB_PATHS= LIB_DIRS= RPATHS= OUTPUT= @@ -40,9 +39,13 @@ function parse_option() { OUTPUT=$opt elif [[ "$opt" =~ ^-l(.*)$ ]]; then LIBS="${BASH_REMATCH[1]} $LIBS" + elif [[ "$opt" =~ ^(.*)\.so$ ]]; then + LIB_PATHS="${opt} $LIB_PATHS" + elif [[ "$opt" =~ ^(.*)\.dylib$ ]]; then + LIB_PATHS="${opt} $LIB_PATHS" elif [[ "$opt" =~ ^-L(.*)$ ]]; then LIB_DIRS="${BASH_REMATCH[1]} $LIB_DIRS" - elif [[ "$opt" =~ ^-Wl,-rpath,\@loader_path/(.*)$ ]]; then + elif [[ "$opt" =~ ^\@loader_path/(.*)$ ]]; then RPATHS="${BASH_REMATCH[1]} ${RPATHS}" elif [[ "$opt" = "-o" ]]; then # output is coming @@ -52,7 +55,7 @@ function parse_option() { # let parse the option list for i in "$@"; do - if [[ "$i" = @* ]]; then + if [[ "$i" = @* && -r "${i:1}" ]]; then while IFS= read -r opt do parse_option "$opt" @@ -68,6 +71,11 @@ done # Call the C++ compiler %{cc} "$@" +# Generate an empty file if header processing succeeded. +if [[ "${OUTPUT}" == *.h.processed ]]; then + echo -n > "${OUTPUT}" +fi + function get_library_path() { for libdir in ${LIB_DIRS}; do if [ -f ${libdir}/lib$1.so ]; then @@ -96,6 +104,11 @@ function get_otool_path() { get_realpath $1 | sed 's|^.*/bazel-out/|bazel-out/|' } +function call_install_name() { + /usr/bin/xcrun install_name_tool -change $(get_otool_path "$1") \ + "@loader_path/$2/$3" "${OUTPUT}" +} + # Do replacements in the output for rpath in ${RPATHS}; do for lib in ${LIBS}; do @@ -110,10 +123,16 @@ for rpath in ${RPATHS}; do 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}" + call_install_name "${libpath}" "${rpath}" "${libname}" + fi + fi + done + for libpath in ${LIB_PATHS}; do + if [ -f "$libpath" ]; then + libname=$(basename "$libpath") + if [ -f "$(dirname ${OUTPUT})/${rpath}/${libname}" ]; then + call_install_name "${libpath}" "${rpath}" "${libname}" fi fi done done - diff --git a/cc/private/toolchain/unix_cc_configure.bzl b/cc/private/toolchain/unix_cc_configure.bzl index 0c936de..0629a50 100644 --- a/cc/private/toolchain/unix_cc_configure.bzl +++ b/cc/private/toolchain/unix_cc_configure.bzl @@ -20,6 +20,7 @@ load( "auto_configure_warning", "auto_configure_warning_maybe", "escape_string", + "execute", "get_env_var", "get_starlark_list", "resolve_labels", @@ -34,16 +35,19 @@ def _uniq(iterable): unique_elements = {element: None for element in iterable} return unique_elements.keys() +def _generate_system_module_map(repository_ctx, dirs, script_path): + return execute(repository_ctx, [script_path] + dirs) + def _prepare_include_path(repo_ctx, path): - """Resolve and sanitize include path before outputting it into the crosstool. + """Resolve include path before outputting it into the crosstool. Args: repo_ctx: repository_ctx object. - path: an include path to be sanitized. + path: an include path to be resolved. Returns: - Sanitized include path that can be written to the crosstoot. Resulting path - is absolute if it is outside the repository and relative otherwise. + Resolved include path. Resulting path is absolute if it is outside the + repository and relative otherwise. """ repo_root = str(repo_ctx.path(".")) @@ -52,22 +56,24 @@ def _prepare_include_path(repo_ctx, path): repo_root += "/" path = str(repo_ctx.path(path)) if path.startswith(repo_root): - return escape_string(path[len(repo_root):]) - return escape_string(path) + return path[len(repo_root):] + return path -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] +def _find_tool(repository_ctx, tool, overridden_tools): + """Find a tool for repository, taking overridden tools into account.""" + if tool in overridden_tools: + return overridden_tools[tool] return which(repository_ctx, tool, "/usr/bin/" + tool) -def _get_tool_paths(repository_ctx, overriden_tools): +def _get_tool_paths(repository_ctx, overridden_tools): """Compute the %-escaped path to the various tools""" return dict({ - k: escape_string(_find_tool(repository_ctx, k, overriden_tools)) + k: escape_string(_find_tool(repository_ctx, k, overridden_tools)) for k in [ "ar", "ld", + "llvm-cov", + "llvm-profdata", "cpp", "gcc", "dwp", @@ -76,6 +82,7 @@ def _get_tool_paths(repository_ctx, overriden_tools): "objcopy", "objdump", "strip", + "c++filt", ] }.items()) @@ -103,17 +110,8 @@ def _cxx_inc_convert(path): 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. - - Args: - repository_ctx: The repository context. - cc: path to the C compiler. - lang_flag: value for the language flag (c, c++). - additional_flags: additional flags to pass to cc. - Returns: - a list of escaped system include directories. - """ +def _get_cxx_include_directories(repository_ctx, print_resource_dir_supported, cc, lang_flag, additional_flags = []): + """Compute the list of 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: @@ -135,9 +133,9 @@ def get_escaped_cxx_inc_directories(repository_ctx, cc, lang_flag, additional_fl for p in inc_dirs.split("\n") ] - if _is_compiler_option_supported(repository_ctx, cc, "-print-resource-dir"): + if print_resource_dir_supported: resource_dir = repository_ctx.execute( - [cc, "-print-resource-dir"], + [cc, "-print-resource-dir"] + additional_flags, ).stdout.strip() + "/share" inc_directories.append(_prepare_include_path(repository_ctx, resource_dir)) @@ -155,10 +153,9 @@ def _is_compiler_option_supported(repository_ctx, cc, option): ]) return result.stderr.find(option) == -1 -def _is_linker_option_supported(repository_ctx, cc, option, pattern): +def _is_linker_option_supported(repository_ctx, cc, force_linker_flags, option, pattern): """Checks that `option` is supported by the C linker. Doesn't %-escape the option.""" - result = repository_ctx.execute([ - cc, + result = repository_ctx.execute([cc] + force_linker_flags + [ option, "-o", "/dev/null", @@ -166,63 +163,50 @@ def _is_linker_option_supported(repository_ctx, cc, option, pattern): ]) return result.stderr.find(pattern) == -1 -def _find_gold_linker_path(repository_ctx, cc): - """Checks if `gold` is supported by the C compiler. +def _find_linker_path(repository_ctx, cc, linker, is_clang): + """Checks if a given linker is supported by the C compiler. Args: repository_ctx: repository_ctx. cc: path to the C compiler. + linker: linker to find + is_clang: whether the compiler is known to be clang Returns: - String to put as value to -fuse-ld= flag, or None if gold couldn't be found. + String to put as value to -fuse-ld= flag, or None if linker 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 + # 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", + "-fuse-ld=" + linker, "-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 - if flag.find("--enable-gold") > -1 or flag.find("--with-plugin-ld") > -1: - # skip build configuration options of gcc itself - # TODO(hlopko): Add redhat-like worker on the CI (#9392) - continue + if not is_clang: + return linker - # 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 + # Extract linker path from: + # /usr/bin/clang ... + # "/usr/bin/ld.lld" -pie -z ... + linker_command = result.stderr.splitlines()[-1] + return linker_command.strip().split(" ")[0].strip("\"'") 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): +def _add_linker_option_if_supported(repository_ctx, cc, force_linker_flags, 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 [] + return [option] if _is_linker_option_supported(repository_ctx, cc, force_linker_flags, option, pattern) else [] def _get_no_canonical_prefixes_opt(repository_ctx, cc): # If the compiler sometimes rewrites paths in the .d files without symlinks @@ -280,11 +264,27 @@ def _coverage_flags(repository_ctx, darwin): link_flags = '"--coverage"' return compile_flags, link_flags -def _find_generic(repository_ctx, name, env_name, overriden_tools, warn = False, silent = False): +def _is_clang(repository_ctx, cc): + return "clang" in repository_ctx.execute([cc, "-v"]).stderr + +def _is_gcc(repository_ctx, cc): + # GCC's version output uses the basename of argv[0] as the program name: + # https://gcc.gnu.org/git/?p=gcc.git;a=blob;f=gcc/gcc.cc;h=158461167951c1b9540322fb19be6a89d6da07fc;hb=HEAD#l8728 + cc_stdout = repository_ctx.execute([cc, "--version"]).stdout + return cc_stdout.startswith("gcc ") or cc_stdout.startswith("gcc-") + +def _get_compiler_name(repository_ctx, cc): + if _is_clang(repository_ctx, cc): + return "clang" + if _is_gcc(repository_ctx, cc): + return "gcc" + return "compiler" + +def _find_generic(repository_ctx, name, env_name, overridden_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] + if name in overridden_tools: + return overridden_tools[name] result = name env_value = repository_ctx.os.environ.get(env_name) @@ -295,7 +295,7 @@ def _find_generic(repository_ctx, name, env_name, overriden_tools, warn = False, 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. + # Absolute path, maybe we should make this supported by our which function. return result result = repository_ctx.which(result) if result == None: @@ -308,23 +308,44 @@ def _find_generic(repository_ctx, name, env_name, overriden_tools, warn = False, 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. +def find_cc(repository_ctx, overridden_tools): + """Find the C compiler (gcc or clang) for the repository, considering overridden tools. Args: repository_ctx: The repository context. - cpu_value: current cpu name. - overriden_tools: overriden tools. + overridden_tools: A dictionary of overridden tools. + + Returns: + The path to the C compiler. + """ + cc = _find_generic(repository_ctx, "gcc", "CC", overridden_tools) + if _is_clang(repository_ctx, cc): + # If clang is run through a symlink with -no-canonical-prefixes, it does + # not find its own include directory, which includes the headers for + # libc++. Resolving the potential symlink here prevents this. + result = repository_ctx.execute(["readlink", "-f", cc]) + if result.return_code == 0: + return result.stdout.strip() + return cc + +def configure_unix_toolchain(repository_ctx, cpu_value, overridden_tools): + """Configure C++ toolchain on Unix platforms. + + Args: + repository_ctx: The repository context. + cpu_value: The CPU value. + overridden_tools: A dictionary of overridden tools. """ paths = resolve_labels(repository_ctx, [ "@rules_cc//cc/private/toolchain:BUILD.tpl", + "@rules_cc//cc/private/toolchain:generate_system_module_map.sh", "@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:validate_static_library.sh.tpl", "@rules_cc//cc/private/toolchain:osx_cc_wrapper.sh.tpl", + "@rules_cc//cc/private/toolchain:clang_deps_scanner_wrapper.sh.tpl", + "@rules_cc//cc/private/toolchain:gcc_deps_scanner_wrapper.sh.tpl", ]) repository_ctx.symlink( @@ -338,24 +359,56 @@ def configure_unix_toolchain(repository_ctx, cpu_value, overriden_tools): ) repository_ctx.file("tools/cpp/empty.cc", "int main() {}") - darwin = cpu_value == "darwin" + darwin = cpu_value.startswith("darwin") + bsd = cpu_value == "freebsd" or cpu_value == "openbsd" - cc = _find_generic(repository_ctx, "gcc", "CC", overriden_tools) - overriden_tools = dict(overriden_tools) - overriden_tools["gcc"] = cc - overriden_tools["gcov"] = _find_generic( + cc = find_cc(repository_ctx, overridden_tools) + is_clang = _is_clang(repository_ctx, cc) + overridden_tools = dict(overridden_tools) + overridden_tools["gcc"] = cc + overridden_tools["gcov"] = _find_generic( repository_ctx, "gcov", "GCOV", - overriden_tools, + overridden_tools, + warn = True, + silent = True, + ) + overridden_tools["llvm-cov"] = _find_generic( + repository_ctx, + "llvm-cov", + "BAZEL_LLVM_COV", + overridden_tools, + warn = True, + silent = True, + ) + overridden_tools["llvm-profdata"] = _find_generic( + repository_ctx, + "llvm-profdata", + "BAZEL_LLVM_PROFDATA", + overridden_tools, + warn = True, + silent = True, + ) + overridden_tools["ar"] = _find_generic( + repository_ctx, + "ar", + "AR", + overridden_tools, warn = True, silent = True, ) if darwin: - overriden_tools["gcc"] = "cc_wrapper.sh" - overriden_tools["ar"] = "/usr/bin/libtool" + overridden_tools["gcc"] = "cc_wrapper.sh" + overridden_tools["ar"] = _find_generic(repository_ctx, "libtool", "LIBTOOL", overridden_tools) + auto_configure_warning_maybe(repository_ctx, "CC used: " + str(cc)) - tool_paths = _get_tool_paths(repository_ctx, overriden_tools) + tool_paths = _get_tool_paths(repository_ctx, overridden_tools) + tool_paths["cpp-module-deps-scanner"] = "deps_scanner_wrapper.sh" + + # The parse_header tool needs to be a wrapper around the compiler as it has + # to touch the output file. + tool_paths["parse_headers"] = "cc_wrapper.sh" cc_toolchain_identifier = escape_string(get_env_var( repository_ctx, "CC_TOOLCHAIN_NAME", @@ -363,6 +416,19 @@ def configure_unix_toolchain(repository_ctx, cpu_value, overriden_tools): False, )) + if "nm" in tool_paths and "c++filt" in tool_paths: + repository_ctx.template( + "validate_static_library.sh", + paths["@rules_cc//cc/private/toolchain:validate_static_library.sh.tpl"], + { + "%{c++filt}": escape_string(str(repository_ctx.path(tool_paths["c++filt"]))), + # Certain weak symbols are otherwise listed with type T in the output of nm on macOS. + "%{nm_extra_args}": "--no-weak" if darwin else "", + "%{nm}": escape_string(str(repository_ctx.path(tool_paths["nm"]))), + }, + ) + tool_paths["validate_static_library"] = "validate_static_library.sh" + 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" ) @@ -374,16 +440,94 @@ def configure_unix_toolchain(repository_ctx, cpu_value, overriden_tools): "%{env}": escape_string(get_env(repository_ctx)), }, ) + deps_scanner_wrapper_src = ( + "@rules_cc//cc/private/toolchain:clang_deps_scanner_wrapper.sh.tpl" if is_clang else "@rules_cc//cc/private/toolchain:gcc_deps_scanner_wrapper.sh.tpl" + ) + deps_scanner = "cpp-module-deps-scanner_not_found" + if is_clang: + cc_str = str(cc) + path_arr = cc_str.split("/")[:-1] + path_arr.append("clang-scan-deps") + deps_scanner = "/".join(path_arr) + repository_ctx.template( + "deps_scanner_wrapper.sh", + paths[deps_scanner_wrapper_src], + { + "%{cc}": escape_string(str(cc)), + "%{deps_scanner}": escape_string(deps_scanner), + "%{env}": escape_string(get_env(repository_ctx)), + }, + ) + + conly_opts = split_escaped(get_env_var( + repository_ctx, + "BAZEL_CONLYOPTS", + "", + False, + ), ":") cxx_opts = split_escaped(get_env_var( repository_ctx, "BAZEL_CXXOPTS", - "-std=c++0x", + "-std=c++17", False, ), ":") - bazel_linklibs = "-lstdc++:-lm" + gold_or_lld_linker_path = ( + _find_linker_path(repository_ctx, cc, "lld", is_clang) or + _find_linker_path(repository_ctx, cc, "gold", is_clang) + ) + 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_flags = ["-B" + escape_string(str(cc_path.dirname))] + else: + # cc is inside the repository, don't set -B. + bin_search_flags = [] + if not gold_or_lld_linker_path: + ld_path = repository_ctx.path(tool_paths["ld"]) + if ld_path.dirname != cc_path.dirname: + bin_search_flags.append("-B" + str(ld_path.dirname)) + force_linker_flags = [] + if gold_or_lld_linker_path: + force_linker_flags.append("-fuse-ld=" + gold_or_lld_linker_path) + + # TODO: It's unclear why these flags aren't added on macOS. + if bin_search_flags and not darwin: + force_linker_flags.extend(bin_search_flags) + use_libcpp = darwin or bsd + is_as_needed_supported = _is_linker_option_supported( + repository_ctx, + cc, + force_linker_flags, + "-Wl,-no-as-needed", + "-no-as-needed", + ) + is_push_state_supported = _is_linker_option_supported( + repository_ctx, + cc, + force_linker_flags, + "-Wl,--push-state", + "--push-state", + ) + if use_libcpp: + bazel_default_libs = ["-lc++", "-lm"] + else: + bazel_default_libs = ["-lstdc++", "-lm"] + if is_as_needed_supported and is_push_state_supported: + # Do not link against C++ standard libraries unless they are actually + # used. + # We assume that --push-state support implies --pop-state support. + bazel_linklibs_elements = [ + arg + for lib in bazel_default_libs + for arg in ["-Wl,--push-state,-as-needed", lib, "-Wl,--pop-state"] + ] + else: + bazel_linklibs_elements = bazel_default_libs + bazel_linklibs = ":".join(bazel_linklibs_elements) bazel_linkopts = "" + link_opts = split_escaped(get_env_var( repository_ctx, "BAZEL_LINKOPTS", @@ -396,33 +540,73 @@ def configure_unix_toolchain(repository_ctx, cpu_value, overriden_tools): 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) + print_resource_dir_supported = _is_compiler_option_supported( + repository_ctx, + cc, + "-print-resource-dir", + ) + no_canonical_prefixes_opt = _get_no_canonical_prefixes_opt(repository_ctx, cc) builtin_include_directories = _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( + _get_cxx_include_directories(repository_ctx, print_resource_dir_supported, cc, "-xc", conly_opts) + + _get_cxx_include_directories(repository_ctx, print_resource_dir_supported, cc, "-xc++", cxx_opts) + + _get_cxx_include_directories( repository_ctx, + print_resource_dir_supported, cc, "-xc++", - cxx_opts + _get_no_canonical_prefixes_opt(repository_ctx, cc), - ), + cxx_opts + ["-stdlib=libc++"], + ) + + _get_cxx_include_directories( + repository_ctx, + print_resource_dir_supported, + cc, + "-xc", + no_canonical_prefixes_opt, + ) + + _get_cxx_include_directories( + repository_ctx, + print_resource_dir_supported, + cc, + "-xc++", + cxx_opts + no_canonical_prefixes_opt, + ) + + _get_cxx_include_directories( + repository_ctx, + print_resource_dir_supported, + cc, + "-xc++", + cxx_opts + no_canonical_prefixes_opt + ["-stdlib=libc++"], + ) + + # Always included in case the user has Xcode + the CLT installed, both + # paths can be used interchangeably + ["/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk"], ) + generate_modulemap = is_clang + if generate_modulemap: + repository_ctx.file("module.modulemap", _generate_system_module_map( + repository_ctx, + builtin_include_directories, + paths["@rules_cc//cc/private/toolchain:generate_system_module_map.sh"], + )) + extra_flags_per_feature = {} + if is_clang: + # Only supported by LLVM 14 and later, but required with C++20 and + # layering_check as C++ modules are the default. + # https://github.com/llvm/llvm-project/commit/0556138624edf48621dd49a463dbe12e7101f17d + result = repository_ctx.execute([ + cc, + "-Xclang", + "-fno-cxx-modules", + "-o", + "/dev/null", + "-c", + str(repository_ctx.path("tools/cpp/empty.cc")), + ]) + if "-fno-cxx-modules" not in result.stderr: + extra_flags_per_feature["use_module_maps"] = ["-Xclang", "-fno-cxx-modules"] + write_builtin_include_directory_paths(repository_ctx, cc, builtin_include_directories) repository_ctx.template( "BUILD", @@ -440,23 +624,24 @@ def configure_unix_toolchain(repository_ctx, cpu_value, overriden_tools): "local", False, )), - "%{cc_compiler_deps}": get_starlark_list([":builtin_include_directory_paths"] + ( - [":cc_wrapper"] if darwin else [] + "%{cc_compiler_deps}": get_starlark_list([ + ":builtin_include_directory_paths", + ":cc_wrapper", + ":deps_scanner_wrapper", + ] + ( + [":validate_static_library"] if "validate_static_library" in tool_paths else [] )), "%{cc_toolchain_identifier}": cc_toolchain_identifier, "%{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? + # All warnings are enabled. "-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 @@ -472,38 +657,34 @@ def configure_unix_toolchain(repository_ctx, cpu_value, overriden_tools): "%{compiler}": escape_string(get_env_var( repository_ctx, "BAZEL_COMPILER", - "compiler", + _get_compiler_name(repository_ctx, cc), False, )), + "%{conly_flags}": get_starlark_list(conly_opts), "%{coverage_compile_flags}": coverage_compile_flags, "%{coverage_link_flags}": coverage_link_flags, "%{cxx_builtin_include_directories}": get_starlark_list(builtin_include_directories), "%{cxx_flags}": get_starlark_list(cxx_opts + _escaped_cplus_include_paths(repository_ctx)), "%{dbg_compile_flags}": get_starlark_list(["-g"]), + "%{extra_flags_per_feature}": repr(extra_flags_per_feature), "%{host_system_name}": escape_string(get_env_var( repository_ctx, "BAZEL_HOST_SYSTEM", "local", False, )), - "%{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", + "%{link_flags}": get_starlark_list(force_linker_flags + ( + ["-Wl,-no-as-needed"] if is_as_needed_supported else [] ) + _add_linker_option_if_supported( repository_ctx, cc, + force_linker_flags, "-Wl,-z,relro,-z,now", "-z", ) + ( [ - "-undefined", - "dynamic_lookup", "-headerpad_max_install_names", - ] if darwin else bin_search_flag + [ + ] if darwin else [ # Gold linker only? Can we enable this by default? # "-Wl,--warn-execstack", # "-Wl,--detect-odr-violations" @@ -515,6 +696,7 @@ def configure_unix_toolchain(repository_ctx, cpu_value, overriden_tools): ) ) + link_opts), "%{link_libs}": get_starlark_list(link_libs), + "%{modulemap}": ("\":module.modulemap\"" if generate_modulemap else "None"), "%{name}": cpu_value, "%{opt_compile_flags}": get_starlark_list( [ @@ -543,15 +725,15 @@ def configure_unix_toolchain(repository_ctx, cpu_value, overriden_tools): ], ), "%{opt_link_flags}": get_starlark_list( - [] if darwin else _add_linker_option_if_supported( + ["-Wl,-dead_strip"] if darwin else _add_linker_option_if_supported( repository_ctx, cc, + force_linker_flags, "-Wl,--gc-sections", "-gc-sections", ), ), - "%{supports_param_files}": "0" if darwin else "1", - "%{supports_start_end_lib}": "True" if gold_linker_path else "False", + "%{supports_start_end_lib}": "True" if gold_or_lld_linker_path else "False", "%{target_cpu}": escape_string(get_env_var( repository_ctx, "BAZEL_TARGET_CPU", @@ -571,7 +753,7 @@ def configure_unix_toolchain(repository_ctx, cpu_value, overriden_tools): False, )), "%{tool_paths}": ",\n ".join( - ['"%s": "%s"' % (k, v) for k, v in tool_paths.items()], + ['"%s": "%s"' % (k, v) for k, v in tool_paths.items() if v != None], ), "%{unfiltered_compile_flags}": get_starlark_list( _get_no_canonical_prefixes_opt(repository_ctx, cc) + [ diff --git a/cc/private/toolchain/unix_cc_toolchain_config.bzl b/cc/private/toolchain/unix_cc_toolchain_config.bzl index 4325a68..5e0789b 100644 --- a/cc/private/toolchain/unix_cc_toolchain_config.bzl +++ b/cc/private/toolchain/unix_cc_toolchain_config.bzl @@ -17,15 +17,137 @@ load("@rules_cc//cc:action_names.bzl", "ACTION_NAMES") load( "@rules_cc//cc:cc_toolchain_config_lib.bzl", + "action_config", + "artifact_name_pattern", + "env_entry", + "env_set", "feature", "feature_set", "flag_group", "flag_set", + "tool", "tool_path", "variable_with_value", "with_feature_set", ) +def _target_os_version(ctx): + platform_type = ctx.fragments.apple.single_arch_platform.platform_type + xcode_config = ctx.attr._xcode_config[apple_common.XcodeVersionConfig] + return xcode_config.minimum_os_for_platform_type(platform_type) + +def layering_check_features(compiler, extra_flags_per_feature, is_macos): + if compiler != "clang": + return [] + return [ + feature( + name = "use_module_maps", + requires = [feature_set(features = ["module_maps"])], + flag_sets = [ + flag_set( + actions = [ + ACTION_NAMES.c_compile, + ACTION_NAMES.cpp_compile, + ACTION_NAMES.cpp_header_parsing, + ACTION_NAMES.cpp_module_compile, + ], + flag_groups = [ + flag_group( + # macOS requires -Xclang because of a bug in Apple Clang + flags = (["-Xclang"] if is_macos else []) + [ + "-fmodule-name=%{module_name}", + ] + (["-Xclang"] if is_macos else []) + [ + "-fmodule-map-file=%{module_map_file}", + ] + extra_flags_per_feature.get("use_module_maps", []), + ), + ], + ), + ], + ), + + # Tell blaze we support module maps in general, so they will be generated + # for all c/c++ rules. + # Note: not all C++ rules support module maps; thus, do not imply this + # feature from other features - instead, require it. + feature(name = "module_maps", enabled = True), + feature( + name = "layering_check", + implies = ["use_module_maps"], + flag_sets = [ + flag_set( + actions = [ + ACTION_NAMES.c_compile, + ACTION_NAMES.cpp_compile, + ACTION_NAMES.cpp_header_parsing, + ACTION_NAMES.cpp_module_compile, + ], + flag_groups = [ + flag_group(flags = [ + "-fmodules-strict-decluse", + "-Wprivate-header", + ]), + flag_group( + iterate_over = "dependent_module_map_files", + flags = (["-Xclang"] if is_macos else []) + [ + "-fmodule-map-file=%{dependent_module_map_files}", + ], + ), + ], + ), + ], + ), + ] + +def parse_headers_support(parse_headers_tool_path): + """ + Returns action configurations and features for parsing headers. + + Args: + parse_headers_tool_path: The path to the tool used for parsing headers. + + Returns: + A tuple containing a list of action configurations and a list of features. + """ + if not parse_headers_tool_path: + return [], [] + action_configs = [ + action_config( + action_name = ACTION_NAMES.cpp_header_parsing, + tools = [ + tool(path = parse_headers_tool_path), + ], + flag_sets = [ + flag_set( + flag_groups = [ + flag_group( + flags = [ + # Note: This treats all headers as C++ headers, which may lead to + # parsing failures for C headers that are not valid C++. + # For such headers, use features = ["-parse_headers"] to selectively + # disable parsing. + "-xc++-header", + "-fsyntax-only", + ], + ), + ], + ), + ], + implies = [ + # Copied from the legacy feature definition in CppActionConfigs.java. + "legacy_compile_flags", + "user_compile_flags", + "sysroot", + "unfiltered_compile_flags", + "compiler_input_flags", + "compiler_output_flags", + ], + ), + ] + features = [ + feature(name = "parse_headers"), + ] + return action_configs, features + all_compile_actions = [ ACTION_NAMES.c_compile, ACTION_NAMES.cpp_compile, @@ -35,6 +157,9 @@ all_compile_actions = [ ACTION_NAMES.cpp_header_parsing, ACTION_NAMES.cpp_module_compile, ACTION_NAMES.cpp_module_codegen, + ACTION_NAMES.cpp_module_deps_scanning, + ACTION_NAMES.cpp20_module_compile, + ACTION_NAMES.cpp20_module_codegen, ACTION_NAMES.clif_match, ACTION_NAMES.lto_backend, ] @@ -45,6 +170,9 @@ all_cpp_compile_actions = [ ACTION_NAMES.cpp_header_parsing, ACTION_NAMES.cpp_module_compile, ACTION_NAMES.cpp_module_codegen, + ACTION_NAMES.cpp_module_deps_scanning, + ACTION_NAMES.cpp20_module_compile, + ACTION_NAMES.cpp20_module_codegen, ACTION_NAMES.clif_match, ] @@ -55,6 +183,8 @@ preprocessor_compile_actions = [ ACTION_NAMES.preprocess_assemble, ACTION_NAMES.cpp_header_parsing, ACTION_NAMES.cpp_module_compile, + ACTION_NAMES.cpp_module_deps_scanning, + ACTION_NAMES.cpp20_module_compile, ACTION_NAMES.clif_match, ] @@ -65,6 +195,7 @@ codegen_compile_actions = [ ACTION_NAMES.assemble, ACTION_NAMES.preprocess_assemble, ACTION_NAMES.cpp_module_codegen, + ACTION_NAMES.cpp20_module_codegen, ACTION_NAMES.lto_backend, ] @@ -80,13 +211,144 @@ lto_index_actions = [ ACTION_NAMES.lto_index_for_nodeps_dynamic_library, ] +def _sanitizer_feature(name = "", specific_compile_flags = [], specific_link_flags = []): + return feature( + name = name, + flag_sets = [ + flag_set( + actions = all_compile_actions, + flag_groups = [ + flag_group(flags = [ + "-fno-omit-frame-pointer", + "-fno-sanitize-recover=all", + ] + specific_compile_flags), + ], + with_features = [ + with_feature_set(features = [name]), + ], + ), + flag_set( + actions = all_link_actions, + flag_groups = [ + flag_group(flags = specific_link_flags), + ], + with_features = [ + with_feature_set(features = [name]), + ], + ), + ], + ) + def _impl(ctx): + is_linux = ctx.attr.target_libc != "macosx" + tool_paths = [ tool_path(name = name, path = path) for name, path in ctx.attr.tool_paths.items() ] action_configs = [] + llvm_cov = ctx.attr.tool_paths.get("llvm-cov") + if llvm_cov: + llvm_cov_action = action_config( + action_name = ACTION_NAMES.llvm_cov, + tools = [ + tool( + path = llvm_cov, + ), + ], + ) + action_configs.append(llvm_cov_action) + + objcopy = ctx.attr.tool_paths.get("objcopy") + if objcopy: + objcopy_action = action_config( + action_name = ACTION_NAMES.objcopy_embed_data, + tools = [ + tool( + path = objcopy, + ), + ], + ) + action_configs.append(objcopy_action) + + validate_static_library = ctx.attr.tool_paths.get("validate_static_library") + if validate_static_library: + validate_static_library_action = action_config( + action_name = ACTION_NAMES.validate_static_library, + tools = [ + tool( + path = validate_static_library, + ), + ], + ) + action_configs.append(validate_static_library_action) + + symbol_check = feature( + name = "symbol_check", + implies = [ACTION_NAMES.validate_static_library], + ) + else: + symbol_check = None + + deps_scanner = "cpp-module-deps-scanner_not_found" + if "cpp-module-deps-scanner" in ctx.attr.tool_paths: + deps_scanner = ctx.attr.tool_paths["cpp-module-deps-scanner"] + cc = ctx.attr.tool_paths.get("gcc") + compile_implies = [ + # keep same with c++-compile + "legacy_compile_flags", + "user_compile_flags", + "sysroot", + "unfiltered_compile_flags", + "compiler_input_flags", + "compiler_output_flags", + ] + cpp_module_scan_deps = action_config( + action_name = ACTION_NAMES.cpp_module_deps_scanning, + tools = [ + tool( + path = deps_scanner, + ), + ], + implies = compile_implies, + ) + action_configs.append(cpp_module_scan_deps) + + cpp20_module_compile = action_config( + action_name = ACTION_NAMES.cpp20_module_compile, + tools = [ + tool( + path = cc, + ), + ], + flag_sets = [ + flag_set( + flag_groups = [ + flag_group( + flags = [ + "-x", + "c++-module" if ctx.attr.compiler == "clang" else "c++", + ], + ), + ], + ), + ], + implies = compile_implies, + ) + action_configs.append(cpp20_module_compile) + + cpp20_module_codegen = action_config( + action_name = ACTION_NAMES.cpp20_module_codegen, + tools = [ + tool( + path = cc, + ), + ], + implies = compile_implies, + ) + action_configs.append(cpp20_module_codegen) + supports_pic_feature = feature( name = "supports_pic", enabled = True, @@ -96,10 +358,35 @@ def _impl(ctx): enabled = True, ) + gcc_quoting_for_param_files_feature = feature( + name = "gcc_quoting_for_param_files", + enabled = True, + ) + + static_link_cpp_runtimes_feature = feature( + name = "static_link_cpp_runtimes", + enabled = False, + ) + default_compile_flags_feature = feature( name = "default_compile_flags", enabled = True, flag_sets = [ + flag_set( + actions = all_compile_actions, + flag_groups = [ + flag_group( + # Security hardening requires optimization. + # We need to undef it as some distributions now have it enabled by default. + flags = ["-U_FORTIFY_SOURCE"], + ), + ], + with_features = [ + with_feature_set( + not_features = ["thin_lto"], + ), + ], + ), flag_set( actions = all_compile_actions, flag_groups = ([ @@ -126,6 +413,14 @@ def _impl(ctx): ] if ctx.attr.opt_compile_flags else []), with_features = [with_feature_set(features = ["opt"])], ), + flag_set( + actions = [ACTION_NAMES.c_compile], + flag_groups = ([ + flag_group( + flags = ctx.attr.conly_flags, + ), + ] if ctx.attr.conly_flags else []), + ), flag_set( actions = all_cpp_compile_actions + [ACTION_NAMES.lto_backend], flag_groups = ([ @@ -159,6 +454,18 @@ def _impl(ctx): with_features = [with_feature_set(features = ["opt"])], ), ], + env_sets = [ + env_set( + actions = all_link_actions + lto_index_actions + [ACTION_NAMES.cpp_link_static_library], + env_entries = ([ + env_entry( + # Required for hermetic links on macOS + key = "ZERO_AR_DATE", + value = "1", + ), + ]), + ), + ], ) dbg_feature = feature(name = "dbg") @@ -178,6 +485,9 @@ def _impl(ctx): ACTION_NAMES.cpp_header_parsing, ACTION_NAMES.cpp_module_compile, ACTION_NAMES.cpp_module_codegen, + ACTION_NAMES.cpp_module_deps_scanning, + ACTION_NAMES.cpp20_module_compile, + ACTION_NAMES.cpp20_module_codegen, ACTION_NAMES.lto_backend, ACTION_NAMES.clif_match, ] + all_link_actions + lto_index_actions, @@ -191,6 +501,76 @@ def _impl(ctx): ], ) + compiler_input_flags_feature = feature( + name = "compiler_input_flags", + enabled = True, + flag_sets = [ + flag_set( + actions = [ + ACTION_NAMES.assemble, + ACTION_NAMES.preprocess_assemble, + ACTION_NAMES.linkstamp_compile, + ACTION_NAMES.c_compile, + ACTION_NAMES.cpp_compile, + ACTION_NAMES.cpp_header_parsing, + ACTION_NAMES.cpp_module_compile, + ACTION_NAMES.cpp_module_codegen, + ACTION_NAMES.cpp_module_deps_scanning, + ACTION_NAMES.cpp20_module_compile, + ACTION_NAMES.cpp20_module_codegen, + ACTION_NAMES.objc_compile, + ACTION_NAMES.objcpp_compile, + ACTION_NAMES.lto_backend, + ], + flag_groups = [ + flag_group( + flags = ["-c", "%{source_file}"], + expand_if_available = "source_file", + ), + ], + ), + ], + ) + + compiler_output_flags_feature = feature( + name = "compiler_output_flags", + enabled = True, + flag_sets = [ + flag_set( + actions = [ + ACTION_NAMES.assemble, + ACTION_NAMES.preprocess_assemble, + ACTION_NAMES.linkstamp_compile, + ACTION_NAMES.c_compile, + ACTION_NAMES.cpp_compile, + ACTION_NAMES.cpp_header_parsing, + ACTION_NAMES.cpp_module_compile, + ACTION_NAMES.cpp_module_codegen, + ACTION_NAMES.cpp_module_deps_scanning, + ACTION_NAMES.cpp20_module_compile, + ACTION_NAMES.cpp20_module_codegen, + ACTION_NAMES.objc_compile, + ACTION_NAMES.objcpp_compile, + ACTION_NAMES.lto_backend, + ], + flag_groups = [ + flag_group( + flags = ["-S"], + expand_if_available = "output_assembly_file", + ), + flag_group( + flags = ["-E"], + expand_if_available = "output_preprocess_file", + ), + flag_group( + flags = ["-o", "%{output_file}"], + expand_if_available = "output_file", + ), + ], + ), + ], + ) + fdo_optimize_feature = feature( name = "fdo_optimize", flag_sets = [ @@ -292,6 +672,8 @@ def _impl(ctx): ACTION_NAMES.cpp_compile, ACTION_NAMES.cpp_module_codegen, ACTION_NAMES.cpp_module_compile, + ACTION_NAMES.cpp20_module_compile, + ACTION_NAMES.cpp20_module_codegen, ], flag_groups = [ flag_group(flags = ["-fPIC"], expand_if_available = "pic"), @@ -302,6 +684,7 @@ def _impl(ctx): per_object_debug_info_feature = feature( name = "per_object_debug_info", + enabled = True, flag_sets = [ flag_set( actions = [ @@ -310,6 +693,7 @@ def _impl(ctx): ACTION_NAMES.c_compile, ACTION_NAMES.cpp_compile, ACTION_NAMES.cpp_module_codegen, + ACTION_NAMES.cpp20_module_codegen, ], flag_groups = [ flag_group( @@ -333,6 +717,9 @@ def _impl(ctx): ACTION_NAMES.cpp_compile, ACTION_NAMES.cpp_header_parsing, ACTION_NAMES.cpp_module_compile, + ACTION_NAMES.cpp_module_deps_scanning, + ACTION_NAMES.cpp20_module_compile, + ACTION_NAMES.cpp20_module_codegen, ACTION_NAMES.clif_match, ], flag_groups = [ @@ -385,60 +772,134 @@ def _impl(ctx): provides = ["profile"], ) - runtime_library_search_directories_feature = feature( - name = "runtime_library_search_directories", - flag_sets = [ - flag_set( - actions = all_link_actions + lto_index_actions, - flag_groups = [ - flag_group( - iterate_over = "runtime_library_search_directories", - flag_groups = [ - flag_group( - flags = [ - "-Wl,-rpath,$EXEC_ORIGIN/%{runtime_library_search_directories}", - ], - expand_if_true = "is_cc_test", - ), - flag_group( - flags = [ - "-Wl,-rpath,$ORIGIN/%{runtime_library_search_directories}", - ], - expand_if_false = "is_cc_test", - ), - ], - expand_if_available = - "runtime_library_search_directories", - ), - ], - with_features = [ - with_feature_set(features = ["static_link_cpp_runtimes"]), - ], - ), - flag_set( - actions = all_link_actions + lto_index_actions, - flag_groups = [ - flag_group( - iterate_over = "runtime_library_search_directories", - flag_groups = [ - flag_group( - flags = [ - "-Wl,-rpath,$ORIGIN/%{runtime_library_search_directories}", - ], - ), - ], - expand_if_available = - "runtime_library_search_directories", - ), - ], - with_features = [ - with_feature_set( - not_features = ["static_link_cpp_runtimes"], - ), - ], - ), - ], - ) + if is_linux: + runtime_library_search_directories_feature = feature( + name = "runtime_library_search_directories", + flag_sets = [ + flag_set( + actions = all_link_actions + lto_index_actions, + flag_groups = [ + flag_group( + iterate_over = "runtime_library_search_directories", + flag_groups = [ + flag_group( + flags = [ + "-Xlinker", + "-rpath", + "-Xlinker", + "$EXEC_ORIGIN/%{runtime_library_search_directories}", + ], + expand_if_true = "is_cc_test", + ), + flag_group( + flags = [ + "-Xlinker", + "-rpath", + "-Xlinker", + "$ORIGIN/%{runtime_library_search_directories}", + ], + expand_if_false = "is_cc_test", + ), + ], + expand_if_available = + "runtime_library_search_directories", + ), + ], + with_features = [ + with_feature_set(features = ["static_link_cpp_runtimes"]), + ], + ), + flag_set( + actions = all_link_actions + lto_index_actions, + flag_groups = [ + flag_group( + iterate_over = "runtime_library_search_directories", + flag_groups = [ + flag_group( + flags = [ + "-Xlinker", + "-rpath", + "-Xlinker", + "$ORIGIN/%{runtime_library_search_directories}", + ], + ), + ], + expand_if_available = + "runtime_library_search_directories", + ), + ], + with_features = [ + with_feature_set( + not_features = ["static_link_cpp_runtimes"], + ), + ], + ), + ], + ) + set_install_name_feature = feature( + name = "set_soname", + flag_sets = [ + flag_set( + actions = [ + ACTION_NAMES.cpp_link_dynamic_library, + ACTION_NAMES.cpp_link_nodeps_dynamic_library, + ], + flag_groups = [ + flag_group( + flags = [ + "-Wl,-soname,%{runtime_solib_name}", + ], + expand_if_available = "runtime_solib_name", + ), + ], + ), + ], + ) + else: + runtime_library_search_directories_feature = feature( + name = "runtime_library_search_directories", + flag_sets = [ + flag_set( + actions = all_link_actions + lto_index_actions, + flag_groups = [ + flag_group( + iterate_over = "runtime_library_search_directories", + flag_groups = [ + flag_group( + flags = [ + "-Xlinker", + "-rpath", + "-Xlinker", + "@loader_path/%{runtime_library_search_directories}", + ], + ), + ], + expand_if_available = "runtime_library_search_directories", + ), + ], + ), + ], + ) + set_install_name_feature = feature( + name = "set_install_name", + enabled = ctx.fragments.cpp.do_not_use_macos_set_install_name, + flag_sets = [ + flag_set( + actions = [ + ACTION_NAMES.cpp_link_dynamic_library, + ACTION_NAMES.cpp_link_nodeps_dynamic_library, + ], + flag_groups = [ + flag_group( + flags = [ + "-Wl,-install_name,@rpath/%{runtime_solib_name}", + ], + expand_if_available = "runtime_solib_name", + ), + ], + ), + ], + ) fission_support_feature = feature( name = "fission_support", @@ -480,6 +941,9 @@ def _impl(ctx): ACTION_NAMES.cpp_compile, ACTION_NAMES.cpp_module_codegen, ACTION_NAMES.cpp_module_compile, + ACTION_NAMES.cpp_module_deps_scanning, + ACTION_NAMES.cpp20_module_compile, + ACTION_NAMES.cpp20_module_codegen, ], flag_groups = [ flag_group( @@ -503,6 +967,8 @@ def _impl(ctx): ACTION_NAMES.cpp_compile, ACTION_NAMES.cpp_header_parsing, ACTION_NAMES.cpp_module_compile, + ACTION_NAMES.cpp_module_deps_scanning, + ACTION_NAMES.cpp20_module_compile, ACTION_NAMES.clif_match, ACTION_NAMES.objc_compile, ACTION_NAMES.objcpp_compile, @@ -574,6 +1040,8 @@ def _impl(ctx): ACTION_NAMES.cpp_compile, ACTION_NAMES.cpp_header_parsing, ACTION_NAMES.cpp_module_compile, + ACTION_NAMES.cpp_module_deps_scanning, + ACTION_NAMES.cpp20_module_compile, ACTION_NAMES.clif_match, ACTION_NAMES.objc_compile, ACTION_NAMES.objcpp_compile, @@ -596,56 +1064,33 @@ def _impl(ctx): ], ) - symbol_counts_feature = feature( - name = "symbol_counts", - flag_sets = [ - flag_set( - actions = all_link_actions + lto_index_actions, - flag_groups = [ - flag_group( - flags = [ - "-Wl,--print-symbol-counts=%{symbol_counts_output}", - ], - expand_if_available = "symbol_counts_output", - ), - ], - ), - ], - ) - - llvm_coverage_map_format_feature = feature( - name = "llvm_coverage_map_format", + external_include_paths_feature = feature( + name = "external_include_paths", flag_sets = [ flag_set( actions = [ ACTION_NAMES.preprocess_assemble, + ACTION_NAMES.linkstamp_compile, ACTION_NAMES.c_compile, ACTION_NAMES.cpp_compile, + ACTION_NAMES.cpp_header_parsing, ACTION_NAMES.cpp_module_compile, + ACTION_NAMES.cpp_module_deps_scanning, + ACTION_NAMES.cpp20_module_compile, + ACTION_NAMES.cpp20_module_codegen, + ACTION_NAMES.clif_match, ACTION_NAMES.objc_compile, ACTION_NAMES.objcpp_compile, ], flag_groups = [ flag_group( - flags = [ - "-fprofile-instr-generate", - "-fcoverage-mapping", - ], + flags = ["-isystem", "%{external_include_paths}"], + iterate_over = "external_include_paths", + expand_if_available = "external_include_paths", ), ], ), - flag_set( - actions = all_link_actions + lto_index_actions + [ - "objc-executable", - "objc++-executable", - ], - flag_groups = [ - flag_group(flags = ["-fprofile-instr-generate"]), - ], - ), ], - requires = [feature_set(features = ["coverage"])], - provides = ["profile"], ) strip_debug_symbols_feature = feature( @@ -693,11 +1138,77 @@ def _impl(ctx): ], ) + libraries_to_link_common_flag_groups = [ + flag_group( + flags = ["-Wl,-whole-archive"], + expand_if_true = + "libraries_to_link.is_whole_archive", + expand_if_equal = variable_with_value( + name = "libraries_to_link.type", + value = "static_library", + ), + ), + flag_group( + flags = ["%{libraries_to_link.object_files}"], + iterate_over = "libraries_to_link.object_files", + expand_if_equal = variable_with_value( + name = "libraries_to_link.type", + value = "object_file_group", + ), + ), + flag_group( + flags = ["%{libraries_to_link.name}"], + expand_if_equal = variable_with_value( + name = "libraries_to_link.type", + value = "object_file", + ), + ), + flag_group( + flags = ["%{libraries_to_link.name}"], + expand_if_equal = variable_with_value( + name = "libraries_to_link.type", + value = "interface_library", + ), + ), + flag_group( + flags = ["%{libraries_to_link.name}"], + expand_if_equal = variable_with_value( + name = "libraries_to_link.type", + value = "static_library", + ), + ), + flag_group( + flags = ["-l%{libraries_to_link.name}"], + expand_if_equal = variable_with_value( + name = "libraries_to_link.type", + value = "dynamic_library", + ), + ), + flag_group( + flags = ["-l:%{libraries_to_link.name}"], + expand_if_equal = variable_with_value( + name = "libraries_to_link.type", + value = "versioned_dynamic_library", + ), + ), + flag_group( + flags = ["-Wl,-no-whole-archive"], + expand_if_true = "libraries_to_link.is_whole_archive", + expand_if_equal = variable_with_value( + name = "libraries_to_link.type", + value = "static_library", + ), + ), + ] + libraries_to_link_feature = feature( name = "libraries_to_link", flag_sets = [ flag_set( - actions = all_link_actions + lto_index_actions, + actions = [ + ACTION_NAMES.cpp_link_executable, + ACTION_NAMES.cpp_link_dynamic_library, + ] + lto_index_actions, flag_groups = [ flag_group( iterate_over = "libraries_to_link", @@ -709,58 +1220,7 @@ def _impl(ctx): value = "object_file_group", ), ), - flag_group( - flags = ["-Wl,-whole-archive"], - expand_if_true = - "libraries_to_link.is_whole_archive", - ), - flag_group( - flags = ["%{libraries_to_link.object_files}"], - iterate_over = "libraries_to_link.object_files", - expand_if_equal = variable_with_value( - name = "libraries_to_link.type", - value = "object_file_group", - ), - ), - flag_group( - flags = ["%{libraries_to_link.name}"], - expand_if_equal = variable_with_value( - name = "libraries_to_link.type", - value = "object_file", - ), - ), - flag_group( - flags = ["%{libraries_to_link.name}"], - expand_if_equal = variable_with_value( - name = "libraries_to_link.type", - value = "interface_library", - ), - ), - flag_group( - flags = ["%{libraries_to_link.name}"], - expand_if_equal = variable_with_value( - name = "libraries_to_link.type", - value = "static_library", - ), - ), - flag_group( - flags = ["-l%{libraries_to_link.name}"], - expand_if_equal = variable_with_value( - name = "libraries_to_link.type", - value = "dynamic_library", - ), - ), - flag_group( - flags = ["-l:%{libraries_to_link.name}"], - expand_if_equal = variable_with_value( - name = "libraries_to_link.type", - value = "versioned_dynamic_library", - ), - ), - flag_group( - flags = ["-Wl,-no-whole-archive"], - expand_if_true = "libraries_to_link.is_whole_archive", - ), + ] + libraries_to_link_common_flag_groups + [ flag_group( flags = ["-Wl,--end-lib"], expand_if_equal = variable_with_value( @@ -777,6 +1237,22 @@ def _impl(ctx): ), ], ), + # Object file groups may contain symbols that aren't referenced in the same target that + # produces the object files and must thus not be wrapped in --start-lib/--end-lib when + # linking a nodeps dynamic library. + flag_set( + actions = [ACTION_NAMES.cpp_link_nodeps_dynamic_library], + flag_groups = [ + flag_group( + iterate_over = "libraries_to_link", + flag_groups = libraries_to_link_common_flag_groups, + ), + flag_group( + flags = ["-Wl,@%{thinlto_param_file}"], + expand_if_true = "thinlto_param_file", + ), + ], + ), ], ) @@ -791,7 +1267,18 @@ def _impl(ctx): iterate_over = "user_link_flags", expand_if_available = "user_link_flags", ), - ] + ([flag_group(flags = ctx.attr.link_libs)] if ctx.attr.link_libs else []), + ], + ), + ], + ) + + default_link_libs_feature = feature( + name = "default_link_libs", + enabled = True, + flag_sets = [ + flag_set( + actions = all_link_actions + lto_index_actions, + flag_groups = [flag_group(flags = ctx.attr.link_libs)] if ctx.attr.link_libs else [], ), ], ) @@ -834,34 +1321,9 @@ def _impl(ctx): ], ) - gcc_coverage_map_format_feature = feature( - name = "gcc_coverage_map_format", - flag_sets = [ - flag_set( - actions = [ - ACTION_NAMES.preprocess_assemble, - ACTION_NAMES.c_compile, - ACTION_NAMES.cpp_compile, - ACTION_NAMES.cpp_module_compile, - ACTION_NAMES.objc_compile, - ACTION_NAMES.objcpp_compile, - "objc-executable", - "objc++-executable", - ], - flag_groups = [ - flag_group( - flags = ["-fprofile-arcs", "-ftest-coverage"], - expand_if_available = "gcov_gcno_file", - ), - ], - ), - flag_set( - actions = all_link_actions + lto_index_actions, - flag_groups = [flag_group(flags = ["--coverage"])], - ), - ], - requires = [feature_set(features = ["coverage"])], - provides = ["profile"], + libtool_feature = feature( + name = "libtool", + enabled = not is_linux, ) archiver_flags_feature = feature( @@ -870,12 +1332,37 @@ def _impl(ctx): flag_set( actions = [ACTION_NAMES.cpp_link_static_library], flag_groups = [ - flag_group(flags = ["rcsD"]), flag_group( - flags = ["%{output_execpath}"], + flags = [ + "rcsD" if is_linux else "rcs", + "%{output_execpath}", + ], expand_if_available = "output_execpath", ), ], + with_features = [ + with_feature_set( + not_features = ["libtool"], + ), + ], + ), + flag_set( + actions = [ACTION_NAMES.cpp_link_static_library], + flag_groups = [ + flag_group( + flags = [ + "-static", + "-o", + "%{output_execpath}", + ], + expand_if_available = "output_execpath", + ), + ], + with_features = [ + with_feature_set( + features = ["libtool"], + ), + ], ), flag_set( actions = [ACTION_NAMES.cpp_link_static_library], @@ -903,6 +1390,24 @@ def _impl(ctx): ), ], ), + flag_set( + actions = [ACTION_NAMES.cpp_link_static_library], + flag_groups = ([ + flag_group( + flags = ctx.attr.archive_flags, + ), + ] if ctx.attr.archive_flags else []), + ), + flag_set( + actions = [ACTION_NAMES.cpp_link_static_library], + flag_groups = [ + flag_group( + flags = ["%{user_archiver_flags}"], + iterate_over = "user_archiver_flags", + expand_if_available = "user_archiver_flags", + ), + ], + ), ], ) @@ -938,6 +1443,8 @@ def _impl(ctx): ACTION_NAMES.objc_compile, ACTION_NAMES.objcpp_compile, ACTION_NAMES.cpp_header_parsing, + ACTION_NAMES.cpp_module_deps_scanning, + ACTION_NAMES.cpp20_module_compile, ACTION_NAMES.clif_match, ], flag_groups = [ @@ -950,6 +1457,32 @@ def _impl(ctx): ], ) + serialized_diagnostics_file_feature = feature( + name = "serialized_diagnostics_file", + flag_sets = [ + flag_set( + actions = [ + ACTION_NAMES.assemble, + ACTION_NAMES.preprocess_assemble, + ACTION_NAMES.c_compile, + ACTION_NAMES.cpp_compile, + ACTION_NAMES.cpp_module_compile, + ACTION_NAMES.objc_compile, + ACTION_NAMES.objcpp_compile, + ACTION_NAMES.cpp_header_parsing, + ACTION_NAMES.cpp_module_deps_scanning, + ACTION_NAMES.clif_match, + ], + flag_groups = [ + flag_group( + flags = ["--serialize-diagnostics", "%{serialized_diagnostics_file}"], + expand_if_available = "serialized_diagnostics_file", + ), + ], + ), + ], + ) + dynamic_library_linker_tool_feature = feature( name = "dynamic_library_linker_tool", flag_sets = [ @@ -975,6 +1508,25 @@ def _impl(ctx): ], ) + generate_linkmap_feature = feature( + name = "generate_linkmap", + flag_sets = [ + flag_set( + actions = [ + ACTION_NAMES.cpp_link_executable, + ], + flag_groups = [ + flag_group( + flags = [ + "-Wl,-Map=%{output_execpath}.map" if is_linux else "-Wl,-map,%{output_execpath}.map", + ], + expand_if_available = "output_execpath", + ), + ], + ), + ], + ) + output_execpath_flags_feature = feature( name = "output_execpath_flags", flag_sets = [ @@ -1081,18 +1633,156 @@ def _impl(ctx): ], ) - is_linux = ctx.attr.target_libc != "macosx" + treat_warnings_as_errors_feature = feature( + name = "treat_warnings_as_errors", + flag_sets = [ + flag_set( + actions = [ACTION_NAMES.c_compile, ACTION_NAMES.cpp_compile], + flag_groups = [flag_group(flags = ["-Werror"])], + ), + flag_set( + actions = all_link_actions, + flag_groups = [flag_group( + flags = ["-Wl,-fatal-warnings"] if is_linux else ["-Wl,-fatal_warnings"], + )], + ), + ], + ) + + archive_param_file_feature = feature( + name = "archive_param_file", + enabled = True, + ) + + asan_feature = _sanitizer_feature( + name = "asan", + specific_compile_flags = [ + "-fsanitize=address", + "-fno-common", + ], + specific_link_flags = [ + "-fsanitize=address", + ], + ) + + tsan_feature = _sanitizer_feature( + name = "tsan", + specific_compile_flags = [ + "-fsanitize=thread", + ], + specific_link_flags = [ + "-fsanitize=thread", + ], + ) + + ubsan_feature = _sanitizer_feature( + name = "ubsan", + specific_compile_flags = [ + "-fsanitize=undefined", + ], + specific_link_flags = [ + "-fsanitize=undefined", + ], + ) + + # If you have Xcode + the CLT installed the version defaults can be + # too old for some standard C apis such as thread locals + macos_minimum_os_feature = feature( + name = "macos_minimum_os", + enabled = True, + flag_sets = [ + flag_set( + actions = all_compile_actions + all_link_actions, + flag_groups = [flag_group(flags = ["-mmacosx-version-min={}".format(_target_os_version(ctx))])], + ), + ], + ) + + # Kept for backwards compatibility with the crosstool that moved. Without + # linking the objc runtime binaries don't link CoreFoundation for free, + # which breaks abseil. + macos_default_link_flags_feature = feature( + name = "macos_default_link_flags", + enabled = True, + flag_sets = [ + flag_set( + actions = all_link_actions, + flag_groups = [flag_group(flags = [ + "-no-canonical-prefixes", + "-fobjc-link-runtime", + ])], + ), + ], + ) + + # Tell bazel we support C++ modules now + cpp_modules_feature = feature( + name = "cpp_modules", + # set default value to False + # to enable the feature + # use --features=cpp_modules + # or add cpp_modules to features attr + enabled = False, + ) + + cpp_module_modmap_file_feature = feature( + name = "cpp_module_modmap_file", + flag_sets = [ + flag_set( + actions = [ + ACTION_NAMES.cpp_compile, + ACTION_NAMES.cpp20_module_compile, + ACTION_NAMES.cpp20_module_codegen, + ], + flag_groups = [ + flag_group( + flags = ["@%{cpp_module_modmap_file}" if ctx.attr.compiler == "clang" else "-fmodule-mapper=%{cpp_module_modmap_file}"], + expand_if_available = "cpp_module_modmap_file", + ), + ], + ), + ], + enabled = True, + ) + if ctx.attr.compiler == "clang": + flag_groups = [ + flag_group( + flags = ["-fmodule-output=%{cpp_module_output_file}"], + expand_if_available = "cpp_module_output_file", + ), + ] + else: + flag_groups = [] + cpp20_module_compile_flags_feature = feature( + name = "cpp20_module_compile_flags", + flag_sets = [ + flag_set( + actions = [ + ACTION_NAMES.cpp20_module_compile, + ], + flag_groups = flag_groups, + ), + ], + enabled = True, + ) # TODO(#8303): Mac crosstool should also declare every feature. if is_linux: + # Linux artifact name patterns are the default. + artifact_name_patterns = [] features = [ + cpp_modules_feature, + cpp_module_modmap_file_feature, + cpp20_module_compile_flags_feature, dependency_file_feature, + serialized_diagnostics_file_feature, random_seed_feature, pic_feature, per_object_debug_info_feature, preprocessor_defines_feature, includes_feature, include_paths_feature, + external_include_paths_feature, fdo_instrument_feature, cs_fdo_instrument_feature, cs_fdo_optimize_feature, @@ -1101,20 +1791,24 @@ def _impl(ctx): autofdo_feature, build_interface_libraries_feature, dynamic_library_linker_tool_feature, - symbol_counts_feature, + generate_linkmap_feature, shared_flag_feature, linkstamps_feature, output_execpath_flags_feature, runtime_library_search_directories_feature, library_search_directories_feature, + libtool_feature, archiver_flags_feature, force_pic_flags_feature, fission_support_feature, strip_debug_symbols_feature, coverage_feature, supports_pic_feature, - gcc_coverage_map_format_feature, - llvm_coverage_map_format_feature, + asan_feature, + tsan_feature, + ubsan_feature, + gcc_quoting_for_param_files_feature, + static_link_cpp_runtimes_feature, ] + ( [ supports_start_end_lib_feature, @@ -1124,6 +1818,7 @@ def _impl(ctx): default_link_flags_feature, libraries_to_link_feature, user_link_flags_feature, + default_link_libs_feature, static_libgcc_feature, fdo_optimize_feature, supports_dynamic_linker_feature, @@ -1131,11 +1826,39 @@ def _impl(ctx): opt_feature, user_compile_flags_feature, sysroot_feature, + compiler_input_flags_feature, + compiler_output_flags_feature, unfiltered_compile_flags_feature, - ] + treat_warnings_as_errors_feature, + archive_param_file_feature, + set_install_name_feature, + ] + layering_check_features(ctx.attr.compiler, ctx.attr.extra_flags_per_feature, is_macos = False) else: + # macOS artifact name patterns differ from the defaults only for dynamic + # libraries. + artifact_name_patterns = [ + artifact_name_pattern( + category_name = "dynamic_library", + prefix = "lib", + extension = ".dylib", + ), + ] features = [ - supports_pic_feature, + cpp_modules_feature, + cpp_module_modmap_file_feature, + cpp20_module_compile_flags_feature, + macos_minimum_os_feature, + macos_default_link_flags_feature, + dependency_file_feature, + runtime_library_search_directories_feature, + set_install_name_feature, + libtool_feature, + archiver_flags_feature, + asan_feature, + tsan_feature, + ubsan_feature, + gcc_quoting_for_param_files_feature, + static_link_cpp_runtimes_feature, ] + ( [ supports_start_end_lib_feature, @@ -1144,21 +1867,36 @@ def _impl(ctx): coverage_feature, default_compile_flags_feature, default_link_flags_feature, + user_link_flags_feature, + default_link_libs_feature, + external_include_paths_feature, fdo_optimize_feature, - supports_dynamic_linker_feature, dbg_feature, opt_feature, user_compile_flags_feature, sysroot_feature, + compiler_input_flags_feature, + compiler_output_flags_feature, unfiltered_compile_flags_feature, - gcc_coverage_map_format_feature, - llvm_coverage_map_format_feature, - ] + treat_warnings_as_errors_feature, + archive_param_file_feature, + generate_linkmap_feature, + ] + layering_check_features(ctx.attr.compiler, ctx.attr.extra_flags_per_feature, is_macos = True) + + parse_headers_action_configs, parse_headers_features = parse_headers_support( + parse_headers_tool_path = ctx.attr.tool_paths.get("parse_headers"), + ) + action_configs += parse_headers_action_configs + features += parse_headers_features + + if symbol_check: + features.append(symbol_check) 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 = ctx.attr.cxx_builtin_include_directories, toolchain_identifier = ctx.attr.toolchain_identifier, host_system_name = ctx.attr.host_system_name, @@ -1169,6 +1907,7 @@ def _impl(ctx): abi_version = ctx.attr.abi_version, abi_libc_version = ctx.attr.abi_libc_version, tool_paths = tool_paths, + builtin_sysroot = ctx.attr.builtin_sysroot, ) cc_toolchain_config = rule( @@ -1176,14 +1915,18 @@ cc_toolchain_config = rule( attrs = { "abi_libc_version": attr.string(mandatory = True), "abi_version": attr.string(mandatory = True), + "archive_flags": attr.string_list(), + "builtin_sysroot": attr.string(), "compile_flags": attr.string_list(), "compiler": attr.string(mandatory = True), + "conly_flags": attr.string_list(), "coverage_compile_flags": attr.string_list(), "coverage_link_flags": attr.string_list(), "cpu": attr.string(mandatory = True), "cxx_builtin_include_directories": attr.string_list(), "cxx_flags": attr.string_list(), "dbg_compile_flags": attr.string_list(), + "extra_flags_per_feature": attr.string_list_dict(), "host_system_name": attr.string(mandatory = True), "link_flags": attr.string_list(), "link_libs": attr.string_list(), @@ -1195,6 +1938,11 @@ cc_toolchain_config = rule( "tool_paths": attr.string_dict(), "toolchain_identifier": attr.string(mandatory = True), "unfiltered_compile_flags": attr.string_list(), + "_xcode_config": attr.label(default = configuration_field( + fragment = "apple", + name = "xcode_config_label", + )), }, + fragments = ["apple", "cpp"], provides = [CcToolchainConfigInfo], ) diff --git a/cc/private/toolchain/validate_static_library.sh.tpl b/cc/private/toolchain/validate_static_library.sh.tpl new file mode 100755 index 0000000..d769408 --- /dev/null +++ b/cc/private/toolchain/validate_static_library.sh.tpl @@ -0,0 +1,44 @@ +#!/usr/bin/env bash +# +# Copyright 2023 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. +set -euo pipefail + +# Find all duplicate symbols in the given static library: +# 1. Use nm to list all global symbols in the library in POSIX format: +# libstatic.a[my_object.o]: my_function T 1234 abcd +# 2. Use sed to transform the output to a format that can be sorted by symbol +# name and is readable by humans: +# my_object.o: T my_function +# By using the `t` and `d` commands, lines for symbols of type U (undefined) +# as well as V and W (weak) and their local lowercase variants are removed. +# 3. Use sort to sort the lines by symbol name. +# 4. Use uniq to only keep the lines corresponding to duplicate symbols. +# 5. Use c++filt to demangle the symbol names. +# c++filt is applied to the duplicated symbols instead of using the -C flag +# of nm because it is not in POSIX and demangled names may not be unique +# (https://gcc.gnu.org/bugzilla/show_bug.cgi?id=35201). +DUPLICATE_SYMBOLS=$( + "%{nm}" -A -g -P %{nm_extra_args} "$1" | + sed -E -e 's/.*\[([^][]+)\]: (.+) ([A-TX-Z]) [a-f0-9]+ [a-f0-9]+/\1: \3 \2/g' -e t -e d | + LC_ALL=C sort -k 3 | + LC_ALL=C uniq -D -f 2 | + "%{c++filt}") +if [[ -n "$DUPLICATE_SYMBOLS" ]]; then + >&2 echo "Duplicate symbols found in $1:" + >&2 echo "$DUPLICATE_SYMBOLS" + exit 1 +else + touch "$2" +fi diff --git a/cc/private/toolchain/vc_installation_error.bat.tpl b/cc/private/toolchain/vc_installation_error.bat.tpl index 9cdd658..2285422 100644 --- a/cc/private/toolchain/vc_installation_error.bat.tpl +++ b/cc/private/toolchain/vc_installation_error.bat.tpl @@ -18,7 +18,7 @@ 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/main/windows.html#using 1>&2 +echo Please check your installation following https://bazel.build/docs/windows#using 1>&2 echo. 1>&2 exit /b 1 diff --git a/cc/private/toolchain/windows_cc_configure.bzl b/cc/private/toolchain/windows_cc_configure.bzl index 598d4b2..bd87d41 100644 --- a/cc/private/toolchain/windows_cc_configure.bzl +++ b/cc/private/toolchain/windows_cc_configure.bzl @@ -25,12 +25,35 @@ load( "write_builtin_include_directory_paths", ) +_targets_archs = {"arm": "amd64_arm", "arm64": "amd64_arm64", "x64": "amd64", "x86": "amd64_x86"} +_targets_lib_folder = {"arm": "arm", "arm64": "arm64", "x86": ""} + +def _lookup_env_var(env, name, default = None): + """Lookup environment variable case-insensitve. + + If a matching (case-insensitive) entry is found in the env dict both + the key and the value are returned. The returned key might differ from + name in casing. + + If a matching key was found its value is returned otherwise + the default is returned. + + Return a (key, value) tuple""" + for key, value in env.items(): + if name.lower() == key.lower(): + return (key, value) + return (name, default) + +def _get_env_var(repository_ctx, name, default = None): + """Returns a value from an environment variable.""" + return _lookup_env_var(repository_ctx.os.environ, name, default)[1] + def _get_path_env_var(repository_ctx, name): """Returns a path from an environment variable. Removes quotes, replaces '/' with '\', and strips trailing '\'s.""" - if name in repository_ctx.os.environ: - value = repository_ctx.os.environ[name] + value = _get_env_var(repository_ctx, name) + if value != None: if value[0] == "\"": if len(value) == 1 or value[-1] != "\"": auto_configure_fail("'%s' environment variable has no trailing quote" % name) @@ -39,9 +62,7 @@ def _get_path_env_var(repository_ctx, name): value = value.replace("/", "\\") if value[-1] == "\\": value = value.rstrip("\\") - return value - else: - return None + return value def _get_temp_env(repository_ctx): """Returns the value of TMP, or TEMP, or if both undefined then C:\\Windows.""" @@ -72,7 +93,7 @@ def _get_escaped_windows_msys_starlark_content(repository_ctx, use_mingw = False tool_bin_path = tool_path_prefix + "/bin" tool_path = {} - for tool in ["ar", "compat-ld", "cpp", "dwp", "gcc", "gcov", "ld", "nm", "objcopy", "objdump", "strip"]: + for tool in ["ar", "cpp", "dwp", "gcc", "gcov", "ld", "nm", "objcopy", "objdump", "strip"]: if msys_root: tool_path[tool] = tool_bin_path + "/" + tool else: @@ -94,13 +115,19 @@ def _get_system_root(repository_ctx): 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" + env_key, env_value = _lookup_env_var(env, "PATH", default = "") + env[env_key] = env_value + ";" + _get_system_root(repository_ctx) + "\\system32" return env -def _find_vc_path(repository_ctx): - """Find Visual C++ build tools install path. Doesn't %-escape the result.""" +def find_vc_path(repository_ctx): + """Find Visual C++ build tools install path. Doesn't %-escape the result. + + Args: + repository_ctx: The repository context. + + Returns: + The path to the Visual C++ build tools installation. + """ # 1. Check if BAZEL_VC or BAZEL_VS is already set by user. bazel_vc = _get_path_env_var(repository_ctx, "BAZEL_VC") @@ -136,7 +163,27 @@ def _find_vc_path(repository_ctx): " installed.", ) - # 2. Check if VS%VS_VERSION%COMNTOOLS is set, if true then try to find and use + # 2. Use vswhere to locate all Visual Studio installations + program_files_dir = _get_path_env_var(repository_ctx, "PROGRAMFILES(X86)") + if not program_files_dir: + program_files_dir = "C:\\Program Files (x86)" + auto_configure_warning_maybe( + repository_ctx, + "'PROGRAMFILES(X86)' environment variable is not set, using '%s' as default" % program_files_dir, + ) + + vswhere_binary = program_files_dir + "\\Microsoft Visual Studio\\Installer\\vswhere.exe" + if repository_ctx.path(vswhere_binary).exists: + result = repository_ctx.execute([vswhere_binary, "-requires", "Microsoft.VisualStudio.Component.VC.Tools.x86.x64", "-property", "installationPath", "-latest"]) + auto_configure_warning_maybe(repository_ctx, "vswhere query result:\n\nSTDOUT(start)\n%s\nSTDOUT(end)\nSTDERR(start):\n%s\nSTDERR(end)\n" % + (result.stdout, result.stderr)) + installation_path = result.stdout.strip() + if not result.stderr and installation_path: + vc_dir = installation_path + "\\VC" + auto_configure_warning_maybe(repository_ctx, "Visual C++ build tools found at %s" % vc_dir) + return vc_dir + + # 3. Check if VS%VS_VERSION%COMNTOOLS is set, if true then try to find and use # vcvarsqueryregistry.bat / VsDevCmd.bat to detect VC++. auto_configure_warning_maybe(repository_ctx, "Looking for VS%VERSION%COMNTOOLS environment variables, " + "eg. VS140COMNTOOLS") @@ -149,15 +196,16 @@ def _find_vc_path(repository_ctx): ("VS100COMNTOOLS", "vcvarsqueryregistry.bat"), ("VS90COMNTOOLS", "vcvarsqueryregistry.bat"), ]: - if vscommontools_env not in repository_ctx.os.environ: + path = _get_path_env_var(repository_ctx, vscommontools_env) + if path == None: continue - script = _get_path_env_var(repository_ctx, vscommontools_env) + "\\" + script + script = path + "\\" + script if not repository_ctx.path(script).exists: continue repository_ctx.file( "get_vc_dir.bat", "@echo off\n" + - "call \"" + script + "\"\n" + + "call \"" + script + "\" > NUL\n" + "echo %VCINSTALLDIR%", True, ) @@ -167,9 +215,8 @@ def _find_vc_path(repository_ctx): 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. + # 4. User might have purged all environment variables. If so, look for Visual C++ in registry. # Works for Visual Studio 2017 and older. (Does not work for Visual Studio 2019 Preview.) - # 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 @@ -189,25 +236,13 @@ def _find_vc_path(repository_ctx): 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 + # 5. 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\\%s\\%s\\VC" % (year, edition) + for year in (2022, 2019, 2017) + for edition in ("Preview", "BuildTools", "Community", "Professional", "Enterprise") + ] + [ "Microsoft Visual Studio 14.0\\VC", ]: path = program_files_dir + "\\" + path @@ -221,18 +256,22 @@ def _find_vc_path(repository_ctx): 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.""" +def _is_vs_2017_or_newer(repository_ctx, vc_path): + """Check if the installed VS version is Visual Studio 2017 or newer.""" - # 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 + # For VS 2017 and later, a `Tools` directory should exist under `BAZEL_VC` + return repository_ctx.path(vc_path).get_child("Tools").exists + +def _is_msbuildtools(vc_path): + """Check if the installed VC version is from MSBuildTools.""" + + # In MSBuildTools (usually container setup), the location of VC is like: + # C:\BuildTools\MSBuild\Microsoft\VC + return vc_path.find("BuildTools") != -1 and vc_path.find("MSBuild") != -1 def _find_vcvars_bat_script(repository_ctx, vc_path): """Find batch script to set up environment variables for VC. Doesn't %-escape the result.""" - if _is_vs_2017_or_2019(vc_path): + if _is_vs_2017_or_newer(repository_ctx, vc_path): vcvars_script = vc_path + "\\Auxiliary\\Build\\VCVARSALL.BAT" else: vcvars_script = vc_path + "\\VCVARSALL.BAT" @@ -250,17 +289,49 @@ def _is_support_vcvars_ver(vc_full_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): + if _is_vs_2017_or_newer(repository_ctx, vc_path): return True # By checking the source code of VCVARSALL.BAT in VC 2015, we know that # when devenv.exe or wdexpress.exe exists, VCVARSALL.BAT supports Windows SDK selection. - vc_common_ide = repository_ctx.path(vc_path).dirname.get_child("Common7").get_child("IDE") + vc_common_ide = repository_ctx.path(vc_path).dirname.get_child("Common7", "IDE") for tool in ["devenv.exe", "wdexpress.exe"]: if vc_common_ide.get_child(tool).exists: return True return False +def _get_vc_env_vars(repository_ctx, vc_path, msvc_vars_x64, target_arch): + """Derive the environment variables set of a given target architecture from the environment variables of the x64 target. + + This is done to avoid running VCVARSALL.BAT script for every target architecture. + + Args: + repository_ctx: the repository_ctx object + vc_path: Visual C++ root directory + msvc_vars_x64: values of MSVC toolchain including the environment variables for x64 target architecture + target_arch: the target architecture to get its environment variables + + Returns: + dictionary of envvars + """ + env = {} + if _is_vs_2017_or_newer(repository_ctx, vc_path): + lib = msvc_vars_x64["%{msvc_env_lib_x64}"] + full_version = _get_vc_full_version(repository_ctx, vc_path) + tools_path = "%s\\Tools\\MSVC\\%s\\bin\\HostX64\\%s" % (vc_path, full_version, target_arch) + + # For native windows(10) on arm64 builds host toolchain runs in an emulated x86 environment + if not repository_ctx.path(tools_path).exists: + tools_path = "%s\\Tools\\MSVC\\%s\\bin\\HostX86\\%s" % (vc_path, full_version, target_arch) + else: + lib = msvc_vars_x64["%{msvc_env_lib_x64}"].replace("amd64", _targets_lib_folder[target_arch]) + tools_path = vc_path + "\\bin\\" + _targets_archs[target_arch] + + env["INCLUDE"] = msvc_vars_x64["%{msvc_env_include_x64}"] + env["LIB"] = lib.replace("x64", target_arch) + env["PATH"] = escape_string(tools_path.replace("\\", "\\\\")) + ";" + msvc_vars_x64["%{msvc_env_path_x64}"] + return env + def setup_vc_env_vars(repository_ctx, vc_path, envvars = [], allow_empty = False, escape = True): """Get environment variables set by VCVARSALL.BAT script. Doesn't %-escape the result! @@ -292,7 +363,7 @@ def setup_vc_env_vars(repository_ctx, vc_path, envvars = [], allow_empty = False # Get VC version set by user. Only supports VC 2017 & 2019. vcvars_ver = "" - if _is_vs_2017_or_2019(vc_path): + if _is_vs_2017_or_newer(repository_ctx, vc_path): full_version = _get_vc_full_version(repository_ctx, vc_path) # Because VCVARSALL.BAT is from the latest VC installed, so we check if the latest @@ -314,6 +385,7 @@ def setup_vc_env_vars(repository_ctx, vc_path, envvars = [], allow_empty = False 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 @@ -347,48 +419,84 @@ def _get_latest_subversion(repository_ctx, vc_path): 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)) + auto_configure_warning_maybe(repository_ctx, "Found the following VC versions:\n%s\n\nChoosing the latest version = %s" % ("\n".join(versions), latest_version)) return latest_version def _get_vc_full_version(repository_ctx, vc_path): """Return the value of BAZEL_VC_FULL_VERSION if defined, otherwise the latest version.""" - if "BAZEL_VC_FULL_VERSION" in repository_ctx.os.environ: - return repository_ctx.os.environ["BAZEL_VC_FULL_VERSION"] + version = _get_env_var(repository_ctx, "BAZEL_VC_FULL_VERSION") + if version != None: + return version return _get_latest_subversion(repository_ctx, vc_path) def _get_winsdk_full_version(repository_ctx): """Return the value of BAZEL_WINSDK_FULL_VERSION if defined, otherwise an empty string.""" - return repository_ctx.os.environ.get("BAZEL_WINSDK_FULL_VERSION", default = "") + return _get_env_var(repository_ctx, "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.""" +def _find_msvc_tools(repository_ctx, vc_path, target_arch = "x64"): + """Find the exact paths of the build tools in MSVC for the given target. Doesn't %-escape the result.""" + build_tools_paths = {} + tools = _get_target_tools(target_arch) + for tool_name in tools: + build_tools_paths[tool_name] = find_msvc_tool(repository_ctx, vc_path, tools[tool_name], target_arch) + return build_tools_paths + +def find_msvc_tool(repository_ctx, vc_path, tool, target_arch = "x64"): + """Find the exact path of a specific build tool in MSVC. Doesn't %-escape the result. + + Args: + repository_ctx: The repository context. + vc_path: Visual C++ root directory. + tool: The name of the tool to find. + target_arch: The target architecture (default is "x64"). + + Returns: + The exact path of the specified build tool in MSVC, or None if not found. + """ tool_path = None - if _is_vs_2017_or_2019(vc_path): + if _is_vs_2017_or_newer(repository_ctx, vc_path) or _is_msbuildtools(vc_path): full_version = _get_vc_full_version(repository_ctx, vc_path) if full_version: - tool_path = "%s\\Tools\\MSVC\\%s\\bin\\HostX64\\x64\\%s" % (vc_path, full_version, tool) + tool_path = "%s\\Tools\\MSVC\\%s\\bin\\HostX64\\%s\\%s" % (vc_path, full_version, target_arch, tool) + + # For native windows(10) on arm64 builds host toolchain runs in an emulated x86 environment + if not repository_ctx.path(tool_path).exists: + tool_path = "%s\\Tools\\MSVC\\%s\\bin\\HostX86\\%s\\%s" % (vc_path, full_version, target_arch, tool) else: # For VS 2015 and older version, the tools are under: # C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\bin\amd64 - tool_path = vc_path + "\\bin\\amd64\\" + tool + tool_path = vc_path + "\\bin\\" + _targets_archs[target_arch] + "\\" + tool if not tool_path or not repository_ctx.path(tool_path).exists: return None return tool_path.replace("\\", "/") -def _find_missing_vc_tools(repository_ctx, vc_path): - """Check if any required tool is missing under given VC path.""" +def _find_missing_vc_tools(repository_ctx, vc_path, target_arch = "x64"): + """Check if any required tool for the given target architecture is missing under given VC path.""" missing_tools = [] if not _find_vcvars_bat_script(repository_ctx, vc_path): missing_tools.append("VCVARSALL.BAT") - 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) - + tools = _get_target_tools(target_arch) + for tool_name in tools: + if not find_msvc_tool(repository_ctx, vc_path, tools[tool_name], target_arch): + missing_tools.append(tools[tool_name]) return missing_tools +def _get_target_tools(target): + """Return a list of required tools names and their filenames for a certain target.""" + tools = { + "arm": {"CL": "cl.exe", "DUMPBIN": "dumpbin.exe", "LIB": "lib.exe", "LINK": "link.exe"}, + "arm64": {"CL": "cl.exe", "DUMPBIN": "dumpbin.exe", "LIB": "lib.exe", "LINK": "link.exe"}, + "x64": {"CL": "cl.exe", "DUMPBIN": "dumpbin.exe", "LIB": "lib.exe", "LINK": "link.exe", "ML": "ml64.exe"}, + "x86": {"CL": "cl.exe", "DUMPBIN": "dumpbin.exe", "LIB": "lib.exe", "LINK": "link.exe", "ML": "ml.exe"}, + } + if tools.get(target) == None: + auto_configure_fail("Target architecture %s is not recognized" % target) + + return tools.get(target) + def _is_support_debug_fastlink(repository_ctx, linker): """Run linker alone to see if it supports /DEBUG:FASTLINK.""" if _use_clang_cl(repository_ctx): @@ -397,8 +505,37 @@ def _is_support_debug_fastlink(repository_ctx, linker): 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.""" +def _is_support_parse_showincludes(repository_ctx, cl, env): + repository_ctx.file( + "main.cpp", + "#include \"bazel_showincludes.h\"\nint main(){}\n", + ) + repository_ctx.file( + "bazel_showincludes.h", + "\n", + ) + result = execute( + repository_ctx, + [cl, "/nologo", "/showIncludes", "/c", "main.cpp", "/out", "main.exe", "/Fo", "main.obj"], + # Attempt to force English language. This may fail if the language pack isn't installed. + environment = env | {"VSLANG": "1033"}, + ) + for file in ["main.cpp", "bazel_showincludes.h", "main.exe", "main.obj"]: + execute(repository_ctx, ["cmd", "/C", "del", file], expect_empty_output = True) + return any([ + line.startswith("Note: including file:") and line.endswith("bazel_showincludes.h") + for line in result.split("\n") + ]) + +def find_llvm_path(repository_ctx): + """Find LLVM install path. + + Args: + repository_ctx: The repository context. + + Returns: + The path to the LLVM installation, or None if not found. + """ # 1. Check if BAZEL_LLVM is already set by user. bazel_llvm = _get_path_env_var(repository_ctx, "BAZEL_LLVM") @@ -443,8 +580,17 @@ def _find_llvm_path(repository_ctx): 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.""" +def find_llvm_tool(repository_ctx, llvm_path, tool): + """Find the exact path of a specific build tool in LLVM. Doesn't %-escape the result. + + Args: + repository_ctx: The repository context. + llvm_path: The path to the LLVM installation. + tool: The name of the tool to find. + + Returns: + The exact path of the specified build tool in LLVM, or None if not found. + """ tool_path = llvm_path + "\\bin\\" + tool if not repository_ctx.path(tool_path).exists: @@ -454,24 +600,37 @@ def _find_llvm_tool(repository_ctx, llvm_path, tool): 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" + return _get_env_var(repository_ctx, "USE_CLANG_CL", default = "0") == "1" def _find_missing_llvm_tools(repository_ctx, llvm_path): """Check if any required tool is missing under given LLVM path.""" missing_tools = [] for tool in ["clang-cl.exe", "lld-link.exe", "llvm-lib.exe"]: - if not _find_llvm_tool(repository_ctx, llvm_path, tool): + 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) + first_line = result.stderr.strip().splitlines()[0].strip() - # Stderr should look like "clang version X.X.X ..." - return result.stderr.splitlines()[0].split(" ")[2] + # The first line of stderr should look like "[vendor ]clang version X.X.X" + if result.return_code != 0 or first_line.find("clang version ") == -1: + auto_configure_fail("Failed to get clang version by running \"%s -v\"" % clang_cl) + return first_line.split(" ")[-1] + +def _get_clang_dir(repository_ctx, llvm_path, clang_version): + """Get the clang installation directory.""" + + # The clang_version string format is "X.X.X" + clang_dir = llvm_path + "\\lib\\clang\\" + clang_version + if repository_ctx.path(clang_dir).exists: + return clang_dir + + # Clang 16 changed the install path to use just the major number. + clang_major_version = clang_version.split(".")[0] + return llvm_path + "\\lib\\clang\\" + clang_major_version def _get_msys_mingw_vars(repository_ctx): """Get the variables we need to populate the msys/mingw toolchains.""" @@ -488,29 +647,31 @@ def _get_msys_mingw_vars(repository_ctx): } return msys_mingw_vars -def _get_msvc_vars(repository_ctx, paths): +def _get_msvc_vars(repository_ctx, paths, target_arch = "x64", msvc_vars_x64 = None): """Get the variables we need to populate the MSVC toolchains.""" msvc_vars = dict() - vc_path = _find_vc_path(repository_ctx) + vc_path = find_vc_path(repository_ctx) missing_tools = None + if not vc_path: repository_ctx.template( - "vc_installation_error.bat", + "vc_installation_error_" + target_arch + ".bat", paths["@rules_cc//cc/private/toolchain:vc_installation_error.bat.tpl"], {"%{vc_error_message}": ""}, ) else: - missing_tools = _find_missing_vc_tools(repository_ctx, vc_path) + missing_tools = _find_missing_vc_tools(repository_ctx, vc_path, target_arch) if missing_tools: message = "\r\n".join([ "echo. 1>&2", "echo Visual C++ build tools seems to be installed at %s 1>&2" % vc_path, "echo But Bazel can't find the following tools: 1>&2", "echo %s 1>&2" % ", ".join(missing_tools), + "echo for %s target architecture 1>&2" % target_arch, "echo. 1>&2", ]) repository_ctx.template( - "vc_installation_error.bat", + "vc_installation_error_" + target_arch + ".bat", paths["@rules_cc//cc/private/toolchain:vc_installation_error.bat.tpl"], {"%{vc_error_message}": message}, ) @@ -518,82 +679,92 @@ def _get_msvc_vars(repository_ctx, paths): if not vc_path or missing_tools: write_builtin_include_directory_paths(repository_ctx, "msvc", [], file_suffix = "_msvc") msvc_vars = { - "%{dbg_mode_debug_flag}": "/DEBUG", - "%{fastbuild_mode_debug_flag}": "/DEBUG", - "%{msvc_cl_path}": "vc_installation_error.bat", - "%{msvc_cxx_builtin_include_directories}": "", - "%{msvc_env_include}": "msvc_not_found", - "%{msvc_env_lib}": "msvc_not_found", - "%{msvc_env_path}": "msvc_not_found", - "%{msvc_env_tmp}": "msvc_not_found", - "%{msvc_lib_path}": "vc_installation_error.bat", - "%{msvc_link_path}": "vc_installation_error.bat", - "%{msvc_ml_path}": "vc_installation_error.bat", + "%{msvc_env_tmp_" + target_arch + "}": "msvc_not_found", + "%{msvc_env_include_" + target_arch + "}": "msvc_not_found", + "%{msvc_cxx_builtin_include_directories_" + target_arch + "}": "", + "%{msvc_env_path_" + target_arch + "}": "msvc_not_found", + "%{msvc_env_lib_" + target_arch + "}": "msvc_not_found", + "%{msvc_cl_path_" + target_arch + "}": "vc_installation_error_" + target_arch + ".bat", + "%{msvc_ml_path_" + target_arch + "}": "vc_installation_error_" + target_arch + ".bat", + "%{msvc_link_path_" + target_arch + "}": "vc_installation_error_" + target_arch + ".bat", + "%{msvc_lib_path_" + target_arch + "}": "vc_installation_error_" + target_arch + ".bat", + "%{dbg_mode_debug_flag_" + target_arch + "}": "/DEBUG", + "%{fastbuild_mode_debug_flag_" + target_arch + "}": "/DEBUG", + "%{msvc_parse_showincludes_" + target_arch + "}": repr(False), } return msvc_vars - 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"]) + if msvc_vars_x64: + env = _get_vc_env_vars(repository_ctx, vc_path, msvc_vars_x64, target_arch) + else: + env = setup_vc_env_vars(repository_ctx, vc_path) escaped_tmp_dir = escape_string(_get_temp_env(repository_ctx).replace("\\", "\\\\")) + escaped_include_paths = escape_string(env["INCLUDE"]) + build_tools = {} llvm_path = "" if _use_clang_cl(repository_ctx): - llvm_path = _find_llvm_path(repository_ctx) + 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") + + build_tools["CL"] = find_llvm_tool(repository_ctx, llvm_path, "clang-cl.exe") + build_tools["ML"] = find_msvc_tool(repository_ctx, vc_path, "ml64.exe", "x64") + build_tools["LINK"] = find_llvm_tool(repository_ctx, llvm_path, "lld-link.exe") + if not build_tools["LINK"]: + build_tools["LINK"] = find_msvc_tool(repository_ctx, vc_path, "link.exe", "x64") + build_tools["LIB"] = find_llvm_tool(repository_ctx, llvm_path, "llvm-lib.exe") + if not build_tools["LIB"]: + build_tools["LIB"] = find_msvc_tool(repository_ctx, vc_path, "lib.exe", "x64") else: - 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") + build_tools = _find_msvc_tools(repository_ctx, vc_path, target_arch) - 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_version = _get_clang_version(repository_ctx, build_tools["CL"]) + clang_dir = _get_clang_dir(repository_ctx, llvm_path, clang_version) clang_include_path = (clang_dir + "\\include").replace("\\", "\\\\") escaped_cxx_include_directories.append("\"%s\"" % clang_include_path) clang_lib_path = (clang_dir + "\\lib\\windows").replace("\\", "\\\\") - escaped_lib_paths = escaped_lib_paths + ";" + clang_lib_path - - support_debug_fastlink = _is_support_debug_fastlink(repository_ctx, link_path) + env["LIB"] = escape_string(env["LIB"]) + ";" + clang_lib_path + support_debug_fastlink = _is_support_debug_fastlink(repository_ctx, build_tools["LINK"]) write_builtin_include_directory_paths(repository_ctx, "msvc", escaped_cxx_include_directories, file_suffix = "_msvc") + + support_parse_showincludes = _is_support_parse_showincludes(repository_ctx, build_tools["CL"], env) + if not support_parse_showincludes: + auto_configure_warning(""" +Header pruning has been disabled since Bazel failed to recognize the output of /showIncludes. +This can result in unnecessary recompilation. +Fix this by installing the English language pack for the Visual Studio installation at {} and run 'bazel sync --configure'.""".format(vc_path)) + msvc_vars = { - "%{dbg_mode_debug_flag}": "/DEBUG:FULL" if support_debug_fastlink else "/DEBUG", - "%{fastbuild_mode_debug_flag}": "/DEBUG:FASTLINK" if support_debug_fastlink else "/DEBUG", - "%{msvc_cl_path}": cl_path, - "%{msvc_cxx_builtin_include_directories}": " " + ",\n ".join(escaped_cxx_include_directories), - "%{msvc_env_include}": escaped_include_paths, - "%{msvc_env_lib}": escaped_lib_paths, - "%{msvc_env_path}": escaped_paths, - "%{msvc_env_tmp}": escaped_tmp_dir, - "%{msvc_lib_path}": lib_path, - "%{msvc_link_path}": link_path, - "%{msvc_ml_path}": msvc_ml_path, + "%{msvc_env_tmp_" + target_arch + "}": escaped_tmp_dir, + "%{msvc_env_include_" + target_arch + "}": escaped_include_paths, + "%{msvc_cxx_builtin_include_directories_" + target_arch + "}": " " + ",\n ".join(escaped_cxx_include_directories), + "%{msvc_env_path_" + target_arch + "}": escape_string(env["PATH"]), + "%{msvc_env_lib_" + target_arch + "}": escape_string(env["LIB"]), + "%{msvc_cl_path_" + target_arch + "}": build_tools["CL"], + "%{msvc_ml_path_" + target_arch + "}": build_tools.get("ML", "msvc_arm_toolchain_does_not_support_ml"), + "%{msvc_link_path_" + target_arch + "}": build_tools["LINK"], + "%{msvc_lib_path_" + target_arch + "}": build_tools["LIB"], + "%{msvc_dumpbin_path_" + target_arch + "}": build_tools["DUMPBIN"], + "%{msvc_parse_showincludes_" + target_arch + "}": repr(support_parse_showincludes), + "%{dbg_mode_debug_flag_" + target_arch + "}": "/DEBUG:FULL" if support_debug_fastlink else "/DEBUG", + "%{fastbuild_mode_debug_flag_" + target_arch + "}": "/DEBUG:FASTLINK" if support_debug_fastlink else "/DEBUG", } return msvc_vars -def _get_clang_cl_vars(repository_ctx, paths, msvc_vars): +def _get_clang_cl_vars(repository_ctx, paths, msvc_vars, target_arch): """Get the variables we need to populate the clang-cl toolchains.""" - llvm_path = _find_llvm_path(repository_ctx) + 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" + if msvc_vars["%{msvc_cl_path_" + target_arch + "}"] == "vc_installation_error_{}.bat".format(target_arch): + error_script = "vc_installation_error_{}.bat".format(target_arch) elif not llvm_path: repository_ctx.template( "clang_installation_error.bat", @@ -621,52 +792,69 @@ def _get_clang_cl_vars(repository_ctx, paths, msvc_vars): if error_script: write_builtin_include_directory_paths(repository_ctx, "clang-cl", [], file_suffix = "_clangcl") clang_cl_vars = { - "%{clang_cl_cl_path}": error_script, - "%{clang_cl_cxx_builtin_include_directories}": "", - "%{clang_cl_dbg_mode_debug_flag}": "/DEBUG", - "%{clang_cl_env_include}": "clang_cl_not_found", - "%{clang_cl_env_lib}": "clang_cl_not_found", - "%{clang_cl_env_path}": "clang_cl_not_found", - "%{clang_cl_env_tmp}": "clang_cl_not_found", - "%{clang_cl_fastbuild_mode_debug_flag}": "/DEBUG", - "%{clang_cl_lib_path}": error_script, - "%{clang_cl_link_path}": error_script, - "%{clang_cl_ml_path}": error_script, + "%{clang_cl_env_tmp_" + target_arch + "}": "clang_cl_not_found", + "%{clang_cl_env_path_" + target_arch + "}": "clang_cl_not_found", + "%{clang_cl_env_include_" + target_arch + "}": "clang_cl_not_found", + "%{clang_cl_env_lib_" + target_arch + "}": "clang_cl_not_found", + "%{clang_cl_cl_path_" + target_arch + "}": error_script, + "%{clang_cl_link_path_" + target_arch + "}": error_script, + "%{clang_cl_lib_path_" + target_arch + "}": error_script, + "%{clang_cl_ml_path_" + target_arch + "}": error_script, + "%{clang_cl_dbg_mode_debug_flag_" + target_arch + "}": "/DEBUG", + "%{clang_cl_fastbuild_mode_debug_flag_" + target_arch + "}": "/DEBUG", + "%{clang_cl_cxx_builtin_include_directories_" + target_arch + "}": "", + "%{clang_cl_parse_showincludes_" + target_arch + "}": repr(False), } return clang_cl_vars - clang_cl_path = _find_llvm_tool(repository_ctx, llvm_path, "clang-cl.exe") - lld_link_path = _find_llvm_tool(repository_ctx, llvm_path, "lld-link.exe") - llvm_lib_path = _find_llvm_tool(repository_ctx, llvm_path, "llvm-lib.exe") + clang_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_dir = _get_clang_dir(repository_ctx, llvm_path, clang_version) clang_include_path = (clang_dir + "\\include").replace("\\", "\\\\") clang_lib_path = (clang_dir + "\\lib\\windows").replace("\\", "\\\\") - clang_cl_include_directories = msvc_vars["%{msvc_cxx_builtin_include_directories}"] + (",\n \"%s\"" % clang_include_path) + clang_cl_include_directories = msvc_vars["%{msvc_cxx_builtin_include_directories_" + target_arch + "}"] + (",\n \"%s\"" % clang_include_path) write_builtin_include_directory_paths(repository_ctx, "clang-cl", [clang_cl_include_directories], file_suffix = "_clangcl") clang_cl_vars = { - "%{clang_cl_cl_path}": clang_cl_path, - "%{clang_cl_cxx_builtin_include_directories}": clang_cl_include_directories, + "%{clang_cl_env_tmp_" + target_arch + "}": msvc_vars["%{msvc_env_tmp_" + target_arch + "}"], + "%{clang_cl_env_path_" + target_arch + "}": msvc_vars["%{msvc_env_path_" + target_arch + "}"], + "%{clang_cl_env_include_" + target_arch + "}": msvc_vars["%{msvc_env_include_" + target_arch + "}"] + ";" + clang_include_path, + "%{clang_cl_env_lib_" + target_arch + "}": msvc_vars["%{msvc_env_lib_" + target_arch + "}"] + ";" + clang_lib_path, + "%{clang_cl_cxx_builtin_include_directories_" + target_arch + "}": clang_cl_include_directories, + "%{clang_cl_cl_path_" + target_arch + "}": clang_cl_path, + "%{clang_cl_link_path_" + target_arch + "}": lld_link_path, + "%{clang_cl_lib_path_" + target_arch + "}": llvm_lib_path, + # clang-cl does not support assembly files as input. + "%{clang_cl_ml_path_" + target_arch + "}": msvc_vars["%{msvc_ml_path_" + target_arch + "}"], # LLVM's lld-link.exe doesn't support /DEBUG:FASTLINK. - "%{clang_cl_dbg_mode_debug_flag}": "/DEBUG", - "%{clang_cl_env_include}": msvc_vars["%{msvc_env_include}"] + ";" + clang_include_path, - "%{clang_cl_env_lib}": msvc_vars["%{msvc_env_lib}"] + ";" + clang_lib_path, - "%{clang_cl_env_path}": msvc_vars["%{msvc_env_path}"], - "%{clang_cl_env_tmp}": msvc_vars["%{msvc_env_tmp}"], - "%{clang_cl_fastbuild_mode_debug_flag}": "/DEBUG", - "%{clang_cl_lib_path}": llvm_lib_path, - "%{clang_cl_link_path}": lld_link_path, - "%{clang_cl_ml_path}": msvc_vars["%{msvc_ml_path}"], + "%{clang_cl_dbg_mode_debug_flag_" + target_arch + "}": "/DEBUG", + "%{clang_cl_fastbuild_mode_debug_flag_" + target_arch + "}": "/DEBUG", + # clang-cl always emits the English language version of the /showIncludes prefix. + "%{clang_cl_parse_showincludes_" + target_arch + "}": repr(True), } return clang_cl_vars +def _get_msvc_deps_scanner_vars(repository_ctx, paths, template_vars, target_arch = "x64"): + repository_ctx.template( + "msvc_deps_scanner_wrapper_" + target_arch + ".bat", + paths["@rules_cc//cc/private/toolchain:msvc_deps_scanner_wrapper.bat.tpl"], + { + "%{cc}": template_vars["%{msvc_cl_path_" + target_arch + "}"], + }, + ) + + return { + "%{msvc_deps_scanner_wrapper_path_" + target_arch + "}": "msvc_deps_scanner_wrapper_" + target_arch + ".bat", + } + def configure_windows_toolchain(repository_ctx): """Configure C++ toolchain on Windows. Args: - repository_ctx: The repository context. + repository_ctx: The repository context. """ paths = resolve_labels(repository_ctx, [ "@rules_cc//cc/private/toolchain:BUILD.windows.tpl", @@ -675,6 +863,7 @@ def configure_windows_toolchain(repository_ctx): "@rules_cc//cc/private/toolchain:vc_installation_error.bat.tpl", "@rules_cc//cc/private/toolchain:msys_gcc_installation_error.bat", "@rules_cc//cc/private/toolchain:clang_installation_error.bat.tpl", + "@rules_cc//cc/private/toolchain:msvc_deps_scanner_wrapper.bat.tpl", ]) repository_ctx.symlink( @@ -691,11 +880,20 @@ def configure_windows_toolchain(repository_ctx): ) 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)) + msvc_vars_x64 = _get_msvc_vars(repository_ctx, paths, "x64") + template_vars.update(msvc_vars_x64) + template_vars.update(_get_clang_cl_vars(repository_ctx, paths, msvc_vars_x64, "x64")) template_vars.update(_get_msys_mingw_vars(repository_ctx)) + template_vars.update(_get_msvc_vars(repository_ctx, paths, "x86", msvc_vars_x64)) + template_vars.update(_get_msvc_vars(repository_ctx, paths, "arm", msvc_vars_x64)) + msvc_vars_arm64 = _get_msvc_vars(repository_ctx, paths, "arm64", msvc_vars_x64) + template_vars.update(msvc_vars_arm64) + template_vars.update(_get_clang_cl_vars(repository_ctx, paths, msvc_vars_arm64, "arm64")) + template_vars.update(_get_msvc_deps_scanner_vars(repository_ctx, paths, template_vars, "x64")) + template_vars.update(_get_msvc_deps_scanner_vars(repository_ctx, paths, template_vars, "x86")) + template_vars.update(_get_msvc_deps_scanner_vars(repository_ctx, paths, template_vars, "arm")) + template_vars.update(_get_msvc_deps_scanner_vars(repository_ctx, paths, template_vars, "arm64")) repository_ctx.template( "BUILD", paths["@rules_cc//cc/private/toolchain:BUILD.windows.tpl"], diff --git a/cc/private/toolchain/windows_cc_toolchain_config.bzl b/cc/private/toolchain/windows_cc_toolchain_config.bzl index 7fa2978..76cd586 100644 --- a/cc/private/toolchain/windows_cc_toolchain_config.bzl +++ b/cc/private/toolchain/windows_cc_toolchain_config.bzl @@ -22,9 +22,9 @@ load( "env_entry", "env_set", "feature", - "feature_set", "flag_group", "flag_set", + "make_variable", "tool", "tool_path", "variable_with_value", @@ -40,6 +40,9 @@ all_compile_actions = [ ACTION_NAMES.cpp_header_parsing, ACTION_NAMES.cpp_module_compile, ACTION_NAMES.cpp_module_codegen, + ACTION_NAMES.cpp_module_deps_scanning, + ACTION_NAMES.cpp20_module_compile, + ACTION_NAMES.cpp20_module_codegen, ACTION_NAMES.clif_match, ACTION_NAMES.lto_backend, ] @@ -50,6 +53,9 @@ all_cpp_compile_actions = [ ACTION_NAMES.cpp_header_parsing, ACTION_NAMES.cpp_module_compile, ACTION_NAMES.cpp_module_codegen, + ACTION_NAMES.cpp_module_deps_scanning, + ACTION_NAMES.cpp20_module_compile, + ACTION_NAMES.cpp20_module_codegen, ACTION_NAMES.clif_match, ] @@ -60,6 +66,8 @@ preprocessor_compile_actions = [ ACTION_NAMES.preprocess_assemble, ACTION_NAMES.cpp_header_parsing, ACTION_NAMES.cpp_module_compile, + ACTION_NAMES.cpp_module_deps_scanning, + ACTION_NAMES.cpp20_module_compile, ACTION_NAMES.clif_match, ] @@ -70,6 +78,7 @@ codegen_compile_actions = [ ACTION_NAMES.assemble, ACTION_NAMES.preprocess_assemble, ACTION_NAMES.cpp_module_codegen, + ACTION_NAMES.cpp20_module_codegen, ACTION_NAMES.lto_backend, ] @@ -80,7 +89,7 @@ all_link_actions = [ ] def _use_msvc_toolchain(ctx): - return ctx.attr.cpu == "x64_windows" and (ctx.attr.compiler == "msvc-cl" or ctx.attr.compiler == "clang-cl") + return ctx.attr.cpu in ["x64_windows", "arm64_windows"] and (ctx.attr.compiler == "msvc-cl" or ctx.attr.compiler == "clang-cl") def _impl(ctx): if _use_msvc_toolchain(ctx): @@ -135,7 +144,6 @@ def _impl(ctx): "output_execpath_flags", "input_param_flags", "user_link_flags", - "default_link_flags", "linker_subsystem_flag", "linker_param_file", "msvc_env", @@ -184,13 +192,25 @@ def _impl(ctx): c_compile_action = action_config( action_name = ACTION_NAMES.c_compile, + implies = [ + "compiler_input_flags", + "compiler_output_flags", + "nologo", + "msvc_env", + "user_compile_flags", + "sysroot", + ], + tools = [tool(path = ctx.attr.msvc_cl_path)], + ) + + linkstamp_compile_action = action_config( + action_name = ACTION_NAMES.linkstamp_compile, implies = [ "compiler_input_flags", "compiler_output_flags", "default_compile_flags", "nologo", "msvc_env", - "parse_showincludes", "user_compile_flags", "sysroot", "unfiltered_compile_flags", @@ -203,13 +223,10 @@ def _impl(ctx): implies = [ "compiler_input_flags", "compiler_output_flags", - "default_compile_flags", "nologo", "msvc_env", - "parse_showincludes", "user_compile_flags", "sysroot", - "unfiltered_compile_flags", ], tools = [tool(path = ctx.attr.msvc_cl_path)], ) @@ -222,7 +239,6 @@ def _impl(ctx): "output_execpath_flags", "input_param_flags", "user_link_flags", - "default_link_flags", "linker_subsystem_flag", "linker_param_file", "msvc_env", @@ -240,7 +256,6 @@ def _impl(ctx): "output_execpath_flags", "input_param_flags", "user_link_flags", - "default_link_flags", "linker_subsystem_flag", "linker_param_file", "msvc_env", @@ -251,15 +266,84 @@ def _impl(ctx): tools = [tool(path = ctx.attr.msvc_link_path)], ) + deps_scanner = "cpp-module-deps-scanner_not_found" + if "cpp-module-deps-scanner" in ctx.attr.tool_paths: + deps_scanner = ctx.attr.tool_paths["cpp-module-deps-scanner"] + cpp_module_scan_deps = action_config( + action_name = ACTION_NAMES.cpp_module_deps_scanning, + tools = [ + tool( + path = deps_scanner, + ), + ], + implies = [ + "compiler_input_flags", + "compiler_output_flags", + "nologo", + "msvc_env", + "user_compile_flags", + "sysroot", + ], + ) + + cpp20_module_compile = action_config( + action_name = ACTION_NAMES.cpp20_module_compile, + tools = [ + tool( + path = ctx.attr.msvc_cl_path, + ), + ], + flag_sets = [ + flag_set( + flag_groups = [ + flag_group( + flags = [ + "/TP", + "/interface", + ], + ), + ], + ), + ], + implies = [ + "compiler_input_flags", + "compiler_output_flags", + "nologo", + "msvc_env", + "user_compile_flags", + "sysroot", + ], + ) + + cpp20_module_codegen = action_config( + action_name = ACTION_NAMES.cpp20_module_codegen, + tools = [ + tool( + path = ctx.attr.msvc_cl_path, + ), + ], + implies = [ + "compiler_input_flags", + "compiler_output_flags", + "nologo", + "msvc_env", + "user_compile_flags", + "sysroot", + ], + ) action_configs = [ assemble_action, preprocess_assemble_action, c_compile_action, + linkstamp_compile_action, cpp_compile_action, cpp_link_executable_action, cpp_link_dynamic_library_action, cpp_link_nodeps_dynamic_library_action, cpp_link_static_library_action, + cpp_module_scan_deps, + cpp20_module_compile, + cpp20_module_codegen, ] else: action_configs = [] @@ -317,10 +401,14 @@ def _impl(ctx): ACTION_NAMES.assemble, ACTION_NAMES.preprocess_assemble, ACTION_NAMES.c_compile, + ACTION_NAMES.linkstamp_compile, ACTION_NAMES.cpp_compile, ACTION_NAMES.cpp_header_parsing, ACTION_NAMES.cpp_module_compile, ACTION_NAMES.cpp_module_codegen, + ACTION_NAMES.cpp_module_deps_scanning, + ACTION_NAMES.cpp20_module_compile, + ACTION_NAMES.cpp20_module_codegen, ACTION_NAMES.cpp_link_executable, ACTION_NAMES.cpp_link_dynamic_library, ACTION_NAMES.cpp_link_nodeps_dynamic_library, @@ -338,15 +426,20 @@ def _impl(ctx): unfiltered_compile_flags_feature = feature( name = "unfiltered_compile_flags", + enabled = True, flag_sets = [ flag_set( actions = [ ACTION_NAMES.preprocess_assemble, ACTION_NAMES.c_compile, + ACTION_NAMES.linkstamp_compile, ACTION_NAMES.cpp_compile, ACTION_NAMES.cpp_header_parsing, ACTION_NAMES.cpp_module_compile, ACTION_NAMES.cpp_module_codegen, + ACTION_NAMES.cpp_module_deps_scanning, + ACTION_NAMES.cpp20_module_compile, + ACTION_NAMES.cpp20_module_codegen, ], flag_groups = [ flag_group( @@ -359,8 +452,14 @@ def _impl(ctx): ], ) + archive_param_file_feature = feature( + name = "archive_param_file", + enabled = True, + ) + compiler_param_file_feature = feature( name = "compiler_param_file", + enabled = True, ) copy_dynamic_libraries_to_binary_feature = feature( @@ -471,10 +570,14 @@ def _impl(ctx): actions = [ ACTION_NAMES.preprocess_assemble, ACTION_NAMES.c_compile, + ACTION_NAMES.linkstamp_compile, ACTION_NAMES.cpp_compile, ACTION_NAMES.cpp_header_parsing, ACTION_NAMES.cpp_module_compile, ACTION_NAMES.cpp_module_codegen, + ACTION_NAMES.cpp_module_deps_scanning, + ACTION_NAMES.cpp20_module_compile, + ACTION_NAMES.cpp20_module_codegen, ], flag_groups = [ flag_group( @@ -498,7 +601,12 @@ def _impl(ctx): expand_if_available = "output_execpath", ), flag_group( - flags = ["/MACHINE:X64"], + flags = ["%{user_archiver_flags}"], + iterate_over = "user_archiver_flags", + expand_if_available = "user_archiver_flags", + ), + flag_group( + flags = ctx.attr.archiver_flags, ), ], ), @@ -516,21 +624,57 @@ def _impl(ctx): ], ) - static_link_msvcrt_feature = feature(name = "static_link_msvcrt") - - dynamic_link_msvcrt_debug_feature = feature( - name = "dynamic_link_msvcrt_debug", + static_link_msvcrt_feature = feature( + name = "static_link_msvcrt", flag_sets = [ + flag_set( + actions = [ACTION_NAMES.c_compile, ACTION_NAMES.cpp_compile], + flag_groups = [flag_group(flags = ["/MT"])], + with_features = [with_feature_set(not_features = ["dbg"])], + ), + flag_set( + actions = [ACTION_NAMES.c_compile, ACTION_NAMES.cpp_compile], + flag_groups = [flag_group(flags = ["/MTd"])], + with_features = [with_feature_set(features = ["dbg"])], + ), + flag_set( + actions = all_link_actions, + flag_groups = [flag_group(flags = ["/DEFAULTLIB:libcmt.lib"])], + with_features = [with_feature_set(not_features = ["dbg"])], + ), + flag_set( + actions = all_link_actions, + flag_groups = [flag_group(flags = ["/DEFAULTLIB:libcmtd.lib"])], + with_features = [with_feature_set(features = ["dbg"])], + ), + ], + ) + + dynamic_link_msvcrt_feature = feature( + name = "dynamic_link_msvcrt", + enabled = True, + flag_sets = [ + flag_set( + actions = [ACTION_NAMES.c_compile, ACTION_NAMES.cpp_compile], + flag_groups = [flag_group(flags = ["/MD"])], + with_features = [with_feature_set(not_features = ["dbg", "static_link_msvcrt"])], + ), flag_set( actions = [ACTION_NAMES.c_compile, ACTION_NAMES.cpp_compile], flag_groups = [flag_group(flags = ["/MDd"])], + with_features = [with_feature_set(features = ["dbg"], not_features = ["static_link_msvcrt"])], + ), + flag_set( + actions = all_link_actions, + flag_groups = [flag_group(flags = ["/DEFAULTLIB:msvcrt.lib"])], + with_features = [with_feature_set(not_features = ["dbg", "static_link_msvcrt"])], ), flag_set( actions = all_link_actions, flag_groups = [flag_group(flags = ["/DEFAULTLIB:msvcrtd.lib"])], + with_features = [with_feature_set(features = ["dbg"], not_features = ["static_link_msvcrt"])], ), ], - requires = [feature_set(features = ["dbg"])], ) dbg_feature = feature( @@ -598,6 +742,9 @@ def _impl(ctx): ACTION_NAMES.cpp_header_parsing, ACTION_NAMES.cpp_module_compile, ACTION_NAMES.cpp_module_codegen, + ACTION_NAMES.cpp_module_deps_scanning, + ACTION_NAMES.cpp20_module_compile, + ACTION_NAMES.cpp20_module_codegen, ACTION_NAMES.lto_backend, ACTION_NAMES.clif_match, ], @@ -629,10 +776,14 @@ def _impl(ctx): env_set( actions = [ ACTION_NAMES.c_compile, + ACTION_NAMES.linkstamp_compile, ACTION_NAMES.cpp_compile, ACTION_NAMES.cpp_module_compile, ACTION_NAMES.cpp_module_codegen, ACTION_NAMES.cpp_header_parsing, + ACTION_NAMES.cpp_module_deps_scanning, + ACTION_NAMES.cpp20_module_compile, + ACTION_NAMES.cpp20_module_codegen, ACTION_NAMES.assemble, ACTION_NAMES.preprocess_assemble, ], @@ -650,9 +801,12 @@ def _impl(ctx): ACTION_NAMES.assemble, ACTION_NAMES.preprocess_assemble, ACTION_NAMES.c_compile, + ACTION_NAMES.linkstamp_compile, ACTION_NAMES.cpp_compile, ACTION_NAMES.cpp_header_parsing, ACTION_NAMES.cpp_module_compile, + ACTION_NAMES.cpp_module_deps_scanning, + ACTION_NAMES.cpp20_module_compile, ], flag_groups = [ flag_group( @@ -668,6 +822,25 @@ def _impl(ctx): name = "generate_pdb_file", ) + generate_linkmap_feature = feature( + name = "generate_linkmap", + flag_sets = [ + flag_set( + actions = [ + ACTION_NAMES.cpp_link_executable, + ], + flag_groups = [ + flag_group( + flags = [ + "/MAP:%{output_execpath}.map", + ], + expand_if_available = "output_execpath", + ), + ], + ), + ], + ) + output_execpath_flags_feature = feature( name = "output_execpath_flags", flag_sets = [ @@ -683,24 +856,6 @@ def _impl(ctx): ], ) - dynamic_link_msvcrt_no_debug_feature = feature( - name = "dynamic_link_msvcrt_no_debug", - flag_sets = [ - flag_set( - actions = [ACTION_NAMES.c_compile, ACTION_NAMES.cpp_compile], - flag_groups = [flag_group(flags = ["/MD"])], - ), - flag_set( - actions = all_link_actions, - flag_groups = [flag_group(flags = ["/DEFAULTLIB:msvcrt.lib"])], - ), - ], - requires = [ - feature_set(features = ["fastbuild"]), - feature_set(features = ["opt"]), - ], - ) - disable_assertions_feature = feature( name = "disable_assertions", enabled = True, @@ -750,43 +905,50 @@ def _impl(ctx): parse_showincludes_feature = feature( name = "parse_showincludes", + enabled = ctx.attr.supports_parse_showincludes, flag_sets = [ flag_set( actions = [ ACTION_NAMES.preprocess_assemble, ACTION_NAMES.c_compile, + ACTION_NAMES.linkstamp_compile, ACTION_NAMES.cpp_compile, ACTION_NAMES.cpp_module_compile, ACTION_NAMES.cpp_header_parsing, + ACTION_NAMES.cpp_module_deps_scanning, + ACTION_NAMES.cpp20_module_compile, ], flag_groups = [flag_group(flags = ["/showIncludes"])], ), ], + env_sets = [ + env_set( + actions = [ + ACTION_NAMES.preprocess_assemble, + ACTION_NAMES.c_compile, + ACTION_NAMES.linkstamp_compile, + ACTION_NAMES.cpp_compile, + ACTION_NAMES.cpp_module_compile, + ACTION_NAMES.cpp_header_parsing, + ], + # Force English (and thus a consistent locale) output so that Bazel can parse + # the /showIncludes output without having to guess the encoding. + env_entries = [env_entry(key = "VSLANG", value = "1033")], + ), + ], ) - static_link_msvcrt_no_debug_feature = feature( - name = "static_link_msvcrt_no_debug", - flag_sets = [ - flag_set( - actions = [ACTION_NAMES.c_compile, ACTION_NAMES.cpp_compile], - flag_groups = [flag_group(flags = ["/MT"])], - ), - flag_set( - actions = all_link_actions, - flag_groups = [flag_group(flags = ["/DEFAULTLIB:libcmt.lib"])], - ), - ], - requires = [ - feature_set(features = ["fastbuild"]), - feature_set(features = ["opt"]), - ], + # MSVC does not emit .d files. + no_dotd_file_feature = feature( + name = "no_dotd_file", + enabled = True, ) treat_warnings_as_errors_feature = feature( name = "treat_warnings_as_errors", flag_sets = [ flag_set( - actions = [ACTION_NAMES.c_compile, ACTION_NAMES.cpp_compile], + actions = [ACTION_NAMES.c_compile, ACTION_NAMES.cpp_compile] + all_link_actions, flag_groups = [flag_group(flags = ["/WX"])], ), ], @@ -805,6 +967,7 @@ def _impl(ctx): ACTION_NAMES.assemble, ACTION_NAMES.preprocess_assemble, ACTION_NAMES.c_compile, + ACTION_NAMES.linkstamp_compile, ACTION_NAMES.cpp_compile, ACTION_NAMES.cpp_header_parsing, ACTION_NAMES.cpp_module_compile, @@ -827,6 +990,34 @@ def _impl(ctx): ], ) + external_include_paths_feature = feature( + name = "external_include_paths", + flag_sets = [ + flag_set( + actions = [ + ACTION_NAMES.preprocess_assemble, + ACTION_NAMES.linkstamp_compile, + ACTION_NAMES.c_compile, + ACTION_NAMES.cpp_compile, + ACTION_NAMES.cpp_header_parsing, + ACTION_NAMES.cpp_module_compile, + ACTION_NAMES.cpp_module_deps_scanning, + ACTION_NAMES.cpp20_module_compile, + ACTION_NAMES.clif_match, + ACTION_NAMES.objc_compile, + ACTION_NAMES.objcpp_compile, + ], + flag_groups = [ + flag_group( + flags = ["/external:I%{external_include_paths}"], + iterate_over = "external_include_paths", + expand_if_available = "external_include_paths", + ), + ], + ), + ], + ) + linkstamps_feature = feature( name = "linkstamps", flag_sets = [ @@ -859,21 +1050,6 @@ def _impl(ctx): ], ) - static_link_msvcrt_debug_feature = feature( - name = "static_link_msvcrt_debug", - flag_sets = [ - flag_set( - actions = [ACTION_NAMES.c_compile, ACTION_NAMES.cpp_compile], - flag_groups = [flag_group(flags = ["/MTd"])], - ), - flag_set( - actions = all_link_actions, - flag_groups = [flag_group(flags = ["/DEFAULTLIB:libcmtd.lib"])], - ), - ], - requires = [feature_set(features = ["dbg"])], - ) - frame_pointer_feature = feature( name = "frame_pointer", flag_sets = [ @@ -906,10 +1082,14 @@ def _impl(ctx): actions = [ ACTION_NAMES.preprocess_assemble, ACTION_NAMES.c_compile, + ACTION_NAMES.linkstamp_compile, ACTION_NAMES.cpp_compile, ACTION_NAMES.cpp_header_parsing, ACTION_NAMES.cpp_module_compile, ACTION_NAMES.cpp_module_codegen, + ACTION_NAMES.cpp_module_deps_scanning, + ACTION_NAMES.cpp20_module_compile, + ACTION_NAMES.cpp20_module_codegen, ], flag_groups = [ flag_group( @@ -951,10 +1131,14 @@ def _impl(ctx): flag_set( actions = [ ACTION_NAMES.c_compile, + ACTION_NAMES.linkstamp_compile, ACTION_NAMES.cpp_compile, ACTION_NAMES.cpp_module_compile, ACTION_NAMES.cpp_module_codegen, ACTION_NAMES.cpp_header_parsing, + ACTION_NAMES.cpp_module_deps_scanning, + ACTION_NAMES.cpp20_module_compile, + ACTION_NAMES.cpp20_module_codegen, ACTION_NAMES.assemble, ACTION_NAMES.preprocess_assemble, ACTION_NAMES.cpp_link_executable, @@ -984,6 +1168,17 @@ def _impl(ctx): ], ) + remove_unreferenced_code_feature = feature( + name = "remove_unreferenced_code", + enabled = True, + flag_sets = [ + flag_set( + actions = [ACTION_NAMES.c_compile, ACTION_NAMES.cpp_compile], + flag_groups = [flag_group(flags = ["/Zc:inline"])], + ), + ], + ) + compiler_input_flags_feature = feature( name = "compiler_input_flags", flag_sets = [ @@ -992,10 +1187,14 @@ def _impl(ctx): ACTION_NAMES.assemble, ACTION_NAMES.preprocess_assemble, ACTION_NAMES.c_compile, + ACTION_NAMES.linkstamp_compile, ACTION_NAMES.cpp_compile, ACTION_NAMES.cpp_header_parsing, ACTION_NAMES.cpp_module_compile, ACTION_NAMES.cpp_module_codegen, + ACTION_NAMES.cpp_module_deps_scanning, + ACTION_NAMES.cpp20_module_compile, + ACTION_NAMES.cpp20_module_codegen, ], flag_groups = [ flag_group( @@ -1028,10 +1227,14 @@ def _impl(ctx): env_set( actions = [ ACTION_NAMES.c_compile, + ACTION_NAMES.linkstamp_compile, ACTION_NAMES.cpp_compile, ACTION_NAMES.cpp_module_compile, ACTION_NAMES.cpp_module_codegen, ACTION_NAMES.cpp_header_parsing, + ACTION_NAMES.cpp_module_deps_scanning, + ACTION_NAMES.cpp20_module_compile, + ACTION_NAMES.cpp20_module_codegen, ACTION_NAMES.assemble, ACTION_NAMES.preprocess_assemble, ACTION_NAMES.cpp_link_executable, @@ -1048,6 +1251,17 @@ def _impl(ctx): ], implies = ["msvc_compile_env", "msvc_link_env"], ) + + symbol_check_feature = feature( + name = "symbol_check", + flag_sets = [ + flag_set( + actions = [ACTION_NAMES.cpp_link_static_library], + flag_groups = [flag_group(flags = ["/WX:4006"])], + ), + ], + ) + features = [ no_legacy_features_feature, nologo_feature, @@ -1060,9 +1274,12 @@ def _impl(ctx): msvc_compile_env_feature, msvc_link_env_feature, include_paths_feature, + external_include_paths_feature, preprocessor_defines_feature, parse_showincludes_feature, + no_dotd_file_feature, generate_pdb_file_feature, + generate_linkmap_feature, shared_flag_feature, linkstamps_feature, output_execpath_flags_feature, @@ -1073,10 +1290,7 @@ def _impl(ctx): default_link_flags_feature, linker_param_file_feature, static_link_msvcrt_feature, - static_link_msvcrt_no_debug_feature, - dynamic_link_msvcrt_no_debug_feature, - static_link_msvcrt_debug_feature, - dynamic_link_msvcrt_debug_feature, + dynamic_link_msvcrt_feature, dbg_feature, fastbuild_feature, opt_feature, @@ -1085,10 +1299,12 @@ def _impl(ctx): determinism_feature, treat_warnings_as_errors_feature, smaller_binary_feature, + remove_unreferenced_code_feature, ignore_noisy_warnings_feature, user_compile_flags_feature, sysroot_feature, unfiltered_compile_flags_feature, + archive_param_file_feature, compiler_param_file_feature, compiler_output_flags_feature, compiler_input_flags_feature, @@ -1097,6 +1313,7 @@ def _impl(ctx): no_windows_export_all_symbols_feature, supports_dynamic_linker_feature, supports_interface_shared_libraries_feature, + symbol_check_feature, ] else: targets_windows_feature = feature( @@ -1114,10 +1331,14 @@ def _impl(ctx): env_set( actions = [ ACTION_NAMES.c_compile, + ACTION_NAMES.linkstamp_compile, ACTION_NAMES.cpp_compile, ACTION_NAMES.cpp_module_compile, ACTION_NAMES.cpp_module_codegen, ACTION_NAMES.cpp_header_parsing, + ACTION_NAMES.cpp_module_deps_scanning, + ACTION_NAMES.cpp20_module_compile, + ACTION_NAMES.cpp20_module_codegen, ACTION_NAMES.assemble, ACTION_NAMES.preprocess_assemble, ACTION_NAMES.cpp_link_executable, @@ -1143,10 +1364,13 @@ def _impl(ctx): ACTION_NAMES.cpp_header_parsing, ACTION_NAMES.cpp_module_compile, ACTION_NAMES.cpp_module_codegen, + ACTION_NAMES.cpp_module_deps_scanning, + ACTION_NAMES.cpp20_module_compile, + ACTION_NAMES.cpp20_module_codegen, ACTION_NAMES.lto_backend, ACTION_NAMES.clif_match, ], - flag_groups = [flag_group(flags = ["-std=gnu++0x"])], + flag_groups = [flag_group(flags = ["-std=gnu++14"] + ctx.attr.default_compile_flags)], ), ], ) @@ -1157,7 +1381,7 @@ def _impl(ctx): flag_sets = [ flag_set( actions = all_link_actions, - flag_groups = [flag_group(flags = ["-lstdc++"])], + flag_groups = [flag_group(flags = ["-lstdc++"] + ctx.attr.default_link_flags)], ), ], ) @@ -1167,7 +1391,42 @@ def _impl(ctx): enabled = True, ) + dbg_feature = feature( + name = "dbg", + flag_sets = [ + flag_set( + actions = [ACTION_NAMES.c_compile, ACTION_NAMES.cpp_compile], + flag_groups = [flag_group(flags = ["-g", "-Og"])], + ), + ], + ) + + opt_feature = feature( + name = "opt", + flag_sets = [ + flag_set( + actions = [ACTION_NAMES.c_compile, ACTION_NAMES.cpp_compile], + flag_groups = [flag_group(flags = [ + "-g0", + "-O3", + "-DNDEBUG", + "-ffunction-sections", + "-fdata-sections", + ])], + ), + flag_set( + actions = all_link_actions, + flag_groups = [flag_group(flags = ["-Wl,--gc-sections"])], + ), + ], + ) + if ctx.attr.cpu == "x64_windows" and ctx.attr.compiler == "mingw-gcc": + archive_param_file_feature = feature( + name = "archive_param_file", + enabled = True, + ) + compiler_param_file_feature = feature( name = "compiler_param_file", ) @@ -1177,23 +1436,18 @@ def _impl(ctx): copy_dynamic_libraries_to_binary_feature, gcc_env_feature, default_compile_flags_feature, + archive_param_file_feature, compiler_param_file_feature, default_link_flags_feature, supports_dynamic_linker_feature, + dbg_feature, + opt_feature, ] else: supports_pic_feature = feature( name = "supports_pic", enabled = True, ) - supports_start_end_lib_feature = feature( - name = "supports_start_end_lib", - enabled = True, - ) - - dbg_feature = feature(name = "dbg") - - opt_feature = feature(name = "opt") sysroot_feature = feature( name = "sysroot", @@ -1208,6 +1462,9 @@ def _impl(ctx): ACTION_NAMES.cpp_header_parsing, ACTION_NAMES.cpp_module_compile, ACTION_NAMES.cpp_module_codegen, + ACTION_NAMES.cpp_module_deps_scanning, + ACTION_NAMES.cpp20_module_compile, + ACTION_NAMES.cpp20_module_codegen, ACTION_NAMES.lto_backend, ACTION_NAMES.clif_match, ACTION_NAMES.cpp_link_executable, @@ -1243,6 +1500,20 @@ def _impl(ctx): provides = ["profile"], ) + treat_warnings_as_errors_feature = feature( + name = "treat_warnings_as_errors", + flag_sets = [ + flag_set( + actions = [ACTION_NAMES.c_compile, ACTION_NAMES.cpp_compile], + flag_groups = [flag_group(flags = ["-Werror"])], + ), + flag_set( + actions = all_link_actions, + flag_groups = [flag_group(flags = ["-Wl,-fatal-warnings"])], + ), + ], + ) + user_compile_flags_feature = feature( name = "user_compile_flags", enabled = True, @@ -1257,6 +1528,9 @@ def _impl(ctx): ACTION_NAMES.cpp_header_parsing, ACTION_NAMES.cpp_module_compile, ACTION_NAMES.cpp_module_codegen, + ACTION_NAMES.cpp_module_deps_scanning, + ACTION_NAMES.cpp20_module_compile, + ACTION_NAMES.cpp20_module_codegen, ACTION_NAMES.lto_backend, ACTION_NAMES.clif_match, ], @@ -1276,7 +1550,6 @@ def _impl(ctx): copy_dynamic_libraries_to_binary_feature, gcc_env_feature, supports_pic_feature, - supports_start_end_lib_feature, default_compile_flags_feature, default_link_flags_feature, fdo_optimize_feature, @@ -1284,6 +1557,7 @@ def _impl(ctx): dbg_feature, opt_feature, user_compile_flags_feature, + treat_warnings_as_errors_feature, sysroot_feature, ] @@ -1292,9 +1566,61 @@ def _impl(ctx): for name, path in ctx.attr.tool_paths.items() ] + make_variables = [] + + # dumpbin.exe is not available in MSYS toolchain + if "dumpbin" in ctx.attr.tool_paths: + make_variables.append(make_variable(name = "DUMPBIN", value = ctx.attr.tool_paths["dumpbin"])) + + # Tell bazel we support C++ modules now + cpp_modules_feature = feature( + name = "cpp_modules", + # set default value to False + # to enable the feature + # use --features=cpp_modules + # or add cpp_modules to features attr + enabled = False, + ) + + cpp_module_modmap_file_feature = feature( + name = "cpp_module_modmap_file", + flag_sets = [ + flag_set( + actions = [ + ACTION_NAMES.cpp_compile, + ACTION_NAMES.cpp20_module_compile, + ACTION_NAMES.cpp20_module_codegen, + ], + flag_groups = [ + flag_group( + flags = ["@%{cpp_module_modmap_file}"], + expand_if_available = "cpp_module_modmap_file", + ), + ], + ), + ], + enabled = True, + ) + cpp20_module_compile_flags_feature = feature( + name = "cpp20_module_compile_flags", + flag_sets = [ + flag_set( + actions = [ + ACTION_NAMES.cpp20_module_compile, + ], + flag_groups = [ + flag_group( + flags = ["/ifcOutput%{cpp_module_output_file}"], + expand_if_available = "cpp_module_output_file", + ), + ], + ), + ], + enabled = True, + ) return cc_common.create_cc_toolchain_config_info( ctx = ctx, - features = features, + features = features + [cpp_modules_feature, cpp_module_modmap_file_feature, cpp20_module_compile_flags_feature], action_configs = action_configs, artifact_name_patterns = artifact_name_patterns, cxx_builtin_include_directories = ctx.attr.cxx_builtin_include_directories, @@ -1307,6 +1633,7 @@ def _impl(ctx): abi_version = ctx.attr.abi_version, abi_libc_version = ctx.attr.abi_libc_version, tool_paths = tool_paths, + make_variables = make_variables, ) cc_toolchain_config = rule( @@ -1314,12 +1641,14 @@ cc_toolchain_config = rule( attrs = { "abi_libc_version": attr.string(), "abi_version": attr.string(), + "archiver_flags": attr.string_list(default = []), "compiler": attr.string(), "cpu": attr.string(mandatory = True), "cxx_builtin_include_directories": attr.string_list(), - "dbg_mode_debug_flag": attr.string(), + "dbg_mode_debug_flag": attr.string(default = ""), + "default_compile_flags": attr.string_list(default = []), "default_link_flags": attr.string_list(default = []), - "fastbuild_mode_debug_flag": attr.string(), + "fastbuild_mode_debug_flag": attr.string(default = ""), "host_system_name": attr.string(), "msvc_cl_path": attr.string(default = "vc_installation_error.bat"), "msvc_env_include": attr.string(default = "msvc_not_found"), @@ -1329,6 +1658,7 @@ cc_toolchain_config = rule( "msvc_lib_path": attr.string(default = "vc_installation_error.bat"), "msvc_link_path": attr.string(default = "vc_installation_error.bat"), "msvc_ml_path": attr.string(default = "vc_installation_error.bat"), + "supports_parse_showincludes": attr.bool(), "target_libc": attr.string(), "target_system_name": attr.string(), "tool_bin_path": attr.string(default = "not_found"), diff --git a/cc/toolchains/actions/BUILD b/cc/toolchains/actions/BUILD index 164a336..7ceb2bd 100644 --- a/cc/toolchains/actions/BUILD +++ b/cc/toolchains/actions/BUILD @@ -53,6 +53,21 @@ cc_action_type( action_name = ACTION_NAMES.cpp_header_parsing, ) +cc_action_type( + name = "cpp_module_deps_scanning", + action_name = ACTION_NAMES.cpp_module_deps_scanning, +) + +cc_action_type( + name = "cpp20_module_compile", + action_name = ACTION_NAMES.cpp20_module_compile, +) + +cc_action_type( + name = "cpp20_module_codegen", + action_name = ACTION_NAMES.cpp20_module_codegen, +) + cc_action_type( name = "cpp_module_compile", action_name = ACTION_NAMES.cpp_module_compile, @@ -68,6 +83,11 @@ cc_action_type( action_name = ACTION_NAMES.preprocess_assemble, ) +cc_action_type( + name = "llvm_cov", + action_name = ACTION_NAMES.llvm_cov, +) + cc_action_type( name = "lto_indexing", action_name = ACTION_NAMES.lto_indexing, @@ -120,7 +140,12 @@ cc_action_type( cc_action_type( name = "objcopy_embed_data", - action_name = "objcopy_embed_data", + action_name = ACTION_NAMES.objcopy_embed_data, +) + +cc_action_type( + name = "validate_static_library", + action_name = ACTION_NAMES.validate_static_library, ) # ld_embed_data is only available within google. @@ -266,9 +291,13 @@ cc_action_type_set( ":cpp_module_codegen", ":cpp_header_analysis", ":cpp_header_parsing", + ":cpp_module_deps_scanning", + ":cpp20_module_compile", + ":cpp20_module_codegen", ":cpp_module_compile", ":assemble", ":preprocess_assemble", + ":llvm_cov", ":lto_indexing", ":lto_backend", ":lto_index_for_executable", @@ -287,5 +316,6 @@ cc_action_type_set( ":objcpp_compile", ":objcpp_executable", ":clif_match", + ":validate_static_library", ], ) diff --git a/cc/toolchains/cc_flags_supplier.bzl b/cc/toolchains/cc_flags_supplier.bzl index 363575f..17adbad 100644 --- a/cc/toolchains/cc_flags_supplier.bzl +++ b/cc/toolchains/cc_flags_supplier.bzl @@ -28,7 +28,7 @@ def _cc_flags_supplier_impl(ctx): cc_flags_supplier = rule( implementation = _cc_flags_supplier_impl, attrs = { - "_cc_toolchain": attr.label(default = Label("@bazel_tools//tools/cpp:current_cc_toolchain")), + "_cc_toolchain": attr.label(default = Label("@rules_cc//cc:current_cc_toolchain")), }, toolchains = use_cc_toolchain(), fragments = ["cpp"], diff --git a/cc/toolchains/compiler_flag.bzl b/cc/toolchains/compiler_flag.bzl index ac943df..502efe7 100644 --- a/cc/toolchains/compiler_flag.bzl +++ b/cc/toolchains/compiler_flag.bzl @@ -23,7 +23,7 @@ def _compiler_flag_impl(ctx): compiler_flag = rule( implementation = _compiler_flag_impl, attrs = { - "_cc_toolchain": attr.label(default = Label("@bazel_tools//tools/cpp:current_cc_toolchain")), + "_cc_toolchain": attr.label(default = Label("@rules_cc//cc:current_cc_toolchain")), }, toolchains = use_cc_toolchain(), ) diff --git a/cc/toolchains/toolchain_config_utils.bzl b/cc/toolchains/toolchain_config_utils.bzl new file mode 100644 index 0000000..82b3ded --- /dev/null +++ b/cc/toolchains/toolchain_config_utils.bzl @@ -0,0 +1,29 @@ +# Copyright 2024 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. +"""Exposing some helper functions for configure cc toolchains.""" + +load("//cc/private/toolchain:cc_configure.bzl", _MSVC_ENVVARS = "MSVC_ENVVARS") +load("//cc/private/toolchain:lib_cc_configure.bzl", _escape_string = "escape_string") +load("//cc/private/toolchain:windows_cc_configure.bzl", _find_vc_path = "find_vc_path", _setup_vc_env_vars = "setup_vc_env_vars") + +MSVC_ENVVARS = _MSVC_ENVVARS + +def find_vc_path(repository_ctx): + return _find_vc_path(repository_ctx) + +def setup_vc_env_vars(repository_ctx): + return _setup_vc_env_vars(repository_ctx) + +def escape_string(string): + return _escape_string(string) diff --git a/examples/custom_toolchain/toolchain_config.bzl b/examples/custom_toolchain/toolchain_config.bzl index e83162b..74b2280 100644 --- a/examples/custom_toolchain/toolchain_config.bzl +++ b/examples/custom_toolchain/toolchain_config.bzl @@ -12,7 +12,7 @@ https://docs.bazel.build/versions/main/tutorial/cc-toolchain-config.html for advanced usage. """ -load("@bazel_tools//tools/cpp:cc_toolchain_config_lib.bzl", "tool_path") +load("@rules_cc//cc:cc_toolchain_config_lib.bzl", "tool_path") # buildifier: disable=deprecated-function def _impl(ctx): tool_paths = [ diff --git a/examples/my_c_archive/my_c_archive.bzl b/examples/my_c_archive/my_c_archive.bzl index 314564f..84b34e5 100644 --- a/examples/my_c_archive/my_c_archive.bzl +++ b/examples/my_c_archive/my_c_archive.bzl @@ -14,8 +14,8 @@ """Example showing how to create a rule that rules_cc can depend on.""" -load("@bazel_tools//tools/cpp:toolchain_utils.bzl", "find_cpp_toolchain", "use_cpp_toolchain") load("@rules_cc//cc:action_names.bzl", "CPP_LINK_STATIC_LIBRARY_ACTION_NAME") +load("@rules_cc//cc:find_cc_toolchain.bzl", "find_cpp_toolchain", "use_cc_toolchain") load("//examples/my_c_compile:my_c_compile.bzl", "MyCCompileInfo") def _my_c_archive_impl(ctx): @@ -92,8 +92,8 @@ my_c_archive = rule( attrs = { "deps": attr.label_list(providers = [CcInfo]), "object": attr.label(mandatory = True, providers = [MyCCompileInfo]), - "_cc_toolchain": attr.label(default = Label("@bazel_tools//tools/cpp:current_cc_toolchain")), + "_cc_toolchain": attr.label(default = Label("@rules_cc//cc:current_cc_toolchain")), }, fragments = ["cpp"], - toolchains = use_cpp_toolchain(), + toolchains = use_cc_toolchain(), ) diff --git a/examples/my_c_compile/my_c_compile.bzl b/examples/my_c_compile/my_c_compile.bzl index d232f91..ac4fea9 100644 --- a/examples/my_c_compile/my_c_compile.bzl +++ b/examples/my_c_compile/my_c_compile.bzl @@ -14,8 +14,8 @@ """Example showing how to create a rule that just compiles C sources.""" -load("@bazel_tools//tools/cpp:toolchain_utils.bzl", "find_cpp_toolchain", "use_cpp_toolchain") load("@rules_cc//cc:action_names.bzl", "C_COMPILE_ACTION_NAME") +load("@rules_cc//cc:find_cc_toolchain.bzl", "find_cpp_toolchain", "use_cc_toolchain") MyCCompileInfo = provider(doc = "", fields = ["object"]) @@ -74,8 +74,8 @@ my_c_compile = rule( implementation = _my_c_compile_impl, attrs = { "src": attr.label(mandatory = True, allow_single_file = True), - "_cc_toolchain": attr.label(default = Label("@bazel_tools//tools/cpp:current_cc_toolchain")), + "_cc_toolchain": attr.label(default = Label("@rules_cc//cc:current_cc_toolchain")), }, - toolchains = use_cpp_toolchain(), + toolchains = use_cc_toolchain(), fragments = ["cpp"], ) diff --git a/examples/write_cc_toolchain_cpu/write_cc_toolchain_cpu.bzl b/examples/write_cc_toolchain_cpu/write_cc_toolchain_cpu.bzl index 3e93b42..a3015c4 100644 --- a/examples/write_cc_toolchain_cpu/write_cc_toolchain_cpu.bzl +++ b/examples/write_cc_toolchain_cpu/write_cc_toolchain_cpu.bzl @@ -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", "use_cpp_toolchain") +load("@rules_cc//cc:find_cc_toolchain.bzl", "find_cpp_toolchain", "use_cc_toolchain") def _write_cc_toolchain_cpu_impl(ctx): cc_toolchain = find_cpp_toolchain(ctx) @@ -26,7 +26,7 @@ def _write_cc_toolchain_cpu_impl(ctx): write_cc_toolchain_cpu = rule( implementation = _write_cc_toolchain_cpu_impl, attrs = { - "_cc_toolchain": attr.label(default = Label("@bazel_tools//tools/cpp:current_cc_toolchain")), + "_cc_toolchain": attr.label(default = Label("@rules_cc//cc:current_cc_toolchain")), }, - toolchains = use_cpp_toolchain(), + toolchains = use_cc_toolchain(), ) diff --git a/tools/migration/crosstool_to_starlark_lib.go b/tools/migration/crosstool_to_starlark_lib.go index 4403a4b..15f5c12 100644 --- a/tools/migration/crosstool_to_starlark_lib.go +++ b/tools/migration/crosstool_to_starlark_lib.go @@ -27,7 +27,7 @@ type CToolchainIdentifier struct { // Writes the load statement for the cc_toolchain_config_lib func getCcToolchainConfigHeader() string { - return `load("@bazel_tools//tools/cpp:cc_toolchain_config_lib.bzl", + return `load("@rules_cc//cc:cc_toolchain_config_lib.bzl", "action_config", "artifact_name_pattern", "env_entry", @@ -118,7 +118,7 @@ var actionNames = map[string]string{ } func getLoadActionsStmt() string { - return "load(\"@bazel_tools//tools/build_defs/cc:action_names.bzl\", \"ACTION_NAMES\")\n\n" + return "load(\"@rules_cc//cc:action_names.bzl\", \"ACTION_NAMES\")\n\n" } // Returns a map {toolchain_identifier : CToolchainIdentifier} diff --git a/tools/migration/crosstool_to_starlark_lib_test.go b/tools/migration/crosstool_to_starlark_lib_test.go index a5db02f..63d9736 100644 --- a/tools/migration/crosstool_to_starlark_lib_test.go +++ b/tools/migration/crosstool_to_starlark_lib_test.go @@ -1533,7 +1533,7 @@ func TestFeatureDeclaration(t *testing.T) { func TestRule(t *testing.T) { simpleToolchain := getSimpleCToolchain("simple") - expected := `load("@bazel_tools//tools/cpp:cc_toolchain_config_lib.bzl", + expected := `load("@rules_cc//cc:cc_toolchain_config_lib.bzl", "action_config", "artifact_name_pattern", "env_entry", @@ -1548,7 +1548,7 @@ func TestRule(t *testing.T) { "variable_with_value", "with_feature_set", ) -load("@bazel_tools//tools/build_defs/cc:action_names.bzl", "ACTION_NAMES") +load("@rules_cc//cc:action_names.bzl", "ACTION_NAMES") def _impl(ctx): toolchain_identifier = "id-simple"