mirror of https://github.com/bazelbuild/rules_cc
Properly support target-specific capabilities
Changes supports_pic and supports_dynamic_linker features to cc_target_capability rules since the capability is tied to target platform capabilities rather than tool capabilities.
This commit is contained in:
parent
5a91c52992
commit
b8045d5626
|
@ -1,3 +1,4 @@
|
|||
load("//cc/toolchains:target_capability.bzl", "cc_target_capability")
|
||||
load("//cc/toolchains:tool_capability.bzl", "cc_tool_capability")
|
||||
|
||||
package(default_visibility = ["//visibility:public"])
|
||||
|
@ -10,10 +11,10 @@ cc_tool_capability(
|
|||
name = "supports_interface_shared_libraries",
|
||||
)
|
||||
|
||||
cc_tool_capability(
|
||||
cc_target_capability(
|
||||
name = "supports_dynamic_linker",
|
||||
)
|
||||
|
||||
cc_tool_capability(
|
||||
cc_target_capability(
|
||||
name = "supports_pic",
|
||||
)
|
||||
|
|
|
@ -119,6 +119,11 @@ FeatureInfo = provider(
|
|||
"allowlist_include_directories": "(depset[DirectoryInfo]) Include directories implied by this feature that should be allowlisted in Bazel's include checker",
|
||||
},
|
||||
)
|
||||
|
||||
FeatureImplyabilityInfo = provider(
|
||||
doc = "Provider used to constrain which kinds of features can be implied",
|
||||
)
|
||||
|
||||
FeatureSetInfo = provider(
|
||||
doc = "A set of features",
|
||||
# @unsorted-dict-items
|
||||
|
@ -161,7 +166,16 @@ ToolInfo = provider(
|
|||
)
|
||||
|
||||
ToolCapabilityInfo = provider(
|
||||
doc = "A capability associated with a tool (eg. supports_pic).",
|
||||
doc = "A capability associated with a tool (eg. supports_start_end_lib).",
|
||||
# @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",
|
||||
},
|
||||
)
|
||||
|
||||
TargetCapabilityInfo = provider(
|
||||
doc = "A capability associated with a target (eg. supports_pic).",
|
||||
# @unsorted-dict-items
|
||||
fields = {
|
||||
"label": "(Label) The label defining this provider. Place in error messages to simplify debugging",
|
||||
|
|
|
@ -23,6 +23,7 @@ load(
|
|||
":cc_toolchain_info.bzl",
|
||||
"ArgsListInfo",
|
||||
"FeatureConstraintInfo",
|
||||
"FeatureImplyabilityInfo",
|
||||
"FeatureInfo",
|
||||
"FeatureSetInfo",
|
||||
"MutuallyExclusiveCategoryInfo",
|
||||
|
@ -87,6 +88,7 @@ def _cc_feature_impl(ctx):
|
|||
|
||||
return [
|
||||
feature,
|
||||
FeatureImplyabilityInfo(),
|
||||
FeatureSetInfo(label = ctx.label, features = depset([feature])),
|
||||
FeatureConstraintInfo(
|
||||
label = ctx.label,
|
||||
|
@ -144,7 +146,7 @@ be enabled.
|
|||
providers = [FeatureSetInfo],
|
||||
),
|
||||
"implies": attr.label_list(
|
||||
providers = [FeatureSetInfo],
|
||||
providers = [FeatureSetInfo, FeatureImplyabilityInfo],
|
||||
doc = """List of features enabled along with this feature.
|
||||
|
||||
Warning: If any of the features cannot be enabled, this feature is
|
||||
|
@ -186,6 +188,7 @@ cc_feature(
|
|||
),
|
||||
},
|
||||
provides = [
|
||||
FeatureImplyabilityInfo,
|
||||
FeatureInfo,
|
||||
FeatureSetInfo,
|
||||
FeatureConstraintInfo,
|
||||
|
|
|
@ -21,6 +21,7 @@ load("//cc/toolchains:feature_constraint.bzl", _cc_feature_constraint = "cc_feat
|
|||
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:target_capability.bzl", _cc_target_capability = "cc_target_capability")
|
||||
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")
|
||||
|
@ -28,6 +29,7 @@ load("//cc/toolchains:toolchain.bzl", _cc_toolchain = "cc_toolchain")
|
|||
load("//cc/toolchains/impl:external_feature.bzl", _cc_external_feature = "cc_external_feature")
|
||||
load("//cc/toolchains/impl:variables.bzl", _cc_variable = "cc_variable")
|
||||
|
||||
cc_target_capability = _cc_target_capability
|
||||
cc_tool_map = _cc_tool_map
|
||||
cc_tool = _cc_tool
|
||||
cc_tool_capability = _cc_tool_capability
|
||||
|
@ -48,6 +50,7 @@ cc_toolchain = _cc_toolchain
|
|||
# links in the generated documentation so that maintainers don't need to manually
|
||||
# ensure every reference to a rule is properly linked.
|
||||
DOCUMENTED_TOOLCHAIN_RULES = [
|
||||
"cc_target_capability",
|
||||
"cc_tool_map",
|
||||
"cc_tool",
|
||||
"cc_tool_capability",
|
||||
|
|
|
@ -0,0 +1,92 @@
|
|||
# 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_target_capability rule."""
|
||||
|
||||
load(
|
||||
":cc_toolchain_info.bzl",
|
||||
"ArgsListInfo",
|
||||
"FeatureConstraintInfo",
|
||||
"FeatureInfo",
|
||||
"FeatureSetInfo",
|
||||
"TargetCapabilityInfo",
|
||||
)
|
||||
|
||||
def _cc_target_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 = (),
|
||||
external = False,
|
||||
overridable = True,
|
||||
overrides = None,
|
||||
allowlist_include_directories = depset(),
|
||||
)
|
||||
|
||||
# Intentionally does not provide FeatureImplyabilityInfo to prevent
|
||||
# features from implying these kinds of rules.
|
||||
return [
|
||||
ft,
|
||||
FeatureSetInfo(label = ctx.label, features = depset([ft])),
|
||||
TargetCapabilityInfo(label = ctx.label, feature = ft),
|
||||
FeatureConstraintInfo(label = ctx.label, all_of = depset([ft])),
|
||||
]
|
||||
|
||||
cc_target_capability = rule(
|
||||
implementation = _cc_target_capability_impl,
|
||||
provides = [TargetCapabilityInfo, FeatureSetInfo, FeatureConstraintInfo],
|
||||
doc = """A target capability is an optional feature that a target platform supports.
|
||||
|
||||
For example, not all target platforms have dynamic loaders (e.g. microcontroller
|
||||
firmware), so a toolchain may conditionally enable the capabilty to communicate
|
||||
the capability to C/C++ rule implementations.
|
||||
|
||||
```
|
||||
load("//cc/toolchains:toolchain.bzl", "cc_toolchain")
|
||||
|
||||
cc_toolchain(
|
||||
name = "universal_cc_toolchain",
|
||||
# Assume no operating system means no dynamic loader support.
|
||||
enabled_features = select({
|
||||
"@platforms//os:none": [],
|
||||
"//conditions:default": [
|
||||
"//cc/toolchains/capabilities:supports_dynamic_linker",
|
||||
],
|
||||
}),
|
||||
# ...
|
||||
)
|
||||
```
|
||||
|
||||
`cc_target_capability` rules cannot be listed in a
|
||||
[`cc_feature.implies`](#cc_feature-implies) list.
|
||||
|
||||
Note: User-defined capabilities should prefer traditional
|
||||
[user-defined build settings](https://bazel.build/extending/config#user-defined-build-settings).
|
||||
This construct exists to communicate these features to preexisting C/C++ rule
|
||||
implementations that expect these options to be exposed as
|
||||
[features](https://bazel.build/docs/cc-toolchain-config-reference#features).
|
||||
""",
|
||||
attrs = {
|
||||
"feature_name": attr.string(doc = "The name of the feature to generate for this capability"),
|
||||
},
|
||||
)
|
|
@ -44,10 +44,11 @@ def _cc_tool_capability_impl(ctx):
|
|||
overrides = None,
|
||||
allowlist_include_directories = depset(),
|
||||
)
|
||||
|
||||
# Intentionally does not provide FeatureImplyabilityInfo to prevent
|
||||
# features from implying these kinds of rules.
|
||||
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])),
|
||||
]
|
||||
|
||||
|
@ -56,28 +57,41 @@ cc_tool_capability = rule(
|
|||
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:
|
||||
For example, not all linkers support --start-lib, so to handle this, we write:
|
||||
|
||||
```
|
||||
load("//cc/toolchains:args.bzl", "cc_args")
|
||||
load("//cc/toolchains:tool.bzl", "cc_tool")
|
||||
|
||||
cc_tool(
|
||||
name = "clang",
|
||||
src = "@host_tools/bin/clang",
|
||||
capabilities = [
|
||||
"//cc/toolchains/capabilities:supports_pic",
|
||||
"//cc/toolchains/capabilities:supports_start_end_lib",
|
||||
],
|
||||
)
|
||||
|
||||
cc_args(
|
||||
name = "pic",
|
||||
requires = [
|
||||
"//cc/toolchains/capabilities:supports_pic"
|
||||
],
|
||||
args = ["-fPIC"],
|
||||
requires = ["//cc/toolchains/capabilities:supports_start_end_lib"],
|
||||
args = ["-Wl,--start-lib"],
|
||||
)
|
||||
```
|
||||
|
||||
This ensures that `-fPIC` is added to the command-line only when we are using a
|
||||
tool that supports PIC.
|
||||
This ensures that `-Wl,--start-lib` is added to the command-line only when using
|
||||
a tool that supports the argument.
|
||||
|
||||
|
||||
`cc_target_capability` rules cannot be listed in a
|
||||
[`cc_feature.implies`](#cc_feature-implies) list, or in
|
||||
[`cc_toolchain.enabled_features`](#cc_toolchain-enabled_features).
|
||||
|
||||
Note: Because [`cc_tool`](#cc_tool) rules are always evaluated under the exec
|
||||
configuration, a `select()` to guide capabilities will `select()` on the
|
||||
properties of the exec configuration. If you need a capability that is
|
||||
conditionally guided by the target configuration, prefer using configurabilty
|
||||
constructs to enable the feature at the
|
||||
[`cc_toolchain.enabled_features`](#cc_toolchain-enabled_features) level.
|
||||
""",
|
||||
attrs = {
|
||||
"feature_name": attr.string(doc = "The name of the feature to generate for this capability"),
|
||||
|
|
|
@ -6,7 +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"],
|
||||
capabilities = ["//cc/toolchains/capabilities:supports_start_end_lib"],
|
||||
data = ["//tests/rule_based_toolchain/testdata:bin"],
|
||||
tags = ["requires-network"],
|
||||
)
|
||||
|
|
|
@ -47,7 +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"],
|
||||
capabilities = ["//cc/toolchains/capabilities:supports_start_end_lib"],
|
||||
)
|
||||
|
||||
cc_sysroot(
|
||||
|
@ -69,7 +69,10 @@ util.helper_target(
|
|||
":sysroot",
|
||||
":c_compile_args",
|
||||
],
|
||||
enabled_features = [":simple_feature"],
|
||||
enabled_features = [
|
||||
":simple_feature",
|
||||
"//cc/toolchains/capabilities:supports_pic",
|
||||
],
|
||||
known_features = [":compile_feature"],
|
||||
tool_map = ":compile_tool_map",
|
||||
)
|
||||
|
|
|
@ -197,6 +197,10 @@ def _toolchain_collects_files_test(env, targets):
|
|||
],
|
||||
)],
|
||||
),
|
||||
legacy_feature(
|
||||
name = "supports_pic",
|
||||
enabled = True,
|
||||
),
|
||||
legacy_feature(
|
||||
name = "compile_feature",
|
||||
enabled = False,
|
||||
|
@ -208,7 +212,7 @@ def _toolchain_collects_files_test(env, targets):
|
|||
)],
|
||||
),
|
||||
legacy_feature(
|
||||
name = "supports_pic",
|
||||
name = "supports_start_end_lib",
|
||||
enabled = False,
|
||||
),
|
||||
legacy_feature(
|
||||
|
@ -225,7 +229,7 @@ def _toolchain_collects_files_test(env, targets):
|
|||
action_name = "c_compile",
|
||||
enabled = True,
|
||||
tools = [legacy_tool(tool = exe)],
|
||||
implies = ["supports_pic"],
|
||||
implies = ["supports_start_end_lib"],
|
||||
flag_sets = [
|
||||
legacy_flag_set(
|
||||
flag_groups = [
|
||||
|
|
Loading…
Reference in New Issue