35

I've run into this issue in the past: LLVM defines __GNUC__, but it can't consume a program GCC can. I'm experiencing it again on Windows: LLVM defines _MSC_VER, but it can't consume the same program VC++ can. The aggravating thing (for me) is we have specialized code paths for LLVM Clang and Apple Clang (different defines due to different version schemes), and we have to fight with the tool to get it to use them.

How do we tell Clang to stop pretending to be other compilers? Is there a switch or option to do it?


The Clang docs discuss the unwanted MS behavior, but they don't say how to stop it:

For compatibility with existing code that compiles with MSVC, clang defines the _MSC_VER and _MSC_FULL_VER macros. These default to the values of 1800 and 180000000 respectively, making clang look like an early release of Visual C++ 2013. The -fms-compatibility-version= flag overrides these values. It accepts a dotted version tuple, such as 19.00.23506. Changing the MSVC compatibility version makes clang behave more like that version of MSVC. For example, -fms-compatibility-version=19 will enable C++14 features and define char16_t and char32_t as builtin types.

jww
  • 97,681
  • 90
  • 411
  • 885

5 Answers5

22

__GNUC__ doesn't mean GCC specifically. All compilers that support GNU C extensions define it, including clang and ICC.

The normal way to detect specifically GCC is by excluding other "compatible" compilers

#if defined(__GNUC__) && !defined(__llvm__) && !defined(__INTEL_COMPILER)
#define REAL_GCC   __GNUC__ // probably
#endif

The Clang front-end defines __clang__, but other front-ends that use the LLVM back-end also define __llvm__ (e.g. IBM XL C/C++ versions 13.1.1 through 16.1). It might be better to just exclude __clang__ instead of __llvm__, depending on why you want to exclude it. (e.g. for parsing reasons, vs. for optimization reasons like LLVM evaluating __builtin_constant_p() before doing inlining, so it's useless on args of an inline function.)

See also https://sourceforge.net/p/predef/wiki/Compilers/ for a large list.

https://blog.kowalczyk.info/article/j/guide-to-predefined-macros-in-c-compilers-gcc-clang-msvc-etc..html came up in google results, too, but is less complete.


The thing you should be complaining about is that GCC itself doesn't define a GCC-specific macro you can detect, only the version of the GNU dialect of C it supports. (GNU C is a language, GCC is a compiler for that language. GCC's __GNUC_MINOR__ / __GNUC_PATCHLEVEL__ macros conflate the two, unfortunately.)

Clang defines __GNUC__ / __GNUC_MINOR__ / __GNUC_PATCHLEVEL__ according to the version of gcc that it claims full compatibility with. (Probably only for stuff that GCC documentation guarantees will work, not for stuff that happens to work with that version or later of gcc. For GCC itself, documented = supported. Being accepted by the compiler doesn't imply it's supported and guaranteed for future GCC versions. That might be how clang justifies claiming support for some GNU C versions).

For example, clang 7.0.1 defines GNUC/MINOR/PATCHLEVEL as 4/2/1, i.e. compat with GCC 4.2.1

e.g. from the GCC manual

#define GCC_VERSION (__GNUC__ * 10000 \
                     + __GNUC_MINOR__ * 100 \
                     + __GNUC_PATCHLEVEL__)
…
/* Test for GCC > 3.2.0 */
#if GCC_VERSION > 30200

If you're testing for a specific GNU C feature that recent GCC supports but recent clang doesn't support (yet), you should probably be doing something like that.

Peter Cordes
  • 328,167
  • 45
  • 605
  • 847
  • 9
    *"__GNUC__ doesn't mean GCC specifically."* - `__GNUC__` means precisely the GCC compiler. It is [well documented](https://gcc.gnu.org/onlinedocs/cpp/Common-Predefined-Macros.html#Common-Predefined-Macros) and has been for years. Even the GCC folks have told Clang to stop defining it because it means the GCC compiler. – jww Apr 30 '19 at 18:28
  • 5
    *"The normal way to detect specifically GCC is by excluding other "compatible" compilers"* - No, that's not the normal way. The normal way to detect GCC is the presence of `__GNUC__`. ICC has a switch to disable the behavior. – jww Apr 30 '19 at 18:29
  • 4
    @jww: It would be nice if GCC had a macro all to itself, but the de-facto reality is the one I described in this answer, where non-GCC compilers have decided to define `__GNUC__` to indicate compatibility with some version of GCC. (Whether that's perfectly accurate or not.) There are too many existing installs of Clang on MacOS to ignore at this point, even if clang were to change tomorrow. (Semi-related, MacOS even installs a `gcc` that's actually a symlink to `clang`, leading to confusion in SO questions, too.) – Peter Cordes Apr 30 '19 at 18:32
  • _The thing you should be complaining about is that GCC itself doesn't define a GCC-specific macro_ - No, [it defines `__GNUC__` for this](https://gcc.gnu.org/onlinedocs/cpp/Common-Predefined-Macros.html): _If all you need to know is whether or not your program is being compiled by GCC, or a non-GCC compiler that claims to accept the GNU C dialects, you can simply test `__GNUC__`_. – legends2k Dec 03 '22 at 05:05
  • @legends2k: Yeah, that's the ideal, and is fine most of the time. The problem is that GCC has different quirks than non-GCC compilers. And worse, I think some clang versions define `__GNUC__` to a feature level of GNU C extensions it doesn't *exactly* match or fully cover. I also suspect that at least some of jww's problems are from relying on things that aren't even officially supported in GNU C, i.e. implementation details / happens-to-work things in GCC, which of course will break on other implementations. – Peter Cordes Dec 03 '22 at 07:30
9

It seems that starting with release 10 clang now has an option for this. See the docs for clang:

-fgnuc-version=

This flag controls the value of GNUC and related macros. This flag does not enable or disable any GCC extensions implemented in Clang. Setting the version to zero causes Clang to leave GNUC and other GNU-namespaced macros, such as GXX_WEAK, undefined.

So to disable this behaviour, specify -fgnuc-version=0 on the clang commandline.

Matthijs Kooijman
  • 2,498
  • 23
  • 30
  • 3
    After using this flag with clang 11, libstdc++, linux and -D_GLIBCXX_DEBUG, I got a million errors inside standard library. So, Peter Cordes's answer is still the only solution. – Ave Milia Apr 05 '21 at 18:45
  • Hm, interesting. I can imagine this causes errors, though I'm surprised that even the (clang?) standard library needs this defined. But I guess there's a reason (legacy code...) that `__GNUC__` is defined by default... Thanks for the extra info and the edit, though! :-) – Matthijs Kooijman Apr 06 '21 at 10:44
