diff options
Diffstat (limited to 'pw_build/docs.rst')
-rw-r--r-- | pw_build/docs.rst | 1189 |
1 files changed, 4 insertions, 1185 deletions
diff --git a/pw_build/docs.rst b/pw_build/docs.rst index a1df9d929..16d2ad8c9 100644 --- a/pw_build/docs.rst +++ b/pw_build/docs.rst @@ -24,1190 +24,9 @@ Beyond just compiling code, Pigweed’s GN build system can also: These are only supported in the GN build, so we recommend using it if possible. -GN / Ninja -========== -The GN / Ninja build system is the primary build system used for upstream -Pigweed development, and is the most tested and feature-rich build system -Pigweed offers. - -This module's ``build.gn`` file contains a number of C/C++ ``config`` -declarations that are used by upstream Pigweed to set some architecture-agnostic -compiler defaults. (See Pigweed's ``//BUILDCONFIG.gn``) - -``pw_build`` also provides several useful GN templates that are used throughout -Pigweed. - -Build system philosophies -------------------------- -While Pigweed's GN build is not hermetic, it strives to adhere to principles of -`hermeticity <https://bazel.build/concepts/hermeticity>`_. Some guidelines to -move towards the ideal of hermeticity include: - -* Only rely on pre-compiled tools provided by CIPD (or some other versioned, - pre-compiled binary distribution mechanism). This eliminates build artifact - differences caused by different tool versions or variations (e.g. same tool - version built with slightly different compilation flags). -* Do not use absolute paths in Ninja commands. Typically, these appear when - using ``rebase_path("//path/to/my_script.py")``. Most of the time, Ninja - steps should be passed paths rebased relative to the build directory (i.e. - ``rebase_path("//path/to/my_script.py", root_build_dir)``). This ensures build - commands are the same across different machines. -* Prevent produced artifacts from relying on or referencing system state. This - includes time stamps, writing absolute paths to generated artifacts, or - producing artifacts that reference system state in a way that prevents them - from working the same way on a different machine. -* Isolate build actions to the build directory. In general, the build system - should not add or modify files outside of the build directory. This can cause - confusion to users, and makes the concept of a clean build more ambiguous. - -Target types ------------- -.. code-block:: - - import("$dir_pw_build/target_types.gni") - - pw_source_set("my_library") { - sources = [ "lib.cc" ] - } - -Pigweed defines wrappers around the four basic GN binary types ``source_set``, -``executable``, ``static_library``, and ``shared_library``. These templates -do several things: - -#. **Add default configs/deps** - - Rather than binding the majority of compiler flags related to C++ standard, - cross-compilation, warning/error policy, etc. directly to toolchain - invocations, these flags are applied as configs to all ``pw_*`` C/C++ target - types. The primary motivations for this are to allow some targets to modify - the default set of flags when needed by specifying ``remove_configs``, and to - reduce the complexity of building novel toolchains. - - Pigweed's global default configs are set in ``pw_build/default.gni``, and - individual platform-specific toolchains extend the list by appending to the - ``default_configs`` build argument. - - Default deps were added to support polyfill, which has since been - deprecated. Default dependency functionality continues to exist for - backwards compatibility. - -#. **Optionally add link-time binding** - - Some libraries like pw_assert and pw_log are borderline impossible to - implement well without introducing circular dependencies. One solution for - addressing this is to break apart the libraries into an interface with - minimal dependencies, and an implementation with the bulk of the - dependencies that would typically create dependency cycles. In order for the - implementation to be linked in, it must be added to the dependency tree of - linked artifacts (e.g. ``pw_executable``, ``pw_static_library``). Since - there's no way for the libraries themselves to just happily pull in the - implementation if someone depends on the interface, the implementation is - instead late-bound by adding it as a direct dependency of the final linked - artifact. This is all managed through ``pw_build_LINK_DEPS``, which is global - for each toolchain and applied to every ``pw_executable``, - ``pw_static_library``, and ``pw_shared_library``. - -#. **Apply a default visibility policy** - - Projects can globally control the default visibility of pw_* target types by - specifying ``pw_build_DEFAULT_VISIBILITY``. This template applies that as the - default visibility for any pw_* targets that do not explicitly specify - a visibility. - -#. **Add source file names as metadata** - - All source file names are collected as - `GN metadata <https://gn.googlesource.com/gn/+/main/docs/reference.md#metadata_collection>`_. - This list can be writen to a file at build time using ``generated_file``. The - primary use case for this is to generate a token database containing all the - source files. This allows PW_ASSERT to emit filename tokens even though it - can't add them to the elf file because of the reasons described at - :ref:`module-pw_assert-assert-api`. - - .. note:: - ``pw_source_files``, if not rebased will default to outputing module - relative paths from a ``generated_file`` target. This is likely not - useful. Adding a ``rebase`` argument to ``generated_file`` such as - ``rebase = root_build_dir`` will result in usable paths. For an example, - see ``//pw_tokenizer/database.gni``'s ``pw_tokenizer_filename_database`` - template. - -The ``pw_executable`` template provides additional functionality around building -complete binaries. As Pigweed is a collection of libraries, it does not know how -its final targets are built. ``pw_executable`` solves this by letting each user -of Pigweed specify a global executable template for their target, and have -Pigweed build against it. This is controlled by the build variable -``pw_executable_config.target_type``, specifying the name of the executable -template for a project. - -In some uncommon cases, a project's ``pw_executable`` template definition may -need to stamp out some ``pw_source_set``\s. Since a pw_executable template can't -import ``$dir_pw_build/target_types.gni`` due to circular imports, it should -import ``$dir_pw_build/cc_library.gni`` instead. - -.. tip:: - - Prefer to use ``pw_executable`` over plain ``executable`` targets to allow - cleanly building the same code for multiple target configs. - -**Arguments** - -All of the ``pw_*`` target type overrides accept any arguments supported by -the underlying native types, as they simply forward them through to the -underlying target. - -Additionally, the following arguments are also supported: - -* **remove_configs**: (optional) A list of configs / config patterns to remove - from the set of default configs specified by the current toolchain - configuration. -* **remove_public_deps**: (optional) A list of targets to remove from the set of - default public_deps specified by the current toolchain configuration. - -.. _module-pw_build-link-deps: - -Link-only deps --------------- -It may be necessary to specify additional link-time dependencies that may not be -explicitly depended on elsewhere in the build. One example of this is a -``pw_assert`` backend, which may need to leave out dependencies to avoid -circular dependencies. Its dependencies need to be linked for executables and -libraries, even if they aren't pulled in elsewhere. - -The ``pw_build_LINK_DEPS`` build arg is a list of dependencies to add to all -``pw_executable``, ``pw_static_library``, and ``pw_shared_library`` targets. -This should only be used as a last resort when dependencies cannot be properly -expressed in the build. - -Python packages ---------------- -GN templates for :ref:`Python build automation <docs-python-build>` are -described in :ref:`module-pw_build-python`. - .. toctree:: - :hidden: - - python - - -.. _module-pw_build-cc_blob_library: - -pw_cc_blob_library ------------------- -The ``pw_cc_blob_library`` template is useful for embedding binary data into a -program. The template 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 CMake build. It is provided by -``pw_build/cc_blob_library.cmake``. - -**Arguments** - -* ``blobs``: A list of GN scopes, where each scope corresponds to a binary blob - to be transformed from file to byte array. This is a required field. Blob - fields 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 or integer 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``: An optional (but highly recommended!) C++ namespace to place - the generated blobs within. - -Example -^^^^^^^ - -**BUILD.gn** - -.. code-block:: - - pw_cc_blob_library("foo_bar_blobs") { - blobs: [ - { - symbol_name: "kFooBlob" - file_path: "${target_out_dir}/stuff/bin/foo.bin" - }, - { - symbol_name: "kBarBlob" - file_path: "//stuff/bin/bar.bin" - linker_section: ".bar_section" - }, - ] - out_header: "my/stuff/foo_bar_blobs.h" - namespace: "my::stuff" - deps = [ ":generate_foo_bin" ] - } - -.. 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-facade: - -pw_facade ---------- -In their simplest form, a :ref:`facade<docs-module-structure-facades>` is a GN -build arg used to change a dependency at compile time. Pigweed targets configure -these facades as needed. - -The ``pw_facade`` template bundles a ``pw_source_set`` with a facade build arg. -This allows the facade to provide header files, compilation options or anything -else a GN ``source_set`` provides. - -The ``pw_facade`` template declares two targets: - -* ``$target_name``: the public-facing ``pw_source_set``, with a ``public_dep`` - on the backend -* ``$target_name.facade``: target used by the backend to avoid circular - dependencies - -.. code-block:: - - # Declares ":foo" and ":foo.facade" GN targets - pw_facade("foo") { - backend = pw_log_BACKEND - public_configs = [ ":public_include_path" ] - public = [ "public/pw_foo/foo.h" ] - } - -Low-level facades like ``pw_assert`` cannot express all of their dependencies -due to the potential for dependency cycles. Facades with this issue may require -backends to place their implementations in a separate build target to be listed -in ``pw_build_LINK_DEPS`` (see :ref:`module-pw_build-link-deps`). The -``require_link_deps`` variable in ``pw_facade`` asserts that all specified build -targets are present in ``pw_build_LINK_DEPS`` if the facade's backend variable -is set. - -.. _module-pw_build-python-action: - -pw_python_action ----------------- -The ``pw_python_action`` template is a convenience wrapper around GN's `action -function <https://gn.googlesource.com/gn/+/main/docs/reference.md#func_action>`_ -for running Python scripts. The main benefit it provides is resolution of GN -target labels to compiled binary files. This allows Python scripts to be written -independently of GN, taking only filesystem paths as arguments. - -Another convenience provided by the template is to allow running scripts without -any outputs. Sometimes scripts run in a build do not directly produce output -files, but GN requires that all actions have an output. ``pw_python_action`` -solves this by accepting a boolean ``stamp`` argument which tells it to create a -placeholder output file for the action. - -**Arguments** - -``pw_python_action`` accepts all of the arguments of a regular ``action`` -target. Additionally, it has some of its own arguments: - -* ``module``: Run the specified Python module instead of a script. Either - ``script`` or ``module`` must be specified, but not both. -* ``capture_output``: Optional boolean. If true, script output is hidden unless - the script fails with an error. Defaults to true. -* ``stamp``: Optional variable indicating whether to automatically create a - placeholder output file for the script. This allows running scripts without - specifying ``outputs``. If ``stamp`` is true, a generic output file is - used. If ``stamp`` is a file path, that file is used as a stamp file. Like any - output file, ``stamp`` must be in the build directory. Defaults to false. -* ``environment``: Optional list of strings. Environment variables to set, - passed as NAME=VALUE strings. -* ``working_directory``: Optional file path. When provided the current working - directory will be set to this location before the Python module or script is - run. -* ``command_launcher``: Optional string. Arguments to prepend to the Python - command, e.g. ``'/usr/bin/fakeroot --'`` will run the Python script within a - fakeroot environment. -* ``venv``: Optional gn target of the pw_python_venv that should be used to run - this action. - -.. _module-pw_build-python-action-expressions: - -Expressions -^^^^^^^^^^^ - -``pw_python_action`` evaluates expressions in ``args``, the arguments passed to -the script. These expressions function similarly to generator expressions in -CMake. Expressions may be passed as a standalone argument or as part of another -argument. A single argument may contain multiple expressions. - -Generally, these expressions are used within templates rather than directly in -BUILD.gn files. This allows build code to use GN labels without having to worry -about converting them to files. - -.. note:: - - We intend to replace these expressions with native GN features when possible. - See `b/234886742 <http://issuetracker.google.com/234886742>`_. - -The following expressions are supported: - -.. describe:: <TARGET_FILE(gn_target)> - - Evaluates to the output file of the provided GN target. For example, the - expression - - .. code-block:: - - "<TARGET_FILE(//foo/bar:static_lib)>" - - might expand to - - .. code-block:: - - "/home/User/project_root/out/obj/foo/bar/static_lib.a" - - ``TARGET_FILE`` parses the ``.ninja`` file for the GN target, so it should - always find the correct output file, regardless of the toolchain's or target's - configuration. Some targets, such as ``source_set`` and ``group`` targets, do - not have an output file, and attempting to use ``TARGET_FILE`` with them - results in an error. - - ``TARGET_FILE`` only resolves GN target labels to their outputs. To resolve - paths generally, use the standard GN approach of applying the - ``rebase_path(path, root_build_dir)`` function. This function - converts the provided GN path or list of paths to be relative to the build - directory, from which all build commands and scripts are executed. - -.. describe:: <TARGET_FILE_IF_EXISTS(gn_target)> - - ``TARGET_FILE_IF_EXISTS`` evaluates to the output file of the provided GN - target, if the output file exists. If the output file does not exist, the - entire argument that includes this expression is omitted, even if there is - other text or another expression. - - For example, consider this expression: - - .. code-block:: - - "--database=<TARGET_FILE_IF_EXISTS(//alpha/bravo)>" - - If the ``//alpha/bravo`` target file exists, this might expand to the - following: - - .. code-block:: - - "--database=/home/User/project/out/obj/alpha/bravo/bravo.elf" - - If the ``//alpha/bravo`` target file does not exist, the entire - ``--database=`` argument is omitted from the script arguments. - -.. describe:: <TARGET_OBJECTS(gn_target)> - - Evaluates to the object files of the provided GN target. Expands to a separate - argument for each object file. If the target has no object files, the argument - is omitted entirely. Because it does not expand to a single expression, the - ``<TARGET_OBJECTS(...)>`` expression may not have leading or trailing text. - - For example, the expression - - .. code-block:: - - "<TARGET_OBJECTS(//foo/bar:a_source_set)>" - - might expand to multiple separate arguments: - - .. code-block:: - - "/home/User/project_root/out/obj/foo/bar/a_source_set.file_a.cc.o" - "/home/User/project_root/out/obj/foo/bar/a_source_set.file_b.cc.o" - "/home/User/project_root/out/obj/foo/bar/a_source_set.file_c.cc.o" - -**Example** - -.. code-block:: - - import("$dir_pw_build/python_action.gni") - - pw_python_action("postprocess_main_image") { - script = "py/postprocess_binary.py" - args = [ - "--database", - rebase_path("my/database.csv", root_build_dir), - "--binary=<TARGET_FILE(//firmware/images:main)>", - ] - stamp = true - } - -.. _module-pw_build-evaluate-path-expressions: - -pw_evaluate_path_expressions ----------------------------- -It is not always feasible to pass information to a script through command line -arguments. If a script requires a large amount of input data, writing to a file -is often more convenient. However, doing so bypasses ``pw_python_action``'s GN -target label resolution, preventing such scripts from working with build -artifacts in a build system-agnostic manner. - -``pw_evaluate_path_expressions`` is designed to address this use case. It takes -a list of input files and resolves target expressions within them, modifying the -files in-place. - -Refer to ``pw_python_action``'s :ref:`module-pw_build-python-action-expressions` -section for the list of supported expressions. - -.. note:: - - ``pw_evaluate_path_expressions`` is typically used as an intermediate - sub-target of a larger template, rather than a standalone build target. - -**Arguments** - -* ``files``: A list of scopes, each containing a ``source`` file to process and - a ``dest`` file to which to write the result. - -**Example** - -The following template defines an executable target which additionally outputs -the list of object files from which it was compiled, making use of -``pw_evaluate_path_expressions`` to resolve their paths. - -.. code-block:: - - import("$dir_pw_build/evaluate_path_expressions.gni") - - template("executable_with_artifacts") { - executable("${target_name}.exe") { - sources = invoker.sources - if defined(invoker.deps) { - deps = invoker.deps - } - } - - _artifacts_input = "$target_gen_dir/${target_name}_artifacts.json.in" - _artifacts_output = "$target_gen_dir/${target_name}_artifacts.json" - _artifacts = { - binary = "<TARGET_FILE(:${target_name}.exe)>" - objects = "<TARGET_OBJECTS(:${target_name}.exe)>" - } - write_file(_artifacts_input, _artifacts, "json") - - pw_evaluate_path_expressions("${target_name}.evaluate") { - files = [ - { - source = _artifacts_input - dest = _artifacts_output - }, - ] - } - - group(target_name) { - deps = [ - ":${target_name}.exe", - ":${target_name}.evaluate", - ] - } - } - -.. _module-pw_build-pw_exec: - -pw_exec -------- -``pw_exec`` allows for execution of arbitrary programs. It is a wrapper around -``pw_python_action`` but allows for specifying the program to execute. - -.. note:: Prefer to use ``pw_python_action`` instead of calling out to shell - scripts, as the python will be more portable. ``pw_exec`` should generally - only be used for interacting with legacy/existing scripts. - -**Arguments** - -* ``program``: The program to run. Can be a full path or just a name (in which - case $PATH is searched). -* ``args``: Optional list of arguments to the program. -* ``deps``: Dependencies for this target. -* ``public_deps``: Public dependencies for this target. In addition to outputs - from this target, outputs generated by public dependencies can be used as - inputs from targets that depend on this one. This is not the case for private - deps. -* ``inputs``: Optional list of build inputs to the program. -* ``outputs``: Optional list of artifacts produced by the program's execution. -* ``env``: Optional list of key-value pairs defining environment variables for - the program. -* ``env_file``: Optional path to a file containing a list of newline-separated - key-value pairs defining environment variables for the program. -* ``args_file``: Optional path to a file containing additional positional - arguments to the program. Each line of the file is appended to the - invocation. Useful for specifying arguments from GN metadata. -* ``skip_empty_args``: If args_file is provided, boolean indicating whether to - skip running the program if the file is empty. Used to avoid running - commands which error when called without arguments. -* ``capture_output``: If true, output from the program is hidden unless the - program exits with an error. Defaults to true. -* ``working_directory``: The working directory to execute the subprocess with. - If not specified it will not be set and the subprocess will have whatever - the parent current working directory is. -* ``visibility``: GN visibility to apply to the underlying target. - -**Example** - -.. code-block:: - - import("$dir_pw_build/exec.gni") - - pw_exec("hello_world") { - program = "/bin/sh" - args = [ - "-c", - "echo hello \$WORLD", - ] - env = [ - "WORLD=world", - ] - } - -pw_input_group --------------- -``pw_input_group`` defines a group of input files which are not directly -processed by the build but are still important dependencies of later build -steps. This is commonly used alongside metadata to propagate file dependencies -through the build graph and force rebuilds on file modifications. - -For example ``pw_docgen`` defines a ``pw_doc_group`` template which outputs -metadata from a list of input files. The metadata file is not actually part of -the build, and so changes to any of the input files do not trigger a rebuild. -This is problematic, as targets that depend on the metadata should rebuild when -the inputs are modified but GN cannot express this dependency. - -``pw_input_group`` solves this problem by allowing a list of files to be listed -in a target that does not output any build artifacts, causing all dependent -targets to correctly rebuild. - -**Arguments** - -``pw_input_group`` accepts all arguments that can be passed to a ``group`` -target, as well as requiring one extra: - -* ``inputs``: List of input files. - -**Example** - -.. code-block:: - - import("$dir_pw_build/input_group.gni") - - pw_input_group("foo_metadata") { - metadata = { - files = [ - "x.foo", - "y.foo", - "z.foo", - ] - } - inputs = metadata.files - } - -Targets depending on ``foo_metadata`` will rebuild when any of the ``.foo`` -files are modified. - -pw_zip ------- -``pw_zip`` is a target that allows users to zip up a set of input files and -directories into a single output ``.zip`` file—a simple automation of a -potentially repetitive task. - -**Arguments** - -* ``inputs``: List of source files as well as the desired relative zip - destination. See below for the input syntax. -* ``dirs``: List of entire directories to be zipped as well as the desired - relative zip destination. See below for the input syntax. -* ``output``: Filename of output ``.zip`` file. -* ``deps``: List of dependencies for the target. - -**Input Syntax** - -Inputs all need to follow the correct syntax: - -#. Path to source file or directory. Directories must end with a ``/``. -#. The delimiter (defaults to ``>``). -#. The desired destination of the contents within the ``.zip``. Must start - with ``/`` to indicate the zip root. Any number of subdirectories are - allowed. If the source is a file it can be put into any subdirectory of the - root. If the source is a file, the zip copy can also be renamed by ending - the zip destination with a filename (no trailing ``/``). - -Thus, it should look like the following: ``"[source file or dir] > /"``. - -**Example** - -Let's say we have the following structure for a ``//source/`` directory: - -.. code-block:: - - source/ - ├── file1.txt - ├── file2.txt - ├── file3.txt - └── some_dir/ - ├── file4.txt - └── some_other_dir/ - └── file5.txt - -And we create the following build target: - -.. code-block:: - - import("$dir_pw_build/zip.gni") - - pw_zip("target_name") { - inputs = [ - "//source/file1.txt > /", # Copied to the zip root dir. - "//source/file2.txt > /renamed.txt", # File renamed. - "//source/file3.txt > /bar/", # File moved to the /bar/ dir. - ] - - dirs = [ - "//source/some_dir/ > /bar/some_dir/", # All /some_dir/ contents copied - # as /bar/some_dir/. - ] - - # Note on output: if the specific output directory isn't defined - # (such as output = "zoo.zip") then the .zip will output to the - # same directory as the BUILD.gn file that called the target. - output = "//$target_out_dir/foo.zip" # Where the foo.zip will end up - } - -This will result in a ``.zip`` file called ``foo.zip`` stored in -``//$target_out_dir`` with the following structure: - -.. code-block:: - - foo.zip - ├── bar/ - │ ├── file3.txt - │ └── some_dir/ - │ ├── file4.txt - │ └── some_other_dir/ - │ └── file5.txt - ├── file1.txt - └── renamed.txt - -.. _module-pw_build-relative-source-file-names: - -pw_relative_source_file_names ------------------------------ -This template recursively walks the listed dependencies and collects the names -of all the headers and source files required by the targets, and then transforms -them such that they reflect the ``__FILE__`` when pw_build's ``relative_paths`` -config is applied. This is primarily intended for side-band generation of -pw_tokenizer tokens so file name tokens can be utilized in places where -pw_tokenizer is unable to embed token information as part of C/C++ compilation. - -This template produces a JSON file containing an array of strings (file paths -with ``-ffile-prefix-map``-like transformations applied) that can be used to -:ref:`generate a token database <module-pw_tokenizer-database-creation>`. - -**Arguments** - -* ``deps``: A required list of targets to recursively extract file names from. -* ``outputs``: A required array with a single element: the path to write the - final JSON file to. - -**Example** - -Let's say we have the following project structure: - -.. code-block:: - - project root - ├── foo/ - │ ├── foo.h - │ └── foo.cc - ├── bar/ - │ ├── bar.h - │ └── bar.cc - ├── unused/ - │ ├── unused.h - │ └── unused.cc - └── main.cc - -And a BUILD.gn at the root: - -.. code-block:: - - pw_source_set("bar") { - public_configs = [ ":bar_headers" ] - public = [ "bar/bar.h" ] - sources = [ "bar/bar.cc" ] - } - - pw_source_set("foo") { - public_configs = [ ":foo_headers" ] - public = [ "foo/foo.h" ] - sources = [ "foo/foo.cc" ] - deps = [ ":bar" ] - } - - - pw_source_set("unused") { - public_configs = [ ":unused_headers" ] - public = [ "unused/unused.h" ] - sources = [ "unused/unused.cc" ] - deps = [ ":bar" ] - } - - pw_executable("main") { - sources = [ "main.cc" ] - deps = [ ":foo" ] - } - - pw_relative_source_file_names("main_source_files") { - deps = [ ":main" ] - outputs = [ "$target_gen_dir/main_source_files.json" ] - } - -The json file written to `out/gen/main_source_files.json` will contain: - -.. code-block:: - - [ - "bar/bar.cc", - "bar/bar.h", - "foo/foo.cc", - "foo/foo.h", - "main.cc" - ] - -Since ``unused`` isn't a transitive dependency of ``main``, its source files -are not included. Similarly, even though ``bar`` is not a direct dependency of -``main``, its source files *are* included because ``foo`` brings in ``bar`` as -a transitive dependency. - -Note how the file paths in this example are relative to the project root rather -than being absolute paths (e.g. ``/home/user/ralph/coding/my_proj/main.cc``). -This is a result of transformations applied to strip absolute pathing prefixes, -matching the behavior of pw_build's ``$dir_pw_build:relative_paths`` config. - -Build time errors: pw_error and pw_build_assert ------------------------------------------------ -In Pigweed's complex, multi-toolchain GN build it is not possible to build every -target in every configuration. GN's ``assert`` statement is not ideal for -enforcing the correct configuration because it may prevent the GN build files or -targets from being referred to at all, even if they aren't used. - -The ``pw_error`` GN template results in an error if it is executed during the -build. These error targets can exist in the build graph, but cannot be depended -on without an error. - -``pw_build_assert`` evaluates to a ``pw_error`` if a condition fails or nothing -(an empty group) if the condition passes. Targets can add a dependency on a -``pw_build_assert`` to enforce a condition at build time. - -The templates for build time errors are defined in ``pw_build/error.gni``. - -Improved Ninja interface ------------------------- -Ninja includes a basic progress display, showing in a single line the number of -targets finished, the total number of targets, and the name of the most recent -target it has either started or finished. - -For additional insight into the status of the build, Pigweed includes a Ninja -wrapper, ``pw-wrap-ninja``, that displays additional real-time information about -the progress of the build. The wrapper is invoked the same way you'd normally -invoke Ninja: - -.. code-block:: sh - - pw-wrap-ninja -C out - -The script lists the progress of the build, as well as the list of targets that -Ninja is currently building, along with a timer that measures how long each -target has been building for: - -.. code-block:: - - [51.3s] Building [8924/10690] ... - [10.4s] c++ pw_strict_host_clang_debug/obj/pw_string/string_test.lib.string_test.cc.o - [ 9.5s] ACTION //pw_console/py:py.lint.mypy(//pw_build/python_toolchain:python) - [ 9.4s] ACTION //pw_console/py:py.lint.pylint(//pw_build/python_toolchain:python) - [ 6.1s] clang-tidy ../pw_log_rpc/log_service.cc - [ 6.1s] clang-tidy ../pw_log_rpc/log_service_test.cc - [ 6.1s] clang-tidy ../pw_log_rpc/rpc_log_drain.cc - [ 6.1s] clang-tidy ../pw_log_rpc/rpc_log_drain_test.cc - [ 5.4s] c++ pw_strict_host_clang_debug/obj/BUILD_DIR/pw_strict_host_clang_debug/gen/pw... - ... and 109 more - -This allows you to, at a glance, know what Ninja's currently building, which -targets are bottlenecking the rest of the build, and which targets are taking -an unusually long time to complete. - -``pw-wrap-ninja`` includes other useful functionality as well. The -``--write-trace`` option writes a build trace to the specified path, which can -be viewed in the `Perfetto UI <https://ui.perfetto.dev/>`_, or via Chrome's -built-in ``chrome://tracing`` tool. - -CMake -===== -Pigweed's `CMake`_ support is provided primarily for projects that have an -existing CMake build and wish to integrate Pigweed without switching to a new -build system. - -The following command generates Ninja build files for a host build in the -``out/cmake_host`` directory: - -.. code-block:: sh - - cmake -B out/cmake_host -S "$PW_ROOT" -G Ninja -DCMAKE_TOOLCHAIN_FILE=$PW_ROOT/pw_toolchain/host_clang/toolchain.cmake - -The ``PW_ROOT`` environment variable must point to the root of the Pigweed -directory. This variable is set by Pigweed's environment setup. - -Tests can be executed with the ``pw_run_tests.GROUP`` targets. To run Pigweed -module tests, execute ``pw_run_tests.modules``: - -.. code-block:: sh - - ninja -C out/cmake_host pw_run_tests.modules - -:ref:`module-pw_watch` supports CMake, so you can also run - -.. code-block:: sh - - pw watch -C out/cmake_host pw_run_tests.modules - -CMake functions ---------------- -CMake convenience functions are defined in ``pw_build/pigweed.cmake``. - -* ``pw_add_library_generic`` -- The base helper used to instantiate CMake - libraries. This is meant for use in downstream projects as upstream Pigweed - modules are expected to use ``pw_add_library``. -* ``pw_add_library`` -- Add an upstream Pigweed library. -* ``pw_add_facade_generic`` -- The base helper used to instantiate facade - libraries. This is meant for use in downstream projects as upstream Pigweed - modules are expected to use ``pw_add_facade``. -* ``pw_add_facade`` -- Declare an upstream Pigweed facade. -* ``pw_set_backend`` -- Set the backend library to use for a facade. -* ``pw_add_test_generic`` -- The base helper used to instantiate test targets. - This is meant for use in downstrema projects as upstream Pigweed modules are - expected to use ``pw_add_test``. -* ``pw_add_test`` -- Declare an upstream Pigweed test target. -* ``pw_add_test_group`` -- Declare a target to group and bundle test targets. -* ``pw_target_link_targets`` -- Helper wrapper around ``target_link_libraries`` - which only supports CMake targets and detects when the target does not exist. - Note that generator expressions are not supported. -* ``pw_add_global_compile_options`` -- Applies compilation options to all - targets in the build. This should only be used to add essential compilation - options, such as those that affect the ABI. Use ``pw_add_library`` or - ``target_compile_options`` to apply other compile options. -* ``pw_add_error_target`` -- Declares target which reports a message and causes - a build failure only when compiled. This is useful when ``FATAL_ERROR`` - messages cannot be used to catch problems during the CMake configuration - phase. -* ``pw_parse_arguments`` -- Helper to parse CMake function arguments. - -See ``pw_build/pigweed.cmake`` for the complete documentation of these -functions. - -Special libraries that do not fit well with these functions are created with the -standard CMake functions, such as ``add_library`` and ``target_link_libraries``. - -Facades and backends --------------------- -The CMake build uses CMake cache variables for configuring -:ref:`facades<docs-module-structure-facades>` and backends. Cache variables are -similar to GN's build args set with ``gn args``. Unlike GN, CMake does not -support multi-toolchain builds, so these variables have a single global value -per build directory. - -The ``pw_add_module_facade`` function declares a cache variable named -``<module_name>_BACKEND`` for each facade. Cache variables can be awkward to -work with, since their values only change when they're assigned, but then -persist accross CMake invocations. These variables should be set in one of the -following ways: - -* Prior to setting a backend, your application should include - ``$ENV{PW_ROOT}/backends.cmake``. This file will setup all the backend targets - such that any misspelling of a facade or backend will yield a warning. - - .. note:: - Zephyr developers do not need to do this, backends can be set automatically - by enabling the appropriate Kconfig options. - -* Call ``pw_set_backend`` to set backends appropriate for the target in the - target's toolchain file. The toolchain file is provided to ``cmake`` with - ``-DCMAKE_TOOLCHAIN_FILE=<toolchain file>``. -* Call ``pw_set_backend`` in the top-level ``CMakeLists.txt`` before other - CMake code executes. -* Set the backend variable at the command line with the ``-D`` option. - - .. code-block:: sh - - cmake -B out/cmake_host -S "$PW_ROOT" -G Ninja \ - -DCMAKE_TOOLCHAIN_FILE=$PW_ROOT/pw_toolchain/host_clang/toolchain.cmake \ - -Dpw_log_BACKEND=pw_log_basic - -* Temporarily override a backend by setting it interactively with ``ccmake`` or - ``cmake-gui``. - -If the backend is set to a build target that does not exist, there will be an -error message like the following: - -.. code-block:: - - CMake Error at pw_build/pigweed.cmake:257 (message): - my_module.my_facade's INTERFACE dep "my_nonexistent_backend" is not - a target. - Call Stack (most recent call first): - pw_build/pigweed.cmake:238:EVAL:1 (_pw_target_link_targets_deferred_check) - CMakeLists.txt:DEFERRED - - -Toolchain setup ---------------- -In CMake, the toolchain is configured by setting CMake variables, as described -in the `CMake documentation <https://cmake.org/cmake/help/latest/manual/cmake-toolchains.7.html>`_. -These variables are typically set in a toolchain CMake file passed to ``cmake`` -with the ``-D`` option (``-DCMAKE_TOOLCHAIN_FILE=path/to/file.cmake``). -For Pigweed embedded builds, set ``CMAKE_SYSTEM_NAME`` to the empty string -(``""``). - -Toolchains may set the ``pw_build_WARNINGS`` variable to a list of ``INTERFACE`` -libraries with compilation options for Pigweed's upstream libraries. This -defaults to a strict set of warnings. Projects may need to use less strict -compilation warnings to compile backends exposed to Pigweed code (such as -``pw_log``) that cannot compile with Pigweed's flags. If desired, Projects can -access these warnings by depending on ``pw_build.warnings``. - -Third party libraries ---------------------- -The CMake build includes third-party libraries similarly to the GN build. A -``dir_pw_third_party_<library>`` cache variable is defined for each third-party -dependency. The variable must be set to the absolute path of the library in -order to use it. If the variable is empty -(``if("${dir_pw_third_party_<library>}" STREQUAL "")``), the dependency is not -available. - -Third-party dependencies are not automatically added to the build. They can be -manually added with ``add_subdirectory`` or by setting the -``pw_third_party_<library>_ADD_SUBDIRECTORY`` option to ``ON``. - -Third party variables are set like any other cache global variable in CMake. It -is recommended to set these in one of the following ways: - -* Set with the CMake ``set`` function in the toolchain file or a - ``CMakeLists.txt`` before other CMake code executes. - - .. code-block:: cmake - - set(dir_pw_third_party_nanopb ${CMAKE_CURRENT_SOURCE_DIR}/external/nanopb CACHE PATH "" FORCE) - -* Set the variable at the command line with the ``-D`` option. - - .. code-block:: sh - - cmake -B out/cmake_host -S "$PW_ROOT" -G Ninja \ - -DCMAKE_TOOLCHAIN_FILE=$PW_ROOT/pw_toolchain/host_clang/toolchain.cmake \ - -Ddir_pw_third_party_nanopb=/path/to/nanopb - -* Set the variable interactively with ``ccmake`` or ``cmake-gui``. - -Use Pigweed from an existing CMake project ------------------------------------------- -To use Pigweed libraries form a CMake-based project, simply include the Pigweed -repository from a ``CMakeLists.txt``. - -.. code-block:: cmake - - add_subdirectory(path/to/pigweed pigweed) - -All module libraries will be available as ``module_name`` or -``module_name.sublibrary``. - -If desired, modules can be included individually. - -.. code-block:: cmake - - add_subdirectory(path/to/pigweed/pw_some_module pw_some_module) - add_subdirectory(path/to/pigweed/pw_another_module pw_another_module) - -Bazel -===== -Bazel is currently very experimental, and only builds for host and ARM Cortex-M -microcontrollers. - -The common configuration for Bazel for all modules is in the ``pigweed.bzl`` -file. The built-in Bazel rules ``cc_binary``, ``cc_library``, and ``cc_test`` -are wrapped with ``pw_cc_binary``, ``pw_cc_library``, and ``pw_cc_test``. -These wrappers add parameters to calls to the compiler and linker. - -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", - ], - ) - - pw_cc_binary( - name = "some_binary", - srcs = ["some_source.c"], - additional_linker_inputs = [":some_linker_script"], - linkopts = ["-T $(location :some_linker_script)"], - ) - -Currently Pigweed is making use of a set of -`open source <https://github.com/silvergasp/bazel-embedded>`_ toolchains. The -host builds are only supported on Linux/Mac based systems. Additionally the -host builds are not entirely hermetic, and will make use of system -libraries and headers. This is close to the default configuration for Bazel, -though slightly more hermetic. The host toolchain is based around clang-11 which -has a system dependency on 'libtinfo.so.5' which is often included as part of -the libncurses packages. On Debian based systems this can be installed using the -command below: - -.. code-block:: sh - - sudo apt install libncurses5 - -The host toolchain does not currently support native Windows, though using WSL -is a viable alternative. - -The ARM Cortex-M Bazel toolchains are based around gcc-arm-non-eabi and are -entirely hermetic. You can target Cortex-M, by using the platforms command line -option. This set of toolchains is supported from hosts; Windows, Mac and Linux. -The platforms that are currently supported are listed below: - -.. code-block:: sh - - bazel build //:your_target --platforms=@pigweed//pw_build/platforms:cortex_m0 - bazel build //:your_target --platforms=@pigweed//pw_build/platforms:cortex_m1 - bazel build //:your_target --platforms=@pigweed//pw_build/platforms:cortex_m3 - bazel build //:your_target --platforms=@pigweed//pw_build/platforms:cortex_m4 - bazel build //:your_target --platforms=@pigweed//pw_build/platforms:cortex_m7 - bazel build //:your_target \ - --platforms=@pigweed//pw_build/platforms:cortex_m4_fpu - bazel build //:your_target \ - --platforms=@pigweed//pw_build/platforms:cortex_m7_fpu - - -The above examples are cpu/fpu oriented platforms and can be used where -applicable for your application. There some more specific platforms for the -types of boards that are included as examples in Pigweed. It is strongly -encouraged that you create your own set of platforms specific for your project, -that implement the constraint_settings in this repository. e.g. - -New board constraint_value: - -.. code-block:: python - - #your_repo/build_settings/constraints/board/BUILD - constraint_value( - name = "nucleo_l432kc", - constraint_setting = "@pigweed//pw_build/constraints/board", - ) - -New chipset constraint_value: - -.. code-block:: python - - # your_repo/build_settings/constraints/chipset/BUILD - constraint_value( - name = "stm32l432kc", - constraint_setting = "@pigweed//pw_build/constraints/chipset", - ) - -New platforms for chipset and board: - -.. code-block:: python - - #your_repo/build_settings/platforms/BUILD - # Works with all stm32l432kc - platforms( - name = "stm32l432kc", - parents = ["@pigweed//pw_build/platforms:cortex_m4"], - constraint_values = - ["@your_repo//build_settings/constraints/chipset:stm32l432kc"], - ) - - # Works with only the nucleo_l432kc - platforms( - name = "nucleo_l432kc", - parents = [":stm32l432kc"], - constraint_values = - ["@your_repo//build_settings/constraints/board:nucleo_l432kc"], - ) - -In the above example you can build your code with the command line: - -.. code-block:: python - - bazel build //:your_target_for_nucleo_l432kc \ - --platforms=@your_repo//build_settings:nucleo_l432kc - - -You can also specify that a specific target is only compatible with one -platform: - -.. code-block:: python - - cc_library( - name = "compatible_with_all_stm32l432kc", - srcs = ["tomato_src.c"], - target_compatible_with = - ["@your_repo//build_settings/constraints/chipset:stm32l432kc"], - ) - - cc_library( - name = "compatible_with_only_nucleo_l432kc", - srcs = ["bbq_src.c"], - target_compatible_with = - ["@your_repo//build_settings/constraints/board:nucleo_l432kc"], - ) + :maxdepth: 1 + gn + cmake + bazel |