6

My project consists of a couple of static libraries, which are linked together in a final step. Now I have the problem, that the link order of the library is important (otherwise I get an undefined symbol linker error). Sometimes I run into the problem, that I have to re-sort the linked libraries (-lcommon -lsetup -lcontrol etc). At the moment it's a stupid trial and error: re-sort, compile, check error, re-sort, compile and so on.

So I wrote a small program to show me the inter-library-dependencies and generates me the order of libraries to link. It reads in the defined ('T', 'B', etc) and undefined symbols ('U') from nm and removes the weak symbols ('w', 'W', 'v' and 'V') from the 'undefined symbol list'. Now it determines for every undefined symbol the library which resolves it.

But my program shows me circular dependencies... what's my mistake?

If they really exist, I could not link at all... so what did I miss, when analyzing the nm output? Or is analyzing the nm output not the way, to get these dependencies?

libcommon.a:
         U _ZN15HardwareUnit23GetHardwareSerialNumberEv
libhardware.a:
00000484 T _ZN15HardwareUnit23GetHardwareSerialNumberEv
libsecurityaccess.a:
         U _ZN15HardwareUnit23GetHardwareSerialNumberEv
---
libhardware.a:
         U _ZN21ApplicationProfile26GetApplicationSettingsPathERK7QString
libsecurityaccess.a:
00004020 T _ZN21ApplicationProfile26GetApplicationSettingsPathERK7QString
         U _ZN21ApplicationProfile26GetApplicationSettingsPathERK7QString
Charly
  • 1,270
  • 19
  • 42

2 Answers2

6

Another option to link libraries with circular dependencies is to use a special linker option for that. Man ld:

   -( archives -)
   --start-group archives --end-group
       The archives should be a list of archive files.  They may be either
       explicit file names, or -l options.

       The specified archives are searched repeatedly until no new
       undefined references are created.  Normally, an archive is searched
       only once in the order that it is specified on the command line.
       If a symbol in that archive is needed to resolve an undefined
       symbol referred to by an object in an archive that appears later on
       the command line, the linker would not be able to resolve that
       reference.  By grouping the archives, they all be searched
       repeatedly until all possible references are resolved.

       Using this option has a significant performance cost.  It is best
       to use it only when there are unavoidable circular references
       between two or more archives.

It is always cleaner to eliminate the circular dependencies though.

Maxim Egorushkin
  • 131,725
  • 17
  • 180
  • 271
  • Is there a way to determine, which 'circular dependencies' will break the compilation and which not? – Charly Jan 24 '11 at 14:15
  • The linker tells you the names of the symbols it failed to resolve. – Maxim Egorushkin Jan 24 '11 at 14:21
  • Yes, this is the way I'm doing it now (when not using the 'group option' - which works great, THX!!). I compile, re-order the library list and run into the next linker error. If I would be able to compute the dependencies in advance, I would create the library order before the compilation and don't have to do it via trial and error. (At the moment there are about 20 libraries and each have dependencies to other modules) – Charly Jan 24 '11 at 14:32
  • Not sure if there are automated tools for that. A script could do for each .a nm its list of unresolved symbols, then find .a's that provide the definition of the symbol and note that dependency. Then you could draw a graph from the dependency notes. – Maxim Egorushkin Jan 24 '11 at 14:37
  • I described a similar script/program in my question, BUT the output of 'nm' does not differ between circular dependencies which could be solved by the linker - and others, which create an linker error. Thus this output is useless - where can I get more detailed information? – Charly Jan 24 '11 at 19:48
2

If you truly have a circular dependency chain of static libraries (and this is not clear from your paste; you show only a non-circular dependency), there are two options:

  1. Remove the circular dependency somehow; for example, you could make sure libcommon does not reference symbols in libpthardware.
  2. Extract the individual .o files from the .a library, and link them directly. Then link order no longer matters.

In the case of 2., you may find it helpful to use partial linking rather than creating static libraries. On systems using GNU bintools, this can be done by invoking something like:

ld -r -o libfoo.o foo.o bar.o

The effect of this is to combine foo.o and bar.o into a single .o file. The order does not matter. You can then simply reference libfoo.o as a normal object file in your final link step.

Note that doing this may interfere with the linker's ability to discard unreferenced portions of the static library (normally this is done at the level of .o files within the .a, I believe). If you're using all or most of these libraries, this is probably not a problem. However, if code memory is an issue, you may want to look into automatically discarding unused code at the function level. If you do this, pass --gc-sections and -s only at the final link stage (and avoid doing so if you need to debug!). Also, static linking with system libraries does not seem to be necessary with modern gcc.

Community
  • 1
  • 1
bdonlan
  • 224,562
  • 31
  • 268
  • 324
  • Thanks a lot. This could solve the symptom - but at the end I would be interested in the dependencies between the libraries. Why does the nm-output show me a circular dependency - but the linking is successful?? – Charly Jan 24 '11 at 09:23
  • Not sure - in my experimentation, I found that certain orderings of libraries with a circular dependency do successfully link, but I'm not sure why. I read your question as asking how to deal with the situation, but if you're more interested in knowing why it succeeded, I'd suggest building a minimal test case (should be fairly trivial) and submitting a question explicitly asking why it succeeds. – bdonlan Jan 24 '11 at 09:36