pw_toolchain#
GN toolchains function both as a set of tools for compilation and as a workspace for evaluating build files. The same compilations and actions can be executed by different toolchains. Each toolchain maintains its own set of build args, and build steps from all toolchains can be executed in parallel.
Toolchains#
Pigweed AI summary: The pw_toolchain module offers GN toolchains for building Pigweed, including various GCC and Clang toolchains for multiple platforms. Toolchain names typically include the compiler and optimization level.
pw_toolchain
module provides GN toolchains that may be used to build
Pigweed. Various GCC and Clang toolchains for multiple platforms are provided.
Toolchains names typically include the compiler (clang
or gcc
and
optimization level (debug
, size_optimized
, speed_optimized
).
Non-C/C++ toolchains#
Pigweed AI summary: The article discusses the use of non-C/C++ toolchains in a multi-toolchain build. The pw_non_c_toolchain template creates toolchains that cannot compile C/C++ source code and can only be used to execute GN actions or declare groups of targets in other toolchains. These toolchains can be used to consolidate actions that should only occur once in a multi-toolchain build, allowing all toolchains to share the same declarations without any duplicated work. The article provides an example of Pigweed using
pw_toolchain/non_c_toolchain.gni
provides the pw_non_c_toolchain
template. This template creates toolchains that cannot compile C/C++ source
code. These toolchains may only be used to execute GN actions or declare groups
of targets in other toolchains. Attempting to compile C/C++ code with either of
these toolchains results in errors.
Non-C/C++ toolchains can be used to consolidate actions that should only occur once in a multi-toolchain build. Build targets from all toolchains can refer to these actions in a non-C/C++ toolchain so they only execute once instead of once per toolchain.
For example, Pigweed runs protobuf compilation and Python package actions like
installation and Pylint in toolchains created with pw_non_c_toolchain
. This
allows all toolchains to cleanly share the same protobuf and Python declarations
without any duplicated work.
Testing other compiler versions#
Pigweed AI summary: The Pigweed toolchain can use a different version of the clang-based compiler by changing the GN build argument to point to the desired directory. However, this should only be done for debugging purposes as Pigweed only officially supports their own provided compilers.
The clang-based toolchain provided by Pigweed can be substituted with another
version by modifying the pw_toolchain_CLANG_PREFIX
GN build argument to
point to the directory that contains the desired clang, clang++, and llvm-ar
binaries. This should only be used for debugging purposes. Pigweed does not
officially support any compilers other than those provided by Pigweed.
Running static analysis checks#
Pigweed AI summary: This section provides information on running static analysis checks using clang-tidy as a compiler replacement. The pw_static_analysis_toolchain template creates toolchains that execute clang-tidy for C/C++ sources and mock implementations of link, alink, and solink tools. The static_analysis scope must be defined on the invoker, and the generate_toolchain supports this scope. The build argument pw_toolchain_STATIC_ANALYSIS_SKIP_SOURCES_RES is used to exclude source files from the analysis, and pw_toolchain
clang-tidy
can be run as a compiler replacement, to analyze all sources
built for a target. pw_toolchain/static_analysis_toolchain.gni
provides
the pw_static_analysis_toolchain
template. This template creates toolchains
that execute clang-tidy
for C/C++ sources, and mock implementations of
the link
, alink
and solink
tools.
In addition to the standard toolchain requirements (cc, cxx, etc..), the
pw_static_analysis_toolchain
template requires a scope static_analysis
to be defined on the invoker.
static_analysis = {
# Configure whether static_analysis should be enabled for invoker toolchain.
# This is must be set true if using pw_static_analysis_toolchain.
enabled = true
# Optionally override clang-tidy binary to use by setting to proper path.
clang_tidy_path = ""
# Optionally specify additional command(s) to run as part of cc tool.
cc_post = ""
# Optionally specify additional command(s) to run as part of cxx tool.
cxx_post = ""
}
The generate_toolchain
supports the above mentioned static_analysis
scope, which if specified must at the very least define the bool enabled
within the scope. If the static_analysis
scope is provided and
static_analysis.enabled = true
, the derived toolchain
${target_name}.static_analysis
will be generated using
pw_generate_static_analysis_toolchain
and the toolchain options.
An example on the utility of the static_analysis
scope args is shown in the
snippet below where we enable clang-tidy caching and add //.clang-tidy
as a
dependency to the generated .d
files for the
pw_static_analysis_toolchain
.
static_analysis = {
clang_tidy_path = "//third_party/ctcache/clang-tidy"
_clang_tidy_cfg_path = rebase_path("//.clang-tidy", root_build_dir)
cc_post = "echo '-: $_clang_tidy_cfg_path' >> {{output}}.d"
cxx_post = "echo '-: $_clang_tidy_cfg_path' >> {{output}}.d"
}
Excluding files from checks#
Pigweed AI summary: This section explains how to exclude source files and header files from static analysis using build arguments in the pw_toolchain. The build argument pw_toolchain_STATIC_ANALYSIS_SKIP_SOURCES_RES is used to exclude source files by providing regular expressions matching individual files. The build argument pw_toolchain_STATIC_ANALYSIS_SKIP_INCLUDE_PATHS is used to exclude header files by providing POSIX-style path suffixes or regular expressions matching include paths. It is important to note that pw_toolchain_STATIC_ANALYSIS_SKIP_INCLUDE_PATHS operates
The build argument pw_toolchain_STATIC_ANALYSIS_SKIP_SOURCES_RES
is used
to exclude source files from the analysis. The list must contain regular
expressions matching individual files, rather than directories. For example,
provide "the_path/.*"
to exclude all files in all directories under
the_path
.
The build argument pw_toolchain_STATIC_ANALYSIS_SKIP_INCLUDE_PATHS
is used
used to exclude header files from the analysis. This argument must be a list of
POSIX-style path suffixes for include paths, or regular expressions matching
include paths. For example, passing the_path/include
excludes all header
files that are accessed from include paths ending in the_path/include
,
while passing .*/third_party/.*
excludes all third-party header files.
Note that pw_toolchain_STATIC_ANALYSIS_SKIP_INCLUDE_PATHS
operates on
include paths, not header file paths. For example, say your compile commands
include -Idrivers
, and this results in a file at drivers/public/i2c.h
being included. You can skip this header by adding drivers
or drivers.*
to pw_toolchain_STATIC_ANALYSIS_SKIP_INCLUDE_PATHS
, but not by adding
drivers/.*
: this last regex matches the header file path, but not the
include path.
Provided toolchains#
Pigweed AI summary: The "pw_toolchain" provides static analysis GN toolchains that can be used to test host targets. These toolchains include various options such as debug, speed-optimized, size-optimized, and fuzz. To run "clang-tidy" on all source dependencies of the default target, a specific code block needs to be generated. However, the status of the static analysis checks may change when relevant files are updated, and it is recommended to clean the output directory before invoking "clang-tidy."
pw_toolchain
provides static analysis GN toolchains that may be used to
test host targets:
pw_toolchain_host_clang.debug.static_analysis
pw_toolchain_host_clang.speed_optimized.static_analysis
pw_toolchain_host_clang.size_optimized.static_analysis
pw_toolchain_host_clang.fuzz.static_analysis (if pw_toolchain_OSS_FUZZ_ENABLED is false)
pw_toolchain_arm_clang.debug.static_analysis
pw_toolchain_arm_clang.speed_optimized.static_analysis
pw_toolchain_arm_clang.size_optimized.static_analysis
For example, to run clang-tidy
on all source dependencies of the
default
target:
generate_toolchain("my_toolchain") {
..
static_analysis = {
enabled = true
}
}
group("static_analysis") {
deps = [ ":default(my_toolchain.static_analysis)" ]
}
Warning
The status of the static analysis checks might change when
any relevant .clang-tidy file is updated. You should
clean the output directory before invoking
clang-tidy
.
Target traits#
Pigweed AI summary: This paragraph discusses target traits in Pigweed, which are constants that describe properties of the target or the toolchain compiling code for it. These traits are exposed as GN args in GN and are defined in pw_toolchain/traits.gni. Traits must never be set by the user and are always set by the target. The paragraph also includes a warning that this feature is under development and may change significantly. Finally, it lists one example of a trait, CXX_STANDARD, which specifies the C++
Pigweed targets expose a set of constants that describe properties of the target or the toolchain compiling code for it. These are referred to as target traits.
In GN, these traits are exposed as GN args and are prefixed with
pw_toolchain_
(e.g. pw_toolchain_CXX_STANDARD
). They are defined in
pw_toolchain/traits.gni
.
Traits must never be set by the user (e.g. with gn args
). Traits are always
set by the target.
Warning
This feature is under development and is likely to change significantly. See b/234883746.
List of traits#
Pigweed AI summary: This paragraph describes the C++ standard used by a toolchain, which must be an integer value matching one of the standard values for the __cplusplus macro. The example given is 201703, which corresponds to C++17. Further details can be found at the provided reference link.
CXX_STANDARD
. The C++ standard used by the toolchain. The value must be an integer value matching one of the standard values for the__cplusplus
macro. For example,201703
corresponds to C++17. See https://en.cppreference.com/w/cpp/preprocessor/replace#Predefined_macros for further details.
C/C++ libraries#
pw_toolchain
provides some toolchain-related C/C++ libraries.
std:abort
wrapper#
Pigweed AI summary: The std:abort function is used to terminate a program abnormally and may be called by standard library functions. However, for embedded builds, the implementation may not work as intended and may have undesired dependencies. The pw_toolchain:wrap_abort library can be used to replace abort in builds where the default behavior is undesirable, redirecting calls to PW_CRASH instead.
The std::abort function is used to terminate a program abnormally. This function may be called by standard library functions, so is often linked into binaries, even if users never intentionally call it.
For embedded builds, the abort
implementation likely does not work as
intended. For example, it may pull in undesired dependencies (e.g.
std::raise
) and end in an infinite loop.
pw_toolchain
provides the pw_toolchain:wrap_abort
library that replaces
abort
in builds where the default behavior is undesirable. It uses the
-Wl,--wrap=abort
linker option to redirect to abort
calls to
PW_CRASH
instead.
arm-none-eabi-gcc support#
Pigweed AI summary: This text discusses the support for the GNU Arm Embedded Toolchain and the Newlib OS interface functions. Targets built with the toolchain should depend on the pw_toolchain/arm_gcc:arm_none_eabi_gcc_support library, which includes the implementation of the OS interface functions and prevents linker warnings. The pw_toolchain/arg_gcc:newlib_os_interface_stubs library is also provided through the same toolchain and implements the OS interface functions, aborting if they are called.
Targets building with the GNU Arm Embedded Toolchain (arm-none-eabi-gcc
)
should depend on the pw_toolchain/arm_gcc:arm_none_eabi_gcc_support
library
into their builds. In GN, that target should be included in
pw_build_LINK_DEPS
.
Newlib OS interface#
Pigweed AI summary: Newlib, the C Standard Library implementation provided with arm-none-eabi-gcc, defines a set of OS interface functions that should be implemented. Default implementations are provided, but using them results in linker warnings. Most of these functions should never be called in embedded builds. The pw_toolchain/arg_gcc:newlib_os_interface_stubs library implements these functions and forces a linker error if they are used. It also wraps some functions related to use of stdout and stderr that abort if they are called
Newlib, the C Standard Library
implementation provided with arm-none-eabi-gcc
, defines a set of OS
interface functions that
should be implemented. Newlib provides default implementations, but using these
results in linker warnings like the following:
readr.c:(.text._read_r+0x10): warning: _read is not implemented and will always fail
Most of the OS interface functions should never be called in embedded builds.
The pw_toolchain/arg_gcc:newlib_os_interface_stubs
library, which is
provided through pw_toolchain/arm_gcc:arm_none_eabi_gcc_support
, implements
these functions and forces a linker error if they are used. It also wraps some
functions related to use of stdout
and stderr
that abort if they are
called.
pw_toolchain/no_destructor.h#
-
template<typename T>
class NoDestructor# Helper type to create a function-local static variable of type
T
whenT
has a non-trivial destructor. Storing aT
in apw::NoDestructor<T>
will prevent~T()
from running, even when the variable goes out of scope.This class is useful when a variable has static storage duration but its type has a non-trivial destructor. Destructor ordering is not defined and can cause issues in multithreaded environments. Additionally, removing destructor calls can save code size.
Except in generic code, do not use
pw::NoDestructor<T>
with trivially destructible types. Use the type directly instead. If the variable can beconstexpr
, make itconstexpr
.pw::NoDestructor<T>
provides a similar API tostd::optional
. Use*
or->
to access the wrapped type.Example usage:
pw::sync::Mutex& GetMutex() { // Use NoDestructor to avoid running the mutex destructor when exit-time // destructors run. static const pw::NoDestructor<pw::sync::Mutex> global_mutex; return *global_mutex; }
In Clang,
pw::NoDestructor
can be replaced with the [[clang::no_destroy]] attribute.pw::NoDestructor<T>
is similar to Chromium’sbase::NoDestructor<T>
in src/base/no_destructor.h.Warning
Misuse of NoDestructor can cause memory leaks and other problems. Only skip destructors when you know it is safe to do so.