xref: /aosp_15_r20/external/bazelbuild-rules_cc/cc/toolchains/feature.bzl (revision eed53cd41c5909d05eedc7ad9720bb158fd93452)
1*eed53cd4SHONG Yifan# Copyright 2024 The Bazel Authors. All rights reserved.
2*eed53cd4SHONG Yifan#
3*eed53cd4SHONG Yifan# Licensed under the Apache License, Version 2.0 (the "License");
4*eed53cd4SHONG Yifan# you may not use this file except in compliance with the License.
5*eed53cd4SHONG Yifan# You may obtain a copy of the License at
6*eed53cd4SHONG Yifan#
7*eed53cd4SHONG Yifan#     http://www.apache.org/licenses/LICENSE-2.0
8*eed53cd4SHONG Yifan#
9*eed53cd4SHONG Yifan# Unless required by applicable law or agreed to in writing, software
10*eed53cd4SHONG Yifan# distributed under the License is distributed on an "AS IS" BASIS,
11*eed53cd4SHONG Yifan# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12*eed53cd4SHONG Yifan# See the License for the specific language governing permissions and
13*eed53cd4SHONG Yifan# limitations under the License.
14*eed53cd4SHONG Yifan"""Implementation of the cc_feature rule."""
15*eed53cd4SHONG Yifan
16*eed53cd4SHONG Yifanload(
17*eed53cd4SHONG Yifan    "//cc/toolchains/impl:collect.bzl",
18*eed53cd4SHONG Yifan    "collect_args_lists",
19*eed53cd4SHONG Yifan    "collect_features",
20*eed53cd4SHONG Yifan    "collect_provider",
21*eed53cd4SHONG Yifan)
22*eed53cd4SHONG Yifanload(
23*eed53cd4SHONG Yifan    ":cc_toolchain_info.bzl",
24*eed53cd4SHONG Yifan    "ArgsListInfo",
25*eed53cd4SHONG Yifan    "FeatureConstraintInfo",
26*eed53cd4SHONG Yifan    "FeatureInfo",
27*eed53cd4SHONG Yifan    "FeatureSetInfo",
28*eed53cd4SHONG Yifan    "MutuallyExclusiveCategoryInfo",
29*eed53cd4SHONG Yifan)
30*eed53cd4SHONG Yifan
31*eed53cd4SHONG Yifandef _cc_feature_impl(ctx):
32*eed53cd4SHONG Yifan    if bool(ctx.attr.feature_name) == (ctx.attr.overrides != None):
33*eed53cd4SHONG Yifan        fail("Exactly one of 'feature_name' and 'overrides' are required")
34*eed53cd4SHONG Yifan
35*eed53cd4SHONG Yifan    if ctx.attr.overrides == None:
36*eed53cd4SHONG Yifan        overrides = None
37*eed53cd4SHONG Yifan
38*eed53cd4SHONG Yifan        # In the future, we may consider making feature_name optional,
39*eed53cd4SHONG Yifan        # defaulting to ctx.label.name. However, starting that way would make it
40*eed53cd4SHONG Yifan        # very difficult if we did want to later change that.
41*eed53cd4SHONG Yifan        name = ctx.attr.feature_name
42*eed53cd4SHONG Yifan    else:
43*eed53cd4SHONG Yifan        overrides = ctx.attr.overrides[FeatureInfo]
44*eed53cd4SHONG Yifan        if not overrides.overridable:
45*eed53cd4SHONG Yifan            fail("Attempting to override %s, which is not overridable" % overrides.label)
46*eed53cd4SHONG Yifan        name = overrides.name
47*eed53cd4SHONG Yifan
48*eed53cd4SHONG Yifan    # In the following scenario:
49*eed53cd4SHONG Yifan    # cc_args(name = "foo", env = {"FOO": "BAR"}, args = ["--foo"])
50*eed53cd4SHONG Yifan    # cc_action_config(name = "ac", args=[":foo"])
51*eed53cd4SHONG Yifan
52*eed53cd4SHONG Yifan    # We will translate this into providers roughly equivalent to the following:
53*eed53cd4SHONG Yifan    # cc_args(name = "implied_by_ac_env", env = {"FOO": "BAR"}, args = ["--foo"])
54*eed53cd4SHONG Yifan    # cc_feature(name = "implied_by_ac", args = [":implied_by_ac_env"])
55*eed53cd4SHONG Yifan    # cc_action_config(
56*eed53cd4SHONG Yifan    #     name = "c_compile",
57*eed53cd4SHONG Yifan    #     implies = [":implied_by_c_compile"]
58*eed53cd4SHONG Yifan    # )
59*eed53cd4SHONG Yifan
60*eed53cd4SHONG Yifan    # The reason for this is because although the legacy providers support
61*eed53cd4SHONG Yifan    # flag_sets in action_config, they don't support env sets.
62*eed53cd4SHONG Yifan    if name.startswith("implied_by_"):
63*eed53cd4SHONG Yifan        fail("Feature names starting with 'implied_by' are reserved")
64*eed53cd4SHONG Yifan
65*eed53cd4SHONG Yifan    feature = FeatureInfo(
66*eed53cd4SHONG Yifan        label = ctx.label,
67*eed53cd4SHONG Yifan        name = name,
68*eed53cd4SHONG Yifan        enabled = ctx.attr.enabled,
69*eed53cd4SHONG Yifan        args = collect_args_lists(ctx.attr.args, ctx.label),
70*eed53cd4SHONG Yifan        implies = collect_features(ctx.attr.implies),
71*eed53cd4SHONG Yifan        requires_any_of = tuple(collect_provider(
72*eed53cd4SHONG Yifan            ctx.attr.requires_any_of,
73*eed53cd4SHONG Yifan            FeatureSetInfo,
74*eed53cd4SHONG Yifan        )),
75*eed53cd4SHONG Yifan        mutually_exclusive = tuple(collect_provider(
76*eed53cd4SHONG Yifan            ctx.attr.mutually_exclusive,
77*eed53cd4SHONG Yifan            MutuallyExclusiveCategoryInfo,
78*eed53cd4SHONG Yifan        )),
79*eed53cd4SHONG Yifan        external = False,
80*eed53cd4SHONG Yifan        overridable = False,
81*eed53cd4SHONG Yifan        overrides = overrides,
82*eed53cd4SHONG Yifan    )
83*eed53cd4SHONG Yifan
84*eed53cd4SHONG Yifan    return [
85*eed53cd4SHONG Yifan        feature,
86*eed53cd4SHONG Yifan        FeatureSetInfo(label = ctx.label, features = depset([feature])),
87*eed53cd4SHONG Yifan        FeatureConstraintInfo(
88*eed53cd4SHONG Yifan            label = ctx.label,
89*eed53cd4SHONG Yifan            all_of = depset([feature]),
90*eed53cd4SHONG Yifan            none_of = depset([]),
91*eed53cd4SHONG Yifan        ),
92*eed53cd4SHONG Yifan        MutuallyExclusiveCategoryInfo(label = ctx.label, name = name),
93*eed53cd4SHONG Yifan    ]
94*eed53cd4SHONG Yifan
95*eed53cd4SHONG Yifancc_feature = rule(
96*eed53cd4SHONG Yifan    implementation = _cc_feature_impl,
97*eed53cd4SHONG Yifan    # @unsorted-dict-items
98*eed53cd4SHONG Yifan    attrs = {
99*eed53cd4SHONG Yifan        "feature_name": attr.string(
100*eed53cd4SHONG Yifan            doc = """The name of the feature that this rule implements.
101*eed53cd4SHONG Yifan
102*eed53cd4SHONG YifanThe feature name is a string that will be used in the `features` attribute of
103*eed53cd4SHONG Yifanrules to enable them (eg. `cc_binary(..., features = ["opt"])`.
104*eed53cd4SHONG Yifan
105*eed53cd4SHONG YifanWhile two features with the same `feature_name` may not be bound to the same
106*eed53cd4SHONG Yifantoolchain, they can happily live alongside each other in the same BUILD file.
107*eed53cd4SHONG Yifan
108*eed53cd4SHONG YifanExample:
109*eed53cd4SHONG Yifan
110*eed53cd4SHONG Yifan    cc_feature(
111*eed53cd4SHONG Yifan        name = "sysroot_macos",
112*eed53cd4SHONG Yifan        feature_name = "sysroot",
113*eed53cd4SHONG Yifan        ...
114*eed53cd4SHONG Yifan    )
115*eed53cd4SHONG Yifan
116*eed53cd4SHONG Yifan    cc_feature(
117*eed53cd4SHONG Yifan        name = "sysroot_linux",
118*eed53cd4SHONG Yifan        feature_name = "sysroot",
119*eed53cd4SHONG Yifan        ...
120*eed53cd4SHONG Yifan    )
121*eed53cd4SHONG Yifan""",
122*eed53cd4SHONG Yifan        ),
123*eed53cd4SHONG Yifan        "enabled": attr.bool(
124*eed53cd4SHONG Yifan            mandatory = True,
125*eed53cd4SHONG Yifan            doc = """Whether or not this feature is enabled by default.""",
126*eed53cd4SHONG Yifan        ),
127*eed53cd4SHONG Yifan        "args": attr.label_list(
128*eed53cd4SHONG Yifan            mandatory = True,
129*eed53cd4SHONG Yifan            doc = """Args that, when expanded, implement this feature.""",
130*eed53cd4SHONG Yifan            providers = [ArgsListInfo],
131*eed53cd4SHONG Yifan        ),
132*eed53cd4SHONG Yifan        "requires_any_of": attr.label_list(
133*eed53cd4SHONG Yifan            doc = """A list of feature sets that define toolchain compatibility.
134*eed53cd4SHONG Yifan
135*eed53cd4SHONG YifanIf *at least one* of the listed `cc_feature_set`s are fully satisfied (all
136*eed53cd4SHONG Yifanfeatures exist in the toolchain AND are currently enabled), this feature is
137*eed53cd4SHONG Yifandeemed compatible and may be enabled.
138*eed53cd4SHONG Yifan
139*eed53cd4SHONG YifanNote: Even if `cc_feature.requires_any_of` is satisfied, a feature is not
140*eed53cd4SHONG Yifanenabled unless another mechanism (e.g. command-line flags, `cc_feature.implies`,
141*eed53cd4SHONG Yifan`cc_feature.enabled`) signals that the feature should actually be enabled.
142*eed53cd4SHONG Yifan""",
143*eed53cd4SHONG Yifan            providers = [FeatureSetInfo],
144*eed53cd4SHONG Yifan        ),
145*eed53cd4SHONG Yifan        "implies": attr.label_list(
146*eed53cd4SHONG Yifan            providers = [FeatureSetInfo],
147*eed53cd4SHONG Yifan            doc = """List of features enabled along with this feature.
148*eed53cd4SHONG Yifan
149*eed53cd4SHONG YifanWarning: If any of the features cannot be enabled, this feature is
150*eed53cd4SHONG Yifansilently disabled.
151*eed53cd4SHONG Yifan""",
152*eed53cd4SHONG Yifan        ),
153*eed53cd4SHONG Yifan        "mutually_exclusive": attr.label_list(
154*eed53cd4SHONG Yifan            providers = [MutuallyExclusiveCategoryInfo],
155*eed53cd4SHONG Yifan            doc = """A list of things that this is mutually exclusive with.
156*eed53cd4SHONG Yifan
157*eed53cd4SHONG YifanIt can be either:
158*eed53cd4SHONG Yifan* A feature, in which case the two features are mutually exclusive.
159*eed53cd4SHONG Yifan* A `cc_mutually_exclusive_category`, in which case all features that write
160*eed53cd4SHONG Yifan    `mutually_exclusive = [":category"]` are mutually exclusive with each other.
161*eed53cd4SHONG Yifan
162*eed53cd4SHONG YifanIf this feature has a side-effect of implementing another feature, it can be
163*eed53cd4SHONG Yifanuseful to list that feature here to ensure they aren't enabled at the
164*eed53cd4SHONG Yifansame time.
165*eed53cd4SHONG Yifan""",
166*eed53cd4SHONG Yifan        ),
167*eed53cd4SHONG Yifan        "overrides": attr.label(
168*eed53cd4SHONG Yifan            providers = [FeatureInfo],
169*eed53cd4SHONG Yifan            doc = """A declaration that this feature overrides a known feature.
170*eed53cd4SHONG Yifan
171*eed53cd4SHONG YifanIn the example below, if you missed the "overrides" attribute, it would complain
172*eed53cd4SHONG Yifanthat the feature "opt" was defined twice.
173*eed53cd4SHONG Yifan
174*eed53cd4SHONG YifanExample:
175*eed53cd4SHONG Yifan
176*eed53cd4SHONG Yifan    cc_feature(
177*eed53cd4SHONG Yifan      name = "opt",
178*eed53cd4SHONG Yifan      feature_name = "opt",
179*eed53cd4SHONG Yifan      ...
180*eed53cd4SHONG Yifan      overrides = "@toolchain//features/well_known:opt",
181*eed53cd4SHONG Yifan    )
182*eed53cd4SHONG Yifan
183*eed53cd4SHONG Yifan""",
184*eed53cd4SHONG Yifan        ),
185*eed53cd4SHONG Yifan    },
186*eed53cd4SHONG Yifan    provides = [
187*eed53cd4SHONG Yifan        FeatureInfo,
188*eed53cd4SHONG Yifan        FeatureSetInfo,
189*eed53cd4SHONG Yifan        FeatureConstraintInfo,
190*eed53cd4SHONG Yifan        MutuallyExclusiveCategoryInfo,
191*eed53cd4SHONG Yifan    ],
192*eed53cd4SHONG Yifan    doc = """Defines the implemented behavior of a C/C++ toolchain feature.
193*eed53cd4SHONG Yifan
194*eed53cd4SHONG YifanA feature is basically a toggleable list of args. There are a variety of
195*eed53cd4SHONG Yifandependencies and compatibility requirements that must be satisfied for the
196*eed53cd4SHONG Yifanlisted args to be applied.
197*eed53cd4SHONG Yifan
198*eed53cd4SHONG YifanA feature may be enabled or disabled through the following mechanisms:
199*eed53cd4SHONG Yifan* Via command-line flags, or a `.bazelrc`.
200*eed53cd4SHONG Yifan* Through inter-feature relationships (enabling one feature may implicitly
201*eed53cd4SHONG Yifan  enable another).
202*eed53cd4SHONG Yifan* Individual rules may elect to manually enable or disable features through the
203*eed53cd4SHONG Yifan  builtin `features` attribute.
204*eed53cd4SHONG Yifan
205*eed53cd4SHONG YifanBecause of the toggleable nature of toolchain features, it's generally best to
206*eed53cd4SHONG Yifanavoid defining features as part of your toolchain with the following exceptions:
207*eed53cd4SHONG Yifan* You want build files to be able to configure compiler flags. For example, a
208*eed53cd4SHONG Yifan  binary might specify `features = ["optimize_for_size"]` to create a small
209*eed53cd4SHONG Yifan  binary instead of optimizing for performance.
210*eed53cd4SHONG Yifan* You need to carry forward Starlark toolchain behaviors. If you're migrating a
211*eed53cd4SHONG Yifan  complex Starlark-based toolchain definition to these rules, many of the
212*eed53cd4SHONG Yifan  workflows and flags were likely based on features. This rule exists to support
213*eed53cd4SHONG Yifan  those existing structures.
214*eed53cd4SHONG Yifan
215*eed53cd4SHONG YifanIf you want to be able to configure flags via the bazel command-line, instead
216*eed53cd4SHONG Yifanconsider making a bool_flag, and then making your `cc_args` `select` on those
217*eed53cd4SHONG Yifanflags.
218*eed53cd4SHONG Yifan
219*eed53cd4SHONG YifanFor more details about how Bazel handles features, see the official Bazel
220*eed53cd4SHONG Yifandocumentation at
221*eed53cd4SHONG Yifanhttps://bazel.build/docs/cc-toolchain-config-reference#features.
222*eed53cd4SHONG Yifan
223*eed53cd4SHONG YifanExamples:
224*eed53cd4SHONG Yifan
225*eed53cd4SHONG Yifan    # A feature that can be easily toggled to optimize for size
226*eed53cd4SHONG Yifan    cc_feature(
227*eed53cd4SHONG Yifan        name = "optimize_for_size",
228*eed53cd4SHONG Yifan        enabled = False,
229*eed53cd4SHONG Yifan        feature_name = "optimize_for_size",
230*eed53cd4SHONG Yifan        args = [":optimize_for_size_args"],
231*eed53cd4SHONG Yifan    )
232*eed53cd4SHONG Yifan
233*eed53cd4SHONG Yifan    # This feature signals a capability, and doesn't have associated flags.
234*eed53cd4SHONG Yifan    #
235*eed53cd4SHONG Yifan    # For a list of well-known features, see:
236*eed53cd4SHONG Yifan    #    https://bazel.build/docs/cc-toolchain-config-reference#wellknown-features
237*eed53cd4SHONG Yifan    cc_feature(
238*eed53cd4SHONG Yifan        name = "supports_pic",
239*eed53cd4SHONG Yifan        enabled = True,
240*eed53cd4SHONG Yifan        overrides = "//cc/toolchains/features:supports_pic
241*eed53cd4SHONG Yifan    )
242*eed53cd4SHONG Yifan""",
243*eed53cd4SHONG Yifan)
244