我正在编写一个使用librt的小型C程序。如果我把链接标志放在开头而不是结尾处,程序将无法编译,我感到非常惊讶:
目前,要编译我执行的程序:
gcc -o prog prog.c -lrt -std=gnu99
如果我要执行以下操作,将无法在librt中找到函数:
gcc -std=gnu99 -lrt -o prog prog.c
然而,这适用于其他图书馆。我在尝试使用简单的Makefile时发现了这个问题。实际编译prog.c而不首先喜欢(使用-c标志),然后进行链接。
这是Makefile:
CC = gcc
CFLAGS = -std=gnu99
LIBS= -lrt
LDFLAGS := -lrt
prog: prog.o
$(CC) -o prog prog.c -lrt -std=gnu99
输入make时我得到的输出是:
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
我现在已经制作了一个Makefile,它将链接放在gcc行的末尾,但是我很困惑,如果链接标志位于开头,它为什么不起作用。
如果有人能向我解释,我将不胜感激。感谢。
答案 0 :(得分:22)
当链接器处理每个模块(无论是库还是目标文件)时,它会尝试解析每个未定义的符号,同时可能会添加到未定义的符号列表中。当它到达模块列表的末尾时,它已解析所有未定义的符号并成功或报告未定义的符号。
在您的情况下,当它处理librt时,它没有未定义的符号。处理proc导致clock_gettime是未定义的符号。 gcc不会返回并在librt中查找未定义的符号。
出于这个原因,你应该首先得到你的代码,然后是你的库,然后是平台提供的库。
希望这有帮助。
答案 1 :(得分:14)
来自ld
(GNU链接器)文档(http://sourceware.org/binutils/docs/ld/Options.html#Options):
链接器将仅在命令行上指定的位置搜索一次存档。如果存档定义了在命令行上存档之前出现的某个对象中未定义的符号,则链接器将包含存档中的相应文件。但是,稍后在命令行中出现的对象中的未定义符号将不会导致链接器再次搜索存档。
因此,如果您过早地指定库,链接器将扫描它,但找不到任何感兴趣的内容。然后链接器移动到编译器生成的目标文件,并找到需要解析的引用,但它已经扫描了库,并且不再费心去查看那里。