| .. _module-pw_build-bazel: |
| |
| Bazel |
| ===== |
| .. pigweed-module-subpage:: |
| :name: pw_build |
| |
| Bazel is currently very experimental, and only builds for host and ARM Cortex-M |
| microcontrollers. |
| |
| .. _module-pw_build-bazel-wrapper-rules: |
| |
| Wrapper rules |
| ------------- |
| The common configuration for Bazel for all modules is in the ``pigweed.bzl`` |
| file. The built-in Bazel rules ``cc_binary``, ``cc_test`` are wrapped with |
| ``pw_cc_binary`` and ``pw_cc_test``. |
| |
| .. _module-pw_build-bazel-pw_linker_script: |
| |
| pw_linker_script |
| ---------------- |
| In addition to wrapping the built-in rules, Pigweed also provides a custom |
| rule for handling linker scripts with Bazel. e.g. |
| |
| .. code-block:: python |
| |
| pw_linker_script( |
| name = "some_linker_script", |
| linker_script = ":some_configurable_linker_script.ld", |
| defines = [ |
| "PW_BOOT_FLASH_BEGIN=0x08000200", |
| "PW_BOOT_FLASH_SIZE=1024K", |
| "PW_BOOT_HEAP_SIZE=112K", |
| "PW_BOOT_MIN_STACK_SIZE=1K", |
| "PW_BOOT_RAM_BEGIN=0x20000000", |
| "PW_BOOT_RAM_SIZE=192K", |
| "PW_BOOT_VECTOR_TABLE_BEGIN=0x08000000", |
| "PW_BOOT_VECTOR_TABLE_SIZE=512", |
| ], |
| deps = [":some_header_library"], |
| ) |
| |
| # You can include headers provided by targets specified in deps. |
| cc_library( |
| name = "some_header_library", |
| hdrs = ["test_header.h"], |
| includes = ["."], |
| ) |
| |
| # You can include the linker script in the deps. |
| cc_binary( |
| name = "some_binary", |
| srcs = ["some_source.cc"], |
| deps = [":some_linker_script"], |
| ) |
| |
| # Alternatively, you can use additional_linker_inputs and linkopts. This |
| # allows you to explicitly specify the command line order of linker scripts, |
| # and may be useful if your project defines more than one. |
| cc_binary( |
| name = "some_binary", |
| srcs = ["some_source.cc"], |
| additional_linker_inputs = [":some_linker_script"], |
| linkopts = ["-T $(location :some_linker_script)"], |
| ) |
| |
| .. _module-pw_build-bazel-pw_facade: |
| |
| pw_facade |
| --------- |
| In Bazel, a :ref:`facade <docs-module-structure-facades>` module has a few |
| components: |
| |
| #. The **facade target**, i.e. the interface to the module. This is what |
| *backend implementations* depend on to know what interface they're supposed |
| to implement. |
| |
| #. The **library target**, i.e. both the facade (interface) and backend |
| (implementation). This is what *users of the module* depend on. It's a |
| regular ``cc_library`` that exposes the same headers as the facade, but |
| has a dependency on the "backend label flag" (discussed next). It may also |
| include some source files (if these are backend-independent). |
| |
| Both the facade and library targets are created using the |
| ``pw_facade`` macro. For example, consider the following |
| macro invocation: |
| |
| .. code-block:: python |
| |
| pw_facade( |
| name = "binary_semaphore", |
| # A backend-independent source file. |
| srcs = [ |
| "binary_semaphore.cc", |
| ], |
| # The facade header. |
| hdrs = [ |
| "public/pw_sync/binary_semaphore.h", |
| ], |
| # Dependencies of this header. |
| deps = [ |
| "//pw_chrono:system_clock", |
| "//pw_preprocessor", |
| ], |
| # The backend, hidden behind a label_flag; see below. |
| backend = [ |
| ":binary_semaphore_backend", |
| ], |
| ) |
| |
| This macro expands to both the library target, named ``binary_semaphore``, |
| and the facade target, named ``binary_semaphore.facade``. |
| |
| #. The **backend label flag**. This is a `label_flag |
| <https://bazel.build/extending/config#label-typed-build-settings>`_: a |
| dependency edge in the build graph that can be overridden by downstream projects. |
| |
| #. The **backend target** implements a particular backend for a facade. It's |
| just a plain ``cc_library``, with a dependency on the facade target. For example, |
| |
| .. code-block:: python |
| |
| cc_library( |
| name = "binary_semaphore", |
| srcs = [ |
| "binary_semaphore.cc", |
| ], |
| hdrs = [ |
| "public/pw_sync_stl/binary_semaphore_inline.h", |
| "public/pw_sync_stl/binary_semaphore_native.h", |
| "public_overrides/pw_sync_backend/binary_semaphore_inline.h", |
| "public_overrides/pw_sync_backend/binary_semaphore_native.h", |
| ], |
| includes = [ |
| "public", |
| "public_overrides", |
| ], |
| deps = [ |
| # Dependencies of the backend's headers and sources. |
| "//pw_assert", |
| "//pw_chrono:system_clock", |
| # A dependency on the facade target, which defines the interface |
| # this backend target implements. |
| "//pw_sync:binary_semaphore.facade", |
| ], |
| ) |
| |
| If a project uses only one backend for a given facade, the backend label |
| flag should point at that backend target. |
| |
| #. The **facade constraint setting** and **backend constraint values**. Every |
| facade has an associated `constraint setting |
| <https://bazel.build/concepts/platforms#api-review>`_ (enum used in platform |
| definition), and each backend for this facade has an associated |
| ``constraint_value`` (enum value). Example: |
| |
| .. code-block:: python |
| |
| # //pw_sync/BUILD.bazel |
| constraint_setting( |
| name = "binary_semaphore_backend_constraint_setting", |
| ) |
| |
| # //pw_sync_stl/BUILD.bazel |
| constraint_value( |
| name = "binary_semaphore_backend", |
| constraint_setting = "//pw_sync:binary_semaphore_backend_constraint_setting", |
| ) |
| |
| # //pw_sync_freertos/BUILD.bazel |
| constraint_value( |
| name = "binary_semaphore_backend", |
| constraint_setting = "//pw_sync:binary_semaphore_backend_constraint_setting", |
| ) |
| |
| `Target platforms <https://bazel.build/extending/platforms>`_ for Pigweed |
| projects should indicate which backend they select for each facade by |
| listing the corresponding ``constraint_value`` in their definition. This can |
| be used in a couple of ways: |
| |
| #. It allows projects to switch between multiple backends based only on the |
| `target platform <https://bazel.build/extending/platforms>`_ using a |
| *backend multiplexer* (see below) instead of setting label flags in |
| their ``.bazelrc``. |
| |
| #. It allows tests or libraries that only support a particular backend to |
| express this through the `target_compatible_with |
| <https://bazel.build/reference/be/common-definitions#common.target_compatible_with>`_ |
| attribute. Bazel will use this to `automatically skip incompatible |
| targets in wildcard builds |
| <https://bazel.build/extending/platforms#skipping-incompatible-targets>`_. |
| |
| #. The **backend multiplexer**. If a project uses more than one backend for a |
| given facade (e.g., it uses different backends for host and embedded target |
| builds), the backend label flag will point to a target that resolves to the |
| correct backend based on the target platform. This will typically be an |
| `alias <https://bazel.build/reference/be/general#alias>`_ with a ``select`` |
| statement mapping constraint values to the appropriate backend targets. For |
| example, |
| |
| .. code-block:: python |
| |
| alias( |
| name = "pw_sync_binary_semaphore_backend_multiplexer", |
| actual = select({ |
| "//pw_sync_stl:binary_semaphore_backend": "@pigweed//pw_sync_stl:binary_semaphore", |
| "//pw_sync_freertos:binary_semaphore_backend": "@pigweed//pw_sync_freertos:binary_semaphore_backend", |
| # If we're building for a host OS, use the STL backend. |
| "@platforms//os:macos": "@pigweed//pw_sync_stl:binary_semaphore", |
| "@platforms//os:linux": "@pigweed//pw_sync_stl:binary_semaphore", |
| "@platforms//os:windows": "@pigweed//pw_sync_stl:binary_semaphore", |
| # Unless the target platform is the host platform, it must |
| # explicitly specify which backend to use. The unspecified_backend |
| # is not compatible with any platform; taking this branch will produce |
| # an informative error. |
| "//conditions:default": "@pigweed//pw_build:unspecified_backend", |
| }), |
| ) |
| |
| pw_cc_blob_library |
| ------------------ |
| The ``pw_cc_blob_library`` rule is useful for embedding binary data into a |
| program. The rule takes in a mapping of symbol names to file paths, and |
| generates a set of C++ source and header files that embed the contents of the |
| passed-in files as arrays of ``std::byte``. |
| |
| The blob byte arrays are constant initialized and are safe to access at any |
| time, including before ``main()``. |
| |
| ``pw_cc_blob_library`` is also available in the :ref:`GN <module-pw_build-cc_blob_library>` |
| and CMake builds. |
| |
| Arguments |
| ^^^^^^^^^ |
| * ``blobs``: A list of ``pw_cc_blob_info`` targets, where each target |
| corresponds to a binary blob to be transformed from file to byte array. This |
| is a required field. ``pw_cc_blob_info`` attributes include: |
| |
| * ``symbol_name``: The C++ symbol for the byte array. |
| * ``file_path``: The file path for the binary blob. |
| * ``linker_section``: If present, places the byte array in the specified |
| linker section. |
| * ``alignas``: If present, uses the specified string verbatim in |
| the ``alignas()`` specifier for the byte array. |
| |
| * ``out_header``: The header file to generate. Users will include this file |
| exactly as it is written here to reference the byte arrays. |
| * ``namespace``: C++ namespace to place the generated blobs within. |
| * ``alwayslink``: Whether this library should always be linked. Defaults to false. |
| |
| Example |
| ^^^^^^^ |
| **BUILD.bazel** |
| |
| .. code-block:: python |
| |
| pw_cc_blob_info( |
| name = "foo_blob", |
| file_path = "foo.bin", |
| symbol_name = "kFooBlob", |
| ) |
| |
| pw_cc_blob_info( |
| name = "bar_blob", |
| file_path = "bar.bin", |
| symbol_name = "kBarBlob", |
| linker_section = ".bar_section", |
| ) |
| |
| pw_cc_blob_library( |
| name = "foo_bar_blobs", |
| blobs = [ |
| ":foo_blob", |
| ":bar_blob", |
| ], |
| out_header = "my/stuff/foo_bar_blobs.h", |
| namespace = "my::stuff", |
| ) |
| |
| .. note:: If the binary blobs are generated as part of the build, be sure to |
| list them as deps to the pw_cc_blob_library target. |
| |
| **Generated Header** |
| |
| .. code-block:: |
| |
| #pragma once |
| |
| #include <array> |
| #include <cstddef> |
| |
| namespace my::stuff { |
| |
| extern const std::array<std::byte, 100> kFooBlob; |
| |
| extern const std::array<std::byte, 50> kBarBlob; |
| |
| } // namespace my::stuff |
| |
| **Generated Source** |
| |
| .. code-block:: |
| |
| #include "my/stuff/foo_bar_blobs.h" |
| |
| #include <array> |
| #include <cstddef> |
| |
| #include "pw_preprocessor/compiler.h" |
| |
| namespace my::stuff { |
| |
| const std::array<std::byte, 100> kFooBlob = { ... }; |
| |
| PW_PLACE_IN_SECTION(".bar_section") |
| const std::array<std::byte, 50> kBarBlob = { ... }; |
| |
| } // namespace my::stuff |
| |
| .. _module-pw_build-bazel-pw_cc_binary_with_map: |
| |
| pw_cc_binary_with_map |
| --------------------- |
| The ``pw_cc_binary_with_map`` rule can be used to build a binary like |
| ``cc_binary`` does but also generate a .map file from the linking step. |
| |
| .. code-block:: python |
| |
| pw_cc_binary_with_map( |
| name = "test", |
| srcs = ["empty_main.cc"], |
| ) |
| |
| This should result in a ``test.map`` file generated next to the ``test`` binary. |
| |
| Note that it's only partially compatible with the ``cc_binary`` interface and |
| certain things are not implemented like make variable substitution. |
| |
| pw_elf_to_bin |
| ------------- |
| The ``pw_elf_to_bin`` rule takes in a binary executable target and produces a |
| file using the ``-Obinary`` option to ``objcopy``. This is only suitable for use |
| with binaries where all the segments are non-overlapping. A common use case for |
| this type of file is booting directly on hardware with no bootloader. |
| |
| .. code-block:: python |
| |
| load("@pigweed//pw_build:binary_tools.bzl", "pw_elf_to_bin") |
| |
| pw_elf_to_bin( |
| name = "bin", |
| elf_input = ":main", |
| bin_out = "main.bin", |
| ) |
| |
| pw_elf_to_dump |
| -------------- |
| The ``pw_elf_to_dump`` rule takes in a binary executable target and produces a |
| text file containing the output of the toolchain's ``objdump -xd`` command. This |
| contains the full binary layout, symbol table and disassembly which is often |
| useful when debugging embedded firmware. |
| |
| .. code-block:: python |
| |
| load("@pigweed//pw_build:binary_tools.bzl", "pw_elf_to_dump") |
| |
| pw_elf_to_dump( |
| name = "dump", |
| elf_input = ":main", |
| dump_out = "main.dump", |
| ) |
| |
| Miscellaneous utilities |
| ----------------------- |
| |
| .. _module-pw_build-bazel-empty_cc_library: |
| |
| empty_cc_library |
| ^^^^^^^^^^^^^^^^ |
| This empty library is used as a placeholder for label flags that need to point |
| to a library of some kind, but don't actually need the dependency to amount to |
| anything. |
| |
| default_link_extra_lib |
| ^^^^^^^^^^^^^^^^^^^^^^ |
| This library groups together all libraries commonly required at link time by |
| Pigweed modules. See :ref:`docs-build_system-bazel_link-extra-lib` for more |
| details. |
| |
| unspecified_backend |
| ^^^^^^^^^^^^^^^^^^^ |
| A special target used instead of a cc_library as the default condition in |
| backend multiplexer select statements to signal that a facade is in an |
| unconfigured state. This produces better error messages than e.g. using an |
| invalid label. |
| |
| Toolchains and platforms |
| ------------------------ |
| Pigweed provides clang-based host toolchains for Linux and Mac Arm gcc |
| toolchain. The clang-based Linux and Arm gcc toolchains are entirely hermetic. |
| We don't currently provide a host toolchain for Windows. |