这里有两个问题:
- 为什么
test.c
编译时没有提供库中例程声明的标头?
- 为什么链接可以在命令行中
test.c
列出的第一个使用,但不能在test.c
命令行的最后列出?
我们无法对第一个提供完整的答案,因为您没有显示源代码。正如其他人所指出的,C 有一些余地来提供隐式声明,主要是出于历史原因。这些隐式声明可能与您的例程的实际定义不匹配,这可能会导致错误,因此您应该避免隐式声明。
你的第二个问题的答案是这样的。给定您显示的两个命令行中的任何一个,编译器都会编译test.c
然后调用链接器。(也可以让编译器做其他事情,例如在不链接的情况下进行编译,或者从先前编译的源中链接目标模块。)当编译器调用链接器时,它会按照与您的顺序相对应的顺序传递链接器参数将它们传递给链接器。特别是,如果您放在-lcde
before test.c
,则编译器在运行链接器时将放在-lcde
来自test.c
,的目标模块之前。test.o
这很重要,因为链接器的操作方式。除此之外,链接器有一个需要定义的符号列表。该列表最初是空的。链接器从左到右处理来自命令行的输入。当链接器在其命令行中看到一个目标模块test.o
时,它会读取该目标模块并对其进行处理。通常,对象模块包含对它未定义的某些符号的引用,例如对库例程的调用。如果链接器已经从以前的文件中定义了这些符号,它会将引用连接到定义。如果它没有定义,它会将符号添加到链接器需要定义的符号列表中。
当链接器处理库文件时,它会检查库中的每个目标模块,以查看该目标模块是否定义了链接器所需定义列表中的符号。如果是这样,链接器会读取该对象模块并将其(及其定义)添加到链接器正在构建的可执行文件中。如果不是,链接器将忽略该目标模块。
Now we can see why test.c -lcde
works but -lcde test.c
does not. In the former case, the linker makes a list of everything that test.o
needs, then it gets those things from the cde
library. In the latter case, the linker sees the cde
library but does not need anything from it yet, so it goes on without taking anything from the library. Then the linker reads test.c
and adds to the list of needed symbols. Then the command line ends, and the linker has no more files but still has symbols without definitions. So it reports an error.
So, generally, libraries should be listed last on command lines.