29

I'm writing a small C program that uses librt. I'm quite surprised that the program won't compile if I place the link flag at the start instead of at the end:

At the moment, to compile the program I do:

gcc -o prog prog.c -lrt -std=gnu99

If I were to do the following, it will fail to find the functions in librt:

gcc -std=gnu99 -lrt -o prog prog.c

Yet, this works with other libraries. I found the issue when attempting to use a simple Makefile. make actually compiled prog.c without liking first (using -c flag) and then did the linking.

This is the Makefile:

CC = gcc

CFLAGS = -std=gnu99

LIBS= -lrt

LDFLAGS := -lrt


prog: prog.o

        $(CC) -o prog prog.c -lrt -std=gnu99

The output I would get when typing make would be:

gcc -std=gnu99   -c -o prog.o prog.c
gcc -lrt  prog.o   -o prog
prog.o: In function `main':
prog.c:(.text+0xe6): undefined reference to `clock_gettime'
prog.c:(.text+0x2fc): undefined reference to `clock_gettime'
collect2: ld returned 1 exit status
make: *** [buff] Error 1

I have now crafted a Makefile that puts the linking at the end of the gcc line, however I'm puzzled why it doesn't work if the linking flag is at the start.

I would appreciate if anybody can explain this to me. Thanks.

theprole
  • 2,274
  • 23
  • 25
  • 1
    I'm not 100% on this, but I think the linker might be looking at librt and deciding it doesn't need anything in it, so just throws it away. Is librt a static library? – spencercw Feb 23 '12 at 16:43
  • See the answers to this question for an explanation of why static linking is order-dependent:http://stackoverflow.com/questions/45135/linker-order-gcc – Nathan Monteleone Feb 23 '12 at 16:45
  • 2
    Might be related to linker's *as-needed* option being used by default. You could try `gcc -std=gnu99 -Wl,-no-as-needed -lrt -o prog prog.c` – another.anon.coward Feb 23 '12 at 16:52
  • Related: http://stackoverflow.com/q/8140494/168175 – Flexo Feb 23 '12 at 17:00

2 Answers2

33

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.

Ludovic Kuty
  • 4,868
  • 3
  • 28
  • 42
Lou
  • 1,955
  • 14
  • 16
  • 4
    Minor note: the order of object files is not important; an object file that references a symbol in another object file doesn't necessarily have to come before it on the command line. Which makes sense, of course, if you consider that all symbols from an object file get included in the final image, even if there is no undefined reference to them yet, and thus get added to the list of defined symbols, so a later reference in another object file will not lead to an undefined symbol. – eriktous Feb 23 '12 at 22:57
  • Thank you for the insight, this was quite helpful. – SRG Sep 14 '18 at 13:06
  • ld is lazy and passes over the .o/.a-files only once. Contrary to a normal linker (MS's link.exe etc), that does 2 passes (+ possibly generates code too). – G.Vanem Jan 23 '22 at 11:47
19

From the ld (the GNU linker) documentation (http://sourceware.org/binutils/docs/ld/Options.html#Options):

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.

So if you specify the library too early, the linker will scan it, but not find anything of interest. Then the linker moves on to the object file produced by the compiler and finds references that need to be resolved, but it has already scanned the library and won't bother looking there again.

Michael Burr
  • 333,147
  • 50
  • 533
  • 760