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