Detect ICC vs GCC at compile time - c++

How to detect at compile time if I'm using gcc or icc?
(I was quite puzzled to find out that icc defines __GNUC__ -- and even __GNUC_MINOR__ and __GNUC_PATCHLEVEL__ ! why?)

We use
#ifdef __INTEL_COMPILER
to split icc off, assuming gcc as a default.

I believe you could check for __INTEL_COMPILER according to this.

The reason ICC defines __GNUC__ etc. is because of code like yours that is inspecting compiler-specific macros and expects to see them...

Traditionally, compilers have defined a symbol of their own as well as their version as preprocessor symbols so that the code could be adapted (generally to work around bugs or specificities).
CLang has introduced a mechanism I had not seen so far, under the form of the __has_feature query. It does not replace the "work around bugs" practices (which is why CLang still exposes specific symbols) but allows a more natural style for querying the compiler capacities. I don't know if other compilers plan on defining such a facility.

You can make the processor output the defined macros in the preprocessor output and look for a macro that suits you. You can generated the preprocessor output like this:
icc -dM -E -o foo.P foo.c
Then look at foo.P (since it is a text file). In my case, I found icc defined an __ICC macro with the version of the compiler. It didn't define any __INTEL_COMPILER though.

Related

Distinguish between Clang CL and MSVC CL

There is CLang-CL which is a drop-in replacement for MSVC's CL.
Does anyone know how to distinguish if my code is currently compiled by clang-cl or msvc's cl? Without passing any extra defined macros on command line.
Using
#ifdef _MSC_VER
//.....
#endif
doesn't work, both compilers define _MSC_VER.
Also in regular CLang on Linux (Windows too) it was possible to do clang -dM -E - < /dev/null which dumps all defined macros. But clang-cl and msvc-cl both don't have such option to dump all defined macros as far as I know, so I don't know of a way to see a difference in list of defined macros for both compilers to figure out which macro to use to distinguish between these compilers.
The macro you're looking for is __clang__.
Note that the regular Clang (not only Clang-CL) also defines it, so you want to check for both __clang__ and _MSC_VER at the same time.

#pragma(* diagnostic) when mixing Clang analyzers with a GCC compiler

I'm compiling on with GCC on Linux, but CMake is kind enough to produce a Clang compatible compilation database. This means that I can run fancy, modern Clang based tools on my codebase and those tools have perfect knowledge of how each file is to be built (flags, defines, include paths, etc.) So far so good.
But today the Clang based static analysis in my IDE started showing a Clang specific warning. I don't think it particularly matters for my question which warning it is, but it was warning: disabled expansion of recursive macro, generated by -Wdisabled-macro-expansion. This particular macro is provided by a third party, so fixing the warning isn't an option, but I would like to suppress it as it occurs several times in the file in question.
What I'm struggling with is how to suppress the warning in Clang based analysis tools without causing new warnings in the GCC build.
Adding #pragma clang diagnostic ignored "-Wdisabled-macro-expansion" suppresses the warning for Clang tools, but causes GCC to issue warning: ignoring #pragma clang diagnostic [-Wunknown-pragmas].
Similarly, adding #pragma GCC diagnostic ignored "-Wdisabled-macro-expansion" suppresses the Clang warning (because Clang tries to be compatible with GCC diagnostics), but causes GCC to issue warning: unknown option after ‘#pragma GCC diagnostic’ kind [-Wpragmas].
Wrapping either of the above with #ifdef __clang__ makes GCC happy, but doesn't suppress the Clang warning because the tooling is smart enough to know that the code isn't compiled with __clang__, but with __GNUC__ instead.
Is there a way to make a diagnostic #pragma visible to Clang tooling, but not to GCC?
the tooling is smart enough to know that the code isn't compiled with __clang__, but with __GNUC__ instead
If it's reporting a clang-only warning, but does not think that __clang__ is defined, that sounds like a problem with the tooling. If it's trying to be that clever about misrepresenting itself, you may be up a creek... but also you should be complaining to the tool author for creating this situation in the first place.
That said, you could try:
#if defined(__has_warning)
# if __has_warning("-Wdisabled-macro-expansion")
# pragma GCC diagnostic ignored "-Wdisabled-macro-expansion"
# endif
#endif
I'm not sure if this will work... it depends on how hard the tooling is pretending to not be clang (__has_warning is a clang-only extension).

Does C++17 provide a cross-platform scheme to record compiler version and options like Fortran?

