3

gcc compiles C programs as C, and C++ programs as C++, thus requiring an 'extern "C"' declaration in C++. Whereas, g++ compiles C programs as C++, and C++ programs as C++, thus requiring that the 'extern "C"' declaration must NOT be used in C++.

Checking standard flags without any input, both

 g++ -E -dM - </dev/null 
 gcc -E -dM - </dev/null 

give the same results.

__GNUG__       is equivalent to testing (__GNUC__ && __cplusplus)

which again will not differentiate gcc from g++ inside a C++ source listing.

What is the magic for

#ifndef __MAGIC_G++_INCLUDE_FLAG_BUT_NOT_GCC__ 

to wrap around the extern "C"{ declarations? Thanks.

Edit: I realize this is a rather esoteric case. The test needs to be done on the compiler flavor, not on the source code flavor. In both cases the test is being performed inside a C++ source code listing (which is why I mentioned GNUG is inadequate). To clarify, for test main.cpp:

#include <iostream>
int 
main( int argc, char **argv )
{
#ifdef __cplusplus  <<<< FIX THIS ONE
  std::cout << "I was compiled using g++" << std::endl;
#else
  std::cout << "I was compiled using gcc" << std::endl;
#endif 
}

when compiled with either

 g++ main.cpp

or

gcc main.cpp -lstdc++

in both cases, it seems to incorrectly give as output "I was compiled using g++". So it would seem that cplusplus is not the correct flag to use in this case. Am I wrong? Or what is the correct flag?

Edit 2: Thanks, guys. Here is one example for you. Large legacy system "Alpha" is written mostly in C, with a little C++, and uses large legacy source package "Charlie", written in C++. It uses the g++ system to compile and link, and demands that Charlie's headers have no extern "C" definitions in them, or else it refuses to link. Large legacy system "Bravo" is written mostly in C, with a little C++, and also uses the same legacy source package Charlie, written in C++. It uses the gcc system to compile and link, and demands that Charlie's headers must have extern "C" definitions in them, or else it refuses to link. New systems "Delta", "Echo", and "Foxtrot" would also like to reuse parts of source from Charlie, compiler to be used is uncertain. The correct answer is to hack Charlie's headers, once and for all, with

#ifndef __MAGIC_G++_INCLUDE_FLAG_BUT_NOT_GCC__ 
extern "C" {
#endif
...
declarations of code
...
#ifndef __MAGIC_G++_INCLUDE_FLAG_BUT_NOT_GCC__ 
}
#endif

and then be done with it. Otherwise there will always be linking problems. Yes, of course it could be possible to compile two sets of libraries in this particular case, one under C and one under the C++ convention, and then mandate that thou shalt use this particular library for this particular flavor of linking. Or I could come up with two sets of headers. Either of those is inelegant and will continue to cause problems down the road, in this example; there are other cases. As to the comment that both g++ and gcc are using the same compiler under the hood, and so it can't possibly matter, sadly, it does. The package as a whole refuses to link when the wrong 'extern "C"' dogma is/isn't included. Yes, there are other ways of attacking the general problem, but it's a simple question. Either such a flag exists, or it is known not to exist, or the answer is not known definitively. I don't know, myself.

DragonLord
  • 6,395
  • 4
  • 36
  • 38
  • Is there a reason why you would need to know that? Is your build script/process/etc. not standard for gcc/g++ compilers? – sedavidw Sep 18 '14 at 18:29
  • 3
    You should be using the `gcc` command to compile C sources and the `g++` command to compile C++ source files. Is there some reason you're doing that? – Keith Thompson Sep 18 '14 at 18:32
  • `__cplusplus` is defined for C++, but not for C. Anyway, both drivers (`gcc` and `g++` are wrappers around the real compiler) can be used to compile both C and C++ sources, though they default to different flags, best suited respectively for C and C++. – Deduplicator Sep 18 '14 at 18:33
  • When maintaining large legacy systems, sometimes code is compiled using gcc and sometimes using g++. g++ in general makes it easier to compile and link mixed systems of C++ and C together, and so is the preferred compiler of use. However, arbitrarily ripping out all the extern "C" declarations is guaranteed to break other legacy code. Hence the need for conditional compilation. Thanks. – DragonLord Sep 18 '14 at 19:51
  • 2
    It doesn't matter if you invoke gcc or g++. If gcc decides that the source file is C++, the same compiler as what g++ would run, namely the binary cc1plus is the one actually run to compile your source code. If you use gcc to compile *and* link, there's a difference in the linking stage though - but not in the compile stage. It would probably help if you explain the actual problem you're trying to solve. – nos Sep 18 '14 at 19:57
  • 1
    Your edit shows why the question makes little sense -- since the file is called `main.cpp`, g++ will be used to compile it regardless of whether you invoke `g++` or `gcc` on the command line (in the latter case, `gcc` will just call `g++` for you), so you always get "compiled using g++". If you want to force using gcc regardless of name, you can use the command line argument `-x c`, but then it won't compile at all, as it's not valid C code. – Chris Dodd Sep 18 '14 at 20:53
  • Your question basically seems to come down to "Is there a way to check while compiling one file what flags will eventually be used to compile some other file?", to which the answer is obviously no -- the second compile might not even have occured yet. Instead, you need to pick some flag (it can be anything you want) and pass it consistently to all compiles. Perhaps `-DUSING_GCC` or `-DUSING_GPP` – Chris Dodd Sep 18 '14 at 20:58
  • I think nos's observation that the compiling and linking stages are separate, could be key. However, by Link time, I would guess that the problem has already been cast in iron--either the objects are already compatible, or they aren't--so it really does come back down to the conditional definition at Compile time. I don't believe the linker is going to change the symbols in the .o, so as to ensure compatibility? I can't believe that a .o gets compiled with two sets of symbols, one C style and one C++, which then somehow get chosen at link time based on gcc vs. g++? That would be unlikely. – DragonLord Sep 19 '14 at 04:50

1 Answers1

5

The standard technique is to check if the preprocessor symbol __cplusplus is defined:

#ifdef __cplusplus
extern "C" {
#endif

/* declarations here */

#ifdef __cplusplus
}
#endif
nobody
  • 19,814
  • 17
  • 56
  • 77
  • Regretfully, this does not solve the question that was asked, see edit. Thanks. – DragonLord Sep 18 '14 at 19:58
  • This is a standard first-order way to shim C code so that it fits into either C or C++, under gcc. It does not look like it addresses the C++ problem I'm attacking. – DragonLord Sep 19 '14 at 04:25
  • It DOES correctly tell the difference between the two compilers when the source code is in C, and not in C++. That is, if I'm working with main.c and not main.cpp, this flag WILL tell the difference between gcc and g++. However, as the extern "C" directive is only useful in C++, it's unclear how this can solve the general problem. – DragonLord Sep 19 '14 at 04:29
  • As a brief case in which this fails, start with a child routine child.c in C, to be called by parent main.cpp. Modify its header child.h by inserting this code around the definitions. This does in fact work for the gcc compiler/linker. However, when using g++, the compiler quietly changes the child's object representation into a C++ style upon compilation. But the parent is still expecting the C style, because the included header is specifying extern "C". As a result, the final linkage fails, under g++. The extern "C"'s should have been left out when using the g++ compiler/linker, I think. – DragonLord Sep 19 '14 at 04:38