3

How do we tell Clang to stop pretending to be other compilers?

I don't know how to do that, nor whether it's even do-able. Why do you want to do this? I have the feeling you want to do this to work around a problem, but perhaps there's a better solution.

[On Windows,] LLVM defines _MSC_VER,

Because you're likely using a standard library that's going to check that in order to produce compatible code.

Clang's goal on Windows is not just to produce standalone code that runs on Windows, but code that can be linked with libraries that were compiled with VC++. From the source code's point of view, it should be indistinguishable whether it's being compiled with clang or VC++.

If you want to be able to call into an existing DLL, and its header files check _MSC_VER, you need it set whether you're using VC++ or clang.

but [clang on Windows] can't consume the same program VC++ can.

Clang's capabilities on Windows have improved quite a bit since this question was written. Several major projects now use clang for their Windows versions.

If you find a correct program that VC++ accepts and clang doesn't, please file a bug report. In most cases, this is probably an oversight. There are a small number of features and VC++ extensions that are not implemented in clang-on-Windows because they weren't a high enough priority. If they're a priority for you, please let us know.

Adrian McCarthy
  • 45,555
  • 16
  • 123
  • 175
  • 9
    *"Why do you want to do this?"* - We have wasted close to three man-months fixing Clang bugs because it can't consume a program for the compiler it pretends to be. And not surprising, it got worse on PowerPC. Clang pretends to be both GCC and IBM XL/C and can't consume programs for either compiler. I am tired of wasting my time supporting Clang. We no longer want Clang to pretend to be other compilers. Instead, Clang can use the straight C/C++ code. Put another way, the jerks who are doing this crap don't pay the penalty; we pay the penalty for the crap they do. – jww Apr 12 '19 at 21:30
  • 4
    C++ is both a language and a library. Except in unusual cases, _"straight C/C++ code"_ depends on libraries that need to know the details of how the compiler works, and the compiler itself depends on its standard library implementation. Which libraries are you trying to use on Windows (e.g., VC++'s standard library, libstd, libc++, something else)? What kinds of code are you finding that VC++ can compile but clang cannot? I (and the rest of the _"jerks"_ on my team) thank you for filing LLVM bug reports and for any contributions you've made to LLVM and clang. – Adrian McCarthy Apr 12 '19 at 21:56
  • @AdrianMcCarthy: I think jww is talking about libcrypto++'s inline asm, and saying that they're giving up on clang by ifdefing so clang uses the pure C/C++ fallback code instead of the code paths with GNU extensions including inline asm. (I wouldn't be surprised if some of the problems are from code that merely *happens* to work on GCC, and depends on wishful thinking rather than any formal guarantees in the docs. It's been a while since I looked at their code but IIRC inline asm was over-used vs. intrinsics, apparently because a few crappy compilers don't support intrinsics.) – Peter Cordes Feb 20 '20 at 21:31
  • 2
    So even for stuff that should have worked, I'm not surprised libcrypto++ was exercising compilers in new ways that pure C/++ code doesn't, and tripping on real compiler bugs. But keep in mind that in other Q&As, I've seen jww basically blame GCC for not working the way he wished it worked, because having a different design philosophy than MSVC about having to enable `-mwhatever` to use intrinsics is inconvenient for the way they want to use libcrypto++. Or something like that. So I take his rants with a grain of salt, although there's often a valid complaint about something in there. – Peter Cordes Feb 20 '20 at 21:37
1

I too was surprised to discover that Clang defined _MSC_VER, but what I did was to do something like this:

#if defined(_MSC_VER) && !defined(__clang__)
// Real MSVC here
#elif defined(__clang__)
// Real CLANG here
Cthutu
  • 8,713
  • 7
  • 33
  • 49
1

You can use Hedley library:

Note that the GCC and GNUC macros are different. Many compilers masquerade as GCC (by defining __GNUC__, __GNUC_MINOR__, and __GNUC_PATCHLEVEL__, but often do not implement all the features that the version of GCC they pretend to be supports. To work around this, the HEDLEY_GCC_VERSION macro is only defined for GCC, whereas HEDLEY_GNUC_VERSION will be defined whenever a compiler defines __GNUC__.

So, HEDLEY_GCC_VERSION is only defined for GCC.

Aykhan Hagverdili
  • 28,141
  • 6
  • 41
  • 93