1.. _docs-build-system: 2 3============= 4Build systems 5============= 6Building software for embedded devices is a complex process. Projects often have 7custom toolchains, target different hardware platforms, and require additional 8configuration and post-processing of artifacts. 9 10As a modern embedded framework, Pigweed's goal is to collect these embedded use 11cases into a powerful and flexible build system, then extend it with support for 12modern software development practices. 13 14See :ref:`docs-python-build` for information about Python build automation with 15Pigweed. 16 17.. toctree:: 18 :hidden: 19 20 bazel_compatibility 21 python_build 22 23What's in a build system? 24========================= 25A quality build system provides a variety of features beyond compiling code. 26Throughout our experience with embedded development, we've found several build 27features to be especially useful, and designed Pigweed's build system with them 28in mind. 29 30Simple toolchain configuration 31------------------------------ 32Embedded projects often use custom build toolchains for their specific hardware. 33Configuring these should be a simple process, both in their initial setup and 34later adjustments. 35 36Multi-target builds 37------------------- 38Virtually every consumer product has firmware that targets different boards or 39MCUs during development. While building for a single board is simple enough, the 40complexity of supporting different targets ranges from changing compiler flags 41to swapping out entire libraries of firmware and drivers. This is often done by 42running multiple builds, configuring each one accordingly. In Pigweed, we've 43designed our build system with first-class multi-target support in mind, 44allowing any number of target configurations to be built simultaneously. 45 46Multi-language support 47---------------------- 48Embedded projects are typically written in C, C++, and assembly. However, it is 49possible to have firmware written in other languages, such as Rust. 50Additionally, projects may have host-side tooling written in a wide variety of 51languages. Having all of these build together proves to be a large time saver. 52 53Custom scripting 54---------------- 55Embedded projects often require post-processing of build artifacts; these may 56include: 57 58* Extracting ELF sections into a different container 59* Injecting metadata into firmware images 60* Image signing 61* Creating databases of symbols for debugging 62* Extracting string tokens into a database (for example, with 63 :ref:`module-pw_tokenizer`) 64 65These are run as steps during a build, facilitated by the build system. 66 67See also 68^^^^^^^^ 69 70* :ref:`module-pw_build-python-action` 71 72Python 73------ 74Python is a favorite scripting language of many development teams, and here at 75Pigweed, we're no exception. Much of Pigweed's host-side tooling is written in 76Python. While Python works great for local development, problems can arise when 77scripts need to be packaged and distributed for vendors or factory teams. Having 78proper support for packaging Python within a build system allows teams to focus 79on writing code instead of worrying about distribution. 80 81Size reporting 82-------------- 83On embedded devices, memory is everything. Most projects have some sort of 84custom tooling to determine how much flash and RAM space their firmware uses. 85Being able to run size reports as part of a build ensures that they are always 86up-to-date and allows space usage to be tracked over time. 87 88See also 89^^^^^^^^ 90 91* :ref:`module-pw_bloat` 92 93Documentation 94------------- 95An oft-neglected part of software development, documentation is invaluable for 96future maintainers of a project. As such, Pigweed has integrated documentation 97which builds alongside its code and combines with other build features, such as 98size reports, to provide high quality, up-to-date references for developers. 99 100See also 101^^^^^^^^ 102 103* :ref:`module-pw_docgen` 104 105Unit testing 106------------ 107Unit tests are essential to ensure that the functionality of code remains 108consistent as changes are made to avoid accidental regressions. Running unit 109tests as part of a build keeps developers constantly aware of the impact of 110their changes. 111 112Host-side unit tests 113^^^^^^^^^^^^^^^^^^^^ 114Though Pigweed targets embedded devices, a lot of its code can be run and tested 115on a host desktop by swapping out backends to host platform libraries. This is 116highly beneficial during development, as it allows tests to consistently run 117without having to go through the process of flashing a device. 118 119Device-side unit tests 120^^^^^^^^^^^^^^^^^^^^^^ 121As useful as host-side tests are, they are not sufficient for developing actual 122firmware, and it is critical to run tests on the actual hardware. Pigweed has 123invested into creating a test framework and build integration for running tests 124across physical devices as part of a build. 125 126See also 127^^^^^^^^ 128 129* :ref:`module-pw_unit_test` 130* :ref:`module-pw_target_runner` 131 132Bonus: pw watch 133--------------- 134In web development, it is common to have a file system watcher listening for 135source file changes and triggering a build for quick iteration. When combined 136with a fast incremental build system, this becomes a powerful feature, allowing 137things such as unit tests and size reports to re-run whenever any dependent 138code is modified. 139 140While initially seen as somewhat of a gimmick, Pigweed's watcher has become a 141staple of Pigweed development, with most Pigweed users having it permanently 142running in a terminal window. 143 144See also 145^^^^^^^^ 146 147* :ref:`module-pw_watch` 148 149Pigweed's build systems 150======================= 151Pigweed can be used either as a monolith or à la carte, slotting into an 152existing project. To this end, Pigweed supports multiple build systems, allowing 153Pigweed-based projects to choose the most suitable one for them. 154 155Of the supported build systems, GN is the most full-featured, followed by CMake, 156and finally Bazel. 157 158.. note:: 159 A quick note on terminology: the word "target" is overloaded within GN/Bazel (and 160 Pigweed)---it can refer to either a GN/Bazel build target, such as a ``source_set`` 161 or ``executable``, or to an output platform (e.g. a specific board, device, or 162 system). 163 164 To avoid confusing the two, we refer to the former as "GN/Bazel targets" and the 165 latter as "Pigweed targets". 166 167.. _docs-build-system-gn: 168 169GN 170-- 171A perhaps unfamiliar name, `GN (Generate Ninja)`_ is a meta-build system that 172outputs `Ninja`_ build files, originally designed for use in Chromium. Pigweed 173first experimented with GN after hearing about it from another team, and we 174quickly came to appreciate its speed and simplicity. GN has become Pigweed's 175primary build system; it is used for all upstream development and strongly 176recommended for Pigweed-based projects where possible. 177 178.. _CMake: https://cmake.org/ 179.. _Bazel: https://bazel.build/ 180.. _GN (Generate Ninja): https://gn.googlesource.com/gn 181.. _Ninja: https://ninja-build.org/ 182 183The GN build 184============ 185This section describes Pigweed's GN build structure, how it is used upstream, 186build conventions, and recommendations for Pigweed-based projects. While 187containing some details about how GN works in general, this section is not 188intended to be a guide on how to use GN. To learn more about the tool itself, 189refer to the official `GN reference`_. 190 191.. _GN reference: https://gn.googlesource.com/gn/+/HEAD/docs/reference.md 192 193Entrypoint: .gn 194--------------- 195The entrypoint to a GN build is the ``.gn`` file, which defines a project's root 196directory (henceforth ``//``). 197 198``.gn`` must point to the location of a ``BUILDCONFIG.gn`` file for the project. 199In Pigweed upstream, this is its only purpose. 200 201Downstream projects may additionally use ``.gn`` to set global overrides for 202Pigweed's build arguments, which apply across all Pigweed targets. For example, 203a project could configure the protobuf libraries that it uses. This is done by 204defining a ``default_args`` scope containing the overrides. 205 206.. code-block:: 207 208 # The location of the BUILDCONFIG file. 209 buildconfig = "//BUILDCONFIG.gn" 210 211 # Build arguments set across all Pigweed targets. 212 default_args = { 213 dir_pw_third_party_nanopb = "//third_party/nanopb-0.4.2" 214 } 215 216Configuration: BUILDCONFIG.gn 217----------------------------- 218The file ``BUILDCONFIG.gn`` configures the GN build by defining any desired 219global variables/options. It can be located anywhere in the build tree, but is 220conventionally placed at the root. ``.gn`` points GN to this file. 221 222``BUILDCONFIG.gn`` is evaluated before any other GN files, and variables defined 223within it are placed into GN's global scope, becoming available in every file 224without requiring imports. 225 226The options configured in this file differ from those in ``.gn`` in two ways: 227 2281. ``BUILDCONFIG.gn`` is evaluated for every GN toolchain (and Pigweed target), 229 whereas ``.gn`` is only evaluated once. This allows ``BUILDCONFIG.gn`` to set 230 different options for each Pigweed target. 2312. In ``.gn``, only GN build arguments can be overridden. ``BUILDCONFIG.gn`` 232 allows defining arbitrary variables. 233 234Generally, it is preferable to expose configuration options through build args 235instead of globals in ``BUILDCONFIG.gn`` (something Pigweed's build previously 236did), as they are more flexible, greppable, and easier to manage. However, it 237may make sense to define project-specific constants in ``BUILDCONFIG.gn``. 238 239Pigweed's upstream ``BUILDCONFIG.gn`` does not define any variables; it just 240sets Pigweed's default toolchain, which GN requires. 241 242.. _top-level-build: 243 244Top-level GN targets: //BUILD.gn 245-------------------------------- 246The root ``BUILD.gn`` file defines all of the libraries, images, tests, and 247binaries built by a Pigweed project. This file is evaluated immediately after 248``BUILDCONFIG.gn``, with the active toolchain (which is the default toolchain 249at the start of a build). 250 251``//BUILD.gn`` is responsible for enumerating each of the Pigweed targets built 252by a project. This is done by instantiating a version of each of the project's 253GN target groups with each Pigweed target's toolchain. For example, in upstream, 254all of Pigweed's GN targets are contained within the ``pigweed_default`` group. 255This group is instantiated multiple times, with different Pigweed target 256toolchains. 257 258These groups include the following: 259 260* ``host`` -- builds ``pigweed_default`` with Clang or GCC, depending on the 261 platform 262* ``host_clang`` -- builds ``pigweed_default`` for the host with Clang 263* ``host_gcc`` -- builds ``pigweed_default`` for the host with GCC 264* ``stm32f429i`` -- builds ``pigweed_default`` for STM32F429i Discovery board 265* ``docs`` -- builds the Pigweed documentation and size reports 266 267Pigweed projects are recommended to follow this pattern, creating a top-level 268group for each of their Pigweed targets that builds a common GN target with the 269appropriate toolchain. 270 271It is important that no dependencies are listed under the default toolchain 272within ``//BUILD.gn``, as it does not configure any build parameters, and 273therefore should not evaluate any other GN files. The pattern that Pigweed uses 274to achieve this is to wrap all dependencies within a condition checking the 275toolchain. 276 277.. code-block:: 278 279 group("my_application_images") { 280 deps = [] # Empty in the default toolchain. 281 282 if (current_toolchain != default_toolchain) { 283 # This is only evaluated by Pigweed target toolchains, which configure 284 # all of the required options to build Pigweed code. 285 deps += [ "//images:evt" ] 286 } 287 } 288 289 # The images group is instantiated for each of the project's Pigweed targets. 290 group("my_pigweed_target") { 291 deps = [ ":my_application_images(//toolchains:my_pigweed_target)" ] 292 } 293 294.. warning:: 295 Pigweed's default toolchain is never used, so it is set to an empty toolchain 296 which doesn't define any tools. ``//BUILD.gn`` contains conditions which check 297 that the current toolchain is not the default before declaring any GN target 298 dependencies to prevent the default toolchain from evaluating any other BUILD 299 files. All GN targets added to the build must be placed under one of these 300 conditional scopes. 301 302"default" group 303^^^^^^^^^^^^^^^ 304The root ``BUILD.gn`` file can define a special group named ``default``. If 305present, Ninja will build this group when invoked without arguments. 306 307.. tip:: 308 Defining a ``default`` group makes using ``pw watch`` simple! 309 310Optimization levels 311^^^^^^^^^^^^^^^^^^^ 312Pigweed's ``//BUILD.gn`` defines the ``pw_DEFAULT_C_OPTIMIZATION_LEVEL`` build 313arg, which specifies the optimization level to use for the default groups 314(``host``, ``stm32f429i``, etc.). The supported values for 315``pw_DEFAULT_C_OPTIMIZATION_LEVEL`` are: 316 317* ``debug`` -- create debugging-friendly binaries (``-Og``) 318* ``size_optimized`` -- optimize for size (``-Os``) 319* ``speed_optimized`` -- optimized for speed, without increasing code size 320 (``-O2``) 321 322Pigweed defines versions of its groups in ``//BUILD.gn`` for each optimization 323level specified in the ``pw_C_OPTIMIZATION_LEVELS`` list. Rather than relying 324on ``pw_DEFAULT_C_OPTIMIZATION_LEVEL``, you may directly build a group at the 325desired optimization level: ``<group>_<optimization>``. Examples include 326``host_clang_debug``, ``host_gcc_size_optimized``, and 327``stm32f429i_speed_optimized``. 328 329Upstream GN target groups 330^^^^^^^^^^^^^^^^^^^^^^^^^ 331In upstream, Pigweed splits its top-level GN targets into a few logical groups, 332which are described below. In order to build a GN target, it *must* be listed in 333one of the groups in this file. 334 335.. important:: 336 337 Pigweed's top-level ``BUILD.gn`` file should not be used by downstream 338 projects. Projects that wish to pull all of Pigweed's code into their build 339 may use the ``pw_modules`` and ``pw_module_tests`` variables in 340 ``modules.gni``. 341 342apps 343~~~~ 344This group defines the application images built in Pigweed. It lists all of the 345common images built across all Pigweed targets, such as modules' example 346executables. Each Pigweed target can additionally provide its own specific 347images through the ``pw_TARGET_APPLICATIONS`` build arg, which is included by 348this group. 349 350host_tools 351~~~~~~~~~~ 352This group defines host-side tooling binaries built for Pigweed. 353 354runtime_sanitizers 355~~~~~~~~~~~~~~~~~~ 356This group defines host-side build targets for Clang runtime sanitizers. 357Next runtime sanitizers supported: 358 359* ``asan`` -- `AddressSanitizer`_ is a fast memory error detector. 360* ``msan`` -- `MemorySanitizer`_ is a detector of uninitialized reads. 361* ``ubsan`` -- `UndefinedBehaviorSanitizer`_ is a fast undefined behavior detector. 362* ``ubsan_heuristic`` -- `UndefinedBehaviorSanitizer`_ with the following 363 additional checks enabled: 364 365 * ``integer``: Checks for undefined or suspicious integer behavior. 366 * ``float-divide-by-zero``: Checks for floating point division by zero. 367 * ``implicit-conversion``: Checks for suspicious behavior of implicit conversions. 368 * ``nullability``: Checks for null as function arg, lvalue and return type. 369 370 These additional checks are heuristic and may not correspond to undefined 371 behavior. 372* ``tsan`` -- `ThreadSanitizer`_ is a tool that detects data races. 373 374Results of building this group are ``host_clang_<sanitizer>`` build directories 375with ``pw_module_tests`` per supported sanitizer. 376 377.. _AddressSanitizer: https://clang.llvm.org/docs/AddressSanitizer.html 378.. _MemorySanitizer: https://clang.llvm.org/docs/MemorySanitizer.html 379.. _UndefinedBehaviorSanitizer: https://clang.llvm.org/docs/UndefinedBehaviorSanitizer.html 380.. _ThreadSanitizer: https://clang.llvm.org/docs/ThreadSanitizer.html 381 382coverage 383~~~~~~~~~~ 384This group defines host-side build target for Clang source-based code coverage. 385 386pw_modules 387~~~~~~~~~~ 388This group lists the main libraries for all of Pigweed's modules. 389 390The modules in the ``pw_modules`` group are listed in the ``pw_modules`` 391variable, which is provided by ``modules.gni``. 392 393pw_module_tests 394~~~~~~~~~~~~~~~ 395All modules' unit tests are collected here, so that they can all be run at once. 396 397The test groups in ``pw_module_tests`` group are listed in the 398``pw_module_tests`` variable, which is provided by ``modules.gni``. 399 400pigweed_default 401~~~~~~~~~~~~~~~ 402This group defines everything built in a Pigweed build invocation by collecting 403the above groups and conditionally depending on them based on the active Pigweed 404target's configuration. Generally, new dependencies should not be added here; 405instead, use one of the groups listed above. 406 407The ``pigweed_default`` group is instantiated for each upstream Pigweed target's 408toolchain. 409 410Pigweed target instantiations 411~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 412These groups wrap ``pigweed_default`` with a specific target toolchain. They are 413named after the Pigweed target, e.g. ``host_clang``, ``stm32f429i``, etc. 414 415Other BUILD files: //\*\*/BUILD.gn 416---------------------------------- 417The rest of the ``BUILD.gn`` files in the tree define libraries, configs, and 418build args for each of the modules in a Pigweed project. 419 420Project configuration: //build_overrides/pigweed.gni 421---------------------------------------------------- 422Each Pigweed project must contain a Pigweed configuration file at a known 423location in the GN build tree. Currently, this file only contains a single build 424argument, which must be set to the GN build path to the root of the Pigweed 425repository within the project. 426 427Module variables 428---------------- 429As Pigweed is intended to be a subcomponent of a larger project, it cannot assume 430where it or its modules is located. Therefore, Pigweed's upstream BUILD.gn files 431do not use absolute paths; instead, variables are defined pointing to each of 432Pigweed's modules, set relative to a project-specific ``dir_pigweed``. 433 434To depend on Pigweed modules from GN code, import Pigweed's overrides file and 435reference these module variables. 436 437.. code-block:: 438 439 # This must be imported before .gni files from any other Pigweed modules. To 440 # prevent gn format from reordering this import, it must be separated by a 441 # blank line from other imports. 442 443 import("//build_overrides/pigweed.gni") 444 445GN target type wrappers 446----------------------- 447To facilitate injecting global configuration options, Pigweed defines wrappers 448around builtin GN target types such as ``source_set`` and ``executable``. These 449are defined within ``$dir_pw_build/target_types.gni``. 450 451.. note:: 452 To take advantage of Pigweed's flexible target configuration system, use 453 ``pw_*`` target types (e.g. ``pw_source_set``) in your BUILD.gn files instead 454 of GN builtins. 455 456Pigweed targets 457--------------- 458To build for a specific hardware platform, builds define Pigweed targets. These 459are essentially GN toolchains which set special arguments telling Pigweed how to 460build. For information on Pigweed's target system, refer to 461:ref:`docs-targets`. 462 463The empty toolchain 464------------------- 465Pigweed's ``BUILDCONFIG.gn`` sets the project's default toolchain to an "empty" 466toolchain which does not specify any compilers or override any build arguments. 467Downstream projects are recommended to do the same, following the steps 468described in :ref:`top-level-build` to configure builds for each of their 469Pigweed targets. 470 471.. admonition:: Why use an empty toolchain? 472 473 To support some of its advanced (and useful!) build features, Pigweed requires 474 the ability to generate new toolchains on the fly. This requires having 475 knowledge of the full configuration of the current toolchain (which is easy if 476 it's all defined within a scope), something which is impractical to achieve 477 using the default toolchain. 478 479 Additionally, there are some cases where GN treats default and non-default 480 toolchains differently. By not using the default toolchain, we avoid having 481 to deal with these inconsistencies. 482 483 It is possible to build Pigweed using only the default toolchain, but it 484 requires a more complicated setup to get everything working and should be 485 avoided unless necessary (for example, when integrating with a large existing 486 GN-based project). 487 488Upstream development examples 489----------------------------- 490If developing for upstream Pigweed, some common build use cases are described 491below. 492 493Building a custom executable/app image 494^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 495 4961. Define your executable GN target using the ``pw_executable`` template. 497 498 .. code-block:: 499 500 # //foo/BUILD.gn 501 pw_executable("foo") { 502 sources = [ "main.cc" ] 503 deps = [ ":libfoo" ] 504 } 505 5062. In the root ``BUILD.gn`` file, add the executable's GN target to the ``apps`` 507 group. 508 509 .. code-block:: 510 511 # //BUILD.gn 512 group("apps") { 513 deps = [ 514 # ... 515 "//foo", # Shorthand for //foo:foo 516 ] 517 } 518 5193. Run the ninja build to compile your executable. The apps group is built by 520 default, so there's no need to provide a target. The executable will be 521 compiled for every supported Pigweed target. 522 523 .. code-block:: 524 525 ninja -C out 526 527 Alternatively, build your executable by itself by specifying its path to 528 Ninja. When building a GN target manually, the Pigweed target for which it 529 is built must be specified on the Ninja command line. 530 531 For example, to build for the Pigweed target ``host_gcc_debug``: 532 533 .. code-block:: 534 535 ninja -C out host_gcc_debug/obj/foo/bin/foo 536 537 .. note:: 538 539 The path passed to Ninja is a filesystem path within the ``out`` directory, 540 rather than a GN path. This path can be found by running ``gn outputs``. 541 5424. Retrieve your compiled binary from the out directory. It is located at the 543 path 544 545 .. code-block:: 546 547 out/<pw_target>/obj/<gn_path>/{bin,test}/<executable> 548 549 where ``pw_target`` is the Pigweed target for which the binary was built, 550 ``gn_path`` is the GN path to the BUILD.gn file defining the executable, 551 and ``executable`` is the executable's GN target name (potentially with an 552 extension). Note that the executable is located within a ``bin`` subdirectory 553 in the module (or ``test`` for unit tests defined with ``pw_test``). 554 555 For example, the ``foo`` executable defined above and compiled for the 556 Pigweed target stm32f429i_disc1_debug is found at: 557 558 .. code-block:: 559 560 out/stm32f429i_disc1_debug/obj/foo/bin/foo 561 562The CMake build 563=============== 564A well-known name in C/C++ development, `CMake`_ is widely used by all kinds of 565projects, including embedded devices. Pigweed's CMake support is provided 566primarily for projects that have an existing CMake build and wish to integrate 567Pigweed modules. 568 569.. _docs-build-system-bazel: 570 571The Bazel build 572=============== 573This section describes Pigweed's Bazel build structure, how it is used upstream, 574build conventions, and recommendations for Pigweed-based projects. While 575containing some details about how Bazel works in general, this section is not 576intended to be a guide on how to use Bazel. To learn more about the tool itself, 577refer to the official `Bazel reference`_. 578 579.. _Bazel reference: https://www.bazel.build/ 580 581General usage 582------------- 583While described in more detail in the Bazel docs there a few Bazel features that 584are of particular importance when targeting embedded platforms. The most 585commonly used commands used in bazel are; 586 587.. code-block:: sh 588 589 bazelisk build //your:target 590 bazelisk test //your:target 591 bazelisk coverage //your:target 592 593.. note:: Code coverage support is only available on the host for now. 594 595Building 596^^^^^^^^ 597When it comes to building/testing your build target for a specific target 598platform (e.g. stm32f429i-discovery) a slight variation is required. 599 600.. code-block:: sh 601 602 bazelisk build //your:target \ 603 --platforms=@pigweed//pw_build/platforms:lm3s6965evb 604 605For more information on how to create your own platforms refer to the official 606`Bazel platforms reference`_. You may also find helpful examples of constraints 607and platforms in the ``//pw_build/platforms`` and ``//pw_build/constraints`` 608directories. 609 610.. _Bazel platforms reference: https://docs.bazel.build/versions/main/platforms.html 611 612Testing 613^^^^^^^ 614Running tests on an embedded target with Bazel is possible although support for 615this is experimental. The easiest way of achieving this at the moment is to use 616Bazel's ``--run_under`` flag. To make this work create a Bazel target 617(``//your_handler``) that: 618 6191. Takes a single argument (the path to the elf) and uploads the elf to your 620 Pigweed target. 6212. Connects with your target using serial or other communication method. 6223. Listens to the communication transport for the keywords ("PASSED", "FAIL") 623 and returns (0, 1) respectively if one of the keywords is intercepted. (This 624 step assumes you are using the pw_unit_test package and it is configured for 625 your target). 626 627Then, run: 628 629 .. code-block:: sh 630 631 bazelisk test //your:test --platforms=//your/platform --run_under=//your_handler 632 633Tag conventions 634~~~~~~~~~~~~~~~ 635Pigweed observes the standard Bazel test `tag conventions 636<https://bazel.build/reference/test-encyclopedia#tag-conventions>`_. We also 637use the following additional tags: 638 639* ``integration``: large, slow integration tests in upstream Pigweed are given 640 the ``integration`` tag. You can skip running these tests using 641 `--test_tag_filters 642 <https://bazel.build/docs/user-manual#test-tag-filters>`_. For example, 643 644 .. code-block:: sh 645 646 bazelisk test --test_tag_filters=-integration //... 647 648 will run all tests *except* for these integration tests. 649 650* ``do_not_build``: targets which should not be built in wildcard builds. Any 651 use of this tag should be associated with a TODO pointing to a bug. Prefer 652 ``do_not_build`` to ``manual`` if the target's build graph is correct, and 653 it just fails at the compilation stage. 654 655* ``do_not_run_test``: test targets which should be built but not executed. 656 Prefer this to ``manual`` or ``do_not_build`` if the code compiles, but the 657 test fails at runtime. Any use of this tag should be associated with a TODO 658 pointing to a bug. 659 660.. _docs-build_system-bazel_coverage: 661 662Code Coverage 663^^^^^^^^^^^^^ 664TODO(`b/304833225 <https://issues.pigweed.dev/issues/304833225>`_): Fix code 665coverage when using the (default) hermetic toolchains. 666 667Making use of the code coverage functionality in Bazel is straightforward. 668 6691. Add the following lines to your '.bazelrc'. 670 671 .. code-block:: sh 672 673 coverage --experimental_generate_llvm_lcov 674 coverage --combined_report=lcov 675 6762. Generate a combined lcov coverage report. This will produce a combined lcov 677 coverage report at the path 'bazel-out/_coverage/_coverage_report.dat'. e.g. 678 679 .. code-block:: sh 680 681 bazelisk coverage //pw_log/... 682 6833. View the results using the command line utility 'lcov'. 684 685 .. code-block:: sh 686 687 lcov --list bazel-out/_coverage/_coverage_report.dat 688 689.. _docs-build_system-bazel_link-extra-lib: 690 691Libraries required at linktime 692^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 693Certain low-level libraries (:ref:`module-pw_assert`, :ref:`module-pw_log`) are 694prone to cyclic dependencies. Handling assertions and logging requires using 695other libraries, which themselves may use assertions or logging. To remove 696these cycles, the full implementations of these libraries are placed in special 697*implementation targets* that are not added to their dependencies. Instead, 698every binary with a dependency on these libraries (direct or indirect) must 699link against the implementation targets. 700 701What this means in practice is that any ``cc_binary`` that depends on Pigweed 702libraries should have a dependency on ``//pw_build:default_link_extra_lib``. 703This can be added in a couple ways: 704 705#. Add ``@pigweed//pw_build:default_link_extra_lib`` directly to the ``deps`` 706 of every embedded ``cc_binary`` in your project. 707 708 The con is that you may forget to add the dependency to some targets, 709 and will then encounter puzzling linker errors. 710 711#. Use `link_extra_lib 712 <https://bazel.build/reference/be/c-cpp#cc_binary.link_extra_lib>`_. Set 713 the ``@bazel_tools//tools/cpp:link_extra_libs`` label flag to point to 714 ``@pigweed//pw_build:default_link_extra_lib``, probably using `bazelrc 715 <https://bazel.build/run/bazelrc>`_. This is only likely to work if you 716 specify the ``--experimental_exclude_starlark_flags_from_exec_config`` 717 flag, available in Bazel 8 and newer; see `bazelbuild/bazel#22457 718 <https://github.com/bazelbuild/bazel/issues/22457>`__. 719 720 The con is that these libraries are linked into *all* C++ binaries that are 721 part of your project's build, including ones that have no dependencies on 722 Pigweed. 723 724 725Note that depending on ``@pigweed//pw_build:link_extra_lib`` will 726*unconditionally* include the symbols in the implementation targets in your 727binary, even if the binary does not use them. If this is a concern (e.g., due 728to the binary size increase), depend only on the individual implementation 729targets you actually require. 730 731See :ref:`module-pw_log-circular-deps` and 732:ref:`module-pw_assert-circular-deps` for more information about the specific 733modules that have link-time dependencies. 734 735Configuration 736------------- 737Generally speaking there are three primary concepts that make up Bazel's 738configuration API. 739 7401. Selects 7412. Compatibility lists 7423. Flags/Build settings 743 744Selects 745^^^^^^^ 746Selects are useful for specifying different dependencies/source depending on the 747platform that is currently being targeted. For more information on this please 748see the `Bazel selects reference`_. e.g. 749 750.. code-block:: py 751 752 cc_library( 753 name = "some_platform_dependant_library", 754 deps = select({ 755 "@platforms//cpu:armv7e-m": [":arm_libs"], 756 "//conditions:default": [":host_libs"], 757 }), 758 ) 759 760Compatibility lists 761^^^^^^^^^^^^^^^^^^^ 762Compatibility lists allow you to specify which platforms your targets are 763compatible with. Consider an example where you want to specify that a target is 764compatible with only a host os; 765 766.. code-block:: py 767 768 cc_library( 769 name = "some_host_only_lib", 770 srcs = ["host.cc"], 771 target_compatible_with = select({ 772 "@platforms//os:windows": [], 773 "@platforms//os:linux": [], 774 "@platforms//os:ios": [], 775 "@platforms//os:macos": [], 776 "//conditions:default": ["@platforms//:incompatible"], 777 }), 778 ) 779 780In this case building from or for either Windows/Linux/Mac will be supported, but 781other OS's will fail if this target is explicitly depended on. However if 782building with a wild card for a non-host platform this target will be skipped 783and the build will continue. e.g. 784 785.. code-block:: sh 786 787 bazelisk build //... --platforms=@pigweed//pw_build/platforms:lm3s6965evb 788 789This allows for you to easily create compatibility matricies without adversely 790affecting your ability build your entire repo for a given Pigweed target. 791For more detailed information on how to use the target_compatible_with attribute 792please see `Bazel target_compatible_with reference`_. 793 794.. _docs-build_system-bazel_flags: 795 796Flags/build settings 797^^^^^^^^^^^^^^^^^^^^ 798Flags/build settings are particularly useful in scenarios where you may want to 799be able to quickly inject a dependency from the command line but don't 800necessarily want to create an entirely new set of constraints to use with a 801select statement. 802 803.. note:: 804 The scope for what is possible with build flags/settings goes well beyond 805 what will be described here. For more detailed information on flags/settings 806 please see `Bazel config reference`_. 807 808A simple example of when it is useful to use a label_flag is when you want to 809swap out a single dependency from the command line. e.g. 810 811.. code-block:: py 812 813 cc_library( 814 name = "some_default_io", 815 srcs = ["default_io.cc"], 816 ) 817 818 cc_library( 819 name = "some_other_io", 820 srcs = ["other_io.cc"], 821 ) 822 823 label_flag( 824 name = "io", 825 default_build_setting = ":some_default_io", 826 ) 827 828 cc_library( 829 name = "some_target_that_needs_io", 830 deps = [":io"], 831 ) 832 833From here the label_flag by default redirects to the target ":some_default_io", 834however it is possible to override this from the command line. e.g. 835 836.. code-block:: sh 837 838 bazelisk build //:some_target_that_needs_io --//:io=//:some_other_io 839 840 841 842.. _Bazel selects reference: https://docs.bazel.build/versions/main/configurable-attributes.html#select-and-dependencies 843 844.. _Bazel target_compatible_with reference: https://docs.bazel.build/versions/main/platforms.html#skipping-incompatible-targets 845 846.. _Bazel config reference: https://docs.bazel.build/versions/main/skylark/config.html 847 848.. _docs-build_system-bazel_configuration: 849 850Facades and backends tutorial 851^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 852This section walks you through an example of configuring :ref:`facade 853<module-pw_build-bazel-pw_facade>` backends in a Pigweed Bazel 854project. 855 856Consider a scenario that you are building a flight controller for a spacecraft. 857But you have very little experience with Pigweed and have just landed here. 858First things first, you would set up your WORKSPACE to fetch Pigweed 859repository. Then, add the dependencies that you need from Pigweed's WORKSPACE. 860 861Maybe you want to try using the :ref:`pw_chrono <module-pw_chrono>` module. So 862you create a target in your repository like so: 863 864.. code-block:: python 865 866 # BUILD.bazel 867 cc_library( 868 name = "time_is_relative", 869 srcs = ["relative_time_on_earth.cc"], 870 deps = ["@pigweed//pw_chrono:system_clock"], 871 ) 872 873This should work out of the box for any host operating system. E.g., running, 874 875.. code-block:: console 876 877 bazelisk build //:time_is_relative 878 879will produce a working library for your host OS. 880 881Using Pigweed-provided backends 882~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 883But you're probably here because Pigweed offers a set of embedded libraries, 884and might be interested in running your code on some micro-controller/FPGA 885combined with an RTOS. For now let's assume you are using FreeRTOS and are 886happy to make use of our default ``//pw_chrono`` backend for FreeRTOS. You 887could build your library with: 888 889.. code-block:: console 890 891 bazelisk build \ 892 --@pigweed/pw_chrono:system_clock_backend=@pigweed//pw_chrono_freertos:system_clock \ 893 //:time_is_relative 894 895Then, ``//pw_chrono:system_clock`` will use the FreeRTOS backend 896``//pw_chrono_freertos:system_clock``. 897 898How does this work? Here's the relevant part of the dependency tree for your 899target: 900 901.. code-block:: 902 903 //:time_is_relative 904 | 905 v 906 @pigweed//pw_chrono:system_clock -------> @pigweed//pw_chrono:system_clock_backend 907 | (Injectable) 908 | | 909 | v 910 | @pigweed//pw_chrono_freertos:system_clock 911 | (Actual backend) 912 v | 913 @pigweed//pw_chrono:system_clock.facade <------------------. 914 915When building ``//:time_is_relative``, Bazel checks the dependencies of 916``@pigweed//pw_chrono:system_clock`` and finds that it depends on 917``@pigweed//pw_chrono:system_clock_backend``, which looks like this: 918 919.. code-block:: python 920 921 # @pigweed//pw_chrono/BUILD.bazel 922 923 label_flag( 924 name = "system_clock_backend", 925 build_setting_default = ":unspecified system_clock_backend", 926 ) 927 928This is a `label_flag 929<https://bazel.build/extending/config#label-typed-build-settings>`_: a 930dependency edge in the build graph that can be overridden by command line 931flags. By setting 932 933.. code-block:: console 934 935 --@pigweed//pw_chrono:system_clock_backend=\ 936 @pigweed//pw_chrono_freertos:system_clock 937 938on the command line, you told Bazel to override the default and use the 939FreeRTOS backend. 940 941Defining a custom backend 942~~~~~~~~~~~~~~~~~~~~~~~~~ 943Continuing with our scenario, let's say that you have read 944:ref:`docs-module-structure` and now want to implement your own backend for 945``//pw_chrono:system_clock`` using a hardware RTC. In this case you would 946create a new directory ``pw_chrono_my_hardware_rtc``, containing some header 947files and a BUILD file like, 948 949.. code-block:: python 950 951 # //pw_chrono_my_hardware_rtc/BUILD.bazel 952 953 cc_library( 954 name = "system_clock", 955 hdrs = [ 956 "public/pw_chrono_stl/system_clock_config.h", 957 "public/pw_chrono_stl/system_clock_inline.h", 958 "public_overrides/pw_chrono_backend/system_clock_config.h", 959 "public_overrides/pw_chrono_backend/system_clock_inline.h", 960 ], 961 includes = [ 962 "public", 963 "public_overrides", 964 ], 965 deps = [ 966 "@pigweed//pw_chrono:system_clock.facade", 967 ], 968 ) 969 970To build your ``//:time_is_relative`` target using this backend, you'd run, 971 972.. code-block:: console 973 974 bazelisk build //:time_is_relative \ 975 --@pigweed//pw_chrono:system_clock_backend=//pw_chrono_my_hardware_rtc:system_clock 976 977This modifies the build graph to look something like this: 978 979.. code-block:: 980 981 //:time_is_relative 982 | 983 v 984 @pigweed//pw_chrono:system_clock -------> @pigweed//pw_chrono:system_clock_backend 985 | (Injectable) 986 | | 987 | v 988 | //pw_chrono_my_hardware_rtc:system_clock 989 | (Actual backend) 990 v | 991 @pigweed//pw_chrono:system_clock.facade <------------------. 992 993Associating backends with platforms through bazelrc 994~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 995As your project grows, you will want to select backends for an increasing 996number of facades. The right backend to choose will depend on the target 997platform (host vs embedded, with potentially multiple target embedded 998platforms). Managing this directly through command-line flags is generally an 999anti-pattern. Instead, group these flags into configs in your 1000`bazelrc <https://bazel.build/run/bazelrc>`_. Eventually, your bazelrc may look 1001something like this: 1002 1003.. code-block:: sh 1004 1005 # The Cortex M7 config 1006 build:m7 --@pigweed//pw_chrono:system_clock_backend=//pw_chrono_my_hardware_rtc:system_clock 1007 build:m7 --@pigweed//pw_sys_io:backend=//cortex-m7:sys_io 1008 1009 # The Cortex M4 config 1010 build:m4 --@pigweed//pw_chrono:system_clock_backend=//pw_chrono_my_hardware_rtc:system_clock 1011 build:m4 --@pigweed//pw_sys_io:backend=//cortex-m4:sys_io 1012 build:m4 --@pigweed//pw_log:backend=@pigweed//pw_log_string 1013 build:m4 --@pigweed//pw_log_string:handler_backend=@pigweed//pw_system:log_backend 1014 1015Then, to build your library for a particular configuration, on the command line 1016you just specify the ``--config`` on the command line: 1017 1018.. code-block:: console 1019 1020 bazelisk build --config=m4 //:time_is_relative 1021