• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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`` are wrapped with
17``pw_cc_binary`` and ``pw_cc_test``.
18
19.. _module-pw_build-bazel-pw_linker_script:
20
21pw_linker_script
22----------------
23In addition to wrapping the built-in rules, Pigweed also provides a custom
24rule for handling linker scripts with Bazel. e.g.
25
26.. code-block:: python
27
28   pw_linker_script(
29     name = "some_linker_script",
30     linker_script = ":some_configurable_linker_script.ld",
31     defines = [
32         "PW_BOOT_FLASH_BEGIN=0x08000200",
33         "PW_BOOT_FLASH_SIZE=1024K",
34         "PW_BOOT_HEAP_SIZE=112K",
35         "PW_BOOT_MIN_STACK_SIZE=1K",
36         "PW_BOOT_RAM_BEGIN=0x20000000",
37         "PW_BOOT_RAM_SIZE=192K",
38         "PW_BOOT_VECTOR_TABLE_BEGIN=0x08000000",
39         "PW_BOOT_VECTOR_TABLE_SIZE=512",
40     ],
41     deps = [":some_header_library"],
42   )
43
44   # You can include headers provided by targets specified in deps.
45   cc_library(
46     name = "some_header_library",
47     hdrs = ["test_header.h"],
48     includes = ["."],
49   )
50
51   # You can include the linker script in the deps.
52   cc_binary(
53     name = "some_binary",
54     srcs = ["some_source.cc"],
55     deps = [":some_linker_script"],
56   )
57
58   # Alternatively, you can use additional_linker_inputs and linkopts. This
59   # allows you to explicitly specify the command line order of linker scripts,
60   # and may be useful if your project defines more than one.
61   cc_binary(
62     name = "some_binary",
63     srcs = ["some_source.cc"],
64     additional_linker_inputs = [":some_linker_script"],
65     linkopts = ["-T $(location :some_linker_script)"],
66   )
67
68.. _module-pw_build-bazel-pw_facade:
69
70pw_facade
71---------
72In Bazel, a :ref:`facade <docs-module-structure-facades>` module has a few
73components:
74
75#. The **facade target**, i.e. the interface to the module. This is what
76   *backend implementations* depend on to know what interface they're supposed
77   to implement.
78
79#. The **library target**, i.e. both the facade (interface) and backend
80   (implementation). This is what *users of the module* depend on. It's a
81   regular ``cc_library`` that exposes the same headers as the facade, but
82   has a dependency on the "backend label flag" (discussed next). It may also
83   include some source files (if these are backend-independent).
84
85   Both the facade and library targets are created using the
86   ``pw_facade`` macro. For example, consider the following
87   macro invocation:
88
89   .. code-block:: python
90
91      pw_facade(
92          name = "binary_semaphore",
93          # A backend-independent source file.
94          srcs = [
95              "binary_semaphore.cc",
96          ],
97          # The facade header.
98          hdrs = [
99              "public/pw_sync/binary_semaphore.h",
100          ],
101          # Dependencies of this header.
102          deps = [
103              "//pw_chrono:system_clock",
104              "//pw_preprocessor",
105          ],
106          # The backend, hidden behind a label_flag; see below.
107          backend = [
108              ":binary_semaphore_backend",
109          ],
110      )
111
112   This macro expands to both the library target, named ``binary_semaphore``,
113   and the facade target, named ``binary_semaphore.facade``.
114
115#. The **backend label flag**. This is a `label_flag
116   <https://bazel.build/extending/config#label-typed-build-settings>`_: a
117   dependency edge in the build graph that can be overridden by downstream projects.
118
119#. The **backend target** implements a particular backend for a facade. It's
120   just a plain ``cc_library``, with a dependency on the facade target. For example,
121
122   .. code-block:: python
123
124      cc_library(
125          name = "binary_semaphore",
126          srcs = [
127              "binary_semaphore.cc",
128          ],
129          hdrs = [
130              "public/pw_sync_stl/binary_semaphore_inline.h",
131              "public/pw_sync_stl/binary_semaphore_native.h",
132              "public_overrides/pw_sync_backend/binary_semaphore_inline.h",
133              "public_overrides/pw_sync_backend/binary_semaphore_native.h",
134          ],
135          includes = [
136              "public",
137              "public_overrides",
138          ],
139          deps = [
140              # Dependencies of the backend's headers and sources.
141              "//pw_assert",
142              "//pw_chrono:system_clock",
143              # A dependency on the facade target, which defines the interface
144              # this backend target implements.
145              "//pw_sync:binary_semaphore.facade",
146          ],
147      )
148
149   If a project uses only one backend for a given facade, the backend label
150   flag should point at that backend target.
151
152#. The **facade constraint setting** and **backend constraint values**. Every
153   facade has an associated `constraint setting
154   <https://bazel.build/concepts/platforms#api-review>`_ (enum used in platform
155   definition), and each backend for this facade has an associated
156   ``constraint_value`` (enum value). Example:
157
158   .. code-block:: python
159
160      # //pw_sync/BUILD.bazel
161      constraint_setting(
162        name = "binary_semaphore_backend_constraint_setting",
163      )
164
165      # //pw_sync_stl/BUILD.bazel
166      constraint_value(
167        name = "binary_semaphore_backend",
168        constraint_setting = "//pw_sync:binary_semaphore_backend_constraint_setting",
169      )
170
171      # //pw_sync_freertos/BUILD.bazel
172      constraint_value(
173        name = "binary_semaphore_backend",
174        constraint_setting = "//pw_sync:binary_semaphore_backend_constraint_setting",
175      )
176
177   `Target platforms <https://bazel.build/extending/platforms>`_ for Pigweed
178   projects should indicate which backend they select for each facade by
179   listing the corresponding ``constraint_value`` in their definition. This can
180   be used in a couple of ways:
181
182   #.  It allows projects to switch between multiple backends based only on the
183       `target platform <https://bazel.build/extending/platforms>`_ using a
184       *backend multiplexer* (see below) instead of setting label flags in
185       their ``.bazelrc``.
186
187   #.  It allows tests or libraries that only support a particular backend to
188       express this through the `target_compatible_with
189       <https://bazel.build/reference/be/common-definitions#common.target_compatible_with>`_
190       attribute. Bazel will use this to `automatically skip incompatible
191       targets in wildcard builds
192       <https://bazel.build/extending/platforms#skipping-incompatible-targets>`_.
193
194#. The **backend multiplexer**. If a project uses more than one backend for a
195   given facade (e.g., it uses different backends for host and embedded target
196   builds), the backend label flag will point to a target that resolves to the
197   correct backend based on the target platform. This will typically be an
198   `alias <https://bazel.build/reference/be/general#alias>`_ with a ``select``
199   statement mapping constraint values to the appropriate backend targets. For
200   example,
201
202   .. code-block:: python
203
204      alias(
205          name = "pw_sync_binary_semaphore_backend_multiplexer",
206          actual = select({
207              "//pw_sync_stl:binary_semaphore_backend": "@pigweed//pw_sync_stl:binary_semaphore",
208              "//pw_sync_freertos:binary_semaphore_backend": "@pigweed//pw_sync_freertos:binary_semaphore_backend",
209              # If we're building for a host OS, use the STL backend.
210              "@platforms//os:macos": "@pigweed//pw_sync_stl:binary_semaphore",
211              "@platforms//os:linux": "@pigweed//pw_sync_stl:binary_semaphore",
212              "@platforms//os:windows": "@pigweed//pw_sync_stl:binary_semaphore",
213              # Unless the target platform is the host platform, it must
214              # explicitly specify which backend to use. The unspecified_backend
215              # is not compatible with any platform; taking this branch will produce
216              # an informative error.
217              "//conditions:default": "@pigweed//pw_build:unspecified_backend",
218          }),
219      )
220
221pw_cc_blob_library
222------------------
223The ``pw_cc_blob_library`` rule is useful for embedding binary data into a
224program. The rule takes in a mapping of symbol names to file paths, and
225generates a set of C++ source and header files that embed the contents of the
226passed-in files as arrays of ``std::byte``.
227
228The blob byte arrays are constant initialized and are safe to access at any
229time, including before ``main()``.
230
231``pw_cc_blob_library`` is also available in the :ref:`GN <module-pw_build-cc_blob_library>`
232and CMake builds.
233
234Arguments
235^^^^^^^^^
236* ``blobs``: A list of ``pw_cc_blob_info`` targets, where each target
237  corresponds to a binary blob to be transformed from file to byte array. This
238  is a required field. ``pw_cc_blob_info`` attributes include:
239
240  * ``symbol_name``: The C++ symbol for the byte array.
241  * ``file_path``: The file path for the binary blob.
242  * ``linker_section``: If present, places the byte array in the specified
243    linker section.
244  * ``alignas``: If present, uses the specified string verbatim in
245    the ``alignas()`` specifier for the byte array.
246
247* ``out_header``: The header file to generate. Users will include this file
248  exactly as it is written here to reference the byte arrays.
249* ``namespace``: C++ namespace to place the generated blobs within.
250* ``alwayslink``: Whether this library should always be linked. Defaults to false.
251
252Example
253^^^^^^^
254**BUILD.bazel**
255
256.. code-block:: python
257
258   pw_cc_blob_info(
259     name = "foo_blob",
260     file_path = "foo.bin",
261     symbol_name = "kFooBlob",
262   )
263
264   pw_cc_blob_info(
265     name = "bar_blob",
266     file_path = "bar.bin",
267     symbol_name = "kBarBlob",
268     linker_section = ".bar_section",
269   )
270
271   pw_cc_blob_library(
272     name = "foo_bar_blobs",
273     blobs = [
274       ":foo_blob",
275       ":bar_blob",
276     ],
277     out_header = "my/stuff/foo_bar_blobs.h",
278     namespace = "my::stuff",
279   )
280
281.. note:: If the binary blobs are generated as part of the build, be sure to
282          list them as deps to the pw_cc_blob_library target.
283
284**Generated Header**
285
286.. code-block::
287
288   #pragma once
289
290   #include <array>
291   #include <cstddef>
292
293   namespace my::stuff {
294
295   extern const std::array<std::byte, 100> kFooBlob;
296
297   extern const std::array<std::byte, 50> kBarBlob;
298
299   }  // namespace my::stuff
300
301**Generated Source**
302
303.. code-block::
304
305   #include "my/stuff/foo_bar_blobs.h"
306
307   #include <array>
308   #include <cstddef>
309
310   #include "pw_preprocessor/compiler.h"
311
312   namespace my::stuff {
313
314   const std::array<std::byte, 100> kFooBlob = { ... };
315
316   PW_PLACE_IN_SECTION(".bar_section")
317   const std::array<std::byte, 50> kBarBlob = { ... };
318
319   }  // namespace my::stuff
320
321.. _module-pw_build-bazel-pw_cc_binary_with_map:
322
323pw_cc_binary_with_map
324---------------------
325The ``pw_cc_binary_with_map`` rule can be used to build a binary like
326``cc_binary`` does but also generate a .map file from the linking step.
327
328.. code-block:: python
329
330   pw_cc_binary_with_map(
331     name = "test",
332     srcs = ["empty_main.cc"],
333   )
334
335This should result in a ``test.map`` file generated next to the ``test`` binary.
336
337Note that it's only partially compatible with the ``cc_binary`` interface and
338certain things are not implemented like make variable substitution.
339
340pw_elf_to_bin
341-------------
342The ``pw_elf_to_bin`` rule takes in a binary executable target and produces a
343file using the ``-Obinary`` option to ``objcopy``. This is only suitable for use
344with binaries where all the segments are non-overlapping. A common use case for
345this type of file is booting directly on hardware with no bootloader.
346
347.. code-block:: python
348
349   load("@pigweed//pw_build:binary_tools.bzl", "pw_elf_to_bin")
350
351   pw_elf_to_bin(
352     name = "bin",
353     elf_input = ":main",
354     bin_out = "main.bin",
355   )
356
357pw_elf_to_dump
358--------------
359The ``pw_elf_to_dump`` rule takes in a binary executable target and produces a
360text file containing the output of the toolchain's ``objdump -xd`` command. This
361contains the full binary layout, symbol table and disassembly which is often
362useful when debugging embedded firmware.
363
364.. code-block:: python
365
366   load("@pigweed//pw_build:binary_tools.bzl", "pw_elf_to_dump")
367
368   pw_elf_to_dump(
369     name = "dump",
370     elf_input = ":main",
371     dump_out = "main.dump",
372   )
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
398Toolchains and platforms
399------------------------
400Pigweed provides clang-based host toolchains for Linux and Mac Arm gcc
401toolchain. The clang-based Linux and Arm gcc toolchains are entirely hermetic.
402We don't currently provide a host toolchain for Windows.
403