include语句的顺序在链接步骤中如何重要
How can the order of include statements matter in the linking step?
我无法解释链接代码时看到的行为。也许有人知道发生了什么…
我有一个多文件C++项目,它使用GNU automake工具作为构建系统(全部在Linux上)。
在将源文件和头文件(称为util.cc
和util.h
)添加到项目中,并且已有一个源文件(calc.cc
)从新添加的文件中调用函数后,我会收到一个链接错误,具体取决于include
语句的出现位置。我重复一遍:错误发生在链接步骤,编译运行良好!!
示例:
在将新的include语句放在先前存在的语句的末尾时,我遇到了一个错误,例如:
calc.cc:
#include "file1.h"
#include "file2.h"
#include "file3.h"
#include "file4.h"
#include "util.h" // new header
这个版本编译得很好。但是链接会产生错误(找不到符号)!!
现在,当将其更改为时
#include "util.h" // new header
#include "file1.h"
#include "file2.h"
#include "file3.h"
#include "file4.h"
那么编译和链接运行良好!
由于链接器只读取.o
文件,这一定意味着根据include语句的出现位置生成不同的内容。这怎么可能?
编译器是g++(GCC)4.4.6
util.h可能有一个#定义,它会更改其他文件之一的行为。
要想弄清楚到底发生了什么,最好的方法是检查这些头文件中缺少的符号的名称,从"工作"answers"非工作"方式编译calc.cc中获得预处理器输出,并比较这两个文件。
简单的头文件可以(重新)定义宏,这些宏可以更改以后宏的解释。
例如,在上面的示例中,如果file1.h执行
#define lseek lseek64
如果util.h有一个调用lseek的内联函数,那么根据包含顺序,生成的对象代码将具有对lseek或lseek64的符号引用。
这就是为什么项目倾向于首先包含config.h(由autoconf生成)的规则。
你绝对是对的:在这两种情况下会产生不同的对象代码。正如@hmjd还指出的,util.h中很可能有一个宏,其他(.h或.c)文件之一使用该宏,并且编译器假设任何未声明的、调用的标识符是一个函数——这很可能是这里的错误。
- lambda参数转换为constexpr技巧,然后获取带链接的数组
- CMake-按正确顺序将项目与C运行时对象文件链接
- 从链接列表c++中删除一个项目
- 有根的二进制搜索树.保留与其父级的链接
- 读取文件的最后一行并输入到链接列表时出错
- 静态数据成员的问题-修复链接错误会导致编译器错误
- node-gyp 在 macOS 上未正确链接库
- 基于boost的程序的静态链接——zlib问题
- 无法链接 CMake 中的本地库
- 内联函数中具有内部链接的全局变量
- 链接阶段在Ubuntu上失败,但在MacOS上失败
- 使用gcc从静态链接的文件中查找可选符号
- 我可以将一个用clang c++11编译的对象与另一个用c++17编译的对象链接起来吗
- 将--whole archive链接器选项与CMake和具有其他库依赖项的库一起使用
- C++:重命名dll和lib并链接
- 为什么与函数相比,链接阶段没有类重定义错误?
- C++不使用"inline"或"static"无类函数的关键字时出现重定义链接错误
- 未定义的引用,但(动态)库被链接.(可能是坏的重定位地址错误)
- 标头重定义错误,链接错误
- 如何检测网页中大多数不常见的超链接和隐式重定向