• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1# Copyright 2024 The Bazel Authors. All rights reserved.
2#
3# Licensed under the Apache License, Version 2.0 (the "License");
4# you may not use this file except in compliance with the License.
5# You may obtain a copy of the License at
6#
7#    http://www.apache.org/licenses/LICENSE-2.0
8#
9# Unless required by applicable law or agreed to in writing, software
10# distributed under the License is distributed on an "AS IS" BASIS,
11# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12# See the License for the specific language governing permissions and
13# limitations under the License.
14"""All providers for rule-based bazel toolchain config."""
15
16load("@bazel_skylib//rules/directory:providers.bzl", "DirectoryInfo")
17load("//cc/toolchains/impl:args_utils.bzl", "validate_nested_args")
18load(
19    "//cc/toolchains/impl:collect.bzl",
20    "collect_action_types",
21    "collect_files",
22    "collect_provider",
23)
24load(
25    "//cc/toolchains/impl:nested_args.bzl",
26    "NESTED_ARGS_ATTRS",
27    "nested_args_provider_from_ctx",
28)
29load(
30    ":cc_toolchain_info.bzl",
31    "ActionTypeSetInfo",
32    "ArgsInfo",
33    "ArgsListInfo",
34    "BuiltinVariablesInfo",
35    "FeatureConstraintInfo",
36)
37
38visibility("public")
39
40def _cc_args_impl(ctx):
41    actions = collect_action_types(ctx.attr.actions)
42
43    nested = None
44    if ctx.attr.args or ctx.attr.nested:
45        nested = nested_args_provider_from_ctx(ctx)
46        validate_nested_args(
47            variables = ctx.attr._variables[BuiltinVariablesInfo].variables,
48            nested_args = nested,
49            actions = actions.to_list(),
50            label = ctx.label,
51        )
52        files = nested.files
53    else:
54        files = collect_files(ctx.attr.data + ctx.attr.allowlist_include_directories)
55
56    requires = collect_provider(ctx.attr.requires_any_of, FeatureConstraintInfo)
57
58    args = ArgsInfo(
59        label = ctx.label,
60        actions = actions,
61        requires_any_of = tuple(requires),
62        nested = nested,
63        env = ctx.attr.env,
64        files = files,
65        allowlist_include_directories = depset(
66            direct = [d[DirectoryInfo] for d in ctx.attr.allowlist_include_directories],
67        ),
68    )
69    return [
70        args,
71        ArgsListInfo(
72            label = ctx.label,
73            args = tuple([args]),
74            files = files,
75            by_action = tuple([
76                struct(action = action, args = tuple([args]), files = files)
77                for action in actions.to_list()
78            ]),
79            allowlist_include_directories = args.allowlist_include_directories,
80        ),
81    ]
82
83_cc_args = rule(
84    implementation = _cc_args_impl,
85    attrs = {
86        "actions": attr.label_list(
87            providers = [ActionTypeSetInfo],
88            mandatory = True,
89            doc = """See documentation for cc_args macro wrapper.""",
90        ),
91        "allowlist_include_directories": attr.label_list(
92            providers = [DirectoryInfo],
93            doc = """See documentation for cc_args macro wrapper.""",
94        ),
95        "env": attr.string_dict(
96            doc = """See documentation for cc_args macro wrapper.""",
97        ),
98        "requires_any_of": attr.label_list(
99            providers = [FeatureConstraintInfo],
100            doc = """See documentation for cc_args macro wrapper.""",
101        ),
102        "_variables": attr.label(
103            default = "//cc/toolchains/variables:variables",
104        ),
105    } | NESTED_ARGS_ATTRS,
106    provides = [ArgsInfo],
107    doc = """Declares a list of arguments bound to a set of actions.
108
109Roughly equivalent to ctx.actions.args()
110
111Examples:
112    cc_args(
113        name = "warnings_as_errors",
114        args = ["-Werror"],
115    )
116""",
117)
118
119def cc_args(
120        *,
121        name,
122        actions = None,
123        allowlist_include_directories = None,
124        args = None,
125        data = None,
126        env = None,
127        format = {},
128        iterate_over = None,
129        nested = None,
130        requires_not_none = None,
131        requires_none = None,
132        requires_true = None,
133        requires_false = None,
134        requires_equal = None,
135        requires_equal_value = None,
136        requires_any_of = None,
137        **kwargs):
138    """Action-specific arguments for use with a `cc_toolchain`.
139
140    This rule is the fundamental building building block for every toolchain tool invocation. Each
141    argument expressed in a toolchain tool invocation (e.g. `gcc`, `llvm-ar`) is declared in a
142    `cc_args` rule that applies an ordered list of arguments to a set of toolchain
143    actions. `cc_args` rules can be added unconditionally to a
144    `cc_toolchain`, conditionally via `select()` statements, or dynamically via an
145    intermediate `cc_feature`.
146
147    Conceptually, this is similar to the old `CFLAGS`, `CPPFLAGS`, etc. environment variables that
148    many build systems use to determine which flags to use for a given action. The significant
149    difference is that `cc_args` rules are declared in a structured way that allows for
150    significantly more powerful and sharable toolchain configurations. Also, due to Bazel's more
151    granular action types, it's possible to bind flags to very specific actions (e.g. LTO indexing
152    for an executable vs a dynamic library) multiple different actions (e.g. C++ compile and link
153    simultaneously).
154
155    Example usage:
156    ```
157    load("//cc/toolchains:args.bzl", "cc_args")
158
159    # Basic usage: a trivial flag.
160    #
161    # An example of expressing `-Werror` as a `cc_args` rule.
162    cc_args(
163        name = "warnings_as_errors",
164        actions = [
165            # Applies to all C/C++ compile actions.
166            "//cc/toolchains/actions:compile_actions",
167        ],
168        args = ["-Werror"],
169    )
170
171    # Basic usage: ordered flags.
172    #
173    # An example of linking against libc++, which uses two flags that must be applied in order.
174    cc_args(
175        name = "link_libcxx",
176        actions = [
177            # Applies to all link actions.
178            "//cc/toolchains/actions:link_actions",
179        ],
180        # On tool invocation, this appears as `-Xlinker -lc++`. Nothing will ever end up between
181        # the two flags.
182        args = [
183            "-Xlinker",
184            "-lc++",
185        ],
186    )
187
188    # Advanced usage: built-in variable expansions.
189    #
190    # Expands to `-L/path/to/search_dir` for each directory in the built-in variable
191    # `library_search_directories`. This variable is managed internally by Bazel through inherent
192    # behaviors of Bazel and the interactions between various C/C++ build rules.
193    cc_args(
194        name = "library_search_directories",
195        actions = [
196            "//cc/toolchains/actions:link_actions",
197        ],
198        args = ["-L{search_dir}"],
199        iterate_over = "//cc/toolchains/variables:library_search_directories",
200        requires_not_none = "//cc/toolchains/variables:library_search_directories",
201        format = {
202            "search_dir": "//cc/toolchains/variables:library_search_directories",
203        },
204    )
205    ```
206
207    For more extensive examples, see the usages here:
208        https://github.com/bazelbuild/rules_cc/tree/main/cc/toolchains/args
209
210    Args:
211        name: (str) The name of the target.
212        actions: (List[Label]) A list of labels of `cc_action_type` or
213            `cc_action_type_set` rules that dictate which actions these
214            arguments should be applied to.
215        allowlist_include_directories: (List[Label]) A list of include paths that are implied by
216            using this rule. These must point to a skylib
217            [directory](https://github.com/bazelbuild/bazel-skylib/tree/main/doc/directory_doc.md#directory)
218            or [subdirectory](https://github.com/bazelbuild/bazel-skylib/tree/main/doc/directory_subdirectory_doc.md#subdirectory) rule.
219            Some flags (e.g. --sysroot) imply certain include paths are available despite
220            not explicitly specifying a normal include path flag (`-I`, `-isystem`, etc.).
221            Bazel checks that all included headers are properly provided by a dependency or
222            allowlisted through this mechanism.
223
224            As a rule of thumb, only use this if Bazel is complaining about absolute paths in
225            your toolchain and you've ensured that the toolchain is compiling with the
226            `-no-canonical-prefixes` and/or `-fno-canonical-system-headers` arguments.
227
228            This can help work around errors like:
229            `the source file 'main.c' includes the following non-builtin files with absolute paths
230            (if these are builtin files, make sure these paths are in your toolchain)`.
231        args: (List[str]) The command-line arguments that are applied by using this rule. This is
232            mutually exclusive with [nested](#cc_args-nested).
233        data: (List[Label]) A list of runtime data dependencies that are required for these
234            arguments to work as intended.
235        env: (Dict[str, str]) Environment variables that should be set when the tool is invoked.
236        format: (Dict[str, Label]) A mapping of format strings to the label of the corresponding
237            `cc_variable` that the value should be pulled from. All instances of
238            `{variable_name}` will be replaced with the expanded value of `variable_name` in this
239            dictionary. The complete list of possible variables can be found in
240            https://github.com/bazelbuild/rules_cc/tree/main/cc/toolchains/variables/BUILD.
241            It is not possible to declare custom variables--these are inherent to Bazel itself.
242        iterate_over: (Label) The label of a `cc_variable` that should be iterated over. This is
243            intended for use with built-in variables that are lists.
244        nested: (List[Label]) A list of `cc_nested_args` rules that should be
245            expanded to command-line arguments when this rule is used. This is mutually exclusive
246            with [args](#cc_args-args).
247        requires_not_none: (Label) The label of a `cc_variable` that should be checked
248            for existence before expanding this rule. If the variable is None, this rule will be
249            ignored.
250        requires_none: (Label) The label of a `cc_variable` that should be checked for
251            non-existence before expanding this rule. If the variable is not None, this rule will be
252            ignored.
253        requires_true: (Label) The label of a `cc_variable` that should be checked for
254            truthiness before expanding this rule. If the variable is false, this rule will be
255            ignored.
256        requires_false: (Label) The label of a `cc_variable` that should be checked
257            for falsiness before expanding this rule. If the variable is true, this rule will be
258            ignored.
259        requires_equal: (Label) The label of a `cc_variable` that should be checked
260            for equality before expanding this rule. If the variable is not equal to
261            (requires_equal_value)[#cc_args-requires_equal_value], this rule will be ignored.
262        requires_equal_value: (str) The value to compare (requires_equal)[#cc_args-requires_equal]
263            against.
264        requires_any_of: (List[Label]) These arguments will be used
265            in a tool invocation when at least one of the [cc_feature_constraint](#cc_feature_constraint)
266            entries in this list are satisfied. If omitted, this flag set will be enabled
267            unconditionally.
268        **kwargs: [common attributes](https://bazel.build/reference/be/common-definitions#common-attributes) that should be applied to this rule.
269    """
270    return _cc_args(
271        name = name,
272        actions = actions,
273        allowlist_include_directories = allowlist_include_directories,
274        args = args,
275        data = data,
276        env = env,
277        # We flip the key/value pairs in the dictionary here because Bazel doesn't have a
278        # string-keyed label dict attribute type.
279        format = {k: v for v, k in format.items()},
280        iterate_over = iterate_over,
281        nested = nested,
282        requires_not_none = requires_not_none,
283        requires_none = requires_none,
284        requires_true = requires_true,
285        requires_false = requires_false,
286        requires_equal = requires_equal,
287        requires_equal_value = requires_equal_value,
288        requires_any_of = requires_any_of,
289        **kwargs
290    )
291