Why Does the Library Linker Flag Sometimes Have to Go at the End Using Gcc

Why does the library linker flag sometimes have to go at the end using GCC?

As the linker processes each module (be it a library or a object file), it attempts to resolve each undefined symbol while potentially adding to its list of undefined symbols. When it gets to the end of the list of modules, it either has resolved all undefined symbols and is successful or it reports undefined symbols.

In your case, when it processed librt, it had no undefined symbols. Processing proc resulted in clock_gettime being an undefined symbol. gcc will not go back and look in librt for the undefined symbols.

For that reason, you should always have your code first, followed by your libraries, followed by platform provided libraries.

Hope this helps.

Why do I have to pass libraries in the end of linker line?

I can't answer you as to why you think it might have worked before. But I can tell you why it doesn't work in general. Most POSIX-style linkers, which includes the GNU binutils ld using on GNU/Linux and others, are single-pass linkers.

That means they walk the elements listed in the command line from the start to the end one time and they don't go back. When the linker starts it's basically looking for one symbol, main. As it walks the command line, any object file (foo.o) the linker finds is always added to the executable. The object provides a list of symbols which are defined, and a list which are undefined (needed from other objects).

When the linker hits a static library (libfoo.a), it looks through the object files in that library and if an object contains any symbol which the linker needs, it adds that object to the executable. If it does not contain any symbol the linker needs, it skips that object.

At the end of the command line, if any symbol was needed but not found, then the link fails.

So, you can see that in order to be sure everything is found in a single pass, the things that NEED symbols from libraries must come before the libraries that provide those symbols, or else when the linker hits the library in its single pass it won't know that the libraries are needed and will skip them.

Why does the order of '-l' option in gcc matter?

Because that's how the linking algorithm used by GNU linker works (a least when it comes to linking static libraries). The linker is a single pass linker and it does not revisit libraries once they have been seen.

A library is a collection (an archive) of object files. When you add a library using the -l option, the linker does not unconditionally take all object files from the library. It only takes those object files that are currently needed, i.e. files that resolve some currently unresolved (pending) symbols. After that, the linker completely forgets about that library.

The list of pending symbols is continuously maintained by the linker as the linker processes input object files, one after another from left to right. As it processes each object file, some symbols get resolved and removed from the list, other newly discovered unresolved symbols get added to the list.

So, if you included some library by using -l, the linker uses that library to resolve as many currently pending symbols as it can, and then completely forgets about that library. If it later suddenly discovers that it now needs some additional object file(s) from that library, the linker will not "return" to that library to retrieve those additional object files. It is already too late.

For this reason, it is always a good idea to use -l option late in the linker's command line, so that by the time the linker gets to that -l it can reliably determine which object files it needs and which it doesn't need. Placing the -l option as the very first parameter to the linker generally makes no sense at all: at the very beginning the list of pending symbols is empty (or, more precisely, consists of single symbol main), meaning that the linker will not take anything from the library at all.

In your case, your object file example.o contains references to symbols ud_init, ud_set_input_file etc. The linker should receive that object file first. It will add these symbols to the list of pending symbols. After that you can use -l option to add the your library: -ludis86. The linker will search your library and take everything from it that resolves those pending symbols.

If you place the -ludis86 option first in the command line, the linker will effectively ignore your library, since at the beginning it does not know that it will need ud_init, ud_set_input_file etc. Later, when processing example.o it will discover these symbols and add them to the pending symbol list. But these symbols will remain unresolved to the end, since -ludis86 was already processed (and effectively ignored).

Sometimes, when two (or more) libraries refer to each other in circular fashion, one might even need to use the -l option twice with the same library, to give linker two chances to retrieve the necessary object files from that library.

Does every library used to build a program need to be linked using a flag in gcc?

  1. Usually, yes. Some libraries work with a script called pkg-config that tells you how to link; e.g. pkg-config --libs libzip will give the linker flags for libzip, which are -lzip -lz.

  2. Headers contain declarations of functions, definitions of data structures, and other things that are relevant at for the compiler, but no information for the linker. This is a bit of a historic accident; it was fixed in the Plan 9 C compiler and I believe also in Microsoft's compiler, but not in common Unix/Linux compilers.

    Mind you, headers and libraries are not in one-to-one correspondence. E.g. some libraries are "header-only", and some libraries including libc have many headers. In other cases, multiple versions of a library can be available (a common version, a debugging version, an optimized version for some processor, ...), all with the same header.

  3. I believe this depends on the GCC version, but I've never figured out which versions require strict ordering and which don't. The safe bet is to link with libraries in reverse dependency order; so if libfoo uses libbar, link with libfoo first, then libbar. The aforementioned pkg-config takes care of this as well for the libraries that support it.

What are the --start-group and --end-group command line options?

It is for resolving circular dependences between several libraries (listed between -( and -)).

Citing Why does the order in which libraries are linked sometimes cause errors in GCC? or man ld http://linux.die.net/man/1/ld

-( archives -) or --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.

So, libraries inside the group can be searched for new symbols several time, and you need no ugly constructs like -llib1 -llib2 -llib1

PS archive means basically a static library (*.a files)

GCC link order changed?

If Mercury puts object files after libraries, Mercury is broken. Libraries belong after object files - always. You may sometimes get away with the reverse order, but not reliably. (Static libraries must go after the object files that reference symbols in the static library. Sometimes, a linker will note the symbols defined by a shared library even when none of the symbols are used; sometimes, the linker will only note the shared library symbols if the shared library provides at least one symbol.)



Related Topics



Leave a reply



Submit