1.. _module-pw_toolchain_bazel-get-started: 2 3=================================== 4Get started with pw_toolchain_bazel 5=================================== 6.. pigweed-module-subpage:: 7 :name: pw_toolchain_bazel 8 9----------- 10Quick start 11----------- 12The fastest way to get started using ``pw_toolchain_bazel`` is to use Pigweed's 13upstream toolchains. 14 151. Enable required features in your project's ``//.bazelrc`` file: 16 17 .. code-block:: sh 18 19 # Required for new toolchain resolution API. 20 build --incompatible_enable_cc_toolchain_resolution 21 22 # Do not attempt to configure an autodetected (local) toolchain. 23 common --repo_env=BAZEL_DO_NOT_DETECT_CPP_TOOLCHAIN=1 24 252. Configure ``pw_toolchain_bazel`` in your project's ``//WORKSPACE`` file: 26 27 .. code-block:: py 28 29 # Add Pigweed itself, as a submodule from `//third_party/pigweed`. 30 # 31 # TODO: b/300695111 - Support depending on Pigweed as a git_repository, 32 # even if you use pw_toolchain. 33 local_repository( 34 name = "pigweed", 35 path = "third_party/pigweed", 36 ) 37 local_repository( 38 name = "pw_toolchain", 39 path = "third_party/pigweed/pw_toolchain_bazel", 40 ) 41 42 # Set up CIPD. 43 load( 44 "@pigweed//pw_env_setup/bazel/cipd_setup:cipd_rules.bzl", 45 "cipd_client_repository", 46 "cipd_repository", 47 ) 48 49 cipd_client_repository() 50 51 # Set up and register Pigweed's toolchains. 52 load( 53 "@pigweed//pw_toolchain:register_toolchains.bzl", 54 "register_pigweed_cxx_toolchains" 55 ) 56 57 register_pigweed_cxx_toolchains() 58 59And you're done! You should now be able to compile for macOS, Linux, and ARM 60Cortex-M devices. 61 62.. _module-pw_toolchain_bazel-get-started-overview: 63 64-------- 65Overview 66-------- 67This guide shows you how to use ``pw_toolchain_bazel`` to assemble a fully 68working toolchain. There are three core elements in a C/C++ toolchain in 69Bazel: 70 71#. The underlying tools used to perform compile and link actions. 72#. Flag declarations that may or may not apply to a given toolchain 73 configuration. 74#. The final toolchain definition that binds tools and flag declarations 75 together to produce working C/C++ compile and link commands. 76 77This guide assumes you have a good grasp on writing Bazel build files, and also 78assumes you have a working understanding of what flags are typically passed to 79various compile and link tool invocations. 80 81-------------------------------- 82Adding Pigweed to your WORKSPACE 83-------------------------------- 84Before you can use Pigweed and ``pw_toolchain_bazel`` in your project, you must 85register Pigweed in your ``//WORKSPACE`` file: 86 87.. code-block:: py 88 89 # Add Pigweed itself, as a submodule from `//third_party/pigweed`. 90 # 91 # TODO: b/300695111 - Support depending on Pigweed as a git_repository, 92 # even if you use pw_toolchain. 93 local_repository( 94 name = "pigweed", 95 path = "third_party/pigweed", 96 ) 97 local_repository( 98 name = "pw_toolchain", 99 path = "third_party/pigweed/pw_toolchain_bazel", 100 ) 101 102.. admonition:: Note 103 104 `b/300695111 <https://issues.pigweed.dev/300695111>`_\: You must add Pigweed 105 as a submodule to use Pigweed in a Bazel project. Pigweed does not yet work 106 when added as a ``http_repository``. 107 108------------------ 109Configure .bazelrc 110------------------ 111To use this module's toolchain rules, you must first add a couple 112flags that tell Bazel how to find toolchain definitions. Bazel's ``.bazelrc`` 113lives at the root of your project, and is the source of truth for your 114project-specific build flags that control Bazel's behavior. 115 116.. code-block:: sh 117 118 # Required for new toolchain resolution API. 119 build --incompatible_enable_cc_toolchain_resolution 120 121 # Do not attempt to configure an autodetected (local) toolchain. We vendor 122 # all our toolchains, and CI VMs may not have any local toolchain to detect. 123 common --repo_env=BAZEL_DO_NOT_DETECT_CPP_TOOLCHAIN=1 124 125.. _module-pw_toolchain_bazel-assemble-a-tool-suite: 126 127--------------------- 128Assemble a tool suite 129--------------------- 130The fastest way to get started is using a toolchain tool repository template. 131``pw_toolchain_bazel`` provides pre-assembled templates for ``clang`` and 132``arm-none-eabi-gcc`` toolchains in the 133`@pw_toolchain//build_external <https://cs.opensource.google/pigweed/pigweed/+/main:pw_toolchain_bazel/build_external/>`_ 134package. These build files can be attached to an external repository in your 135``WORKSPACE`` file using the ``build_file`` attribute of ``http_archive``, 136``git_repository``, or ``cipd_repository``. 137 138.. code-block:: py 139 140 # Declare a toolchain tool suite for Linux. 141 http_archive( 142 name = "linux_clang_toolchain", 143 build_file = "@pw_toolchain//build_external:llvm_clang_legacy.BUILD", 144 sha256 = "884ee67d647d77e58740c1e645649e29ae9e8a6fe87c1376be0f3a30f3cc9ab3", 145 strip_prefix = "clang+llvm-17.0.6-x86_64-linux-gnu-ubuntu-22.04", 146 url = "https://github.com/llvm/llvm-project/releases/download/llvmorg-17.0.6/clang+llvm-17.0.6-x86_64-linux-gnu-ubuntu-22.04.tar.xz", 147 ) 148 149--------------------------- 150Create toolchain definition 151--------------------------- 152To set up a complete toolchain definition, you'll need ``toolchain`` and 153``pw_cc_toolchain`` rules that serve as the core of your toolchain. 154A simplified example is provided below. 155 156.. code-block:: py 157 158 load("@pw_toolchain//cc_toolchain:defs.bzl", "pw_cc_toolchain") 159 160 pw_cc_toolchain( 161 name = "host_toolchain", 162 action_configs = [ 163 "@linux_clang_toolchain//:ar", 164 "@linux_clang_toolchain//:clang", 165 "@linux_clang_toolchain//:clang++", 166 "@linux_clang_toolchain//:lld", 167 "@linux_clang_toolchain//:llvm-cov", 168 "@linux_clang_toolchain//:llvm-objcopy", 169 "@linux_clang_toolchain//:llvm-objdump", 170 "@linux_clang_toolchain//:llvm-strip", 171 ], 172 cxx_builtin_include_directories = [ 173 "%package(@linux_clang_toolchain//)%/include/x86_64-unknown-linux-gnu/c++/v1", 174 "%package(@linux_clang_toolchain//)%/include/c++/v1", 175 "%package(@linux_clang_toolchain//)%/lib/clang/17/include", 176 ], 177 toolchain_identifier = "host-linux-toolchain", 178 flag_sets = [ 179 "@pw_toolchain//flag_sets:c++17", 180 "@pw_toolchain//flag_sets:debugging", 181 "@pw_toolchain//flag_sets:no_canonical_prefixes", 182 ], 183 ) 184 185 toolchain( 186 name = "host_cc_toolchain_linux", 187 # This is the list of constraints that must be satisfied for the suite of 188 # toolchain tools to be determined as runnable on the current machine. 189 exec_compatible_with = [ 190 "@platforms//os:linux", 191 ], 192 # This is the list of constraints that dictates compatibility of the final 193 # artifacts produced by this toolchain. 194 target_compatible_with = [ 195 "@platforms//os:linux", 196 ], 197 toolchain = ":host_toolchain", 198 toolchain_type = "@bazel_tools//tools/cpp:toolchain_type", 199 ) 200 201The ``toolchain`` rule 202====================== 203The ``toolchain`` rule communicates to Bazel what kind of toolchains are 204available, what environments the tools can run on, and what environment the 205artifacts are intended for. A quick overview of the critical parts of this 206rule are outlined below. 207 208- ``name``: The name of the toolchain rule. This is the label that you 209 reference when registering a toolchain so Bazel knows it may use this 210 toolchain. 211- ``toolchain_type``: The language this toolchain is designed for. Today, 212 ``pw_toolchain_bazel`` only supports C/C++ toolchains via the 213 ``@bazel_tools//tools/cpp:toolchain_type`` type. 214- ``exec_compatible_with``: What constraints must be satisfied for this 215 toolchain to be compatible with the execution environment. In simpler terms, 216 if the machine that is currently running the build is a Linux x86_64 machine, 217 it can only use toolchains designed to run on that OS and architecture. 218 ``exec_compatible_with`` is what prevents a Linux machine from trying to 219 compile using tools designed for a Windows machine and vice versa. 220- ``target_compatible_with``: What constraints must be satisfied for this 221 toolchain to be compatible with the targeted environment. Rather than 222 specifying whether the *tools* are compatible, this specifies the 223 compatibility of the final artifacts produced by this toolchain. 224 For example, ``target_compatible_with`` is what tells Bazel that a toolchain 225 is building firmware for a Cortex-M4. 226- ``toolchain``: The rule that implements the toolchain behavior. When using 227 ``pw_toolchain_bazel``, this points to a :py:class:`pw_cc_toolchain` rule. 228 Multiple ``toolchain`` rules can point to the same 229 :py:class:`pw_cc_toolchain`, which can be useful for creating parameterized 230 toolchains that have a lot in common. 231 232 233The ``pw_cc_toolchain`` rule 234============================ 235This is the heart of your C/C++ toolchain configuration, and has two main 236configuration surfaces of interest. 237 238- :py:attr:`pw_cc_toolchain.action_configs`\: This is a list of bindings that 239 map various toolchain actions to the appropriate tools. Typically you'll just 240 want to list all of the :py:class:`pw_cc_action_config` rules included in your 241 toolchain repository from 242 :ref:`module-pw_toolchain_bazel-assemble-a-tool-suite`. If you need to swap 243 out a particular tool, you can just create a custom 244 :py:class:`pw_cc_tool` and :py:class:`pw_cc_action_config` and list it here. 245- :py:attr:`pw_cc_toolchain.flag_sets`\: This lists all the flags 246 that are applied when compiling with this toolchain. Each 247 :py:class:`pw_cc_flag_set` listed here includes at least one flag that applies 248 to at least one kind of action. 249 250While the other attributes of a :py:class:`pw_cc_toolchain` are still required, 251their behaviors are less interesting from a configuration perspective and are 252required for correctness and completeness reasons. See the full 253API reference for :py:class:`pw_cc_toolchain` for more information. 254 255----------------------- 256Register your toolchain 257----------------------- 258Once you've declared a complete toolchain to your liking, you'll need to 259register it in your project's ``WORKSPACE`` file so Bazel knows it can use the 260new toolchain. An example for a ``toolchain`` with the name 261``host_cc_toolchain_linux`` living in ``//toolchains/BUILD`` is illustrated 262below. 263 264.. code-block:: py 265 266 register_toolchains( 267 "//toolchains:host_cc_toolchain_linux", 268 ) 269 270At this point, you should have a custom, working toolchain! For more extensive 271examples, consider taking a look at Pigweed's 272`fully instantiated and supported toolchains <https://cs.opensource.google/pigweed/pigweed/+/main:pw_toolchain/host_clang/BUILD.bazel>`_ 273 274--------------------------------- 275Customize behavior with flag sets 276--------------------------------- 277Now that your toolchain is working, you can customize it by introducing new flag 278sets. 279 280Configure warnings 281================== 282Enabling compiler warnings and setting them to be treated as errors is a great 283way to prevent unintentional bugs that stem from dubious code. 284 285.. code-block:: py 286 287 load( 288 "@pw_toolchain//cc_toolchain:defs.bzl", 289 "pw_cc_flag_set", 290 ) 291 292 pw_cc_flag_set( 293 name = "warnings", 294 actions = [ 295 "@pw_toolchain//actions:all_c_compiler_actions", 296 "@pw_toolchain//actions:all_cpp_compiler_actions", 297 ], 298 flags = [ 299 "-Wall", 300 "-Wextra", 301 "-Werror", # Make all warnings errors, except for the exemptions below. 302 "-Wno-error=cpp", # preprocessor #warning statement 303 "-Wno-error=deprecated-declarations", # [[deprecated]] attribute 304 ], 305 ) 306 307Omit unreferenced symbols 308========================= 309If a function, variable, or data section isn't used anywhere in your binaries, 310it can be omitted with the following flag sets. 311 312.. code-block:: py 313 314 load( 315 "@pw_toolchain//cc_toolchain:defs.bzl", 316 "pw_cc_flag_set", 317 ) 318 319 # Treats symbols representing functions and data as individual sections. 320 # This is mostly relevant when using `:omit_unused_sections`. 321 pw_cc_flag_set( 322 name = "function_and_data_sections", 323 actions = [ 324 "@pw_toolchain//actions:all_c_compiler_actions", 325 "@pw_toolchain//actions:all_cpp_compiler_actions", 326 ], 327 flags = [ 328 "-ffunction-sections", 329 "-fdata-sections", 330 ], 331 ) 332 333 pw_cc_flag_set( 334 name = "omit_unused_sections", 335 actions = ["@pw_toolchain//actions:all_link_actions"], 336 # This flag is parameterized by operating system. macOS and iOS require 337 # a different flag to express this concept. 338 flags = select({ 339 "@platforms//os:macos": ["-Wl,-dead_strip"], 340 "@platforms//os:ios": ["-Wl,-dead_strip"], 341 "//conditions:default": ["-Wl,--gc-sections"], 342 }), 343 ) 344 345Set global defines 346================== 347Toolchains may declare preprocessor defines that are available for all compile 348actions. 349 350.. code-block:: py 351 352 load( 353 "["@pw_toolchain//cc_toolchain:defs.bzl"]", 354 "pw_cc_flag_set", 355 ) 356 357 # Specify global defines that should be available to all compile actions. 358 pw_cc_flag_set( 359 name = "global_defines", 360 actions = [ 361 "@pw_toolchain//actions:all_asm_compiler_actions", 362 "@pw_toolchain//actions:all_c_compiler_actions", 363 "@pw_toolchain//actions:all_cpp_compiler_actions", 364 ], 365 flags = [ 366 "-DPW_LOG_LEVEL=PW_LOG_LEVEL_INFO", # Omit all debug logs. 367 ], 368 ) 369 370Bind custom flags to a toolchain 371================================ 372After you've assembled a selection of custom flag sets, you can bind them to 373your toolchain definition by listing them in 374:py:attr:`pw_cc_toolchain.flag_sets`\: 375 376.. code-block:: py 377 :emphasize-lines: 12,13,14,15 378 379 pw_cc_toolchain( 380 name = "host_toolchain", 381 action_configs = [ 382 "@linux_clang_toolchain//:ar", 383 "@linux_clang_toolchain//:clang", 384 "@linux_clang_toolchain//:clang++", 385 ... 386 flag_sets = [ 387 "@pw_toolchain//flag_sets:c++17", 388 "@pw_toolchain//flag_sets:debugging", 389 "@pw_toolchain//flag_sets:no_canonical_prefixes", 390 ":warnings", # Newly added pw_cc_flag_set from above. 391 ":function_and_data_sections", # Newly added pw_cc_flag_set from above. 392 ":omit_unused_sections", # Newly added pw_cc_flag_set from above. 393 ":global_defines", # Newly added pw_cc_flag_set from above. 394 ], 395 ) 396 397.. admonition:: Note 398 399 Flags appear in the tool invocations in the order as they are listed 400 in :py:attr:`pw_cc_toolchain.flag_sets`\, so if you need a flag 401 to appear earlier in the command-line invocation of the tool just move it to 402 towards the beginning of the list. 403 404You can use ``pw_cc_flag_set`` rules to add support for new architectures, 405enable/disable warnings, add preprocessor defines, enable LTO, and more. 406