Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why does the order in which libraries are linked sometimes cause errors in GCC?

Tags:

gcc

linker

Why does the order in which libraries are linked sometimes cause errors in GCC?

like image 652
Landon Avatar asked Sep 05 '08 02:09

Landon


People also ask

Does order of linking libraries matter?

Link order certainly does matter, at least on some platforms. I have seen crashes for applications linked with libraries in wrong order (where wrong means A linked before B but B depends on A).

Does order matter in GCC?

For the most part, the order you use doesn't matter. Order does matter when you use several options of the same kind; for example, if you specify -L more than once, the directories are searched in the order specified.

What is Link order?

1 Link order of libraries. The traditional behavior of linkers is to search for external functions from left to right in the libraries specified on the command line. This means that a library containing the definition of a function should appear after any source files or object files which use it.

What does linker do GCC?

The job of the linker is to link together a bunch of object files ( .o files) into a binary executable. The process of linking mainly involves resolving symbolic addresses to numerical addresses. The result of the link process is normally an executable program.


1 Answers

(See the history on this answer to get the more elaborate text, but I now think it's easier for the reader to see real command lines).


Common files shared by all below commands

$ cat a.cpp extern int a; int main() {   return a; }  $ cat b.cpp extern int b; int a = b;  $ cat d.cpp int b; 

Linking to static libraries

$ g++ -c b.cpp -o b.o $ ar cr libb.a b.o $ g++ -c d.cpp -o d.o $ ar cr libd.a d.o  $ g++ -L. -ld -lb a.cpp # wrong order $ g++ -L. -lb -ld a.cpp # wrong order $ g++ a.cpp -L. -ld -lb # wrong order $ g++ a.cpp -L. -lb -ld # right order 

The linker searches from left to right, and notes unresolved symbols as it goes. If a library resolves the symbol, it takes the object files of that library to resolve the symbol (b.o out of libb.a in this case).

Dependencies of static libraries against each other work the same - the library that needs symbols must be first, then the library that resolves the symbol.

If a static library depends on another library, but the other library again depends on the former library, there is a cycle. You can resolve this by enclosing the cyclically dependent libraries by -( and -), such as -( -la -lb -) (you may need to escape the parens, such as -\( and -\)). The linker then searches those enclosed lib multiple times to ensure cycling dependencies are resolved. Alternatively, you can specify the libraries multiple times, so each is before one another: -la -lb -la.

Linking to dynamic libraries

$ export LD_LIBRARY_PATH=. # not needed if libs go to /usr/lib etc $ g++ -fpic -shared d.cpp -o libd.so $ g++ -fpic -shared b.cpp -L. -ld -o libb.so # specifies its dependency!  $ g++ -L. -lb a.cpp # wrong order (works on some distributions) $ g++ -Wl,--as-needed -L. -lb a.cpp # wrong order $ g++ -Wl,--as-needed a.cpp -L. -lb # right order 

It's the same here - the libraries must follow the object files of the program. The difference here compared with static libraries is that you need not care about the dependencies of the libraries against each other, because dynamic libraries sort out their dependencies themselves.

Some recent distributions apparently default to using the --as-needed linker flag, which enforces that the program's object files come before the dynamic libraries. If that flag is passed, the linker will not link to libraries that are not actually needed by the executable (and it detects this from left to right). My recent archlinux distribution doesn't use this flag by default, so it didn't give an error for not following the correct order.

It is not correct to omit the dependency of b.so against d.so when creating the former. You will be required to specify the library when linking a then, but a doesn't really need the integer b itself, so it should not be made to care about b's own dependencies.

Here is an example of the implications if you miss specifying the dependencies for libb.so

$ export LD_LIBRARY_PATH=. # not needed if libs go to /usr/lib etc $ g++ -fpic -shared d.cpp -o libd.so $ g++ -fpic -shared b.cpp -o libb.so # wrong (but links)  $ g++ -L. -lb a.cpp # wrong, as above $ g++ -Wl,--as-needed -L. -lb a.cpp # wrong, as above $ g++ a.cpp -L. -lb # wrong, missing libd.so $ g++ a.cpp -L. -ld -lb # wrong order (works on some distributions) $ g++ -Wl,--as-needed a.cpp -L. -ld -lb # wrong order (like static libs) $ g++ -Wl,--as-needed a.cpp -L. -lb -ld # "right" 

If you now look into what dependencies the binary has, you note the binary itself depends also on libd, not just libb as it should. The binary will need to be relinked if libb later depends on another library, if you do it this way. And if someone else loads libb using dlopen at runtime (think of loading plugins dynamically), the call will fail as well. So the "right" really should be a wrong as well.

like image 188
Johannes Schaub - litb Avatar answered Jan 04 '23 08:01

Johannes Schaub - litb