views:

1972

answers:

5

Let's say we got a main executable called "my_app" and it uses several other libraries: 3 libraries are linked statically, and other 3 are linked dynamically. In which order should they be linked against "my_app"?

But in which order should these be linked?

Let's say we got libSA (as in Static A) which depends on libSB, and libSC which depends on libSB:

libSA -> libSB -> libSC

and three dynamic libraries: libDA -> libDB -> libDC (libDA is the basic, libDC is the highest)

in which order should these be linked? the basic one first or last?

g++ ... -g libSA libSB libSC -lDA -lDB -lDC -o my_app

seems like the currect order, but is that so? what if there are dependencies between any dynamic library to a static one, or the other way?

A: 

The dependencies for linking a library or executable have to be present at link-time, so you cannot link libXC before libXB is present. It doesn't matter if statically or dynamically.

Start with the most basic one, which has no (or just outside of your project) dependencies.

Kosi2801
A: 

It's good practice to keep libraries independent of each other to avoid link order issues.

Scottie T
+3  A: 

In the static case, it doesn't really matter, because you don't actually link static libraries - all you do is pack some object files together in one archive. All you have to is compile your object files, and you can create static libraries right away.

The situation with dynamic libraries is more convoluted, there are two aspects:

  1. A shared library works exactly the same way as static library (except for shared segments, if they are present), which means, you can just do the same - just link your shared library as soon as you have the object files. This means for example symbols from libDA will appear as undefined in libDB

  2. You can specify the libraries to link to on the command line when linking shared objects. This has the same effect as 1., but, marks libDB as needing libDA.

The difference is that if you use the former way, you have to specify all three libraries (-lDA, -lDB, -lDC) on the command line when linking the executable. If you use the latter, you just specify -lDC and it will pull the others automatically at link time. Note that link time is just before your program runs (which means you can get different versions of symbols, even from different libraries).

This all applies to UNIX; Windows DLL work quite differently.

Edit after clarification of the question:

Quote from the ld info manual.

The linker will search an archive only once, at the location where it is specified on the command line. If the archive defines a symbol which was undefined in some object which appeared before the archive on the command line, the linker will include the appropriate file(s) from the archive. However, an undefined symbol in an object appearing later on the command line will not cause the linker to search the archive again.

See the `-(' option for a way to force the linker to search archives multiple times.

You may list the same archive multiple times on the command line.

This type of archive searching is standard for Unix linkers. However, if you are using `ld' on AIX, note that it is different from the behaviour of the AIX linker.

That means:

Any static library or object that depends on other library should be placed before it in the command line. If static libraries depend on each other circularly, you can eg. use the -( command line option, or place the libraries on the command line twice (-lDA -lDB -lDA). The order of dynamic libraries doesn't matter.

jpalecek
+1 : I've seen this problem all too often. As static libs are not widely used nowaday, the reason / solution is not that well known ... Another solution is to use the linker whole-archive option. It includes all archive objects. It it used to create dynamic libs from static libs but works for the archives link order problem ...
neuro
A: 

This is the sort of question that's best solved by a trivial example. Really! Take 2 minutes, code up a simple example, and try it out! You'll learn something, and it's faster than asking.

For example, given files:

a1.cc

#include <stdio.h>
void a1() { printf("a1\n"); }

a2.cc

#include <stdio.h>
extern void a1();
void a2() { printf("a2\n");  a1(); }

a3.cc

#include <stdio.h>
extern void a2();
void a3() { printf("a3\n"); a2(); }

aa.cc

extern void a3();
int main()
{
  a3();
}

Running:

g++ -Wall -g -c a1.cc
g++ -Wall -g -c a2.cc
g++ -Wall -g -c a3.cc
ar -r liba1.a a1.o
ar -r liba2.a a2.o
ar -r liba3.a a3.o
g++ -Wall -g aa.cc -o aa -la1 -la2 -la3 -L.

Shows:

./liba3.a(a3.o)(.text+0x14): In function `a3()':
/tmp/z/a3.C:4: undefined reference to `a2()'

Whereas:

g++ -Wall -g -c a1.C
g++ -Wall -g -c a2.C
g++ -Wall -g -c a3.C
ar -r liba1.a a1.o
ar -r liba2.a a2.o
ar -r liba3.a a3.o
g++ -Wall -g aa.C -o aa -la3 -la2 -la1 -L.

Succeeds. (Just the -la3 -la2 -la1 parameter order is changed.)

PS:

nm --demangle liba*.a

liba1.a:
a1.o:
                 U __gxx_personality_v0
                 U printf
0000000000000000 T a1()

liba2.a:
a2.o:
                 U __gxx_personality_v0
                 U printf
                 U a1()
0000000000000000 T a2()

liba3.a:
a3.o:
                 U __gxx_personality_v0
                 U printf
                 U a2()
0000000000000000 T a3()

From man nm:

  • If lowercase, the symbol is local; if uppercase, the symbol is global (external).

  • "T" The symbol is in the text (code) section.

  • "U" The symbol is undefined.

Mr.Ree
A: 

I worked in a project with a bunch of internal libraries that unfortunately depended on each other (and it got worse over time). We ended up "solving" this by setting up SCons to specify all libs twice when linking:

g++ ... -la1 -la2 -la3 -la1 -la2 -la3 ...
Fredrik Jansson