1.. _module-pw_build-bazel: 2 3===== 4Bazel 5===== 6.. pigweed-module-subpage:: 7 :name: pw_build 8 9Bazel is currently very experimental, and only builds for host and ARM Cortex-M 10microcontrollers. 11 12.. _module-pw_build-bazel-wrapper-rules: 13 14----- 15Rules 16----- 17 18Wrapper rules 19============= 20.. _pigweed.bzl: https://cs.opensource.google/pigweed/pigweed/+/main:pw_build/pigweed.bzl 21 22The built-in Bazel rules ``cc_binary``, ``cc_test``, ``py_binary``, and 23``py_test`` are wrapped with :ref:`module-pw_build-bazel-pw_cc_binary`, 24``pw_cc_test``, ``pw_py_binary``, and ``pw_py_test``, respectively. 25To access a wrapper, load its individual ``.bzl`` file. For example, to 26access ``pw_cc_binary``: 27 28.. code-block:: python 29 30 load("@pigweed//pw_build:pw_cc_binary.bzl", "pw_cc_binary") 31 32.. _module-pw_build-bazel-pw_linker_script: 33 34pw_linker_script 35================ 36In addition to wrapping the built-in rules, Pigweed also provides a custom 37rule for handling linker scripts with Bazel. e.g. 38 39.. code-block:: python 40 41 pw_linker_script( 42 name = "some_linker_script", 43 linker_script = ":some_configurable_linker_script.ld", 44 defines = [ 45 "PW_BOOT_FLASH_BEGIN=0x08000200", 46 "PW_BOOT_FLASH_SIZE=1024K", 47 "PW_BOOT_HEAP_SIZE=112K", 48 "PW_BOOT_MIN_STACK_SIZE=1K", 49 "PW_BOOT_RAM_BEGIN=0x20000000", 50 "PW_BOOT_RAM_SIZE=192K", 51 "PW_BOOT_VECTOR_TABLE_BEGIN=0x08000000", 52 "PW_BOOT_VECTOR_TABLE_SIZE=512", 53 ], 54 deps = [":some_header_library"], 55 ) 56 57 # You can include headers provided by targets specified in deps. 58 cc_library( 59 name = "some_header_library", 60 hdrs = ["test_header.h"], 61 includes = ["."], 62 ) 63 64 # You can include the linker script in the deps. 65 cc_binary( 66 name = "some_binary", 67 srcs = ["some_source.cc"], 68 deps = [":some_linker_script"], 69 ) 70 71 # Alternatively, you can use additional_linker_inputs and linkopts. This 72 # allows you to explicitly specify the command line order of linker scripts, 73 # and may be useful if your project defines more than one. 74 cc_binary( 75 name = "some_binary", 76 srcs = ["some_source.cc"], 77 additional_linker_inputs = [":some_linker_script"], 78 linkopts = ["-T $(execpath :some_linker_script)"], 79 ) 80 81.. _module-pw_build-bazel-pw_facade: 82 83pw_facade 84========= 85In Bazel, a :ref:`facade <docs-module-structure-facades>` module has a few 86components: 87 88#. The **facade target**, i.e. the interface to the module. This is what 89 *backend implementations* depend on to know what interface they're supposed 90 to implement. 91 92#. The **library target**, i.e. both the facade (interface) and backend 93 (implementation). This is what *users of the module* depend on. It's a 94 regular ``cc_library`` that exposes the same headers as the facade, but 95 has a dependency on the "backend label flag" (discussed next). It may also 96 include some source files (if these are backend-independent). 97 98 Both the facade and library targets are created using the 99 ``pw_facade`` macro. For example, consider the following 100 macro invocation: 101 102 .. code-block:: python 103 104 pw_facade( 105 name = "binary_semaphore", 106 # A backend-independent source file. 107 srcs = [ 108 "binary_semaphore.cc", 109 ], 110 # The facade header. 111 hdrs = [ 112 "public/pw_sync/binary_semaphore.h", 113 ], 114 # Dependencies of this header. 115 deps = [ 116 "//pw_chrono:system_clock", 117 "//pw_preprocessor", 118 ], 119 # The backend, hidden behind a label_flag; see below. 120 backend = [ 121 ":binary_semaphore_backend", 122 ], 123 ) 124 125 This macro expands to both the library target, named ``binary_semaphore``, 126 and the facade target, named ``binary_semaphore.facade``. 127 128#. The **backend label flag**. This is a `label_flag 129 <https://bazel.build/extending/config#label-typed-build-settings>`_: a 130 dependency edge in the build graph that can be overridden by downstream projects. 131 132#. The **backend target** implements a particular backend for a facade. It's 133 just a plain ``cc_library``, with a dependency on the facade target. For example, 134 135 .. code-block:: python 136 137 cc_library( 138 name = "binary_semaphore", 139 srcs = [ 140 "binary_semaphore.cc", 141 ], 142 hdrs = [ 143 "public/pw_sync_stl/binary_semaphore_inline.h", 144 "public/pw_sync_stl/binary_semaphore_native.h", 145 "public_overrides/pw_sync_backend/binary_semaphore_inline.h", 146 "public_overrides/pw_sync_backend/binary_semaphore_native.h", 147 ], 148 includes = [ 149 "public", 150 "public_overrides", 151 ], 152 deps = [ 153 # Dependencies of the backend's headers and sources. 154 "//pw_assert", 155 "//pw_chrono:system_clock", 156 # A dependency on the facade target, which defines the interface 157 # this backend target implements. 158 "//pw_sync:binary_semaphore.facade", 159 ], 160 ) 161 162The backend label flag should point at the backend target. Typically, the 163backend you want to use depends on the platform you are building for. See the 164:ref:`docs-build_system-bazel_configuration` for advice on how to set this up. 165 166pw_cc_blob_library 167================== 168The ``pw_cc_blob_library`` rule is useful for embedding binary data into a 169program. The rule takes in a mapping of symbol names to file paths, and 170generates a set of C++ source and header files that embed the contents of the 171passed-in files as arrays of ``std::byte``. 172 173The blob byte arrays are constant initialized and are safe to access at any 174time, including before ``main()``. 175 176``pw_cc_blob_library`` is also available in the :ref:`GN <module-pw_build-cc_blob_library>` 177and CMake builds. 178 179Arguments 180--------- 181* ``blobs``: A list of ``pw_cc_blob_info`` targets, where each target 182 corresponds to a binary blob to be transformed from file to byte array. This 183 is a required field. ``pw_cc_blob_info`` attributes include: 184 185 * ``symbol_name``: The C++ symbol for the byte array. 186 * ``file_path``: The file path for the binary blob. 187 * ``linker_section``: If present, places the byte array in the specified 188 linker section. 189 * ``alignas``: If present, uses the specified string verbatim in 190 the ``alignas()`` specifier for the byte array. 191 192* ``out_header``: The header file to generate. Users will include this file 193 exactly as it is written here to reference the byte arrays. 194* ``namespace``: C++ namespace to place the generated blobs within. 195* ``alwayslink``: Whether this library should always be linked. Defaults to false. 196 197Example 198------- 199**BUILD.bazel** 200 201.. code-block:: python 202 203 pw_cc_blob_info( 204 name = "foo_blob", 205 file_path = "foo.bin", 206 symbol_name = "kFooBlob", 207 ) 208 209 pw_cc_blob_info( 210 name = "bar_blob", 211 file_path = "bar.bin", 212 symbol_name = "kBarBlob", 213 linker_section = ".bar_section", 214 ) 215 216 pw_cc_blob_library( 217 name = "foo_bar_blobs", 218 blobs = [ 219 ":foo_blob", 220 ":bar_blob", 221 ], 222 out_header = "my/stuff/foo_bar_blobs.h", 223 namespace = "my::stuff", 224 ) 225 226.. note:: If the binary blobs are generated as part of the build, be sure to 227 list them as deps to the pw_cc_blob_library target. 228 229**Generated Header** 230 231.. code-block:: 232 233 #pragma once 234 235 #include <array> 236 #include <cstddef> 237 238 namespace my::stuff { 239 240 extern const std::array<std::byte, 100> kFooBlob; 241 242 extern const std::array<std::byte, 50> kBarBlob; 243 244 } // namespace my::stuff 245 246**Generated Source** 247 248.. code-block:: 249 250 #include "my/stuff/foo_bar_blobs.h" 251 252 #include <array> 253 #include <cstddef> 254 255 #include "pw_preprocessor/compiler.h" 256 257 namespace my::stuff { 258 259 const std::array<std::byte, 100> kFooBlob = { ... }; 260 261 PW_PLACE_IN_SECTION(".bar_section") 262 const std::array<std::byte, 50> kBarBlob = { ... }; 263 264 } // namespace my::stuff 265 266.. _module-pw_build-bazel-pw_cc_binary: 267 268pw_cc_binary 269============ 270.. _cc_binary: https://bazel.build/reference/be/c-cpp#cc_binary 271.. _//pw_build/pw_cc_binary.bzl: https://cs.opensource.google/pigweed/pigweed/+/main:pw_build/pw_cc_binary.bzl 272 273``pw_cc_binary`` is a wrapper of `cc_binary`_. It's implemented at 274`//pw_build/pw_cc_binary.bzl`_. Usage of this wrapper is optional; 275downstream Pigweed projects can instead use ``cc_binary`` if preferred. 276 277Basic usage: 278 279.. code-block:: python 280 281 load("@pigweed//pw_build:pw_cc_binary.bzl", "pw_cc_binary") 282 283 pw_cc_binary( 284 name = "…", 285 srcs = ["…"], 286 deps = [ 287 "…", 288 ], 289 ) 290 291Pros of using ``pw_cc_binary``: 292 293* It simplifies :ref:`link-time dependency 294 <docs-build_system-bazel_link-extra-lib>`. Projects using ``cc_binary`` 295 must set up (and document) link-time dependency themselves. 296 297Cons of using ``pw_cc_binary``: 298 299.. _magical: https://en.wikipedia.org/wiki/Magic_(programming) 300 301* It makes the configuration of :ref:`module-pw_log` and 302 :ref:`module-pw_assert` a bit more `magical`_. 303 304.. _module-pw_build-bazel-pw_cc_binary_with_map: 305 306pw_cc_binary_with_map 307===================== 308The ``pw_cc_binary_with_map`` rule can be used to build a binary like 309``cc_binary`` does but also generate a .map file from the linking step. 310 311.. code-block:: python 312 313 pw_cc_binary_with_map( 314 name = "test", 315 srcs = ["empty_main.cc"], 316 ) 317 318This should result in a ``test.map`` file generated next to the ``test`` binary. 319 320Note that it's only partially compatible with the ``cc_binary`` interface and 321certain things are not implemented like make variable substitution. 322 323.. _module-pw_build-bazel-pw_elf_to_bin: 324 325pw_elf_to_bin 326============= 327The ``pw_elf_to_bin`` rule takes in a binary executable target and produces a 328file using the ``-Obinary`` option to ``objcopy``. This is only suitable for use 329with binaries where all the segments are non-overlapping. A common use case for 330this type of file is booting directly on hardware with no bootloader. 331 332.. code-block:: python 333 334 load("@pigweed//pw_build:binary_tools.bzl", "pw_elf_to_bin") 335 336 pw_elf_to_bin( 337 name = "bin", 338 elf_input = ":main", 339 bin_out = "main.bin", 340 ) 341 342.. _module-pw_build-bazel-pw_elf_to_dump: 343 344pw_elf_to_dump 345============== 346The ``pw_elf_to_dump`` rule takes in a binary executable target and produces a 347text file containing the output of the toolchain's ``objdump -xd`` command. This 348contains the full binary layout, symbol table and disassembly which is often 349useful when debugging embedded firmware. 350 351.. code-block:: python 352 353 load("@pigweed//pw_build:binary_tools.bzl", "pw_elf_to_dump") 354 355 pw_elf_to_dump( 356 name = "dump", 357 elf_input = ":main", 358 dump_out = "main.dump", 359 ) 360 361pw_copy_and_patch_file 362====================== 363Provides the ability to patch a file as part of the build. 364 365The source file will not be patched in place, but instead copied before 366patching. The output of this target will be the patched file. 367 368Arguments 369--------- 370- ``name``: The name of the target. 371 372- ``source``: The source file to be patched. 373 374- ``out``: The output file containing the patched contents. 375 376- ``patch_file``: The patch file. 377 378Example 379------- 380To apply the patch `changes.patch` to the file `data/file.txt` which is located 381in the bazel dependency `@external-sdk//`. 382 383.. code-block:: 384 385 pw_copy_and_patch_file( 386 name = "apply_patch", 387 src = "@external-sdk//data/file.txt", 388 out = "data/patched_file.txt", 389 patch_file = "changes.patch", 390 ) 391 392pw_py_importable_runfile 393======================== 394An importable ``py_library`` that makes loading runfiles easier. 395 396When using Bazel runfiles from Python, 397`Rlocation() <https://rules-python.readthedocs.io/en/latest/api/py/runfiles/runfiles.runfiles.html#runfiles.runfiles.Runfiles.Rlocation>`__ 398takes two arguments: 399 4001. The ``path`` of the runfiles. This is the apparent repo name joined with 401 the path within that repo. 4022. The ``source_repo`` to evaluate ``path`` from. This is related to how 403 apparent repo names and canonical repo names are handled by Bazel. 404 405Unfortunately, it's easy to get these arguments wrong. 406 407This generated Python library short-circuits this problem by letting Bazel 408generate the correct arguments to ``Rlocation()`` so users don't even have 409to think about what to pass. 410 411For example: 412 413.. code-block:: python 414 415 # In @bloaty//:BUILD.bazel, or wherever is convenient: 416 pw_py_importable_runfile( 417 name = "bloaty_runfiles", 418 src = "//:bin/bloaty", 419 executable = True, 420 import_location = "bloaty.bloaty_binary", 421 visibility = ["//visibility:public"], 422 ) 423 424 # Using the pw_py_importable_runfile from a py_binary in a 425 # BUILD.bazel file: 426 py_binary( 427 name = "my_binary", 428 srcs = ["my_binary.py"], 429 main = "my_binary.py", 430 deps = ["@bloaty//:bloaty_runfiles"], 431 ) 432 433 # In my_binary.py: 434 import bloaty.bloaty_binary 435 from python.runfiles import runfiles # type: ignore 436 437 r = runfiles.Create() 438 bloaty_path = r.Rlocation(*bloaty.bloaty_binary.RLOCATION) 439 440.. note:: 441 442 Because this exposes runfiles as importable Python modules, 443 the import paths of the generated libraries may collide with existing 444 Python libraries. When this occurs, you need to 445 :ref:`docs-style-python-extend-generated-import-paths`. 446 447Attrs 448----- 449 450.. list-table:: 451 :header-rows: 1 452 453 * - Name 454 - Description 455 * - import_location 456 - The final Python import path of the generated module. By default, this is ``path.to.package.label_name``. 457 * - target 458 - The file this library exposes as runfiles. 459 * - executable 460 - Whether or not the source file is executable. 461 * - \*\*kwargs 462 - Common attributes to forward both underlying targets. 463 464Platform compatibility rules 465============================ 466Macros and rules related to platform compatibility are provided in 467``//pw_build:compatibility.bzl``. 468 469.. _module-pw_build-bazel-boolean_constraint_value: 470 471boolean_constraint_value 472------------------------ 473This macro is syntactic sugar for declaring a `constraint setting 474<https://bazel.build/reference/be/platforms-and-toolchains#constraint_setting>`__ 475with just two possible `constraint values 476<https://bazel.build/reference/be/platforms-and-toolchains#constraint_value>`__. 477The only exposed target is the ``constraint_value`` corresponding to ``True``; 478the default value of the setting is ``False``. 479 480This macro is meant to simplify declaring 481:ref:`docs-bazel-compatibility-module-specific`. 482 483host_backend_alias 484------------------ 485An alias that resolves to the backend for host platforms. This is useful when 486declaring a facade that provides a default backend for host platform use. 487 488 489---------------- 490Starlark helpers 491---------------- 492 493Platform-based flag merging 494=========================== 495Macros that help with using platform-based flags are in 496``//pw_build:merge_flags.bzl``. These are useful, for example, when you wish to 497:ref:`docs-bazel-compatibility-facade-backend-dict`. 498 499 500glob_dirs 501========= 502A starlark helper for performing ``glob()`` operations strictly on directories. 503 504.. py:function:: glob_dirs(include: List[str], exclude: List[str] = [], allow_empty: bool = True) -> List[str] 505 506 Matches the provided glob pattern to identify a list of directories. 507 508 This helper follows the same semantics as Bazel's native ``glob()`` function, 509 but only matches directories. 510 511 Args: 512 include: A list of wildcard patterns to match against. 513 exclude: A list of wildcard patterns to exclude. 514 allow_empty: Whether or not to permit an empty list of matches. 515 516 Returns: 517 List of directory paths that match the specified constraints. 518 519match_dir 520========= 521A starlark helper for using a wildcard pattern to match a single directory 522 523.. py:function:: match_dir(include: List[str], exclude: List[str] = [], allow_empty: bool = True) -> Optional[str] 524 525 Identifies a single directory using a wildcard pattern. 526 527 This helper follows the same semantics as Bazel's native ``glob()`` function, 528 but only matches a single directory. If more than one match is found, this 529 will fail. 530 531 Args: 532 include: A list of wildcard patterns to match against. 533 exclude: A list of wildcard patterns to exclude. 534 allow_empty: Whether or not to permit returning ``None``. 535 536 Returns: 537 Path to a single directory that matches the specified constraints, or 538 ``None`` if no match is found and ``allow_empty`` is ``True``. 539 540------------- 541Build targets 542------------- 543 544.. _module-pw_build-bazel-empty_cc_library: 545 546empty_cc_library 547================ 548This empty library is used as a placeholder for label flags that need to point 549to a library of some kind, but don't actually need the dependency to amount to 550anything. 551 552default_link_extra_lib 553====================== 554This library groups together all libraries commonly required at link time by 555Pigweed modules. See :ref:`docs-build_system-bazel_link-extra-lib` for more 556details. 557 558unspecified_backend 559=================== 560A special target used instead of a cc_library as the default condition in 561backend multiplexer select statements to signal that a facade is in an 562unconfigured state. This produces better error messages than e.g. using an 563invalid label. 564 565------------------------ 566Toolchains and platforms 567------------------------ 568Pigweed provides clang-based host toolchains for Linux and Mac Arm gcc 569toolchain. The clang-based Linux and Arm gcc toolchains are entirely hermetic. 570We don't currently provide a host toolchain for Windows. 571