xref: /aosp_15_r20/external/pigweed/seed/0113.rst (revision 61c4878ac05f98d0ceed94b57d316916de578985)
1.. _seed-0113:
2
3===========================================
40113: Add modular Bazel C/C++ toolchain API
5===========================================
6.. seed::
7   :number: 0113
8   :name: Add modular Bazel C/C++ toolchain API
9   :status: Accepted
10   :proposal_date: 2023-09-28
11   :cl: 173453
12   :authors: Armando Montanez
13   :facilitator: Ted Pudlik
14
15-------
16Summary
17-------
18This SEED proposes custom Starlark rules for declaring C/C++ toolchains in
19Bazel, and scalable patterns for sharing modular components of C/C++ toolchain
20definitions.
21
22----------
23Motivation
24----------
25There is a lot of boilerplate involved in standing up a Bazel C/C++ toolchain.
26While a good portion of the verbosity of specifying a new toolchain is
27important, necessary machinery, nearly as much suffers from one or more of the
28following problems:
29
30- **Underdocumented patterns**: The
31  `create_cc_toolchain_config_info() <https://bazel.build/rules/lib/toplevel/cc_common#create_cc_toolchain_config_info>`_
32  method has an attribute called ``target_cpu`` that doesn't have an associated
33  list of expected values, which suggests the argument is for bookkeeping
34  purposes and doesn't affect Bazel behavior. The reality is this argument
35  *does* have expected values that change behavior, but these are undocumented
36  (see `this GitHub issue <https://github.com/bazelbuild/bazel/issues/19353>`_
37  for more information).
38
39- **Not inherently modular**: Bazel expects the overwhelming majority of a
40  C/C++ toolchain to be specified as part of a call to
41  ``create_cc_toolchain_config_info()``. Because this is a Starlark method,
42  there's a lot of flexibility with how you construct a toolchain config, but
43  very little by way of existing patterns for creating something that is
44  testable, sharable, or in other ways modular. The existing
45  `tutorial for creating a C/C++ toolchain <https://bazel.build/tutorials/ccp-toolchain-config#configure-cc-toolchain>`_
46  illustrates expanding out the toolchain definition as a no-argument Starlark
47  rule.
48
49As Pigweed fully embraces multi-platform builds, it is critical for both
50Pigweed and users of Pigweed that it is easy to stand up custom toolchain
51definitions that work for the relevant hardware project-specific code/libraries.
52
53This SEED seeks to address the shortcomings in Bazel C/C++ toolchain
54declaration by establishing patterns and providing custom build rules that
55are owned and maintained by Pigweed.
56
57--------
58Proposal
59--------
601. Introduce rules for defining C/C++ toolchains
61================================================
62In an effort to improve the experience of defining a C/C++ toolchain, Pigweed
63will introduce new Bazel rules that allow toolchains to share common boilerplate
64without hindering power-user functionality.
65
66While this work centers around an improved experience for defining a toolchain
67via ``create_cc_toolchain_config_info()``, other build rules will be introduced
68for closely related aspects of the toolchain definition process.
69
70An example of what these rules would look like in practice is as follows:
71
72.. code-block::
73
74   # A tool that can be used by various build actions.
75   pw_cc_tool(
76       name = "clang_tool",
77       path = "@cipd_llvm_toolchain//:bin/clang",
78       additional_files = [
79          "@cipd_llvm_toolchain//:all",
80       ],
81   )
82
83   # A mapping of a tool to actions, with flag sets that define behaviors.
84   pw_cc_action_config(
85       name = "clang",
86       actions = ALL_ASM_ACTIONS + ALL_C_COMPILER_ACTIONS,
87       tools = [
88           ":clang_tool",
89       ],
90       flag_sets = [
91           # Most flags should NOT end up here. Only unconditional flags that
92           # should ALWAYS be bound to this tool (e.g. static library
93           # workaround fix for macOS).
94           "@pw_toolchain//flag_sets:generate_depfile",
95       ],
96   )
97
98   # A trivial flag to be consumed by a C/C++ toolchain.
99   pw_cc_flag_set(
100       name = "werror",
101       actions = ALL_COMPILE_ACTIONS,
102       flags = [
103           "-Werror",
104       ],
105   )
106
107   # A list of flags that can be added to a toolchain configuration.
108   pw_cc_flag_set(
109       name = "user_compile_options",
110       actions = ALL_COMPILE_ACTIONS,
111       flag_groups = [
112           ":user_compile_options_flags",
113       ]
114   )
115
116   # A more complex compiler flag that requires template expansion.
117   pw_cc_flag_group(
118       name = "user_compile_options_flags",
119       flags = ["%{user_compile_flags}"],
120       iterate_over = "user_compile_flags",
121       expand_if_available = "user_compile_flags",
122   )
123
124   # The underlying definition of a complete C/C++ toolchain.
125   pw_cc_toolchain(
126       name = "host_toolchain_linux",
127       action_configs = [
128           ":clang",
129           ":clang++",
130           # ...
131       ],
132       additional_files = ":linux_sysroot_files",
133       action_config_flag_sets = [
134           "@pw_toolchain//flag_sets:no_canonical_prefixes",
135           ":user_compile_options",
136           ":werror",
137       ],
138       features = [
139           "@pw_toolchain//features:c++17",
140       ],
141       target_cpu = "x86_64",
142       target_system_name = "x86_64-unknown-linux-gnu",
143       toolchain_identifier = "host-toolchain-linux",
144   )
145
146   # Toolchain resolution parameters for the above C/C++ toolchain.
147   toolchain(
148       name = "host_cc_toolchain_linux",
149       exec_compatible_with = [
150           "@platforms//os:linux",
151       ],
152       target_compatible_with = [
153           "@platforms//os:linux",
154       ],
155       toolchain = ":host_toolchain_linux",
156       toolchain_type = "@bazel_tools//tools/cpp:toolchain_type",
157   )
158
1592. Provide standard toolchain building-blocks
160=============================================
161Pigweed will build out a repository of sharable instantiations of the
162aforementioned custom rules to give projects the resources they need to quickly
163and easily assemble toolchains for desktop and embedded targets. This includes,
164but is not limited to:
165
166- Rules that define tool sets for common toolchains (LLVM/clang, GNU/gcc).
167- Fully specified, modular
168  `features <https://bazel.build/docs/cc-toolchain-config-reference#features>`_.
169- Common flag sets that users may want to apply directly to their toolchains.
170  (enabling/disabling warnings, C++ standard version, etc.)
171- Platform/architecture support rules, including host OS SDK integrations
172  (Xcode, Windows SDK) and architecture-specific flag sets.
173
174These components will help establish patterns that will make it significantly
175easier for Pigweed users (and Bazel users at large) to define their own
176toolchains.
177
178---------------------
179Problem investigation
180---------------------
181This section explores previous work, and details why existing solutions don't
182meet Pigweed's needs.
183
184bazelembedded/rules_cc_toolchain
185================================
186The `rules_cc_toolchain <https://github.com/bazelembedded/rules_cc_toolchain>`_
187as part of the larger bazelembedded suite was actually the initial foundation
188of Pigweed's Bazel build. While this served as a very good initial foundation,
189it didn't provide the flexibility needed to easily stand up additional
190toolchains in ways that gave downstream projects sufficient control over the
191flags, libraries, tools, and sysroot.
192
193To work around the limited configurability of toolchain flags, Pigweed employed
194the following workarounds:
195
196#. Place ``copts`` and ``linkopts`` in ``.bazelrc``: This was problematic
197   because ``.bazelrc`` is not intrinsically shared with or propagated to
198   downstream users of Pigweed. Also, flags here are unilaterally applied
199   without OS-specific considerations.
200#. Attach flags to build targets with custom wrappers: This approach
201   intrinsically requires the existence of the ``pw_cc_library``, which
202   introduces difficulty around consistent interoperability with other Bazel
203   projects (among other issues detailed in
204   `b/267498492 <https://issues.pigweed.dev/issues/267498492>`_).
205
206Some other issues encountered when working with this solution include:
207
208- These rules intended to be modular, but in practice were relatively tightly
209  coupled.
210- Transitive dependencies throughout the toolchain definition process resulted
211  in some hard-to-debug issues (see
212  `this pull request <https://github.com/bazelembedded/rules_cc_toolchain/pull/39>`_
213  and `b/254518544 <https://issues.pigweed.dev/issues/254518544>`_.
214
215bazelembedded/modular_cc_toolchains
216===================================
217The `modular_cc_toolchains <https://github.com/bazelembedded/modular_cc_toolchains>`_
218repository is a new attempt as part of the bazelembedded suite at providing
219truly modular toolchain rules. The proposed direction is much more in-line
220with the needs of Pigweed, but at the moment the repository exists as an
221initial draft of ideas rather than a complete implementation.
222
223This repository greatly inspired Pigweed's initial prototype for modular
224toolchains, but diverges significantly from the underlying Bazel C/C++
225toolchain building-blocks. If this work was already complete and
226well-established, it probably would have satisfied some of Pigweed's key needs.
227
228lowRISC/crt
229===========
230The `compiler repository toolkit <https://github.com/lowRISC/crt>`_ is another
231scalable approach at toolchains. This repository strives to be an all-in-one
232repository for embedded toolchains, and does a very good job at providing
233scalable models for establishing toolchains. This repository is relatively
234monolithic, though, and doesn't necessarily address the concern of quickly
235and easily standing up custom toolchains. Instead, it's more suited towards
236contributing new one-size-fits-all toolchains to ``crt`` directly.
237
238Android's toolchain
239===================
240Android's Bazel-based build has invested heavily in toolchains, but they're
241very tightly coupled to the use cases of Android. For example,
242`this <https://cs.android.com/android/platform/superproject/main/+/main:build/bazel/toolchains/clang/host/linux-x86/cc_toolchain_features.bzl;l=375-389;drc=097d710c349758fc2732497fe5c3d1b0a32fa4a8>`_ binds ``-fstrict-aliasing`` to a condition based on the target architecture.
243These toolchains scale for the purpose of Android, but unfortunately are
244inherently not modular or reusable outside of that context.
245
246Due to the sheer amount of investment in these toolchains, though, they serve
247as a good reference for building out a complete toolchain in Bazel.
248
249Pigweed's modular Bazel toolchain prototype
250===========================================
251As part of an exploratory phase of getting toolchains set up for Linux and
252macOS,
253`an initial prototype <https://pigweed-review.googlesource.com/c/pigweed/pigweed/+/157634>`_
254for modular Bazel toolchains was drafted and deployed to Pigweed. This work
255introduced two key build rules: ``pw_cc_toolchain_feature`` and
256``pw_cc_toolchain``. With both of these rules, it’s possible to instantiate a
257vast array of toolchain variants without writing a single line of Starlark. A
258few examples of these building blocks in action are provided below.
259
260.. code-block::
261
262   # pw_cc_toolchain example taken from https://cs.opensource.google/pigweed/pigweed/+/main:pw_toolchain/host_clang/BUILD.bazel;l=113-143;drc=7df1768d915fe11dae05751f70f143e60acfb17a.
263
264   pw_cc_toolchain(
265       name = "host_toolchain_linux",
266       abi_libc_version = "unknown",
267       abi_version = "unknown",
268       all_files = ":all_linux_files",
269       ar = "@llvm_toolchain//:bin/llvm-ar",
270
271       # TODO: b/305737273 - Globbing all files for every action has a
272       # performance hit, make these more granular.
273       ar_files = ":all_linux_files",
274       as_files = ":all_linux_files",
275       compiler = "unknown",
276       compiler_files = ":all_linux_files",
277       coverage_files = ":all_linux_files",
278       cpp = "@llvm_toolchain//:bin/clang++",
279       dwp_files = ":all_linux_files",
280       feature_deps = [
281           ":linux_sysroot",
282            "@pw_toolchain//features:no_canonical_prefixes",
283       ],
284       gcc = "@llvm_toolchain//:bin/clang",
285       gcov = "@llvm_toolchain//:bin/llvm-cov",
286       host_system_name = "unknown",
287       ld = "@llvm_toolchain//:bin/clang++",
288       linker_files = ":all_linux_files",
289       objcopy_files = ":all_linux_files",
290       strip = "@llvm_toolchain//:bin/llvm-strip",
291       strip_files = ":all_linux_files",
292       supports_param_files = 0,
293       target_cpu = "unknown",
294       target_libc = "unknown",
295       target_system_name = "unknown",
296       toolchain_identifier = "host-toolchain-linux",
297   )
298
299   # pw_cc_toolchain_feature examples taken from https://cs.opensource.google/pigweed/pigweed/+/main:pw_toolchain_bazel/features/BUILD.bazel;l=21-34;drc=f96fd31675d136bd37a7f3840102cb256d555cea.
300
301   # Disables linking of the default C++ standard library to allow linking of a
302   # different version.
303   pw_cc_toolchain_feature(
304       name = "no_default_cpp_stdlib",
305       linkopts = ["-nostdlib++"],
306   )
307
308   # Prevent relative paths from being converted to absolute paths.
309   # Note: This initial prototype made this a feature, but it should instead
310   # exist as a flag_set.
311   pw_cc_toolchain_feature(
312       name = "no_canonical_prefixes",
313       copts = [
314           "-no-canonical-prefixes",
315       ],
316   )
317
318What’s worth noting is that the ``pw_cc_toolchain_feature`` build rule looks
319very similar to a GN ``config``. This was no mistake, and was an attempt to
320substantially reduce the boiler plate for creating new sharable compiler flag
321groups.
322
323Unfortunately, it quickly became apparent that this approach limited control
324over the underlying toolchain definition creation process. In order to support
325``always_link`` on macOS, a custom logic and flags had to be directly baked into
326the rule used to declare toolchains
327(`relevant change <https://pigweed-review.googlesource.com/c/pigweed/pigweed/+/168614/17/pw_toolchain_bazel/cc_toolchain/private/cc_toolchain.bzl>`_).
328While workarounds like this should be possible, the fact that this had to be
329upstreamed internally to ``pw_cc_toolchain`` exposed limitations in the
330abstraction patterns that were established. Such limitations could preclude
331some project from using ``pw_cc_toolchain`` at all.
332
333---------------
334Detailed design
335---------------
336The core design proposal is to transform the providers used by
337``cc_common.create_cc_toolchain_config_info()`` into build rules. The approach
338has been prototyped
339`here <https://pigweed-review.googlesource.com/c/pigweed/pigweed/+/168351/1>`_,
340and retains API compatibility with the initial prototype as a proof-of-concept.
341
342One core pattern established by this design is transforming content that would
343typically live as Starlark to instead live in build files. This is done to
344make it easier to read and reference existing work.
345
346Implementation requirements
347===========================
348Compatibility with native C/C++ rules
349-------------------------------------
350The core of Pigweed's toolchain build rules will rely on the providers
351defined as part of Bazel's
352`rules_cc <https://github.com/bazelbuild/rules_cc/blob/main/cc/cc_toolchain_config_lib.bzl>`_. This means that the new rules can interop with
353existing work that directly uses these toolchain primitives. It also provides
354a clear path for migrating existing toolchains piece-by-piece (which may be
355written completely in Starlark).
356
357Any extensions beyond the existing providers (e.g. specifying
358``additional_files`` on a ``pw_cc_tool``) must happen parallel to existing
359providers so that rules that consume the ``cc_toolchain_config_lib`` providers
360can work with vanilla providers.
361
362Compatibility with Bazel rules ecosystem
363----------------------------------------
364In following with the larger Bazel rules ecosystem, the toolchain building
365blocks will be designed such that they can be used independently from Pigweed.
366This allows this work to be used for non-embedded projects, and reduces the
367overhead for standing up a custom Bazel C/C++ toolchain in any arbitrary
368project.
369
370Initially, the work will live as ``pw_toolchain_bazel`` in the main Pigweed
371repository to facilitate testing. This module must not depend on any other
372aspects of Pigweed. As the toolchain rules mature, they will eventually be
373available as a separate repository to match the modularity patterns used by
374the larger Bazel rules ecosystem.
375
376Introduce ``pw_cc_flag_set`` and ``pw_cc_flag_group``
377=====================================================
378The majority of build flags would be expressed as ``pw_cc_flag_set`` and
379``pw_cc_flag_group`` pairs.
380
381.. code-block::
382
383   # A simple flag_set with a single flag.
384   pw_cc_flag_set(
385       name = "werror",
386       # Only applies to C/C++ compile actions (i.e. no assemble/link/ar).
387       actions = ALL_CPP_COMPILER_ACTIONS + ALL_C_COMPILER_ACTIONS,
388       flags = [
389           "-Werror",
390       ],
391   )
392
393   # A flag_group that potentially expands to multiple flags.
394   pw_cc_flag_group(
395       name = "user_compile_options_flags",
396       flags = ["%{user_compile_flags}"],
397       iterate_over = "user_compile_flags",
398       expand_if_available = "user_compile_flags",
399   )
400
401   # A flag_set that relies on a non-trivial or non-constant expression of
402   # flags.
403   pw_cc_flag_set(
404       name = "user_compile_options",
405       actions = ALL_COMPILE_ACTIONS,
406       flag_groups = [
407           ":user_compile_options_flags",
408       ]
409   )
410
411These closely mimic the API of ``cc_toolchain_config_lib.flag_set()`` and
412``cc_toolchain_config_lib.flag_group()``, with the following exceptions:
413
414**pw_cc_flag_set**
415
416*Added*
417
418- ``flags`` (added): Express a constant, trivial list of flags. If this is
419  specified, ``flag_groups`` may not be specified. This eliminates the need
420  for specifying a corresponding ``pw_cc_flag_group`` for every
421  ``pw_cc_flag_set`` for most flags.
422
423**pw_cc_flag_group**
424
425*Removed*
426
427- ``expand_if_true``\, ``expand_if_false``\, ``expand_if_equal``\: More complex
428  rules that rely on these should live as custom Starlark rules that provide a
429  ``FlagGroupInfo``\, or ``FlagSetInfo`` (depending on which is more ergonomic
430  to express the intent). See :ref:`pw_cc_flag_set-exceptions` below for an
431  example that illustrates how express more complex ``flag_group``\s that rely
432  on these attributes.
433
434Application of flags
435--------------------
436Flags can be applied to a toolchain in three ways. This section attempts to
437provide initial guidance for where flags should be applied, though it's likely
438better practices will evolve as this work sees more use. For the latest
439guidance, please consult the official documentation when it rolls out to
440``pw_toolchain_bazel``.
441
442Flags unconditionally applied to a toolchain
443~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
444The majority of flags fall into this category. Architecture flags,
445globally-applied warnings, global defines, and other similar flags should be
446applied in the ``action_config_flag_sets`` attribute of a ``pw_cc_toolchain``
447(see :ref:`pw_cc_toolchain-toolchain-declarations` for more information). Each
448``pw_cc_flag_set`` (or other rule that provides a ``FlagSetInfo`` provider)
449listed in ``action_config_flag_sets`` is unconditionally applied to every tool
450that matches the ``actions`` listed in the flag set.
451
452.. _application-of-flags-feature-flags:
453
454Feature flags
455~~~~~~~~~~~~~
456Flag sets applied as features may or may not be enabled even if they are listed
457in the ``features`` attribute of a ``pw_cc_toolchain``. The
458`official Bazel documentation on features <https://bazel.build/docs/cc-toolchain-config-reference#features>`_
459provides some good guidance on when features should be employed. To summarize,
460features should be used when either they should be controllable by users
461invoking the build, or if they affect build behavior beyond simply
462adding/removing flags (e.g. by introducing additional build actions).
463
464Flags unconditionally applied to a tool
465~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
466These flags are flags that are bound to a particular tool. These are not
467expressed as part of a ``pw_cc_toolchain``, and are instead bound to a
468``pw_cc_action_config``. This means that the flag set is unconditionally
469applied to every user of that action config. These kinds of flag applications
470should be reserved for flags required to assemble a working set of tools (such
471as generating a depfile, or adding support for static library link handling
472:ref:`as illustrated below <pw_cc_flag_set-exceptions>`).
473
474Flag application order
475~~~~~~~~~~~~~~~~~~~~~~
476When invoking the underlying tools, the intended order of flags is as follows:
477
478#. Flags listed in the ``flag_sets`` list of a ``pw_cc_action_config``.
479#. Flags listed in ``action_config_flag_sets`` of a ``pw_cc_toolchain``.
480#. Flags listed in ``features`` of a ``pw_cc_toolchain``.
481
482These lists are intended to be sensitive to ordering, earlier items in the lists
483should appear in the final tool invocation flags before later items in the list.
484
485As transitive dependencies between features/flags are not supported as part of
486this proposal, exact traversal of transitive flag dependencies will be left
487to be decided if/when that feature is introduced. This proposal suggests
488postorder handling of flags as the most intuitive order.
489
490.. _pw_cc_flag_set-exceptions:
491
492Exceptions
493----------
494Some flags are too complex to be nicely expressed in a Bazel build file. These
495flag sets or flag groups will need to be expressed in Starlark as custom rules.
496Fortunately, this will interop well with simpler flag sets since the underlying
497providers are all the same.
498
499**Example**
500
501In a Starlark file (e.g. ``//tools/llvm/llvm_ar_patch.bzl``), the required
502``flag_set`` can be defined:
503
504.. code-block::
505
506   # Starlark rules in a .bzl file for a relatively complicated workaround for
507   # what would normally be inherently managed by Bazel internally.
508   # TODO: b/297413805 - Remove this implementation.
509
510   def _pw_cc_static_libs_to_link_impl():
511      """Returns a flag_set provider that sets up static libraries to link."""
512      return flag_set(
513               actions = [
514                   ACTION_NAMES.cpp_link_static_library,
515               ],
516               flag_groups = [
517                   flag_group(
518                       expand_if_available = "libraries_to_link",
519                       iterate_over = "libraries_to_link",
520                       flag_groups = [
521                           flag_group(
522                               expand_if_equal = variable_with_value(
523                                   name = "libraries_to_link.type",
524                                   value = "object_file",
525                               ),
526                               flags = ["%{libraries_to_link.name}"],
527                           ),
528                           flag_group(
529                               expand_if_equal = variable_with_value(
530                                   name = "libraries_to_link.type",
531                                   value = "object_file_group",
532                               ),
533                               flags = ["%{libraries_to_link.object_files}"],
534                               iterate_over = "libraries_to_link.object_files",
535                           ),
536                       ],
537                   ),
538               ],
539           )
540
541   pw_cc_static_libs_to_link = rule(
542       implementation = _pw_cc_static_libs_to_link_impl,
543       provides = [FlagSetInfo],
544   )
545
546And then in the ``BUILD.bazel`` file, the rules would be used as if they
547were a ``pw_cc_flag_set``:
548
549.. code-block::
550
551   load(
552       "@pw_toolchain//tools/llvm:llvm_ar_patch.bzl",
553       "pw_cc_static_libs_to_link"
554   )
555
556   pw_cc_static_libs_to_link(
557       name = "static_library_action_flags",
558   )
559
560   pw_cc_action_config(
561       name = "llvm_ar",
562       actions = ACTION_NAMES.cpp_link_static_library,
563       tools = [
564           ":llvm_ar_tool",
565       ],
566       flag_sets = [
567           ":static_library_action_flags",
568       ],
569   )
570
571Introduce ``pw_cc_feature`` and ``pw_cc_feature_set``
572=====================================================
573These types are just permutations of the ``cc_toolchain_config_lib.feature()``
574and ``cc_toolchain_config_lib.with_feature_set()`` API. For guidance on when
575these should be used, see
576:ref:`application of feature flags <application-of-flags-feature-flags>`.
577
578.. code-block::
579
580   pw_cc_feature_set(
581       name = "static_pie_requirements",
582       with_features = ["pie"],
583       # If this doesn't work when certain features are enabled, they should
584       # be specified as ``without_features``.
585   )
586
587   pw_cc_feature(
588       name = "static_pie",
589       flag_sets = [
590           "//flag_sets:static_pie",
591       ],
592       implies = ["static_link_flag"],
593       requires = [
594           ":static_pie_requirements",
595       ],
596   )
597
598Introduce ``pw_cc_action_config`` and ``pw_cc_tool``
599====================================================
600These are closely related to the ``ActionConfigInfo`` and ``ToolInfo``
601providers, but allow additional files to be attached and a list of actions to
602be attached rather than a single action.
603
604.. code-block::
605
606   pw_cc_tool(
607       name = "clang_tool",
608       path = "@llvm_toolchain//:bin/clang",
609       additional_files = [
610           "@llvm_toolchain//:all",
611       ],
612   )
613
614   pw_cc_action_config(
615       name = "clang",
616       actions = ALL_ASM_ACTIONS + ALL_C_COMPILER_ACTIONS,
617       tools = [
618           ":clang_tool",
619       ],
620       flag_sets = [
621           # Most flags should NOT end up here. Only unconditional flags that
622           # should ALWAYS be bound to this tool (e.g. static library
623           # workaround fix for macOS).
624           "//flag_sets:generate_depfile",
625       ],
626   )
627
628.. _pw_cc_toolchain-toolchain-declarations:
629
630Toolchain declarations
631======================
632In following with the other proposed rules, ``pw_cc_toolchain`` largely
633follows the API of ``cc_common.create_cc_toolchain_config_info()``. Most of the
634attributes are logically passed through, with the following exceptions:
635
636- **action_config_flag_sets**: Flag sets to apply to action configs. Since flag
637  sets are intrinsically bound to actions, there’s no need to divide them at
638  this level.
639- **additional_files**: Now that tools can spec out required files, those
640  should be propagated and mostly managed internally. The ``\*_files`` members
641  will still be available, but shouldn’t see much use. additional_files is like
642  “all_files”, but applies to all action_configs.
643
644.. code-block::
645
646   pw_cc_toolchain(
647       name = "host_toolchain_linux",
648       abi_libc_version = "unknown",  # We should consider how to move this out in the future.
649       abi_version = "unknown",
650       action_configs = [
651           "@llvm_toolchain//tools:clang",
652           "@llvm_toolchain//tools:clang++",
653           "@llvm_toolchain//tools:lld",
654           "@llvm_toolchain//tools:llvm_ar",
655           "@llvm_toolchain//tools:llvm_cov",
656           "@llvm_toolchain//tools:llvm_strip",
657       ],
658       additional_files = ":linux_sysroot_files",
659       action_config_flag_sets = [
660           ":linux_sysroot",
661           "@pw_toolchain//flag_collections:strict_warnings",
662           "@pw_toolchain//flag_sets:no_canonical_prefixes",
663       ],
664       features = [
665           "@pw_toolchain//features:c++17",
666       ],
667       host_system_name = "unknown",
668       supports_param_files = 0,  # Seems like this should be attached to a pw_cc_action_config...
669       target_cpu = "unknown",
670       target_libc = "unknown",
671       target_system_name = "unknown",
672       toolchain_identifier = "host-toolchain-linux",
673       cxx_builtin_include_directories = [
674           "%package(@llvm_toolchain//)%/include/x86_64-unknown-linux-gnu/c++/v1",
675           "%package(@llvm_toolchain//)%/include/c++/v1",
676           "%package(@llvm_toolchain//)%/lib/clang/17/include",
677           "%sysroot%/usr/local/include",
678           "%sysroot%/usr/include/x86_64-linux-gnu",
679           "%sysroot%/usr/include",
680       ],
681   )
682
683------------
684Alternatives
685------------
686Improve Bazel's native C/C++ toolchain rules
687============================================
688Improving Bazel's native rules for defining C/C++ toolchains is out of the
689scope of Pigweed's work. Changing the underlying toolchain API as Bazel
690understands it is a massive undertaking from the perspective of migrating
691existing code. We hope that the custom rule effort can help guide future
692decisions when it comes to toolchain scalability and maintainability.
693
694----------
695Next steps
696----------
697Rust toolchain interop
698======================
699Pigweed's Rust toolchains have some interoperability concerns and requirements.
700The extend of this needs to be thoroughly investigated as a next step to ensure
701that the Rust/C/C++ toolchain experience is relatively unified and ergonomic.
702
703More maintainable ``cxx_builtin_include_directories``
704=====================================================
705In the future, it would be nice to have a more sharable solution for managing
706``cxx_builtin_include_directories`` on a ``pw_cc_toolchain``. This could
707plausibly be done by allowing ``pw_cc_flag_set`` to express
708``cxx_builtin_include_directories`` so they can be propagated back up to the
709``pw_cc_toolchain``.
710
711Feature name collision guidance
712===============================
713Features support relatively complex relationships among each other, but
714traditionally rely on string names to express these relationships rather than
715labels. This introduces significant ambiguity, as it's possible for multiple
716features to use the same logical name so long as they aren't both employed in
717the same toolchain. In practice, the only way to tell what features will end up
718enabled is to manually unpack what features a toolchain pulls in, and
719cross-reference it against the output of
720`--experimental_save_feature_state <https://bazel.build/reference/command-line-reference#flag--experimental_save_feature_state>`_.
721
722One potential solution to this problem is to add a mechanism for expressing
723features as labels, which will allow relationships to be expressed more
724concretely, and help prevent unintended naming collisions. This would not
725replace the ability to express relationships with features not accessible via
726labels, but rather live alongside it.
727