我在包含文件方面遇到了一个奇怪的问题,并且 Eclipse 的构建过程与其错误报告之间明显脱节。我将提供重现此问题的详细步骤,以便我们尽快缩小原因范围。
面向 C/C++ Linux 开发人员的 Eclipse 3.7.1 (Indigo SR1),Ubuntu 10.10 64 位
这一切都是从我导入一个现有的项目开始的,这个项目本身就“做得很好”:我认为 Eclipse 会大大有助于导航文件和弄清楚什么是什么。然而,一些 #include
d 系统 header 在 Eclipse 的 View 中似乎没有产生正确的效果。这非常令人费解,在对此进行调查的过程中,我设法在一个小沙盒中重现了这个问题。
第一步:使用 File: New: C Project
创建一个新的 C 项目 ( Hello World ANSI C Project
)样本。参数是Executable: Hello World ANSI C Project/Linux GCC
, 剩下的 Empty
项目设置为 Linux GCC
, 和 GNU Autotools
设置为 Hello World ANSI C Autotools Project
.称之为“你好”。一定要自动生成makefile(高级设置,我相信这是默认的)。
第二步:调整包含路径。使用 Project: Properties: C/C++ General: Paths and Symbols: Includes: GNU C
, 将搜索路径设置为 /usr/local/include
, /usr/lib/gcc/x86_64-linux-gnu/4.4.5/include
, /usr/include
.第二条路径取决于您安装的 gcc 的确切版本。这无关紧要,只要构建路径至少包含 /usr/include
。 .
现在如果你打开 hello.c
, 看起来很简单,Eclipse 除了return EXIT_SUCCESS;
还是蛮开心的,无法解析 EXIT_SUCCESS
.替换 EXIT_SUCCESS
带有零 ( 0
) 并且 Eclipse 给出了全部清除。选择 Project: Build Project
生成可执行文件。
打开命令行窗口并深入到 Eclipse 工作区文件夹的 hello/Debug
子文件夹。在那里,您可以使用 ./hello
行运行可执行文件.
现在乐趣开始了。修改hello.c
阅读其后半部分:
#include <fcntl.h>
int main(void) {
printf("Hello World!\n");
int zz = SPLICE_F_MOVE;
printf("zz (SPLICE_F_MOVE) is '%d'\n", zz);
printf("Bye World!\n");
return 0;
}
您会在 int zz...
上收到错误消息行:"Symbol 'SPLICE_F_MOVE' could not be resolved"
.如果您构建项目,您将在控制台 View 中收到类似的错误:"error: 'SPLICE_F_MOVE' undeclared"
.
现在,如果您将序言更改为:
#define _GNU_SOURCE
#include <fcntl.h>
您仍然在 int zz
上得到错误行(在编辑器中),但项目将正确构建!您可以通过在之前打开的命令行窗口中运行二进制文件来确认这一点。这真的很奇怪,因为检查了/usr/include/fcntl.h
会显示它 #include
s <bits/fcntl.h>
,以及后一个标题 #define
s SPLICE_F_MOVE
(和其他一些人)在一个由 #ifdef __USE_GNU
守卫的街区中(如果 __USE_GNU
是 #define
d,_GNU_SOURCE
得到 #define
d)。为什么地球上不是我们的 #define _GNU_SOURCE
在工作区透视图中正确传播?
简而言之,这是我的问题:为什么编辑器(和所有 Eclipse CDT)报告错误(显然是拒绝正确处理包含),但底层构建成功?
最佳答案
我在使用 GNU 和非 GNU 兼容工具链交叉编译各种微 Controller 时遇到了类似的问题。 CDT 报告了很多错误,但实际构建工作完美,即使所有 header 都正确位于项目设置中也是如此。
问题在于 CDT 如何与您的 make 系统构建区分开来。 CDT 是一个独立的词法分析器、解析器和预处理器,不使用您用于构建的工具链。一旦您将项目设置设置为将作为命令行参数生成的那些生成的设置与您的构建工具相匹配,这通常会很好地工作,但是许多工具链经常将隐藏的隐式定义作为其编译器/预处理器本身的一部分。根据我的经验,隐含/隐藏定义的文档通常是粗略和不完整的,这使得几乎不可能确定为给定工具链设置了哪些定义(有时甚至取决于构建选项)以及它们的含义。虽然看起来你已经设置了所有正确的定义来达到你遇到问题的那个,但我通常发现(尤其是 GNU)你遗漏了一些阻止开关按照你的方式处理的东西预期的。
当我调试这样的东西时,我首先确保首先找到我的项目目录中的任何标题,如果它们的名称与其他目录中的标题匹配,然后我慢慢开始将标题从标准包含文件夹移动到我的项目文件夹。 CDT 不能很好地指示它首先解析的头文件的可能版本,并且它经常在您最不期望的时候提取系统环境设置,但它确实会首先在您的项目文件夹中查找头文件(如果您没有'在项目设置中设置系统头文件路径优先)。通过将系统头文件从您正在查看的位置移动到您的项目目录,您可以确切地知道 CDT 正在解析哪个头文件。此外,如果您在执行移动后重建索引,然后在 Eclipse 中打开文件,CDT 将通过灰显或折叠 header 中未启用的分支来指示它认为启用或禁用的开关。遵循这个过程每次都为我解决了这个确切的问题,揭示了我何时拥有同一 header 的多个副本的路径、意外重复的 header 、在意外开关下定义或包含等。
关于c - Eclipse CDT、包含的系统头文件和底层 C 构建之间奇怪的断开连接,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/8333887/