g++: In what order should static and dynamic libraries be linked?

17,419

Solution 1

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.

Solution 2

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.

Solution 3

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 ...
Share:
17,419

Related videos on Youtube

PopunderCode
Author by

PopunderCode

Updated on March 10, 2020

Comments

  • PopunderCode
    PopunderCode about 4 years

    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?

  • neuro
    neuro over 14 years
    +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 ...
  • Noldorin
    Noldorin over 9 years
    Sorry, but the first part is just plain wrong! Static libraries are linked in, at least in the sense that symbol resolution is done as they are bundled together. And thus the order is of paramount importance!
  • kevin
    kevin over 9 years
    @Noldorin I agree with you. I found another post about this topic. Linker order - GCC
  • Noldorin
    Noldorin over 9 years
    @kevin: Yep, I've seen that post too... it's a good informative overview. Make sure you read the comments too for the fine points. :)
  • venkrao
    venkrao over 9 years
    -Wl,--start-group, and -Wl,--end-group may also come in handy.
  • Geoffrey Irving
    Geoffrey Irving over 7 years
    Writing up an example is dramatically slower than asking for someone finding this 7 years later.