背景
在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链接库会在首先指定的库中"贪婪匹配"所有未定义的函数、变量,因此,
即使两个库有相同的函数、变量的定义,只会使用最先找到的库中的定义
分类:
C++/C
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!
2016-01-04 两个结构体ifconf和ifreq
2016-01-04 struct ifconf和struct ifreq,获取网线插入状态
2016-01-04 Linux中ifreq 结构体分析和使用 及其在项目中的简单应用
2016-01-04 Linux中ifreq 结构体分析和使用
2016-01-04 linux 系统获取网络ip, mask, gateway, dns信息小程序
2016-01-04 struct ifreq结构体与ip,子网掩码,网关等信息
2016-01-04 结构体中的柔性数组成员(数组长度为0成员)!