编译的时候,偶尔会碰到“undefined reference to `xxx_function’”的错误,遇到这种问题怎么解决呢?

怎么解决?

首先我们需要知道,出现这样现象的时候,都是在编译的链接阶段,在出现这样的编译错误打印时,可以看到有“ld returned 1 exit status”的信息,这个时候就可以知道是链接某函数时没有找到相应的库导致的编译错误。

那么,类似这样的问题,我们怎么解决呢?

既然编译是说没有定义某个函数,所以我们先看看这个函数是哪一个库实现的。直接搜索编译环境的include目录,看看 xxx_function 这个函数是定义到哪一个头文件,再看看这个函数是哪个源文件实现并编译为库。假设 xxx_function 函数由 xxx.c 实现并最终编译输出为 xxx.so,接着使用readelf -d xxx.so,查看该命令输出的“Library soname:”信息,比如输出了“libxxx.so”,我们再在Makefile的LDFLAGS增加 -lxxx即可,这样编译的时候链接工具将会链接libxxx.so并查找得到xxx_function函数的符号链接成功。
有些时候是没有链接系统的某些库导致的,有时候又会是没有链接第三方库导致的,具体根据问题现象相应查找实现该函数的库,再相应的链接该库即可。

为什么会出现这样的错误呢?

我们在机器中运行一个程序,程序都是由源代码经过预编译编译汇编链接四个阶段组成。

预编译

假设我们的是 .c 源文件和相关头文件,将会被与编译器 gcc 预编译为一个 .i 文件,预编译使用 -E 参数即可。预编译可以简单理解就是处理源码中已“#”开始的预编译指令,比如“#include”、“#define”等。当我们无法判断宏定义是否正确或头文件包含是否正确时,可以查看预编译后的文件来确定问题。

编译

编译过程就是把预处理完的文件进行一系列词法分析、语法分析、语义分析及优化后生成相应的汇编代码文件。使用 - S 参数将输出为汇编文件。

汇编

汇编器就是将汇编代码转换为机器可以执行的指令,每一个汇编语句几乎都对应一条机器指令。使用 -c 参数即可,经过预编译、编译和汇编将会输出目标文件。

链接

我们看汇编代码中,经常会看到 jmp aaa_function,我们知道这个是一个跳转指令,将会跳转到 aaa_function 函数执行,aaa_function 此时是一个符号,我们在编译的时候,最终就会将可执行程序中使用的各个符号链接起来,知道运行的时候到哪里查找得到该符号,知道跳转的地址是多少。链接的过程主要包括了地址和空间分配、符号决议和重定位等这些步骤。

所以出现上面“undefined reference to `xxx_function’”错误的时候就是没有在当前的符号表中没有找到xxx_function符号的定义,链接器ld就报错了,我们将会需要通过 -l 指令,告知链接器需要链接哪些库,使其可以找到相应的符号定义。

最后

上面很多方面没有描述清楚,很多步骤也没有理解好,强烈建议有需要的小伙伴看看《程序员的自我修养------链接、装载与库》这本书,这本书非常详细的介绍了一个可执行程序链接到加载运行的各个操作,相信各位认真看完之后必定功力大增。

Logo

旨在为数千万中国开发者提供一个无缝且高效的云端环境,以支持学习、使用和贡献开源项目。

更多推荐