The problem with
g++ -o myApp -lfoo -lbar -lfoo
is that there is no guarantee, that two passes over libfoo
and one pass over libbar
are enough.
The approach with Wl,--start-group ... -Wl,--end-group
is better, because more robust.
Consider the following scenario (all symbols are in different object-files):
myApp
needs symbolfooA
defined inlibfoo
.- Symbol
fooA
needs symbolbarB
defined inlibbar
. - Symbol
barB
needs symbolfooC
defined inlibfoo
. This is the circular dependency, which can be handled by-lfoo -lbar -lfoo
. - Symbol
fooC
needs symbolbarD
defined inlibbar
.
To be able to build in the case above, we would need to pass -lfoo -lbar -lfoo -lbar
to the linker. Why?
- The linker sees
libfoo
for the first time and uses definitions of symbolfooA
but notfooC
, because so far it doesn’t see a necessity to include alsofooC
into the binary. The linker however starts to look for definition ofbarB
, because its definition is needed forfooA
to function. - The linker sees
-libbar
, includes the definition ofbarB
(but notbarD
) and starts to look for definition offooC
. - The definition of
fooC
is found inlibfoo
, when it processed for the second time. Now it becomes evident, that also the definition ofbarD
is needed – but too late there is nolibbar
on the command line anymore!
The example above can be extended to an arbitrary dependency depth (but this happens seldom in real life).
Thus using
g++ -o myApp -Wl,--start-group -lfoo -lbar -Wl,--end-group
is a more robust approach, because linker passes as often over the library group as needed – only when a pass didn’t change the symbol table will the linker move on to the the next library on the command line.
There is however a small performance penalty to pay: in the first example -lbar
were scanned once more compared with the manual command line -lfoo -lbar -lfoo
. Not sure whether it is worth mentioning/thinking about through.