Linker Scripts#
pw_build: Integrations for Bazel, GN, and CMake
pw_build
provides utilities for working with linker scripts in embedded
projects. If using the GN
or Bazel
build systems you can preprocess your
linker script using the C preprocessor with the pw_linker_script
rules.
Bazel pw_linker_script
Linker Script Helpers#
PW_MUST_PLACE
#
-
PW_MUST_PLACE(isection)#
PW_MUST_PLACE is a macro intended for use in linker scripts to ensure inputs are non-zero sized.
Say you want to place a specific object file into a particular section. You can reference it by file path like:
SECTIONS { .special_code { */src/path/libspecial_code.a:*.o } }
This works but is fragile as it will silently break if the filename or path changes. Use PW_MUST_PLACE to get a linker assertion if the input is empty.
#include "pw_build/must_place.ld.h" SECTIONS { .special_code { PW_MUST_PLACE(*/src/path/libspecial_code.a:*.o) } }
If the wildcard match fails PW_MUST_PLACE will generate an error telling you which input had no symbols.
Error: No symbols found in pattern below */src/path/libspecial_code.a:*.o
This could be because you had a typo, the path changed, or the symbols were dropped due to linker section garbage collection.In the latter case, you can choose to add
KEEP()
around your input to prevent garbage collection.
LinkerSymbol
#
-
template<class T = uintptr_t>
class LinkerSymbol# Represents a symbol provided by the linker, i.e. via a linker script.
LinkerSymbol objects are used with linker-provided symbols that don’t have storage (which is common), and only provide a value e.g.
MY_LINKER_VARIABLE = 42
LinkerSymbol objects are not actual variables (do not have storage) and thus cannot be created; they can only be used with an
extern "C"
declaration. The purpose is to communicate values from the linker script to C++ code.Example:
#include "pw_build/linker_symbol.h" extern "C" pw::LinkerSymbol<uint32_t> MY_LINKER_VARIABLE; uint32_t GetMyLinkerVariable() { return MY_LINKER_VARIABLE.value(); }
- Template Parameters:
T – The type of the value communicated by the linker, defaulting to
uintptr_t
. Must be an integral or enum type, no larger thanuintptr_t
.
Note
LinkerSymbol
does not support, and is not necessary for, symbols that
communicate a pointer value (i.e. an address). For those, simply define an
extern variable of the pointed-to type, e.g.:
extern "C" uint32_t PTR_SYM;
LinkerSymbol
is superior to the traditional extern uint8_t FOO;
(uint32_t)&FOO
method because it catches subtle errors:
Missing
extern
specifier:error: use of deleted function 'pw::build::LinkerSymbol::LinkerSymbol()' | LinkerSymbol oops; | ^~~~
Missing
&
operator:error: invalid cast from type 'pw::build::LinkerSymbol' to type 'uint32_t' {aka 'long unsigned int'} | uint32_t val = (uint32_t)FOO_SYM; | ^~~~~~~~~~~~~~~~~