本文的重点是讲述gcc库的链接顺序。刚开始的时候,在链接参数部分,我的顺序是这么安排的: -lc -lgcc -lm。结果compile正常,但是在ld的时候,遇到问题了,总是报log函数找不到errno变量。经过仔细分析,发现我的程序本身是有问题的,运算表达式可以总结为:log(a)。结果a为0了,log函数会报错,会将错误代码赋给__errno这个全局变量。而__errno变量是声明在errno.h头文件中,但是定义在libc的某个file中。gcc库的链接顺序,官方是这么解释的:https://gcc.gnu.org/onlinedocs/gcc-5.2.0/gcc/Link-Options.html#Link-Optionsgcc -l 解释如下: -l library Search the library named library when linking. (The second alter- native with the library as a separate argument is only for POSIX compliance and is not recommended.)
It makes a difference where in the command you write this option; the linker searches and processes libraries and object files in the order they are specified. Thus, foo.o -lz bar.o searches library z after file foo.o but before bar.o. If bar.o refers to functions in z, those functions may not be loaded.这句话翻译过来的意思就是说,如果你的库在链接时安排的顺序是:foo.o -lz bar.o。那么gcc的链接器先搜索库foo,然后是z库,然后是bar库。这样就带来一个问题,如果库bar调用了库z里面的函数,但是链接器是先搜索的库z,这时候并没有发现库bar调用库z啊,所以就不会把库z中的这部分函数体挑出来进行链接。而是只把库z中,被foo库调用的函数体挑出来。 回到我们之前的描述。由于__errno全局变量是定义在库libc中,而库libm中的log函数会访问__errno全局变量。这就要求链接时,libm在libc的前面。所以我们应该这样安排库的链接顺序: -lm -lgcc -lc 一句话,越是被别人调用的越底层的库,就越放在后面;越是调用别人的越上层的库,就越放在前面。