[Interest] Link failure with undefined references, on Ubuntu but not macOS

Thiago Macieira thiago.macieira at intel.com
Thu Apr 30 05:43:41 CEST 2020


On Wednesday, 29 April 2020 18:57:24 PDT Ben Haller via Interest wrote:
>   Aha!  And I figured out that the order in which I declare the dependencies
> in my .pro file determines the order in which those dependencies appear in
> the link command.  I fixed that, and now it builds.
> 
>   I guess this was not biting me before because I used to link these
> internal libraries dynamically instead; perhaps the link order is not
> important with dynamic linking? 

Correct, searching for symbols in dynamic libraries is different because the 
linker searches all of them. It doesn't need to solve from one to the other, 
since that was resolved when each library was itself linked.

Hint: make sure you're using -Wl,--no-undefined. In your .pro file, for each 
library and plugin:

QMAKE_LFLAGS += $$QMAKE_LFLAGS_NOUNDEF

> So when I recently changed to static
> linking for these internal libraries, the link order suddenly mattered, and
> my build broke.  And I guess perhaps the linker on macOS doesn’t have this
> requirement, and so the build continued to work there?

I don't know how the Apple linker works.

The traditional linker works sequentially to avoid a very long link time. 
After it's created the list of all outstanding undefined symbols from your 
binary's .o files, it iterates over the library list. For each one, it checks 
if the library solves some symbols and then each individual .o in the static 
library to the build. After that, it promptly forgets about the library and 
moves on to the next one. That's why libB.a can't depend on libA.a: the linker 
won't search it again.

If it did, you could write:
  -lA -lB -lA

Then the linker will search libA.a again for other .o that have symbols that 
libB requires.

Note that this may add .o that need more symbols from libB.a that haven't been 
added to the build yet. That means your linker line would need to be:

  -lA -lB -lA -lB

This isn't infinite because there's a finite number of .o files in each 
library. The GNU linker has a shorthand for this but I won't mention it here. 
Read the docs if needed.

Conclusion: break the cycle. The library dependency graph should be one way 
(directed acyclic graph). That's why I recommended that --no-undefined for 
dynamic linking: it'll prevent you from making the cycles.

-- 
Thiago Macieira - thiago.macieira (AT) intel.com
  Software Architect - Intel System Software Products





More information about the Interest mailing list