Question
Modern Fortran offers a few cross-platform mechanisms to record the compiler version and settings used to build an application. What methods does C++17 have to capture this information? The book by Horton and Van Weert, Beginning C++17, does not appear to address this question.
The Fortran tools are surveyed below.
1. Access to compiler versions and options
The iso_fortran_env in Fortran provides a standard way to access the compiler version and settings used to compile a code. A sample snippet follows.
Code sample
program check_compiler
use, intrinsic :: iso_fortran_env, only : compiler_options, compiler_version
implicit none
write ( *, 100 ) "compiler version = ", compiler_version ()
write ( *, 100 ) "compiler options = ", trim ( compiler_options () )
100 format ( A, A, / )
stop "normal termination . . ."
end program check_compiler
Sample output
$ gfortran -o check_compiler check_compiler.f08
$ ./check_compiler
compiler version = GCC version 8.0.0 20170604 (experimental)
compiler options = -fPIC -mmacosx-version-min=10.12.7 -mtune=core2
STOP normal termination . . .
2. Probing and interacting with host OS
Fortran commands like execute_command_line, get_command, and get_environment_variable offer another route to record information at compile time.
What methods does C++17 have to capture this information?
None. The C++ standard does not even recognize the concept of "compiler" or "options"; there is merely the "implementation".
Furthermore, it would not really make sense, as different C++ files linked into the same program can be compiled with different options. And I'm not just talking about DLL/SOs; you can in theory statically link files that were compiled with different options or even different compiler versions.
Different compilers have ways to specify what version they are through macros. But each one has its own way to report this.
Searching the C++20 standard draft, which is available in GitHub, I find no results for closely-localted "compiler" and "version", nor have I found something like this looking at the text of the standard.
C++20 is at this time still very close to C++17, and certainly such a mechanism has not been removed, so I think it's pretty safe to say that there's no such thing in C++20.
Each compiler injects their own preproxessor tokens indicating itmwas compiled by them, and what version. These tokens are cross platform on compilers that compile on and to kore than one platdorm, such as icc, gcx and clang.
There are now standard defined ways to detect the existence of some srd header files. Boost has extensive headers that decode compiler capabilities based of a myriad of techniques.
__cplusplus in theory is defined to the standard version, but compilers lie.
The language standard specifies macros __cplusplus that encode the version of the standard that the compiler claims to support. It expands to 201703L on a C++17 compiler, 201710L on a C++14 compiler, and so on. It might also define _STDC and _STDC_VERSION. Beyond that, everything is a vendor-specific extension that you should look up in your compiler's manual.
Some but not all compilers, including GCC and Clang, predefine a macro named __VERSION__ that expands to a string describing the compiler version. You can check for this with #ifdef. Beyond that, many compilers contain macros that expand to version numbers, which you can stringify and concatenate. However, be aware that some compilers treat these as compatibility tests, and will claim to be a different compiler if you ask. In addition to its own version numbers, Clang defines __GNUC__, __GNUC_VERSION__ and __GNUC_PATCHLEVEL__ to indicate its compatibility with GCC, and the Windows version will also define _MSC_VER, _MSC_FULL_VER and so on in its Microsoft-compatiblity mode.
You could therefore create a complicated set of nested #elif blocks to recognize various compilers' version macros, but it could never be complete or forward-compatible.

Is #error directive crossplatform and crosscompiler

I know that #error directive works at least with GCC and MSVC
#if !defined(__cplusplus)
#error C++ compiler required.
#endif
But is it crossplatform and crosscompiler in general? Is it a part of some standard maybe?
PS. Because even looking at examples given in GCC and MSVC manuals one sees differences. While it works both with quotes or not, it makes a sad feeling, that it might be somehow compiler dependent.
GCC example
#error "Won't work on ..." // quotes here
MSVC example
#error C++ compiler required. // no qutes
Yes it is. It's a standard preprocessor directive in C and C++.
References:
http://en.cppreference.com/w/cpp/preprocessor/error
http://en.cppreference.com/w/c/preprocessor/error

Gnu C++ macro __cplusplus standard conform?

The Gnu C++ compiler seems to define __cplusplus to be 1
#include <iostream>
int main() {
std::cout << __cplusplus << std::endl;
}
This prints 1 with gcc in standard c++ mode, as well as in C++0x mode, with gcc 4.3.4, and gcc 4.7.0.
The C++11 FDIS says in "16.8 Predefined macro names [cpp.predefined]" that
The name __cplusplus is defined to the value 201103L when compiling a C++ translation unit. (Footnote: It is intended that future versions of this standard will replace the value of this macro with a greater value. Non-conforming com-
pilers should use a value with at most five decimal digits.)
The old std C++03 had a similar rule.
Is the GCC deliberatly setting this to 1, because it is "non-conforming"?
By reading through that list I thought that I could use __cplusplus to check in a portable way if I have a C++11 enabled compiler. But with g++ this does not seem to work. I know about the ...EXPERIMENTAL... macro, but got curious why g++ is defining __cplusplus this way.
My original problem was switch between different null-pointer-variants. Something like this:
#if __cplusplus > 201100L
# define MYNULL nullptr
#else
# define MYNULL NULL
#endif
Is there a simple and reasonably portable way to implement such a switch?
This was fixed about a month ago (for gcc 4.7.0). The bug report makes for an interesting read: http://gcc.gnu.org/bugzilla/show_bug.cgi?id=1773
If I recall correctly this has to do with Solaris 8 causing issues when __cplusplus is set as it should. The gcc team decided at the time to support the Solaris 8 platform rather than be compliant in this particular clause. But I noticed that the latest version of gcc ends the Solaris 8 support, and I guess this is a first step in the right direction.
It is a very old g++ bug.
That is, the compiler is not conforming.
Apparently it can't be fixed because fixing it would break something on a crazy platform.
EDIT: oh, I see from #birryree's comment that has just been fixed, in version 4.7.0. So, it was not impossible to fix after all. Heh.
Cheers & hth.