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):
myAppneeds symbolfooAdefined inlibfoo.- Symbol
fooAneeds symbolbarBdefined inlibbar. - Symbol
barBneeds symbolfooCdefined inlibfoo. This is the circular dependency, which can be handled by-lfoo -lbar -lfoo. - Symbol
fooCneeds symbolbarDdefined 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
libfoofor the first time and uses definitions of symbolfooAbut notfooC, because so far it doesn’t see a necessity to include alsofooCinto the binary. The linker however starts to look for definition ofbarB, because its definition is needed forfooAto function. - The linker sees
-libbar, includes the definition ofbarB(but notbarD) and starts to look for definition offooC. - The definition of
fooCis found inlibfoo, when it processed for the second time. Now it becomes evident, that also the definition ofbarDis needed – but too late there is nolibbaron 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.