Detect gcc as opposed to msvc / clang with macro
Asked Answered
H

3

92

I am working on a project that has been built with both gcc and msvc so far. We recently started building with clang as well.

There are some parts in the code, where platform-specific things are done:

#ifndef _WIN32
// ignore this in msvc
#endif

Since gcc has previously been the only non-windows build, this was equivalent to saying "do this only for gcc". But now it means "do this only for gcc and clang".

However there are still situations, where I would like to handle something specifically for gcc, and not for clang. Is there a simple and robust way to detect gcc, i.e.

#ifdef ???
// do this *only* for gcc
#endif
Hoahoactzin answered 27/1, 2015 at 9:0 Comment(5)
Why are you building with a multitude of compilers?Proceleusmatic
possible duplicate of How to #ifdef by CompilerType ? GCC or VC++Bleier
nope, the other question does not even mention clang...Hoahoactzin
Possible duplicate of What predefined macro can I use to detect clang? for clang + #15128022 for VCMargay
You are confusing operating systems and compilers.Bradski
E
133
__GNUC__
__GNUC_MINOR__
__GNUC_PATCHLEVEL__

These macros are defined by all GNU compilers that use the C preprocessor: C, C++, Objective-C and Fortran. Their values are the major version, minor version, and patch level of the compiler, as integer constants. For example, GCC 3.2.1 will define __GNUC__ to 3, __GNUC_MINOR__ to 2, and __GNUC_PATCHLEVEL__ to 1. These macros are also defined if you invoke the preprocessor directly.

Also:

__GNUG__

The GNU C++ compiler defines this. Testing it is equivalent to testing (__GNUC__ && __cplusplus).

Source

Apparently, clang uses them too. However it also defines:

__clang__
__clang_major__
__clang_minor__
__clang_patchlevel__

So you can do:

#ifdef __GNUC__
    #ifndef __clang__
...

Or even better (note the order):

#if defined(__clang__)
....
#elif defined(__GNUC__) || defined(__GNUG__)
....
#elif defined(_MSC_VER)
....
Eureetloir answered 27/1, 2015 at 9:2 Comment(11)
These things are all collected in the much more robust Boost.Predef, and the (now outdated) original wiki that sprung that Boost library is located here. Note that the Intel compiler will define __GNUC__ or _MSC_VER on the relevant platforms as well.Triste
All compilers that support the GNU C set of language extensions define those macros, right down to __GNUC_PATCHLEVEL__. So to detect support for a specific GNU C feature on any compiler, you check those macros. On gcc itself, they also map to the actual version of the compiler you're using, but they're best used to tell you what version of the GNU C language is supported, more than the compiler type / version.Denationalize
This does not seem to work when using clang-cl. In this case __clang__ and _MSC_VER is defined.Urbanist
__clang__, __clang_major__, __clang_minor__ and __clang_patchlevel__ are all defined on gcc. What kind of sadistic maniac would design it that way?Whilst
@Whilst Pardon ? Clang emulates either GCC or MSVC, not the other way around!Bradski
@JohanBoulé they both emulate each otherWhilst
@Whilst I insist that GCC does NOT define __clang__. Where did you see that happen ?Bradski
@JohanBoulé I tested it myselfWhilst
@Whilst The only explanation is you had a glitch in you test. Again, GCC does not define __clang__, so the compiler that you tested was either really Clang or something else than GCC.Bradski
When GNUG is equivalent to GNUC && cpp then it's useless to test for both: GNUC || GNUG <=> GNUC || GNUC && cpp <=> GNUC && (1 || cpp) <=> GNUC...Marcelo
there is an easier macro for clang: __clang_version__ and it produces something like 3.2 (tags/RELEASE_32/final)Hanse
V
15

I use this define:

#define GCC_COMPILER (defined(__GNUC__) && !defined(__clang__))

And test with it:

#if GCC_COMPILER
...
#endif
Vilmavim answered 4/4, 2017 at 11:1 Comment(3)
That won't exclude ICC.Denationalize
@PeterCordes why notGina
@Ayxan: because ICC supports GNU extensions, and thus defines __GNUC__. You'd also have to check for !defined(__INTEL_COMPILER), like for clang. software.intel.com/en-us/forums/intel-c-compiler/topic/281802Denationalize
H
12

With Boost, this becomes very simple:

#include <boost/predef.h>

#if BOOST_COMP_GNUC
// do this *only* for gcc
#endif

See also the Using the predefs section of the boost documentation.

(credit to rubenvb who mentioned this in a comment, to Alberto M for adding the include, and to Frederik Aalund for correcting #ifdef to #if)

Hoahoactzin answered 27/1, 2015 at 9:33 Comment(4)
The header to include to get the symbol is <boost/predef.h>.Gubernatorial
You're supposed to use #if BOOST_COMP_GNUC and not #ifdef since the macro is always defined (but may be zero). See boost.org/doc/libs/1_66_0/doc/html/predef/…Intoxication
Yes, thanks for pointing it out, I thought I tested this when I first posted the answer, but it looks like #ifdef probably never worked, at least not for boost versions 1.55 or later.Hoahoactzin
Note that using Boost isn't always the correct solution. Boost can be handy, indeed, but thanks to its size and complexity, can add a large amount of overhead.#Insure

© 2022 - 2024 — McMap. All rights reserved.