Linking objects ST's CubeIDE issues a command like this:
arm-none-eabi-g++ -mcpu=cortex-m33 --specs=nosys.specs -Wl,-Map=mymap.map -Wl,--gc-sections -static --specs=nano.specs -mfpu=fpv5-sp-d16 -mfloat-abi=hard -mthumb -Wl,--start-group -lc -lm -lstdc++ -lsupc++ -Wl,--end-group -Tmyldscript.ld @myobjects.txt -o myelf.elf
I am trying to understand why they use -Wl
several times and --start-group
/ --end-group
.
Is there a valid reason for that? Could this command be simplified?
-Wl
-Wl
is used multiple times because it is needed every time GCC has to be told that
it should pass one or more linker options straight through to the linker, ld
, rather than
trying to obey the option(s) itself (and likely giving a an unknown option error).
-Wl,<linker-option>[,<linker-option>...]
is a GCC option that means pass <linker-option> [<linker-option>...]
to the linker. See the GCC Manual: 3.15 Options for Linking.
--start-group/--end-group
Used as in:
--start-group -liba [-libb...] --end-group
are paired linker options. By default the linker will consider a static library as a candidate
for resolving undefined symbol references that the linkage has so far accrued only when the static library
is first input and never again (unless the library is input again). The --start-group/--end-group
options
tell the linker to suspend its default policy for the enclosed sequence of static libraries -liba [-libb...]
and instead to consider and reconsider them cyclically, resolving undefined references and accruing new ones,
until no new ones accrue. See the GNU ld manual: 2.1 Command-line Options
--start-group/--end-group
are necessary when there are cyclic dependencies amongst the enclosed static
libraries -liba [-libb...]
, meaning that it would not be possible for the linker to resolve all the undefined
references that arise from their linkage if each library was considered only once when first seen. Such cyclic dependencies are unusual and suggestive of ill-considered library design.
--start-group/--end-group
are useful, though not necessary, when there are not any cyclic dependencies amongst
-liba [-libb...]
but the person or build system composing the linkage commandline does not know that and does not
know a successful order in which to input the libraries under the default policy.
If --start-group/--end-group
are used to "brute force" a successful linkage of disordered libraries that could have been input in dependency order
with the linker's default policy then some inefficiency is incurred: the linker must revisit libraries that it would
not need to revisit if they were input in the right order.
In general it impossible to tell just by looking at a linkage commandline whether the use of --start-group/--end-group
is necessary, because it is impossible to tell just by looking whether the enclosed -liba [-libb...]
contain
cyclic dependencies. "High level" build systems, such as CMake, Meson, and others, may impose their own --start-group/--end-group
default policy on sequences of libraries in a linkage in order to brute-force the successful linkage of static libraries
that the build-system does not want to insist on being put in dependency order by the user.
--start-group -liba [-libb...] --end-group
have no effect on enclosed libraries that are shared, not static libraries,
but a build-system may enclose them regardless because this will be harmless even if all the libraries turn out to be
shared libraries. In your case, all of the library options:
-lc -lm -lstdc++ -lsupc++
must be resolved to static libraries because the option -static
has been specified beforehand.
Could this command be simplified?
The fragment:
-Wl,--start-group -lc -lm -lstdc++ -lsupc++ -Wl,--end-group
could be rewritten as:
-Wl,--start-group,-lc,-lm,-lstdc++,-lsupc++,--end-group
using one less -Wl
. That is because the option -l lib
is an option for both GCC and for the linker, and has the same meaning for both. (It is
in fact a linker option used so commonly that GCC will pass it to the linker without needing a -Wl
. Other such linker options
are -L dir
and -static
). It is conventional however to apply -Wl
only to linker options that GCC does not recognise itself.
The use of --start-group/--end-group
in your linkage is a brute-forcing use. Without it, the libraries could be linked
in the dependency order:
lstdc++ -lsupc++ -lm -lc