• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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