aboutsummaryrefslogtreecommitdiff
path: root/seed/0113-bazel-cc-toolchain-api.rst
diff options
context:
space:
mode:
Diffstat (limited to 'seed/0113-bazel-cc-toolchain-api.rst')
-rw-r--r--seed/0113-bazel-cc-toolchain-api.rst724
1 files changed, 724 insertions, 0 deletions
diff --git a/seed/0113-bazel-cc-toolchain-api.rst b/seed/0113-bazel-cc-toolchain-api.rst
new file mode 100644
index 000000000..758e32350
--- /dev/null
+++ b/seed/0113-bazel-cc-toolchain-api.rst
@@ -0,0 +1,724 @@
+.. _seed-0113:
+
+===========================================
+0113: Add modular Bazel C/C++ toolchain API
+===========================================
+.. seed::
+ :number: 0113
+ :name: Add modular Bazel C/C++ toolchain API
+ :status: Accepted
+ :proposal_date: 2023-09-28
+ :cl: 173453
+
+-------
+Summary
+-------
+This SEED proposes custom Starlark rules for declaring C/C++ toolchains in
+Bazel, and scalable patterns for sharing modular components of C/C++ toolchain
+definitions.
+
+----------
+Motivation
+----------
+There is a lot of boilerplate involved in standing up a Bazel C/C++ toolchain.
+While a good portion of the verbosity of specifying a new toolchain is
+important, necessary machinery, nearly as much suffers from one or more of the
+following problems:
+
+- **Underdocumented patterns**: The
+ `create_cc_toolchain_config_info() <https://bazel.build/rules/lib/toplevel/cc_common#create_cc_toolchain_config_info>`_
+ method has an attribute called ``target_cpu`` that doesn't have an associated
+ list of expected values, which suggests the argument is for bookkeeping
+ purposes and doesn't affect Bazel behavior. The reality is this argument
+ *does* have expected values that change behavior, but these are undocumented
+ (see `this GitHub issue <https://github.com/bazelbuild/bazel/issues/19353>`_
+ for more information).
+
+- **Not inherently modular**: Bazel expects the overwhelming majority of a
+ C/C++ toolchain to be specified as part of a call to
+ ``create_cc_toolchain_config_info()``. Because this is a Starlark method,
+ there's a lot of flexibility with how you construct a toolchain config, but
+ very little by way of existing patterns for creating something that is
+ testable, sharable, or in other ways modular. The existing
+ `tutorial for creating a C/C++ toolchain <https://bazel.build/tutorials/ccp-toolchain-config#configuring_the_c_toolchain>`_
+ illustrates expanding out the toolchain definition as a no-argument Starlark
+ rule.
+
+As Pigweed fully embraces multi-platform builds, it is critical for both
+Pigweed and users of Pigweed that it is easy to stand up custom toolchain
+definitions that work for the relevant hardware project-specific code/libraries.
+
+This SEED seeks to address the shortcomings in Bazel C/C++ toolchain
+declaration by establishing patterns and providing custom build rules that
+are owned and maintained by Pigweed.
+
+--------
+Proposal
+--------
+1. Introduce rules for defining C/C++ toolchains
+================================================
+In an effort to improve the experience of defining a C/C++ toolchain, Pigweed
+will introduce new Bazel rules that allow toolchains to share common boilerplate
+without hindering power-user functionality.
+
+While this work centers around an improved experience for defining a toolchain
+via ``create_cc_toolchain_config_info()``, other build rules will be introduced
+for closely related aspects of the toolchain definition process.
+
+An example of what these rules would look like in practice is as follows:
+
+.. code-block::
+
+ # A tool that can be used by various build actions.
+ pw_cc_tool(
+ name = "clang_tool",
+ path = "@cipd_llvm_toolchain//:bin/clang",
+ additional_files = [
+ "@cipd_llvm_toolchain//:all",
+ ],
+ )
+
+ # A mapping of a tool to actions, with flag sets that define behaviors.
+ pw_cc_action_config(
+ name = "clang",
+ actions = ALL_ASM_ACTIONS + ALL_C_COMPILER_ACTIONS,
+ tools = [
+ ":clang_tool",
+ ],
+ flag_sets = [
+ # Most flags should NOT end up here. Only unconditional flags that
+ # should ALWAYS be bound to this tool (e.g. static library
+ # workaround fix for macOS).
+ "@pw_toolchain//flag_sets:generate_depfile",
+ ],
+ )
+
+ # A trivial flag to be consumed by a C/C++ toolchain.
+ pw_cc_flag_set(
+ name = "werror",
+ actions = ALL_COMPILE_ACTIONS,
+ flags = [
+ "-Werror",
+ ],
+ )
+
+ # A list of flags that can be added to a toolchain configuration.
+ pw_cc_flag_set(
+ name = "user_compile_options",
+ actions = ALL_COMPILE_ACTIONS,
+ flag_groups = [
+ ":user_compile_options_flags",
+ ]
+ )
+
+ # A more complex compiler flag that requires template expansion.
+ pw_cc_flag_group(
+ name = "user_compile_options_flags",
+ flags = ["%{user_compile_flags}"],
+ iterate_over = "user_compile_flags",
+ expand_if_available = "user_compile_flags",
+ )
+
+ # The underlying definition of a complete C/C++ toolchain.
+ pw_cc_toolchain(
+ name = "host_toolchain_linux",
+ action_configs = [
+ ":clang",
+ ":clang++",
+ # ...
+ ],
+ additional_files = ":linux_sysroot_files",
+ action_config_flag_sets = [
+ "@pw_toolchain//flag_sets:no_canonical_prefixes",
+ ":user_compile_options",
+ ":werror",
+ ],
+ features = [
+ "@pw_toolchain//features:c++17",
+ ],
+ target_cpu = "x86_64",
+ target_system_name = "x86_64-unknown-linux-gnu",
+ toolchain_identifier = "host-toolchain-linux",
+ )
+
+ # Toolchain resolution parameters for the above C/C++ toolchain.
+ toolchain(
+ name = "host_cc_toolchain_linux",
+ exec_compatible_with = [
+ "@platforms//os:linux",
+ ],
+ target_compatible_with = [
+ "@platforms//os:linux",
+ ],
+ toolchain = ":host_toolchain_linux",
+ toolchain_type = "@bazel_tools//tools/cpp:toolchain_type",
+ )
+
+2. Provide standard toolchain building-blocks
+=============================================
+Pigweed will build out a repository of sharable instantiations of the
+aforementioned custom rules to give projects the resources they need to quickly
+and easily assemble toolchains for desktop and embedded targets. This includes,
+but is not limited to:
+
+- Rules that define tool sets for common toolchains (LLVM/clang, GNU/gcc).
+- Fully specified, modular
+ `features <https://bazel.build/docs/cc-toolchain-config-reference#features>`_.
+- Common flag sets that users may want to apply directly to their toolchains.
+ (enabling/disabling warnings, C++ standard version, etc.)
+- Platform/architecture support rules, including host OS SDK integrations
+ (Xcode, Windows SDK) and architecture-specific flag sets.
+
+These components will help establish patterns that will make it significantly
+easier for Pigweed users (and Bazel users at large) to define their own
+toolchains.
+
+---------------------
+Problem investigation
+---------------------
+This section explores previous work, and details why existing solutions don't
+meet Pigweed's needs.
+
+bazelembedded/rules_cc_toolchain
+================================
+The `rules_cc_toolchain <https://github.com/bazelembedded/rules_cc_toolchain>`_
+as part of the larger bazelembedded suite was actually the initial foundation
+of Pigweed's Bazel build. While this served as a very good initial foundation,
+it didn't provide the flexibility needed to easily stand up additional
+toolchains in ways that gave downstream projects sufficient control over the
+flags, libraries, tools, and sysroot.
+
+To work around the limited configurability of toolchain flags, Pigweed employed
+the following workarounds:
+
+#. Place ``copts`` and ``linkopts`` in ``.bazelrc``: This was problematic
+ because ``.bazelrc`` is not intrinsically shared with or propagated to
+ downstream users of Pigweed. Also, flags here are unilaterally applied
+ without OS-specific considerations.
+#. Attach flags to build targets with custom wrappers: This approach
+ intrinsically requires the existence of the ``pw_cc_library``, which
+ introduces difficulty around consistent interoperability with other Bazel
+ projects (among other issues detailed in
+ `b/267498492 <https://issues.pigweed.dev/issues/267498492>`_).
+
+Some other issues encountered when working with this solution include:
+
+- These rules intended to be modular, but in practice were relatively tightly
+ coupled.
+- Transitive dependencies throughout the toolchain definition process resulted
+ in some hard-to-debug issues (see
+ `this pull request <https://github.com/bazelembedded/rules_cc_toolchain/pull/39>`_
+ and `b/254518544 <https://issues.pigweed.dev/issues/254518544>`_.
+
+bazelembedded/modular_cc_toolchains
+===================================
+The `modular_cc_toolchains <https://github.com/bazelembedded/modular_cc_toolchains>`_
+repository is a new attempt as part of the bazelembedded suite at providing
+truly modular toolchain rules. The proposed direction is much more in-line
+with the needs of Pigweed, but at the moment the repository exists as an
+initial draft of ideas rather than a complete implementation.
+
+This repository greatly inspired Pigweed's initial prototype for modular
+toolchains, but diverges significantly from the underlying Bazel C/C++
+toolchain building-blocks. If this work was already complete and
+well-established, it probably would have satisfied some of Pigweed's key needs.
+
+lowRISC/crt
+===========
+The `compiler repository toolkit <https://github.com/lowRISC/crt>`_ is another
+scalable approach at toolchains. This repository strives to be an all-in-one
+repository for embedded toolchains, and does a very good job at providing
+scalable models for establishing toolchains. This repository is relatively
+monolithic, though, and doesn't necessarily address the concern of quickly
+and easily standing up custom toolchains. Instead, it's more suited towards
+contributing new one-size-fits-all toolchains to ``crt`` directly.
+
+Android's toolchain
+===================
+Android's Bazel-based build has invested heavily in toolchains, but they're
+very tightly coupled to the use cases of Android. For example,
+`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.
+These toolchains scale for the purpose of Android, but unfortunately are
+inherently not modular or reusable outside of that context.
+
+Due to the sheer amount of investment in these toolchains, though, they serve
+as a good reference for building out a complete toolchain in Bazel.
+
+Pigweed's modular Bazel toolchain prototype
+===========================================
+As part of an exploratory phase of getting toolchains set up for Linux and
+macOS,
+`an initial prototype <https://pigweed-review.googlesource.com/c/pigweed/pigweed/+/157634>`_
+for modular Bazel toolchains was drafted and deployed to Pigweed. This work
+introduced two key build rules: ``pw_cc_toolchain_feature`` and
+``pw_cc_toolchain``. With both of these rules, it’s possible to instantiate a
+vast array of toolchain variants without writing a single line of Starlark. A
+few examples of these building blocks in action are provided below.
+
+.. code-block::
+
+ # pw_cc_toolchain example taken from https://cs.opensource.google/pigweed/pigweed/+/main:pw_toolchain/host_clang/BUILD.bazel;l=113-143;drc=7df1768d915fe11dae05751f70f143e60acfb17a.
+
+ pw_cc_toolchain(
+ name = "host_toolchain_linux",
+ abi_libc_version = "unknown",
+ abi_version = "unknown",
+ all_files = ":all_linux_files",
+ ar = "@llvm_toolchain//:bin/llvm-ar",
+
+ # TODO: b/305737273 - Globbing all files for every action has a
+ # performance hit, make these more granular.
+ ar_files = ":all_linux_files",
+ as_files = ":all_linux_files",
+ compiler = "unknown",
+ compiler_files = ":all_linux_files",
+ coverage_files = ":all_linux_files",
+ cpp = "@llvm_toolchain//:bin/clang++",
+ dwp_files = ":all_linux_files",
+ feature_deps = [
+ ":linux_sysroot",
+ "@pw_toolchain//features:no_canonical_prefixes",
+ ],
+ gcc = "@llvm_toolchain//:bin/clang",
+ gcov = "@llvm_toolchain//:bin/llvm-cov",
+ host_system_name = "unknown",
+ ld = "@llvm_toolchain//:bin/clang++",
+ linker_files = ":all_linux_files",
+ objcopy_files = ":all_linux_files",
+ strip = "@llvm_toolchain//:bin/llvm-strip",
+ strip_files = ":all_linux_files",
+ supports_param_files = 0,
+ target_cpu = "unknown",
+ target_libc = "unknown",
+ target_system_name = "unknown",
+ toolchain_identifier = "host-toolchain-linux",
+ )
+
+ # 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.
+
+ # Disables linking of the default C++ standard library to allow linking of a
+ # different version.
+ pw_cc_toolchain_feature(
+ name = "no_default_cpp_stdlib",
+ linkopts = ["-nostdlib++"],
+ )
+
+ # Prevent relative paths from being converted to absolute paths.
+ # Note: This initial prototype made this a feature, but it should instead
+ # exist as a flag_set.
+ pw_cc_toolchain_feature(
+ name = "no_canonical_prefixes",
+ copts = [
+ "-no-canonical-prefixes",
+ ],
+ )
+
+What’s worth noting is that the ``pw_cc_toolchain_feature`` build rule looks
+very similar to a GN ``config``. This was no mistake, and was an attempt to
+substantially reduce the boiler plate for creating new sharable compiler flag
+groups.
+
+Unfortunately, it quickly became apparent that this approach limited control
+over the underlying toolchain definition creation process. In order to support
+``always_link`` on macOS, a custom logic and flags had to be directly baked into
+the rule used to declare toolchains
+(`relevant change <https://pigweed-review.googlesource.com/c/pigweed/pigweed/+/168614/17/pw_toolchain_bazel/cc_toolchain/private/cc_toolchain.bzl>`_).
+While workarounds like this should be possible, the fact that this had to be
+upstreamed internally to ``pw_cc_toolchain`` exposed limitations in the
+abstraction patterns that were established. Such limitations could preclude
+some project from using ``pw_cc_toolchain`` at all.
+
+---------------
+Detailed design
+---------------
+The core design proposal is to transform the providers used by
+``cc_common.create_cc_toolchain_config_info()`` into build rules. The approach
+has been prototyped
+`here <https://pigweed-review.googlesource.com/c/pigweed/pigweed/+/168351/1>`_,
+and retains API compatibility with the initial prototype as a proof-of-concept.
+
+One core pattern established by this design is transforming content that would
+typically live as Starlark to instead live in build files. This is done to
+make it easier to read and reference existing work.
+
+Implementation requirements
+===========================
+Compatibility with native C/C++ rules
+-------------------------------------
+The core of Pigweed's toolchain build rules will rely on the providers
+defined as part of Bazel's
+`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
+existing work that directly uses these toolchain primitives. It also provides
+a clear path for migrating existing toolchains piece-by-piece (which may be
+written completely in Starlark).
+
+Any extensions beyond the existing providers (e.g. specifying
+``additional_files`` on a ``pw_cc_tool``) must happen parallel to existing
+providers so that rules that consume the ``cc_toolchain_config_lib`` providers
+can work with vanilla providers.
+
+Compatibility with Bazel rules ecosystem
+----------------------------------------
+In following with the larger Bazel rules ecosystem, the toolchain building
+blocks will be designed such that they can be used independently from Pigweed.
+This allows this work to be used for non-embedded projects, and reduces the
+overhead for standing up a custom Bazel C/C++ toolchain in any arbitrary
+project.
+
+Initially, the work will live as ``pw_toolchain_bazel`` in the main Pigweed
+repository to facilitate testing. This module must not depend on any other
+aspects of Pigweed. As the toolchain rules mature, they will eventually be
+available as a separate repository to match the modularity patterns used by
+the larger Bazel rules ecosystem.
+
+Introduce ``pw_cc_flag_set`` and ``pw_cc_flag_group``
+=====================================================
+The majority of build flags would be expressed as ``pw_cc_flag_set`` and
+``pw_cc_flag_group`` pairs.
+
+.. code-block::
+
+ # A simple flag_set with a single flag.
+ pw_cc_flag_set(
+ name = "werror",
+ # Only applies to C/C++ compile actions (i.e. no assemble/link/ar).
+ actions = ALL_CPP_COMPILER_ACTIONS + ALL_C_COMPILER_ACTIONS,
+ flags = [
+ "-Werror",
+ ],
+ )
+
+ # A flag_group that potentially expands to multiple flags.
+ pw_cc_flag_group(
+ name = "user_compile_options_flags",
+ flags = ["%{user_compile_flags}"],
+ iterate_over = "user_compile_flags",
+ expand_if_available = "user_compile_flags",
+ )
+
+ # A flag_set that relies on a non-trivial or non-constant expression of
+ # flags.
+ pw_cc_flag_set(
+ name = "user_compile_options",
+ actions = ALL_COMPILE_ACTIONS,
+ flag_groups = [
+ ":user_compile_options_flags",
+ ]
+ )
+
+These closely mimic the API of ``cc_toolchain_config_lib.flag_set()`` and
+``cc_toolchain_config_lib.flag_group()``, with the following exceptions:
+
+**pw_cc_flag_set**
+
+*Added*
+
+- ``flags`` (added): Express a constant, trivial list of flags. If this is
+ specified, ``flag_groups`` may not be specified. This eliminates the need
+ for specifying a corresponding ``pw_cc_flag_group`` for every
+ ``pw_cc_flag_set`` for most flags.
+
+**pw_cc_flag_group**
+
+*Removed*
+
+- ``expand_if_true``\, ``expand_if_false``\, ``expand_if_equal``\: More complex
+ rules that rely on these should live as custom Starlark rules that provide a
+ ``FlagGroupInfo``\, or ``FlagSetInfo`` (depending on which is more ergonomic
+ to express the intent). See :ref:`pw_cc_flag_set-exceptions` below for an
+ example that illustrates how express more complex ``flag_group``\s that rely
+ on these attributes.
+
+Application of flags
+--------------------
+Flags can be applied to a toolchain in three ways. This section attempts to
+provide initial guidance for where flags should be applied, though it's likely
+better practices will evolve as this work sees more use. For the latest
+guidance, please consult the official documentation when it rolls out to
+``pw_toolchain_bazel``.
+
+Flags unconditionally applied to a toolchain
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+The majority of flags fall into this category. Architecture flags,
+globally-applied warnings, global defines, and other similar flags should be
+applied in the ``action_config_flag_sets`` attribute of a ``pw_cc_toolchain``
+(see :ref:`pw_cc_toolchain-toolchain-declarations` for more information). Each
+``pw_cc_flag_set`` (or other rule that provides a ``FlagSetInfo`` provider)
+listed in ``action_config_flag_sets`` is unconditionally applied to every tool
+that matches the ``actions`` listed in the flag set.
+
+.. _application-of-flags-feature-flags:
+
+Feature flags
+~~~~~~~~~~~~~
+Flag sets applied as features may or may not be enabled even if they are listed
+in the ``features`` attribute of a ``pw_cc_toolchain``. The
+`official Bazel documentation on features <https://bazel.build/docs/cc-toolchain-config-reference#features>`_
+provides some good guidance on when features should be employed. To summarize,
+features should be used when either they should be controllable by users
+invoking the build, or if they affect build behavior beyond simply
+adding/removing flags (e.g. by introducing additional build actions).
+
+Flags unconditionally applied to a tool
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+These flags are flags that are bound to a particular tool. These are not
+expressed as part of a ``pw_cc_toolchain``, and are instead bound to a
+``pw_cc_action_config``. This means that the flag set is unconditionally
+applied to every user of that action config. These kinds of flag applications
+should be reserved for flags required to assemble a working set of tools (such
+as generating a depfile, or adding support for static library link handling
+:ref:`as illustrated below <pw_cc_flag_set-exceptions>`).
+
+Flag application order
+~~~~~~~~~~~~~~~~~~~~~~
+When invoking the underlying tools, the intended order of flags is as follows:
+
+#. Flags listed in the ``flag_sets`` list of a ``pw_cc_action_config``.
+#. Flags listed in ``action_config_flag_sets`` of a ``pw_cc_toolchain``.
+#. Flags listed in ``features`` of a ``pw_cc_toolchain``.
+
+These lists are intended to be sensitive to ordering, earlier items in the lists
+should appear in the final tool invocation flags before later items in the list.
+
+As transitive dependencies between features/flags are not supported as part of
+this proposal, exact traversal of transitive flag dependencies will be left
+to be decided if/when that feature is introduced. This proposal suggests
+postorder handling of flags as the most intuitive order.
+
+.. _pw_cc_flag_set-exceptions:
+
+Exceptions
+----------
+Some flags are too complex to be nicely expressed in a Bazel build file. These
+flag sets or flag groups will need to be expressed in Starlark as custom rules.
+Fortunately, this will interop well with simpler flag sets since the underlying
+providers are all the same.
+
+**Example**
+
+In a Starlark file (e.g. ``//tools/llvm/llvm_ar_patch.bzl``), the required
+``flag_set`` can be defined:
+
+.. code-block::
+
+ # Starlark rules in a .bzl file for a relatively complicated workaround for
+ # what would normally be inherently managed by Bazel internally.
+ # TODO: b/297413805 - Remove this implementation.
+
+ def _pw_cc_static_libs_to_link_impl():
+ """Returns a flag_set provider that sets up static libraries to link."""
+ return flag_set(
+ actions = [
+ ACTION_NAMES.cpp_link_static_library,
+ ],
+ flag_groups = [
+ flag_group(
+ expand_if_available = "libraries_to_link",
+ iterate_over = "libraries_to_link",
+ flag_groups = [
+ flag_group(
+ expand_if_equal = variable_with_value(
+ name = "libraries_to_link.type",
+ value = "object_file",
+ ),
+ flags = ["%{libraries_to_link.name}"],
+ ),
+ flag_group(
+ expand_if_equal = variable_with_value(
+ name = "libraries_to_link.type",
+ value = "object_file_group",
+ ),
+ flags = ["%{libraries_to_link.object_files}"],
+ iterate_over = "libraries_to_link.object_files",
+ ),
+ ],
+ ),
+ ],
+ )
+
+ pw_cc_static_libs_to_link = rule(
+ implementation = _pw_cc_static_libs_to_link_impl,
+ provides = [FlagSetInfo],
+ )
+
+And then in the ``BUILD.bazel`` file, the rules would be used as if they
+were a ``pw_cc_flag_set``:
+
+.. code-block::
+
+ load(
+ "@pw_toolchain//tools/llvm:llvm_ar_patch.bzl",
+ "pw_cc_static_libs_to_link"
+ )
+
+ pw_cc_static_libs_to_link(
+ name = "static_library_action_flags",
+ )
+
+ pw_cc_action_config(
+ name = "llvm_ar",
+ actions = ACTION_NAMES.cpp_link_static_library,
+ tools = [
+ ":llvm_ar_tool",
+ ],
+ flag_sets = [
+ ":static_library_action_flags",
+ ],
+ )
+
+Introduce ``pw_cc_feature`` and ``pw_cc_feature_set``
+=====================================================
+These types are just permutations of the ``cc_toolchain_config_lib.feature()``
+and ``cc_toolchain_config_lib.with_feature_set()`` API. For guidance on when
+these should be used, see
+:ref:`application of feature flags <application-of-flags-feature-flags>`.
+
+.. code-block::
+
+ pw_cc_feature_set(
+ name = "static_pie_requirements",
+ with_features = ["pie"],
+ # If this doesn't work when certain features are enabled, they should
+ # be specified as ``without_features``.
+ )
+
+ pw_cc_feature(
+ name = "static_pie",
+ flag_sets = [
+ "//flag_sets:static_pie",
+ ],
+ implies = ["static_link_flag"],
+ requires = [
+ ":static_pie_requirements",
+ ],
+ )
+
+Introduce ``pw_cc_action_config`` and ``pw_cc_tool``
+====================================================
+These are closely related to the ``ActionConfigInfo`` and ``ToolInfo``
+providers, but allow additional files to be attached and a list of actions to
+be attached rather than a single action.
+
+.. code-block::
+
+ pw_cc_tool(
+ name = "clang_tool",
+ path = "@llvm_toolchain//:bin/clang",
+ additional_files = [
+ "@llvm_toolchain//:all",
+ ],
+ )
+
+ pw_cc_action_config(
+ name = "clang",
+ actions = ALL_ASM_ACTIONS + ALL_C_COMPILER_ACTIONS,
+ tools = [
+ ":clang_tool",
+ ],
+ flag_sets = [
+ # Most flags should NOT end up here. Only unconditional flags that
+ # should ALWAYS be bound to this tool (e.g. static library
+ # workaround fix for macOS).
+ "//flag_sets:generate_depfile",
+ ],
+ )
+
+.. _pw_cc_toolchain-toolchain-declarations:
+
+Toolchain declarations
+======================
+In following with the other proposed rules, ``pw_cc_toolchain`` largely
+follows the API of ``cc_common.create_cc_toolchain_config_info()``. Most of the
+attributes are logically passed through, with the following exceptions:
+
+- **action_config_flag_sets**: Flag sets to apply to action configs. Since flag
+ sets are intrinsically bound to actions, there’s no need to divide them at
+ this level.
+- **additional_files**: Now that tools can spec out required files, those
+ should be propagated and mostly managed internally. The ``\*_files`` members
+ will still be available, but shouldn’t see much use. additional_files is like
+ “all_files”, but applies to all action_configs.
+
+.. code-block::
+
+ pw_cc_toolchain(
+ name = "host_toolchain_linux",
+ abi_libc_version = "unknown", # We should consider how to move this out in the future.
+ abi_version = "unknown",
+ action_configs = [
+ "@llvm_toolchain//tools:clang",
+ "@llvm_toolchain//tools:clang++",
+ "@llvm_toolchain//tools:lld",
+ "@llvm_toolchain//tools:llvm_ar",
+ "@llvm_toolchain//tools:llvm_cov",
+ "@llvm_toolchain//tools:llvm_strip",
+ ],
+ additional_files = ":linux_sysroot_files",
+ action_config_flag_sets = [
+ ":linux_sysroot",
+ "@pw_toolchain//flag_collections:strict_warnings",
+ "@pw_toolchain//flag_sets:no_canonical_prefixes",
+ ],
+ features = [
+ "@pw_toolchain//features:c++17",
+ ],
+ host_system_name = "unknown",
+ supports_param_files = 0, # Seems like this should be attached to a pw_cc_action_config...
+ target_cpu = "unknown",
+ target_libc = "unknown",
+ target_system_name = "unknown",
+ toolchain_identifier = "host-toolchain-linux",
+ cxx_builtin_include_directories = [
+ "%package(@llvm_toolchain//)%/include/x86_64-unknown-linux-gnu/c++/v1",
+ "%package(@llvm_toolchain//)%/include/c++/v1",
+ "%package(@llvm_toolchain//)%/lib/clang/17/include",
+ "%sysroot%/usr/local/include",
+ "%sysroot%/usr/include/x86_64-linux-gnu",
+ "%sysroot%/usr/include",
+ ],
+ )
+
+------------
+Alternatives
+------------
+Improve Bazel's native C/C++ toolchain rules
+============================================
+Improving Bazel's native rules for defining C/C++ toolchains is out of the
+scope of Pigweed's work. Changing the underlying toolchain API as Bazel
+understands it is a massive undertaking from the perspective of migrating
+existing code. We hope that the custom rule effort can help guide future
+decisions when it comes to toolchain scalability and maintainability.
+
+----------
+Next steps
+----------
+Rust toolchain interop
+======================
+Pigweed's Rust toolchains have some interoperability concerns and requirements.
+The extend of this needs to be thoroughly investigated as a next step to ensure
+that the Rust/C/C++ toolchain experience is relatively unified and ergonomic.
+
+More maintainable ``cxx_builtin_include_directories``
+=====================================================
+In the future, it would be nice to have a more sharable solution for managing
+``cxx_builtin_include_directories`` on a ``pw_cc_toolchain``. This could
+plausibly be done by allowing ``pw_cc_flag_set`` to express
+``cxx_builtin_include_directories`` so they can be propagated back up to the
+``pw_cc_toolchain``.
+
+Feature name collision guidance
+===============================
+Features support relatively complex relationships among each other, but
+traditionally rely on string names to express these relationships rather than
+labels. This introduces significant ambiguity, as it's possible for multiple
+features to use the same logical name so long as they aren't both employed in
+the same toolchain. In practice, the only way to tell what features will end up
+enabled is to manually unpack what features a toolchain pulls in, and
+cross-reference it against the output of
+`--experimental_save_feature_state <https://bazel.build/reference/command-line-reference#flag--experimental_save_feature_state>`_.
+
+One potential solution to this problem is to add a mechanism for expressing
+features as labels, which will allow relationships to be expressed more
+concretely, and help prevent unintended naming collisions. This would not
+replace the ability to express relationships with features not accessible via
+labels, but rather live alongside it.