1.. _module-pw_toolchain-bazel: 2 3=============================== 4Bazel build system integrations 5=============================== 6Pigweed provides a suite of Bazel build integrations to compliment existing 7Bazel toolchain constructs such as `rules_cc toolchains <https://github.com/bazelbuild/rules_cc/blob/main/cc/toolchains/README.md>`_ 8to make it easier to design robust, feature-rich toolchains. 9 10.. _module-pw_toolchain-bazel-upstream-pigweed-toolchains: 11 12--------------------------- 13Upstream Pigweed toolchains 14--------------------------- 15Pigweed's C/C++ toolchains are automatically registered when using Pigweed from 16a Bzlmod Bazel project. Legacy WORKSPACE-based projects can use Pigweed's 17upstream toolchains by calling ``register_pigweed_cxx_toolchains()``: 18 19.. code-block:: py 20 21 load("@pigweed//pw_toolchain:register_toolchains.bzl", "register_pigweed_cxx_toolchains") 22 23 register_pigweed_cxx_toolchains() 24 25 26.. admonition:: Note 27 :class: warning 28 29 Pigweed's upstream toolchains are subject to change without notice. If you 30 would prefer more stability in toolchain configurations, consider declaring 31 custom toolchains in your project. 32 33.. _module-pw_toolchain-bazel-layering-check: 34 35Layering check 36============== 37Upstream Pigweed toolchains have support for `layering check 38<https://maskray.me/blog/2022-09-25-layering-check-with-clang>`__. In short, 39enabling layering check makes it a compile-time error to ``#include`` a header 40that's not in the ``hdrs`` of a ``cc_library`` you directly depend on. This 41produces cleaner dependency graphs and is recommended for all users. 42 43.. admonition:: Note 44 45 Layering check requires Bazel 8.0.0 or newer. 46 47How to enable layering check? 48----------------------------- 49#. Add ``common --@pigweed//pw_toolchain/host_clang:layering_check`` to your 50 ``.bazelrc``. This does not by itself enable the check, it only instructs 51 Bazel to include support for it in the toolchain configuration. (This flag 52 will become true by default and be removed once all known Pigweed users are 53 on Bazel 8.) 54#. Enable the ``layering_check`` feature to enable enforcement. The recommended 55 way to do this is to add a `REPO.bazel 56 <https://bazel.build/external/overview#repo.bazel>`__ file at the root of 57 your project, with the following content: 58 59 .. code-block:: py 60 61 repo( 62 features = ["layering_check"], 63 ) 64 65 This will enable ``layering_check`` for all code in your project, but not for 66 code coming from any external dependencies also built with Bazel. 67 68Gradual rollout 69--------------- 70When you enable layering check for the first time, you will likely get a very 71large number of errors, since many packages in your project will contain 72layering violations. If there are too many errors to fix at once, here's one way 73to roll out ``layering_check`` gradually: 74 75#. Enable the ``layering_check`` feature for the entire repo, as discussed 76 above. 77#. In the same commit, disable layering check for each individual package 78 (``BUILD.bazel`` file). This can be done using the following `buildozer 79 <https://github.com/bazelbuild/buildtools/blob/main/buildozer/README.md>`__ 80 one-liner: 81 82 .. code-block:: console 83 84 buildozer 'add features -layering_check' '//...:__pkg__' 85 86 Note the ``-`` in front of ``layering_check`` in the command above! 87 88#. Re-enable layering check package by package by removing the lines added by 89 buildozer. When no ``-layering_check`` remains in your codebase, you've 90 enabled layering check for the entire repo! 91 92You can also enable or disable the ``layering_check`` feature for individual 93targets, using the `features 94<https://bazel.build/reference/be/common-definitions#common.features>`__ 95attribute. 96 97Limitations 98----------- 99#. Layering check only applies to ``#include`` statements in source files, not 100 in header files. To also apply it to header files, you need the 101 ``parse_headers`` feature. Pigweed's toolchains do not yet contain its 102 implementation. Adding it is tracked at :bug:`391367050`. 103#. Layering check will not prevent you from using symbols from transitively 104 included headers. For this, use `misc-include-cleaner 105 <https://clang.llvm.org/extra/clang-tidy/checks/misc/include-cleaner.html>`__ 106 in clang-tidy. See also :bug:`329671260`. 107#. A pattern we use for swapping header implementations using a label flag 108 leads to layering check violations. Figuring out an alternative pattern is 109 tracked at :bug:`391394448`. 110 111.. _module-pw_toolchain-bazel-clang-tidy: 112 113clang-tidy 114========== 115To integrate Pigweed's toolchain with `bazel_clang_tidy 116<https://github.com/erenon/bazel_clang_tidy>`_: 117 118#. Add a ``.clang-tidy`` file at the root of your repository listing the checks 119 you wish to enable. `Pigweed's own .clang-tidy file 120 <https://cs.opensource.google/pigweed/pigweed/+/main:.clang-tidy>`__ shows 121 some checks we recommend. 122 123#. Create a ``filegroup`` target containing that file in ``BUILD.bazel`` at 124 the root of your repo. 125 126 .. code-block:: python 127 128 filegroup( 129 name = "clang_tidy_config", 130 srcs = [".clang-tidy"], 131 ) 132 133#. Add `bazel_clang_tidy`_ to your ``MODULE.bazel``. 134 135 .. code-block::python 136 137 git_repository = use_repo_rule( 138 "@bazel_tools//tools/build_defs/repo:git.bzl", 139 "git_repository", 140 ) 141 git_repository( 142 name = "bazel_clang_tidy", 143 # Check the repository for the latest version! 144 commit = "db677011c7363509a288a9fb3bf0a50830bbf791", 145 remote = "https://github.com/erenon/bazel_clang_tidy.git", 146 ) 147 148#. Add a ``clang-tidy`` config in your ``.bazelrc`` file. 149 150 .. code-block:: python 151 152 # clang-tidy configuration 153 build:clang-tidy --aspects @bazel_clang_tidy//clang_tidy:clang_tidy.bzl%clang_tidy_aspect 154 build:clang-tidy --output_groups=report 155 build:clang-tidy --@bazel_clang_tidy//:clang_tidy_config=//:clang_tidy_config 156 # Use the clang-tidy executable from Pigweed's toolchain, and include 157 # our sysroot headers. 158 build:clang-tidy --@bazel_clang_tidy//:clang_tidy_executable=@pigweed//pw_toolchain/host_clang:copy_clang_tidy 159 build:clang-tidy --@bazel_clang_tidy//:clang_tidy_additional_deps=@pigweed//pw_toolchain/host_clang:sysroot_root 160 # Skip any targets with tags = ["noclangtidy"]. This allows a gradual 161 # rollout. 162 build:clang-tidy --build_tag_filters=-noclangtidy 163 # We need to disable this warning to avoid spurious "#pragma once in main file" 164 # warnings for header-only libraries. For another approach, see 165 # https://github.com/mongodb-forks/bazel_clang_tidy/pull/2 166 build:clang-tidy --copt=-Wno-pragma-once-outside-header 167 168Now ``bazelisk build --config=clang-tidy //...`` will run clang-tidy for all 169``cc_library`` targets in your repo! 170 171.. _module-pw_toolchain-bazel-compiler-specific-logic: 172 173----------------------------- 174Compiler-specific build logic 175----------------------------- 176Whenever possible, avoid introducing compiler-specific behaviors in Bazel 177``BUILD`` files. Instead, prefer to design build logic against 178more intentional :ref:`docs-bazel-compatibility`. For compiler-specific 179behavior, this means defining and/or using compiler capabilities like 180`@rules_cc//cc/toolchains/capabilities:supports_interface_shared_libraries <https://github.com/bazelbuild/rules_cc/blob/main/cc/toolchains/capabilities/BUILD>`__ 181 182If you need to expose a toolchain capability as a choice in a select, you 183can use ``pw_cc_toolchain_feature_is_enabled``. 184 185Example: 186 187.. code-block:: py 188 189 load( 190 "@pigweed//pw_toolchain/cc/current_toolchain:pw_cc_toolchain_feature_is_enabled.bzl", 191 "pw_cc_toolchain_feature_is_enabled", 192 ) 193 194 pw_cc_toolchain_feature_is_enabled( 195 name = "llvm_libc_enabled", 196 feature_name = "llvm_libc", 197 ) 198 199 cc_library( 200 name = "libfoo", 201 deps = select({ 202 ":llvm_libc_enabled": ["//foo:llvm_libc_extras"], 203 "//conditions:default": [], 204 }), 205 ) 206 207If you absolutely must introduce a ``select`` statement that checks the current 208compiler, use Pigweed's helper macros. 209 210Example: 211 212.. code-block:: py 213 214 load( 215 "@pigweed//pw_toolchain/cc/current_toolchain:conditions.bzl", 216 "if_compiler_is_clang", 217 "if_linker_is_gcc", 218 ) 219 220 cc_library( 221 copts = if_compiler_is_clang( 222 ["-fno-codegen"], 223 default = [], 224 ), 225 linkopts = if_linker_is_gcc( 226 ["-Wl,--delete-main"], 227 default = [], 228 ), 229 srcs = ["lib.cc"], 230 ) 231