背景
在GCC中已经指定链接库,然而编译时却提示动态库函数未定义!
测试出现的错误提示如下:
-
[GMPY@13:48 tmp]$gcc -o test -L. -lmylib test.c
-
/tmp/ccysQZI3.o:在函数‘main’中:
-
test.c:(.text+0x1a):对‘func_lib’未定义的引用
-
collect2: error: ld returned 1 exit status
而在测试用的动态库libmylib.so
中是有定义函数func_lib
的
-
[GMPY@13:55 tmp]$cat mylib.c
-
#include <stdio.h>
-
-
int func_lib(void)
-
{
-
printf("In share library\n");
-
return 0;
-
}
-
[GMPY@13:56 tmp]$gcc -fPIC -shared mylib.c -o libmylib.so
GCC的链接坑
此处的"坑"指对不熟悉GCC机制的童鞋而言,会出现无法理解的不符合预期的效果
在用gcc编译时,我们可以用-L
指定链接库位置,用-l
指定。
man gcc
查询时,我发现这么一段描述:
-
-llibrary
-
-l library
-
... ## 这里为了方便阅读,对原文进行了换行排版优化
-
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.
-
...
嗯,这段话什么意思呢? 如果-l
链接库在源码之前,就会链接不到库!!
就像下面两个命令的差别:
-
异常:gcc -o test -L. -lmylib test.c
-
正常:gcc -o test -L. test.c -lmylib
竟然对执行时参数的位置都有要求,也是醉了
GCC的链接步骤
感谢 @firstrose 提供的原理说明链接
GCC是怎么样理解-l
的呢?
-
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.
什么个意思呢?就是说,GCC链接器按下面的步骤链接文件:
- 从左往右链接源文件
- 在链接时,如果出现源文件调用了却没有定义的函数、变量等,则记录下来
- 如果遇到-l指定的库,则在库中尽可能检索所有记录下来的没有定义的函数、变量,只从库中提取用到的部分,其他完全抛弃
- 在全部链接完后,如果依然存在未定义的函数、变量,则报错
正因为GCC链接器的"始乱终弃",在检索-l
的库后,就抛弃了这个库,后面还需要用时,自然就找不到了
GCC并不会回过头来检索之前链接过的库
从这样的链接步骤,我猜测还会有个特性:
由于GCC链接库会在首先指定的库中"贪婪匹配"所有未定义的函数、变量,因此,
即使两个库有相同的函数、变量的定义,只会使用最先找到的库中的定义