Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Strange disconnect between Eclipse CDT, included system headers, and the underlying C build

I'm having a strange problem with include files and an apparent disconnect between Eclipse's build process and its error reporting. I'll give detailed steps to reproducing this problem, so we can narrow the causes down as quickly as possible.

Eclipse 3.7.1 (Indigo SR1) for C/C++ Linux Developers, Ubuntu 10.10 64-bits

It all started when I imported an existing project that "makes" just fine on its own: I thought Eclipse would help considerably in navigating the files and figuring out what does what. However, some of the #included system headers seemed not to be having the correct effect in Eclipse's view. This was very puzzling, and in the course of investigating this, I managed to recreate the problem in a tiny sand box.

Step one: Create a new C project (File: New: C Project) using the Hello World ANSI C Project sample. The parameters are Executable: Hello World ANSI C Project/Linux GCC, the remaining Empty projects set to Linux GCC, and GNU Autotools set to Hello World ANSI C Autotools Project. Call it "hello". Be sure to generate the makefile automatically (Advanced Settings, I believe it is the default).

Step two: Adjust the include path. Using Project: Properties: C/C++ General: Paths and Symbols: Includes: GNU C, set the search path to /usr/local/include, /usr/lib/gcc/x86_64-linux-gnu/4.4.5/include, /usr/include. The second path depends on the exact version of gcc you have installed. This doesn't matter too much, as long as the build path includes at least /usr/include.

Now if you open hello.c, it looks very simple, and Eclipse is quite happy except for return EXIT_SUCCESS;, which cannot resolve EXIT_SUCCESS. Replace EXIT_SUCCESS with a zero (0) and Eclipse gives the all-clear. Select Project: Build Project to generate the executable.

Open a command-line window and drill down to your Eclipse workspace folder's hello/Debug subfolder. Once there, you can run the executable with the line ./hello.

Now the fun begins. Modify hello.c to read in its latter part:

#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;
}

You'll get an error on the int zz... line: "Symbol 'SPLICE_F_MOVE' could not be resolved". If you Build the project, you'll get a similar error in the console view: "error: 'SPLICE_F_MOVE' undeclared".

Now if you change the preamble to:

#define _GNU_SOURCE
#include <fcntl.h>

You still get the error on the int zz line (in the editor), but the project will Build correctly! You can confirm this by running the binary in the command-line window you opened earlier. This is really odd since examination of /usr/include/fcntl.h will show that it #includes <bits/fcntl.h>, and that latter header #defines SPLICE_F_MOVE (and a bunch of others) in a block guarded by #ifdef __USE_GNU (__USE_GNU gets #defined if _GNU_SOURCE is #defined). Why on Earth isn't our #define _GNU_SOURCE properly propagated in the workspace perspective?

So this is my problem in a nutshell: why is it the editor (and all of Eclipse CDT) reports an error (apparently by refusing to process correctly an include), but that the underlying build succeeds?

like image 624
Urhixidur Avatar asked Nov 30 '11 22:11

Urhixidur


1 Answers

I had similar problems working with GNU and non-GNU compliant toolchains for cross-compiling various microcontrollers. CDT reports lots of errors, but the actual build works perfectly, even when all the header includes are correctly located in the project settings.

The problem is in how CDT operates as distinct from your make system build. CDT is a standalone lexer, parser, and preprocessor and doesn't make use of the toolchain you're using to do the build. This normally would work fine once you set the project settings to match those generated as command-line arguments to your build tools, but many toolchains frequently include hidden implicit defines as part of their compiler/preprocessor itself. The documentation for the implict/hidden defines is usually sketchy and incomplete in my experience, making it nearly impossible to determine which defines are set for a given toolchain (sometimes even dependent on build options) and what they mean. While it may look like you have all the correct defines set to reach the one you're having a problem with, I usually find (especially with GNU) that there are some you're missing that prevent the switch from being processed the way you expected.

When I debug something like this, I first make sure any headers in my project directory are found first if they have names matching those in other directories, then I slowly start moving headers from the standard include folder to my project folder. CDT doesn't do a very good job of indicating which possible versions of a header file it's parsing first, and it frequently pulls system environment settings when you least expect it, but it does look in your project folder for headers first (if you haven't set the system headers path in your project settings to take precedence). By moving the system headers from the location you're looking at to your project directory, you know for sure exactly which header file is being parsed by CDT. Furthermore, if you rebuild your index after doing the move, then open the file in Eclipse, CDT will indicate what switches it believes are enabled or disabled by greying-out or folding the branches not enabled in the header. Following this process has solved this exact problem for me every time, revealing when I had paths to multiple copies of the same header, accidentally duplicated headers, had defines or includes under unexpected switches, etc.

like image 80
mtalexan Avatar answered Oct 19 '22 05:10

mtalexan