• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1.. _module-pw_toolchain:
2
3============
4pw_toolchain
5============
6.. pigweed-module::
7   :name: pw_toolchain
8
9GN toolchains function both as a set of tools for compilation and as a workspace
10for evaluating build files. The same compilations and actions can be executed by
11different toolchains. Each toolchain maintains its own set of build args, and
12build steps from all toolchains can be executed in parallel.
13
14---------------------------------
15C/C++ toolchain support libraries
16---------------------------------
17``pw_toolchain`` provides some toolchain-related C/C++ libraries.
18
19``std:abort`` wrapper
20=====================
21The `std::abort <https://en.cppreference.com/w/cpp/utility/program/abort>`_
22function is used to terminate a program abnormally. This function may be called
23by standard library functions, so is often linked into binaries, even if users
24never intentionally call it.
25
26For embedded builds, the ``abort`` implementation likely does not work as
27intended. For example, it may pull in undesired dependencies (e.g.
28``std::raise``) and end in an infinite loop.
29
30``pw_toolchain`` provides the ``pw_toolchain:wrap_abort`` library that replaces
31``abort`` in builds where the default behavior is undesirable. It uses the
32``-Wl,--wrap=abort`` linker option to redirect to ``abort`` calls to
33``PW_CRASH`` instead.
34
35arm-none-eabi-gcc support
36=========================
37Targets building with the GNU Arm Embedded Toolchain (``arm-none-eabi-gcc``)
38should depend on the ``pw_toolchain/arm_gcc:arm_none_eabi_gcc_support``
39library. In GN, that target should be included in ``pw_build_LINK_DEPS``. In
40Bazel, it should be added to `link_extra_lib
41<https://bazel.build/reference/be/c-cpp#cc_binary.link_extra_lib>`__ or
42directly to the `deps` of any binary being build with that toolchain:
43
44.. code-block:: python
45
46   cc_binary(
47      deps = [
48        # Other deps, omitted
49      ] + select({
50        "@platforms//cpu:armv7e-m": [
51          "@pigweed//pw_toolchain/arm_gcc:arm_none_eabi_gcc_support",
52        ],
53        "//conditions:default": [],
54      }),
55   )
56
57Newlib OS interface
58-------------------
59`Newlib <https://sourceware.org/newlib/>`_, the C Standard Library
60implementation provided with ``arm-none-eabi-gcc``, defines a set of `OS
61interface functions <https://sourceware.org/newlib/libc.html#Stubs>`_ that
62should be implemented. Newlib provides default implementations, but using these
63results in linker warnings like the following:
64
65.. code-block:: none
66
67   readr.c:(.text._read_r+0x10): warning: _read is not implemented and will always fail
68
69Most of the OS interface functions should never be called in embedded builds.
70The ``pw_toolchain/arg_gcc:newlib_os_interface_stubs`` library, which is
71provided through ``pw_toolchain/arm_gcc:arm_none_eabi_gcc_support``, implements
72these functions and forces a linker error if they are used. It also
73automatically includes a wrapper for ``abort`` for use of ``stdout`` and
74``stderr`` which abort if they are called.
75
76If you need to use your own wrapper for ``abort``, include the library directly
77using ``pw_toolchain/arm_gcc:newlib_os_interface_stubs``.
78
79.. _module-pw_toolchain-cpp-globals:
80
81Global variables: constant initialization and binary size
82=========================================================
83Global variables---variables with static storage duration---are initialized
84either during compilation (constant initialization) or at runtime.
85Runtime-initialized globals are initialized before ``main``; function ``static``
86variables are initialized when the function is called the first time.
87
88Constant initialization is guaranteed for ``constinit`` or ``constexpr``
89variables. However, the compiler may constant initialize any variable, even if
90it is not ``constinit`` or ``constexpr`` constructible.
91
92Constant initialization is usually better than runtime initialization. Constant
93initialization:
94
95- Reduces binary size. The binary stores initialized variable in the binary
96  (e.g. in ``.data`` or ``.rodata``), instead of the code needed to produce that
97  data, which is typically larger.
98- Saves CPU cycles. Initialization is a simple ``memcpy``.
99- Avoids the `static initialization order fiasco
100  <https://en.cppreference.com/w/cpp/language/siof>`_. Constant initialization
101  is order-independent and occurs before static initialization.
102
103Constant initialization may be undesirable if initialized data is larger than
104the code that produces it. Variables that are initialized to all 0s are
105placed in a zero-initialized segment (e.g. ``.bss``) and never affect binary
106size. Non-zero globals may increase binary size if they are constant
107initialized, however.
108
109Should I constant initialize?
110-----------------------------
111Globals should usually be constant initialized when possible. Consider the
112following when deciding:
113
114- If the global is zero-initialized, make it ``constinit`` or ``constexpr`` if
115  possible. It will not increase binary size.
116- If the global is initialized to anything other than 0 or ``nullptr``,
117  it will occupy space in the binary.
118
119  - If the variable is small (e.g. a few words), make it ``constinit`` or
120    ``constexpr``. The initialized variable takes space in the binary, but it
121    probably takes less space than the code to initialize it would.
122  - If the variable is large, weigh its size against the size and runtime
123    cost of its initialization code.
124
125There is no hard-and-fast rule for when to constant initialize or not. The
126decision must be considered in light of each project's memory layout and
127capabilities. Experimentation may be necessary.
128
129**Example**
130
131.. literalinclude:: globals_test.cc
132   :start-after: [pw_toolchain-globals-init]
133   :end-before: [pw_toolchain-globals-init]
134   :language: cpp
135
136.. note::
137
138   Objects cannot be split between ``.data`` and ``.bss``. If an object contains
139   a single ``bool`` initialized to ``true`` followed by a 4KB array of zeroes,
140   it will be placed in ``.data``, and all 4096 zeroes will be present in the
141   binary.
142
143   A global ``pw::Vector`` works like this. A default-initialized
144   ``pw::Vector<char, 4096>`` includes one non-zero ``uint16_t``. If constant
145   initialized, the entire ``pw::Vector`` is stored in the binary, even though
146   it is mostly zeroes.
147
148Controlling constant initialization of globals
149----------------------------------------------
150Pigweed offers two utilities for declaring global variables:
151
152- :cpp:class:`pw::NoDestructor` -- Removes the destructor, which is not
153  necessary for globals. Constant initialization is supported, but not required.
154- :cpp:class:`pw::RuntimeInitGlobal` -- Removes the destructor. Prevents
155  constant initialization.
156
157It is recommended to specify constant or runtime initialization for all global
158variables.
159
160.. list-table:: **Declaring globals**
161   :header-rows: 1
162
163   * - Initialization
164     - Mutability
165     - Declaration
166   * - constant
167     - mutable
168     - | ``constinit T``
169       | ``constinit pw::NoDestructor<T>``
170   * - constant
171     - constant
172     - ``constexpr T``
173   * - runtime
174     - mutable
175     - ``pw::RuntimeInitGlobal<T>``
176   * - runtime
177     - constant
178     - ``const pw::RuntimeInitGlobal<T>``
179   * - unspecified
180     - constant
181     - | ``const T``
182       | ``const pw::NoDestructor<T>``
183   * - unspecified
184     - mutable
185     - | ``T``
186       | ``pw::NoDestructor<T>``
187
188API reference
189=============
190pw_toolchain/constexpr_tag.h
191----------------------------
192.. doxygenstruct:: pw::ConstexprTag
193
194.. doxygenvariable:: pw::kConstexpr
195
196pw_toolchain/globals.h
197----------------------
198.. doxygenclass:: pw::RuntimeInitGlobal
199
200pw_toolchain/no_destructor.h
201----------------------------
202.. doxygenclass:: pw::NoDestructor
203
204pw_toolchain/infinite_loop.h
205----------------------------
206.. doxygenfunction:: pw::InfiniteLoop
207
208builtins
209========
210builtins are LLVM's equivalent of libgcc, the compiler will insert calls to
211these routines. Setting the ``dir_pw_third_party_builtins`` gn var to your
212compiler-rt/builtins checkout will enable building builtins from source instead
213of relying on the shipped libgcc.
214
215.. toctree::
216   :hidden:
217   :maxdepth: 1
218
219   bazel
220   gn
221