Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

g++ fails mysteriously only if a .h is in a certain directory

Tags:

c++

xcode

macos

g++

I'm experiencing an extremely weird problem in a fresh OSX 10.4.11 + Xcode 2.5 installation. I've reduced it to a minimal test case. Here's test.cpp:

#include "macros.h"

int main (void)
{
    return 1;
}

And here's macros.h:

#ifndef __JUST_TESTING__
#define __JUST_TESTING__

template<typename T> void swap (T& pT1, T& pT2)
{
    T pTmp = pT1;
    pT1 = pT2;
    pT2 = pTmp;
}

#endif //__JUST_TESTING__

This compiles and works just fine if both files are in the same directory. HOWEVER, if I put macros.h in /usr/include/gfc2 (it's part of a custom library I use) and change the #include in test.cpp, compilation fails with this error :

/usr/include/gfc2/macros.h:4: error: template with C linkage

I researched that error and most of the comments point to a "dangling extern C", which doesn't seem to be the case at all.

I'm at a complete loss here. Is g++ for some reason assuming everything in /usr/include/gfc2 is C even though it's included from a .cpp file that doesn't say extern "C" anywhere?

Any ideas?

EDIT : It does compile if I use the full path in the #include, ie #include "/usr/include/gfc2/macros.h"

EDIT2 : It's not including the wrong header. I've verified this using cpp, g++ -E, and renaming macros.h to foobarmacros.h

like image 408
ggambett Avatar asked Feb 24 '10 17:02

ggambett


2 Answers

G++ may well indeed be assuming that everything in /usr/include is C. Try compiling your code with -E and studying the line markers in the preprocessor output:

g++ -E test.cpp | grep '^#'

You'll likely see things like

# 1 "/usr/include/gfc2/macros.h" 1 3 4

The 4 is the preprocessor hinting to G++ that it should wrap everything in extern "C", on the supposition that your platform's ancient header files in /usr/include predate C++. See Preprocessor Output in the CPP manual.

These days G++ mostly ignores this hint, because most platforms' C headers are no longer ancient. See the NO_IMPLICIT_EXTERN_C target macro in the GCC Internals manual. But it may be that this old version of Xcode has GCC configured without NO_IMPLICIT_EXTERN_C and thus is listening to the preprocessor's hint. (This is set when GCC itself is built -- I don't think there's a command-line switch to override it.)

You may be able to work around this by wrapping the contents of your header file in extern "C++".

like image 173
John Marshall Avatar answered Oct 31 '22 21:10

John Marshall


This is a shot in the dark, but is there another file named macros.h somewhere under /usr/include or in your GCC installation? GCC has a facility for wrapping headers, called #include_next, which might be the cause of your problem.

One thing you can do to disambiguate your macros.h from any other macros.h in the include path is to include it as gfc2/macros.h. This way, the compiler will search every directory in the include path for a subdirectory named gfc2 containing a file named macros.h, reducing the chance of a collision. It also prevents you from having to add /usr/include/gfc2 to the include path.

BTW, #include "file.h" searches the current directory first. To skip that and go straight to the include path, use #include <file.h>:

#include <stdio.h>
#include <gfc2/macros.h>

Another approach is to choose a filename that is more likely to be unique, like gfc2macros.h.

like image 35
bk1e Avatar answered Oct 31 '22 21:10

bk1e