From 0b955ca0d371e7ecbb6bdcc82f1b2e9f8cdcd8ac Mon Sep 17 00:00:00 2001 From: Paul Mathieu Date: Tue, 17 Dec 2019 13:47:22 -0800 Subject: [PATCH] arm_gcc: help ld link all these libs together There is some confusion as to what the following flags do: --start-group/--end-group --[no-]whole-archive Before explaining them further, the following facts should be highlighted: Fact: the linker loads *all* input *.o objects Fact: a static library is an archive of object files Fact: the linker will try to resolve symbols across *all* currently loaded object Fact: if a symbol cannot be resolved among currently loaded object, the linker will consider static libraries in the order provided and load the first object that provides that symbol Fact: the linker only considers static libraries once and in the order provided --start-group/--end-group pairs tell the linker to re-attempt considering the libraries contained within the pair, and *in the order provded* for as long as new unresolved symbols can be resolved that way. --whole-archive/--no-whole-archive pairs tell the linker to load all objects from the libraries contained within the pair, making it equivalent to manually extracting all the object files out of these libraries and providing them on the command line to the linker In well-formed cases, none of these flags are necessary. An acyclic chain of depencies can be established within these libraries by making them into source_set() targets that depend on each other. In this case, gn will output the correct order for these libraries. There are cases where this is not possible. This is typically the case when vendor-provided libraries have circular dependencies among them. In these cases, either --start-group/--end-group or --whole-archive/--no-whole-archive pairs need to be used. --whole-archive/--no-whole-archive is safer because it allows the proper resolution of weak/strong symbols. Example: libfoo.a: foo.o: w foo libbar.a: bar.o: T foo main.o: U foo $ gcc main.o libfoo.a libbar.a will result in the weak symbol defined in libfoo.a to be used. $ gcc main.o --Wl,--whole-archive libfoo.a libbar.a -wl,--no-whole-archive will result in the strong symbol defined in libbar.a to be used. In light of all of the above, we propose always using --whole-archive/--no-whole-archive and relying on --gc-sections to trim the resulting executable to a reasonable size. Change-Id: I355200961b6df6e797f3035f7945eb1a7f9e30b7 --- pw_toolchain/arm_gcc.gni | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/pw_toolchain/arm_gcc.gni b/pw_toolchain/arm_gcc.gni index 4361fa043..a19e2aaf0 100644 --- a/pw_toolchain/arm_gcc.gni +++ b/pw_toolchain/arm_gcc.gni @@ -150,13 +150,20 @@ template("arm_gcc_toolchain") { _toolchain_cflags, _toolchain_ldflags, - # The start groups / end groups tag causes the linker to repeatedly - # re-link until there are no more missing symbols. - "-Wl,--start-group", "{{inputs}}", - "-Wl,--end-group", + # Load all object files from all libraries to resolve symbols. + # Short of living in the ideal world where all dependency graphs + # among static libs are acyclic and all developers diligently + # express such graphs in terms that GN understands, this is the + # safest option. + # Make sure you use this with --gc-sections, otherwise the + # resulting binary will contain every symbol defined in every + # input file and every static library. That could be quite a lot. + "-Wl,--whole-archive", "{{libs}}", + "-Wl,--no-whole-archive", + "-o $_link_outfile", ])