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")
|
load("//cc/toolchains:tool_capability.bzl", "cc_tool_capability")
|
||||||
|
|
||||||
package(default_visibility = ["//visibility:public"])
|
package(default_visibility = ["//visibility:public"])
|
||||||
|
@ -10,10 +11,10 @@ cc_tool_capability(
|
||||||
name = "supports_interface_shared_libraries",
|
name = "supports_interface_shared_libraries",
|
||||||
)
|
)
|
||||||
|
|
||||||
cc_tool_capability(
|
cc_target_capability(
|
||||||
name = "supports_dynamic_linker",
|
name = "supports_dynamic_linker",
|
||||||
)
|
)
|
||||||
|
|
||||||
cc_tool_capability(
|
cc_target_capability(
|
||||||
name = "supports_pic",
|
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",
|
"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(
|
FeatureSetInfo = provider(
|
||||||
doc = "A set of features",
|
doc = "A set of features",
|
||||||
# @unsorted-dict-items
|
# @unsorted-dict-items
|
||||||
|
@ -161,7 +166,16 @@ ToolInfo = provider(
|
||||||
)
|
)
|
||||||
|
|
||||||
ToolCapabilityInfo = 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
|
# @unsorted-dict-items
|
||||||
fields = {
|
fields = {
|
||||||
"label": "(Label) The label defining this provider. Place in error messages to simplify debugging",
|
"label": "(Label) The label defining this provider. Place in error messages to simplify debugging",
|
||||||
|
|
|
@ -23,6 +23,7 @@ load(
|
||||||
":cc_toolchain_info.bzl",
|
":cc_toolchain_info.bzl",
|
||||||
"ArgsListInfo",
|
"ArgsListInfo",
|
||||||
"FeatureConstraintInfo",
|
"FeatureConstraintInfo",
|
||||||
|
"FeatureImplyabilityInfo",
|
||||||
"FeatureInfo",
|
"FeatureInfo",
|
||||||
"FeatureSetInfo",
|
"FeatureSetInfo",
|
||||||
"MutuallyExclusiveCategoryInfo",
|
"MutuallyExclusiveCategoryInfo",
|
||||||
|
@ -87,6 +88,7 @@ def _cc_feature_impl(ctx):
|
||||||
|
|
||||||
return [
|
return [
|
||||||
feature,
|
feature,
|
||||||
|
FeatureImplyabilityInfo(),
|
||||||
FeatureSetInfo(label = ctx.label, features = depset([feature])),
|
FeatureSetInfo(label = ctx.label, features = depset([feature])),
|
||||||
FeatureConstraintInfo(
|
FeatureConstraintInfo(
|
||||||
label = ctx.label,
|
label = ctx.label,
|
||||||
|
@ -144,7 +146,7 @@ be enabled.
|
||||||
providers = [FeatureSetInfo],
|
providers = [FeatureSetInfo],
|
||||||
),
|
),
|
||||||
"implies": attr.label_list(
|
"implies": attr.label_list(
|
||||||
providers = [FeatureSetInfo],
|
providers = [FeatureSetInfo, FeatureImplyabilityInfo],
|
||||||
doc = """List of features enabled along with this feature.
|
doc = """List of features enabled along with this feature.
|
||||||
|
|
||||||
Warning: If any of the features cannot be enabled, this feature is
|
Warning: If any of the features cannot be enabled, this feature is
|
||||||
|
@ -186,6 +188,7 @@ cc_feature(
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
provides = [
|
provides = [
|
||||||
|
FeatureImplyabilityInfo,
|
||||||
FeatureInfo,
|
FeatureInfo,
|
||||||
FeatureSetInfo,
|
FeatureSetInfo,
|
||||||
FeatureConstraintInfo,
|
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: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: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: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.bzl", _cc_tool = "cc_tool")
|
||||||
load("//cc/toolchains:tool_capability.bzl", _cc_tool_capability = "cc_tool_capability")
|
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: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:external_feature.bzl", _cc_external_feature = "cc_external_feature")
|
||||||
load("//cc/toolchains/impl:variables.bzl", _cc_variable = "cc_variable")
|
load("//cc/toolchains/impl:variables.bzl", _cc_variable = "cc_variable")
|
||||||
|
|
||||||
|
cc_target_capability = _cc_target_capability
|
||||||
cc_tool_map = _cc_tool_map
|
cc_tool_map = _cc_tool_map
|
||||||
cc_tool = _cc_tool
|
cc_tool = _cc_tool
|
||||||
cc_tool_capability = _cc_tool_capability
|
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
|
# links in the generated documentation so that maintainers don't need to manually
|
||||||
# ensure every reference to a rule is properly linked.
|
# ensure every reference to a rule is properly linked.
|
||||||
DOCUMENTED_TOOLCHAIN_RULES = [
|
DOCUMENTED_TOOLCHAIN_RULES = [
|
||||||
|
"cc_target_capability",
|
||||||
"cc_tool_map",
|
"cc_tool_map",
|
||||||
"cc_tool",
|
"cc_tool",
|
||||||
"cc_tool_capability",
|
"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,
|
overrides = None,
|
||||||
allowlist_include_directories = depset(),
|
allowlist_include_directories = depset(),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# Intentionally does not provide FeatureImplyabilityInfo to prevent
|
||||||
|
# features from implying these kinds of rules.
|
||||||
return [
|
return [
|
||||||
ToolCapabilityInfo(label = ctx.label, feature = ft),
|
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])),
|
FeatureConstraintInfo(label = ctx.label, all_of = depset([ft])),
|
||||||
]
|
]
|
||||||
|
|
||||||
|
@ -56,28 +57,41 @@ cc_tool_capability = rule(
|
||||||
provides = [ToolCapabilityInfo, FeatureConstraintInfo],
|
provides = [ToolCapabilityInfo, FeatureConstraintInfo],
|
||||||
doc = """A capability is an optional feature that a tool supports.
|
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(
|
cc_tool(
|
||||||
name = "clang",
|
name = "clang",
|
||||||
src = "@host_tools/bin/clang",
|
src = "@host_tools/bin/clang",
|
||||||
capabilities = [
|
capabilities = [
|
||||||
"//cc/toolchains/capabilities:supports_pic",
|
"//cc/toolchains/capabilities:supports_start_end_lib",
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
|
|
||||||
cc_args(
|
cc_args(
|
||||||
name = "pic",
|
name = "pic",
|
||||||
requires = [
|
requires = ["//cc/toolchains/capabilities:supports_start_end_lib"],
|
||||||
"//cc/toolchains/capabilities:supports_pic"
|
args = ["-Wl,--start-lib"],
|
||||||
],
|
|
||||||
args = ["-fPIC"],
|
|
||||||
)
|
)
|
||||||
```
|
```
|
||||||
|
|
||||||
This ensures that `-fPIC` is added to the command-line only when we are using a
|
This ensures that `-Wl,--start-lib` is added to the command-line only when using
|
||||||
tool that supports PIC.
|
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 = {
|
attrs = {
|
||||||
"feature_name": attr.string(doc = "The name of the feature to generate for this capability"),
|
"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(
|
cc_tool(
|
||||||
name = "tool",
|
name = "tool",
|
||||||
src = "//tests/rule_based_toolchain/testdata:bin_wrapper.sh",
|
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"],
|
data = ["//tests/rule_based_toolchain/testdata:bin"],
|
||||||
tags = ["requires-network"],
|
tags = ["requires-network"],
|
||||||
)
|
)
|
||||||
|
|
|
@ -47,7 +47,7 @@ cc_tool(
|
||||||
name = "c_compile_tool",
|
name = "c_compile_tool",
|
||||||
src = "//tests/rule_based_toolchain/testdata:bin_wrapper",
|
src = "//tests/rule_based_toolchain/testdata:bin_wrapper",
|
||||||
allowlist_include_directories = ["//tests/rule_based_toolchain/testdata:subdirectory_3"],
|
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(
|
cc_sysroot(
|
||||||
|
@ -69,7 +69,10 @@ util.helper_target(
|
||||||
":sysroot",
|
":sysroot",
|
||||||
":c_compile_args",
|
":c_compile_args",
|
||||||
],
|
],
|
||||||
enabled_features = [":simple_feature"],
|
enabled_features = [
|
||||||
|
":simple_feature",
|
||||||
|
"//cc/toolchains/capabilities:supports_pic",
|
||||||
|
],
|
||||||
known_features = [":compile_feature"],
|
known_features = [":compile_feature"],
|
||||||
tool_map = ":compile_tool_map",
|
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(
|
legacy_feature(
|
||||||
name = "compile_feature",
|
name = "compile_feature",
|
||||||
enabled = False,
|
enabled = False,
|
||||||
|
@ -208,7 +212,7 @@ def _toolchain_collects_files_test(env, targets):
|
||||||
)],
|
)],
|
||||||
),
|
),
|
||||||
legacy_feature(
|
legacy_feature(
|
||||||
name = "supports_pic",
|
name = "supports_start_end_lib",
|
||||||
enabled = False,
|
enabled = False,
|
||||||
),
|
),
|
||||||
legacy_feature(
|
legacy_feature(
|
||||||
|
@ -225,7 +229,7 @@ def _toolchain_collects_files_test(env, targets):
|
||||||
action_name = "c_compile",
|
action_name = "c_compile",
|
||||||
enabled = True,
|
enabled = True,
|
||||||
tools = [legacy_tool(tool = exe)],
|
tools = [legacy_tool(tool = exe)],
|
||||||
implies = ["supports_pic"],
|
implies = ["supports_start_end_lib"],
|
||||||
flag_sets = [
|
flag_sets = [
|
||||||
legacy_flag_set(
|
legacy_flag_set(
|
||||||
flag_groups = [
|
flag_groups = [
|
||||||
|
|
Loading…
Reference in New Issue