0

So let's say I have two statically built libraries. libFoo.a and libBar.a.

libFoo.a uses functions from libBar.a and libBar.a also happens to use functions from libFoo.a.

Now, let's create a program baz.cpp that uses libFoo and libBar. Normally, you'd type:

g++ baz.cpp -lfoo -lbar

However, because these two static libraries use each other...well there's no obvious solution to me as to how to get the compile-time linker to accept such a situation and link them all together.

Is this even a sensible and allowed thing by C++ standards? And if so, is there a non-hacky way to handle this?

Or would the preferred method be to compile all the object files from libBar and libFoo together into a single static library?

Roguebantha
  • 814
  • 4
  • 19
  • C++ standards have nothing to say about libraries. Usual way to handle this is to mention one of the libraries twice `-lfoo -lbar -lfoo` – john Feb 11 '19 at 22:04
  • I think you can ranlib both libraries.a files, at least on some systems. Note, of course, that this is a very odd thing to do to your code organization. – Joseph Larson Feb 11 '19 at 22:05
  • https://softwareengineering.stackexchange.com/questions/211999/are-nested-static-library-dependencies-possible – πάντα ῥεῖ Feb 11 '19 at 22:05
  • 4
    I think if you have circular dependencies, then your library design is flawed. Either the two libraries should be merged into one, or a third library should be refactored out. – Jonathon Reinhart Feb 11 '19 at 22:05
  • @Jonathon: I had circular dependencies a couple of times, even in completely orthogonal designs. Think of a logging library which needs time information and the time functions also want the possibility to log errors. Note that there is not necessarily a circular dependency in the call graph and you still have the linker problem. – Johannes Overmann Feb 11 '19 at 22:17
  • @JohannesOvermann The question then becomes: Is there a way in which that solution could be implemented without the circular dependencies? For example should the functions which utilize time + logging reside in a third library? Or should the two libraries be combined together to create a 'time aware logging library'? Or is the correct solution to truly have circular dependencies? – user6567423 Feb 11 '19 at 22:38
  • @Jonathon: For me the answer is easy, at least for me: The linker design is flawed. The incremental linking has no benefits, it is purely historic. Why should I change my library design (especially merging stuff together) to work around a linker bug? But yes, it is rather rare to have such circular dependencies. Not a common thing. – Johannes Overmann Feb 11 '19 at 22:43

1 Answers1

3

There are two alternative solutions:

  • Repeat library name: -lfoo -lbar -lfoo.
  • Use linker groups: -Wl,--start-group -lfoo -lbar -Wl,--end-group

The effect of repeating library names is that the linker throws the libraries at the currently undefined symbols and resolves everything it can, so by mentioning one library again it will resolve symbols from all previous libraries. This can always be used to break all cycles.

The effect of linker groups is that it effectively changes the linker algorithm: It first throws all object files and libraries in the group into one bug basket, then tries to resolve everything (regardless of the order inside the linker group) and then proceeds with the next group.

Johannes Overmann
  • 4,914
  • 22
  • 38
  • 4
    Third option: Solve the obvious bad design in the two libraries, either pull the common code out into a 3rd library that both depend on, or combine the two into a single library. Circular dependencies are often a sign of a bigger issue with cohesion – user6567423 Feb 11 '19 at 22:08
  • 1
    One option is to extract all the object files from each of the libraries and then create a single `libfoobar.a` library holding them all. The only problem that ca n easily arise is if there are two object files with the same name, one from each library. Judicious renaming can fix that. – Jonathan Leffler Feb 11 '19 at 22:10
  • Linker groups sound pretty darn good to me. Thanks Johannes. – Roguebantha Feb 15 '19 at 17:30