xref: /aosp_15_r20/external/pigweed/pw_toolchain_bazel/api.rst (revision 61c4878ac05f98d0ceed94b57d316916de578985)
1.. _module-pw_toolchain_bazel-api:
2
3=============
4API reference
5=============
6.. pigweed-module-subpage::
7   :name: pw_toolchain_bazel
8
9.. py:class:: pw_cc_toolchain
10
11  This rule is the core of a C/C++ toolchain definition. Critically, it is
12  intended to fully specify the following:
13
14  * Which tools to use for various compile/link actions.
15  * Which `well-known features <https://bazel.build/docs/cc-toolchain-config-reference#wellknown-features>`_
16    are supported.
17  * Which flags to apply to various actions.
18
19   .. py:attribute:: action_configs
20      :type: List[label]
21
22      List of :py:class:`pw_cc_action_config` labels that bind tools to the
23      appropriate actions. This is how Bazel knows which binaries to use when
24      compiling, linking, or taking other actions like embedding data using
25      objcopy.
26
27   .. py:attribute:: flag_sets
28      :type: List[label]
29
30      List of flag sets to unconditionally apply to the respective
31      :py:class:`pw_cc_action_config`\s. The labels listed here will point to
32      :py:class:`pw_cc_flag_set` rules.
33
34   .. py:attribute:: extra_action_files
35      :type: List[label]
36
37      List of extra files to give to each different type of action. Replaces
38      all_files, ar_files, compiler_files, ... in the existing toolchain
39      definition.
40
41   .. py:attribute:: toolchain_identifier
42      :type: str
43
44      See  `cc_common.create_cc_toolchain_config_info() <https://bazel.build/rules/lib/toplevel/cc_common#create_cc_toolchain_config_info>`_\.
45
46   .. py:attribute:: host_system_name
47      :type: str
48
49      See  `cc_common.create_cc_toolchain_config_info() <https://bazel.build/rules/lib/toplevel/cc_common#create_cc_toolchain_config_info>`_\.
50
51   .. py:attribute:: target_system_name
52      :type: str
53
54      See  `cc_common.create_cc_toolchain_config_info() <https://bazel.build/rules/lib/toplevel/cc_common#create_cc_toolchain_config_info>`_\.
55
56   .. py:attribute:: target_cpu
57      :type: str
58
59      See  `cc_common.create_cc_toolchain_config_info() <https://bazel.build/rules/lib/toplevel/cc_common#create_cc_toolchain_config_info>`_\.
60
61   .. py:attribute:: target_libc
62      :type: str
63
64      See  `cc_common.create_cc_toolchain_config_info() <https://bazel.build/rules/lib/toplevel/cc_common#create_cc_toolchain_config_info>`_\.
65
66   .. py:attribute:: compiler
67      :type: str
68
69      See  `cc_common.create_cc_toolchain_config_info() <https://bazel.build/rules/lib/toplevel/cc_common#create_cc_toolchain_config_info>`_\.
70
71   .. py:attribute:: abi_version
72      :type: str
73
74      See  `cc_common.create_cc_toolchain_config_info() <https://bazel.build/rules/lib/toplevel/cc_common#create_cc_toolchain_config_info>`_\.
75
76   .. py:attribute:: abi_libc_version
77      :type: str
78
79      See  `cc_common.create_cc_toolchain_config_info() <https://bazel.build/rules/lib/toplevel/cc_common#create_cc_toolchain_config_info>`_\.
80
81   .. py:attribute:: cc_target_os
82      :type: str
83
84      See  `cc_common.create_cc_toolchain_config_info() <https://bazel.build/rules/lib/toplevel/cc_common#create_cc_toolchain_config_info>`_\.
85
86   .. py:attribute:: builtin_sysroot
87      :type: str
88
89      See  `cc_common.create_cc_toolchain_config_info() <https://bazel.build/rules/lib/toplevel/cc_common#create_cc_toolchain_config_info>`_\.
90
91   .. py:attribute:: cxx_builtin_include_directories
92      :type: List[str]
93
94      See  `cc_common.create_cc_toolchain_config_info() <https://bazel.build/rules/lib/toplevel/cc_common#create_cc_toolchain_config_info>`_\.
95
96.. py:class:: pw_cc_flag_set
97
98   Declares an ordered set of flags bound to a set of actions.
99
100   Flag sets can be attached to a :py:class:`pw_cc_toolchain` via
101   :py:attr:`pw_cc_toolchain.flag_sets`\.
102
103   Examples:
104
105   .. code-block:: py
106
107      pw_cc_flag_set(
108          name = "warnings_as_errors",
109          flags = ["-Werror"],
110      )
111
112      pw_cc_flag_set(
113          name = "layering_check",
114          flag_groups = [
115              ":strict_module_headers",
116              ":dependent_module_map_files",
117          ],
118      )
119
120   .. inclusive-language: disable
121
122   Note: In the vast majority of cases, alphabetical sorting is not desirable
123   for the :py:attr:`pw_cc_flag_set.flags` and
124   :py:attr:`pw_cc_flag_set.flag_groups` attributes.
125   `Buildifier <https://github.com/bazelbuild/buildtools/blob/master/buildifier/README.md>`_
126   shouldn't ever try to sort these, but in the off chance it starts to these
127   members should be listed as exceptions in the ``SortableDenylist``.
128
129   .. inclusive-language: enable
130
131   .. py:attribute:: actions
132      :type: List[str]
133
134      A list of action names that this flag set applies to.
135
136      .. inclusive-language: disable
137
138      Valid choices are listed at
139      `@rules_cc//cc:action_names.bzl <https://github.com/bazelbuild/bazel/blob/master/tools/build_defs/cc/action_names.bzl>`_\.
140
141      .. inclusive-language: enable
142
143      It is possible for some needed action names to not be enumerated in this list,
144      so there is not rigid validation for these strings. Prefer using constants
145      rather than manually typing action names.
146
147   .. py:attribute:: flags
148      :type: List[str]
149
150      Flags that should be applied to the specified actions.
151
152      These are evaluated in order, with earlier flags appearing earlier in the
153      invocation of the underlying tool. If you need expansion logic, prefer
154      enumerating flags in a :py:class:`pw_cc_flag_group` or create a custom
155      rule that provides ``FlagGroupInfo``.
156
157      Note: :py:attr:`pw_cc_flag_set.flags` and
158      :py:attr:`pw_cc_flag_set.flag_groups` are mutually exclusive.
159
160   .. py:attribute:: flag_groups
161      :type: List[label]
162
163      Labels pointing to :py:class:`pw_cc_flag_group` rules.
164
165      This is intended to be compatible with any other rules that provide
166      ``FlagGroupInfo``. These are evaluated in order, with earlier flag groups
167      appearing earlier in the invocation of the underlying tool.
168
169      Note: :py:attr:`pw_cc_flag_set.flag_groups` and
170      :py:attr:`pw_cc_flag_set.flags` are mutually exclusive.
171
172.. py:class:: pw_cc_flag_group
173
174   Declares an (optionally parametric) ordered set of flags.
175
176   :py:class:`pw_cc_flag_group` rules are expected to be consumed exclusively by
177   :py:class:`pw_cc_flag_set` rules. Though simple lists of flags can be
178   expressed by populating ``flags`` on a :py:class:`pw_cc_flag_set`,
179   :py:class:`pw_cc_flag_group` provides additional power in the following two
180   ways:
181
182    1. Iteration and conditional expansion. Using
183       :py:attr:`pw_cc_flag_group.iterate_over`,
184       :py:attr:`pw_cc_flag_group.expand_if_available`\, and
185       :py:attr:`pw_cc_flag_group.expand_if_not_available`\, more complex
186       flag expressions can be made. This is critical for implementing things
187       like the ``libraries_to_link`` feature, where library names are
188       transformed into flags that end up in the final link invocation.
189
190       Note: ``expand_if_equal``, ``expand_if_true``, and ``expand_if_false``
191       are not yet supported.
192
193    2. Flags are tool-independent. A :py:class:`pw_cc_flag_group` expresses
194       ordered flags that may be reused across various
195       :py:class:`pw_cc_flag_set` rules. This is useful for cases where multiple
196       :py:class:`pw_cc_flag_set` rules must be created to implement a feature
197       for which flags are slightly different depending on the action (e.g.
198       compile vs link). Common flags can be expressed in a shared
199       :py:class:`pw_cc_flag_group`, and the differences can be relegated to
200       separate :py:class:`pw_cc_flag_group` instances.
201
202   Examples:
203
204   .. code-block:: py
205
206      pw_cc_flag_group(
207          name = "user_compile_flag_expansion",
208          flags = ["%{user_compile_flags}"],
209          iterate_over = "user_compile_flags",
210          expand_if_available = "user_compile_flags",
211      )
212
213      # This flag_group might be referenced from various FDO-related
214      # `pw_cc_flag_set` rules. More importantly, the flag sets pulling this in
215      # may apply to different sets of actions.
216      pw_cc_flag_group(
217          name = "fdo_profile_correction",
218          flags = ["-fprofile-correction"],
219          expand_if_available = "fdo_profile_path",
220      )
221
222   .. py:attribute:: flags
223      :type: List[str]
224
225      List of flags provided by this rule.
226
227      For extremely complex expressions of flags that require nested flag groups
228      with multiple layers of expansion, prefer creating a custom rule in
229      `Starlark <https://bazel.build/rules/language>`_ that provides
230      ``FlagGroupInfo`` or ``FlagSetInfo``.
231
232
233   .. py:attribute:: iterate_over
234      :type: str
235
236      Expands :py:attr:`pw_cc_flag_group.flags` for items in the named list.
237
238      Toolchain actions have various variables accessible as names that can be
239      used to guide flag expansions. For variables that are lists,
240      :py:attr:`pw_cc_flag_group.iterate_over` must be used to expand the list into a series of flags.
241
242      Note that :py:attr:`pw_cc_flag_group.iterate_over` is the string name of a
243      build variable, and not an actual list. Valid options are listed in the
244      `C++ Toolchain Configuration <https://bazel.build/docs/cc-toolchain-config-reference#cctoolchainconfiginfo-build-variables>`_
245      reference.
246
247
248
249      Note that the flag expansion stamps out the entire list of flags in
250      :py:attr:`pw_cc_flag_group.flags` once for each item in the list.
251
252      Example:
253
254      .. code-block:: py
255
256         # Expands each path in ``system_include_paths`` to a series of
257         # ``-isystem`` includes.
258         #
259         # Example input:
260         #     system_include_paths = ["/usr/local/include", "/usr/include"]
261         #
262         # Expected result:
263         #     "-isystem /usr/local/include -isystem /usr/include"
264         pw_cc_flag_group(
265             name = "system_include_paths",
266             flags = ["-isystem", "%{system_include_paths}"],
267             iterate_over = "system_include_paths",
268         )
269
270   .. py:attribute:: expand_if_available
271      :type: str
272
273      Expands the expression in :py:attr:`pw_cc_flag_group.flags` if the
274      specified build variable is set.
275
276   .. py:attribute:: expand_if_not_available
277      :type: str
278
279      Expands the expression in :py:attr:`pw_cc_flag_group.flags` if the
280      specified build variable is **NOT** set.
281
282.. py:class:: pw_cc_tool
283
284   Declares a singular tool that can be bound to action configs.
285
286   :py:class:`pw_cc_tool` rules are intended to be consumed exclusively by
287   :py:class:`pw_cc_action_config` rules. These rules declare an underlying tool
288   that can be used to fulfill various actions. Many actions may reuse a shared
289   tool.
290
291   Examples:
292
293   .. code-block:: py
294
295      # A project-provided tool.
296      pw_cc_tool(
297          name = "clang_tool",
298          tool = "@llvm_toolchain//:bin/clang",
299      )
300
301      # A tool expected to be preinstalled on a user's machine.
302      pw_cc_tool(
303          name = "clang_tool",
304          path = "/usr/bin/clang",
305      )
306
307   .. py:attribute:: tool
308      :type: label
309
310      The underlying tool that this rule represents.
311
312      This attribute is a label rather than a simple file path. This means that
313      the file must be referenced relative to the BUILD file that exports it.
314      For example:
315
316      .. code-block:: none
317
318         @llvm_toolchain//:bin/clang
319         ^              ^  ^
320
321      Where:
322
323      * ``@llvm_toolchain`` is the repository.
324      * ``//`` is the directory of the BUILD file that exports the file of
325        interest.
326      * ``bin/clang`` is the path of the actual binary relative to the BUILD
327        file of interest.
328
329      Note: :py:attr:`pw_cc_tool.tool` and :py:attr:`pw_cc_tool.path` are
330      mutually exclusive.
331
332   .. py:attribute:: path
333      :type: Path
334
335      An absolute path to a binary to use for this tool.
336
337      Relative paths are also supported, but they are relative to the
338      :py:class:`pw_cc_toolchain` that uses this tool rather than relative to
339      this :py:class:`pw_cc_tool` rule.
340
341      Note: :py:attr:`pw_cc_tool.path` and :py:attr:`pw_cc_tool.tool` are
342      mutually exclusive.
343
344      .. admonition:: Note
345         :class: warning
346
347         This method of listing a tool is NOT recommended, and is provided as an
348         escape hatch for edge cases. Prefer using :py:attr:`pw_cc_tool.tool`
349         whenever possible.
350
351   .. py:attribute:: execution_requirements
352      :type: List[str]
353
354      A list of strings that provide hints for execution environment
355      compatibility (e.g. ``requires-darwin``).
356
357   .. py:attribute:: requires_any_of
358      :type: List[label]
359
360      This tool may only be enabled when at least one of the constraints are
361      met.
362
363      If omitted, this tool will be enabled unconditionally.
364
365   .. py:attribute:: additional_files
366      :type: List[label]
367
368      Additional files that are required for this tool to correctly operate.
369      These files are propagated up to the :py:class:`pw_cc_toolchain` so you
370      typically won't need to explicitly specify the ``*_files`` attributes
371      on a :py:class:`pw_cc_toolchain`.
372
373
374.. py:class:: pw_cc_action_config
375
376   Declares the configuration and selection of `pw_cc_tool` rules.
377
378   Action configs are bound to a toolchain through `action_configs`, and are the
379   driving mechanism for controlling toolchain tool invocation/behavior.
380
381   Action configs define three key things:
382
383   * Which tools to invoke for a given type of action.
384   * Tool features and compatibility.
385   * :py:class:`pw_cc_flag_set`\s that are unconditionally bound to a tool
386     invocation.
387
388   Examples:
389
390   .. code-block:: py
391
392      pw_cc_action_config(
393          name = "ar",
394          action_names = ["@pw_toolchain//actions:all_ar_actions"],
395          implies = [
396              "@pw_toolchain//features/legacy:archiver_flags",
397              "@pw_toolchain//features/legacy:linker_param_file",
398          ],
399          tools = [":ar_tool"],
400      )
401
402      pw_cc_action_config(
403          name = "clang",
404          action_names = [
405              "@pw_toolchain//actions:all_asm_actions",
406              "@pw_toolchain//actions:all_c_compiler_actions",
407          ]
408          tools = [":clang_tool"],
409      )
410
411   .. py:attribute:: action_names
412      :type: List[str]
413
414      A list of action names to apply this action to.
415
416      .. inclusive-language: disable
417
418      Valid choices are listed at
419      `@rules_cc//cc:action_names.bzl <https://github.com/bazelbuild/bazel/blob/master/tools/build_defs/cc/action_names.bzl>`_\.
420
421      .. inclusive-language: enable
422
423      It is possible for some needed action names to not be enumerated in this list,
424      so there is not rigid validation for these strings. Prefer using constants
425      rather than manually typing action names.
426
427   .. py:attribute:: enabled
428      :type: bool
429
430      Whether or not this action config is enabled by default.
431
432      .. admonition:: Note
433
434         This defaults to ``True`` since it's assumed that most listed action
435         configs will be enabled and used by default. This is the opposite of
436         Bazel's native default.
437
438   .. py:attribute:: tools
439      :type: List[label]
440
441      The tool to use for the specified actions.
442
443      A tool can be a :py:class:`pw_cc_tool`, or a binary.
444
445      If multiple tools are specified, the first tool that has ``with_features``
446      that satisfy the currently enabled feature set is used.
447
448   .. py:attribute:: flag_sets
449      :type: List[label]
450
451      Labels that point to :py:class:`pw_cc_flag_set`\s that are unconditionally
452      bound to the specified actions.
453
454      .. admonition:: Note
455
456         The flags in the :py:class:`pw_cc_flag_set` are only bound to matching
457         action names. If an action is listed in this rule's
458         :py:attr:`pw_cc_action_config.action_names`,
459         but is NOT listed in the :py:class:`pw_cc_flag_set`\'s
460         :py:attr:`pw_cc_flag_set.actions`, the flag will not be applied to that
461         action.
462
463   .. py:attribute:: implies
464      :type: List[str]
465
466      Names of features that should be automatically enabled when this tool is
467      used.
468
469      .. admonition:: Note
470         :class: warning
471
472         If this action config implies an unknown feature, this action config
473         will silently be disabled. This behavior is native to Bazel itself, and
474         there's no way to detect this and emit an error instead. For this
475         reason, be very cautious when listing implied features!
476
477.. py:class:: pw_cc_feature
478
479   Defines the implemented behavior of a C/C++ toolchain feature.
480
481
482   This rule is effectively a wrapper for the ``feature`` constructor in
483   `@rules_cc//cc:cc_toolchain_config_lib.bzl <https://github.com/bazelbuild/rules_cc/blob/main/cc/cc_toolchain_config_lib.bzl>`_.
484
485   A feature is basically a dynamic flag set. There are a variety of
486   dependencies and compatibility requirements that must be satisfied for the
487   listed flag sets to be applied.
488
489   A feature may be enabled or disabled through the following mechanisms:\
490
491   * Via command-line flags, or a
492     `.bazelrc file <https://bazel.build/run/bazelrc>`_\.
493   * Through inter-feature relationships (enabling one feature may implicitly
494     enable another).
495   * Individual rules may elect to manually enable or disable features through
496     the
497     `builtin features attribute <https://bazel.build/reference/be/common-definitions#common.features>`_\.
498
499   Because of the dynamic nature of toolchain features, it's generally best to
500   avoid enumerating features as part of your toolchain with the following
501   exceptions:
502
503   * You want the flags to be controllable via Bazel's CLI. For example, adding
504     ``-v`` to a compiler invocation is often too verbose to be useful for most
505     workflows, but can be instrumental when debugging obscure errors. By
506     expressing compiler verbosity as a feature, users may opt-in when
507     necessary.
508   * You need to carry forward Starlark toolchain behaviors. If you're migrating
509     a complex Starlark-based toolchain definition to these rules, many of the
510     workflows and flags were likely based on features. This rule exists to
511     support those existing structures.
512
513   For more details about how Bazel handles features, see the official Bazel
514   documentation at
515   https://bazel.build/docs/cc-toolchain-config-reference#features.
516
517   Note: ``env_sets`` are not yet supported.
518
519   Examples:
520
521   .. code-block:: py
522
523      # A feature that can be easily toggled to include extra compiler output to
524      # help debug things like include search path ordering and showing all the
525      # flags passed to the compiler.
526      #
527      # Add `--features=verbose_compiler_output` to your Bazel invocation to
528      # enable.
529      pw_cc_feature(
530          name = "verbose_compiler_output",
531          enabled = False,
532          feature_name = "verbose_compiler_output",
533          flag_sets = [":verbose_compiler_flags"],
534      )
535
536      # This feature signals a capability, and doesn't have associated flags.
537      #
538      # For a list of well-known features, see:
539      #    https://bazel.build/docs/cc-toolchain-config-reference#wellknown-features
540      pw_cc_feature(
541          name = "link_object_files",
542          enabled = True,
543          feature_name = "supports_start_end_lib",
544      )
545
546   .. py:attribute:: feature_name
547      :type: str
548
549      The name of the feature that this rule implements.
550
551      Feature names are used to express feature dependencies and compatibility.
552      Because features are tracked by string names rather than labels, there's
553      great flexibility in swapping out feature implementations or overriding
554      the built-in legacy features that Bazel silently binds to every
555      toolchain.
556
557      :py:attr:`pw_cc_feature.feature_name` is used rather than ``name`` to
558      distinguish between the rule name, and the intended final feature name.
559      This allows similar rules to exist in the same package, even if slight
560      differences are required.
561
562      Example:
563
564      .. code-block:: py
565
566         pw_cc_feature(
567             name = "sysroot_macos",
568             feature_name = "sysroot",
569             ...
570         )
571
572         pw_cc_feature(
573             name = "sysroot_linux",
574             feature_name = "sysroot",
575             ...
576         )
577
578      While two features with the same :py:attr:`pw_cc_feature.feature_name` may
579      not be bound to the same toolchain, they can happily live alongside each
580      other in the same BUILD file.
581
582   .. py:attribute:: enabled
583      :type: bool
584
585      Whether or not this feature is enabled by default.
586
587   .. py:attribute:: flag_sets
588      :type: List[label]
589
590      Flag sets that, when expanded, implement this feature.
591
592   .. py:attribute:: requires_any_of
593      :type: List[label]
594
595      A list of feature sets that define toolchain compatibility.
596
597      If **at least one** of the listed :py:class:`pw_cc_feature`\s or
598      :py:class:`pw_cc_feature_set`\s are satisfied (all features exist in the
599      toolchain AND are currently enabled), this feature is deemed compatible
600      and may be enabled.
601
602      If this feature **cannot** be enabled (such as if, in the first example
603      below, thin_lto didn't exist in the toolchain), it will throw an error.
604
605      .. code-block:: py
606
607         pw_cc_feature(
608             name = "requires_thin_lto_and_opt",
609             feature_name = "requires_thin_lto_and_opt",
610             requires_any_of = [":thin_lto_requirements"]
611         )
612
613         pw_cc_feature(
614             name = "requires_thin_lto_or_opt",
615             feature_name = "requires_thin_lto_or_opt",
616             requires_any_of = [":thin_lto", ":opt"]
617         )
618
619      .. admonition:: Note
620
621         Even if :py:attr:`pw_cc_feature.requires_any_of` is satisfied, a
622         feature is not enabled unless another mechanism (e.g. command-line
623         flags, :py:attr:`pw_cc_feature.implies`, or
624         :py:attr:`pw_cc_feature.enabled`\) signals that the feature should
625         actually be enabled.
626
627   .. py:attribute:: implies
628      :type: List[label]
629
630      List of features or action configs enabled along with this feature.
631
632      .. admonition:: Note
633         :class: warning
634
635         If any of the named features cannot be enabled, this feature is
636         silently disabled.
637
638   .. py:attribute:: mutually_exclusive
639      :type: List[Label]
640
641      A list of feature or mutually exclusive categories that this feature is
642      mutually exclusive with.
643
644      .. admonition:: Note
645
646         This feature cannot be enabled if another feature also provides the
647         listed feature.
648
649
650.. py:class:: pw_cc_feature_set
651
652   Defines a group of features.
653
654   Semantically equivalent to "all of the specified features", and may be used
655   wherever you can provide multiple features.
656
657   Example:
658
659   .. code-block:: py
660
661      pw_cc_feature_set(
662          name = "thin_lto_requirements",
663          all_of = [
664              ":thin_lto",
665              ":opt",
666          ],
667      )
668
669   .. py:attribute:: features
670      :type: List[label]
671
672      Features that must be enabled for this feature set to be deemed compatible
673      with the current toolchain configuration.
674