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