I have found that writing
#ifdef ...
#elseif defined(...)
#else
#endif
always results in using either the #ifdef or the #else condition, never the #elseif. But substituting #elif causes it to work as expected based on what's defined. What convoluted purpose, if any, is served by the existence of #elseif? And if none, why doesn't the preprocessor complain?
Maybe this is why for years (decades, really), I've been using ugly #else/#endif blocks, since at least they're reliable!
#elseif is not defined. The preprocessor doesn't complain because your #ifdef is false, and the directives within that #ifdef block are not parsed. To illustrate it, this code is valid:
#if 0
#random nonsense
#else
// This must be valid
#endif
I just uncovered in IAR Embedded Workbench for MSP430, v7.11.1, which reports icc430 --version as "IAR C/C++ Compiler V7.11.1.983/W32 for MSP430",
that #elseif compiles without error, but does NOT evaluate the same as #elif.
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
__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)
....
I use this define:
#define GCC_COMPILER (defined(__GNUC__) && !defined(__clang__))
And test with it:
#if GCC_COMPILER
...
#endif
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)
I have been working with qt creator and recently tried to change the compiler from gcc to clang. Since I don't get any info (or can't see it) on whether this worked (I'm struggling to understand the interface) I wanted to ask if there's a way for my c++ code to print out the compiler under which it's being compiled.
Compilers set certain #defines to help out with things like this.
In your case,
#ifdef __GNUC__ //GCC
//do whatever GCC-specific stuff you need to do here
#endif
#ifdef __clang__ //clang
//do whatever clang-specific stuff you need to do here
#endif
This page on SourceForge shows a list of such compiler-specific #define values.
EDIT: as pointed out in the comments, clang sets __GNUC__, and possibly __GNUC_MINOR__ and __GNUC_PATCHLEVEL__. You might be better off using a double test to make sure clang isn't misleading you:
#if defined(__GNUC__) && !defined(__clang__)
//do whatever GCC-specific stuff you need to do here
#endif
Use the informational macros of boost.
#include <boost/config.hpp>
#ifdef BOOST_CLANG
printf("Successfully changed to clang\n");
#endif
I want to show error when someone try to compile my code under other system than WIN32 and LINUX. But this code:
#ifdef WIN32
// Some code here for windows
#elif LINUX
// Some code for linux
#else
#error OS unsupported!
#endif
But this gives me an error:
#error OS unsupported
and compiler doesn't say anything else, just error.
What is wrong?
Two issues here:
your #elif does not test for the mere existence of the symbol, but for its truth (ie. defined and non-zero). You should use #elif defined(...) and, to be consistent, #if defined(...) at the start.
the symbols you are matching for are wrong. You should use, respectively, _WIN32 and __linux__. See this reference for more platforms.
LINUX is not a standard predefined macro. You probably want to check for __linux not LINUX
I know some code checks for _WIN32 but I don't know what's correct on Windows.
I often see __WIN32, WIN32 or __WIN32__. I assume that this depends on the used preprocessor (either one from visual studio, or gcc etc).
Do I now have to check first for os and then for the used compiler? We are using here G++ 4.4.x, Visual Studio 2008 and Xcode (which I assume is a gcc again) and ATM we are using just __WIN32__, __APPLE__ and __LINUX__.
This article answers your question:
C/C++ tip: How to detect the operating system type using compiler predefined macros (plus archive.org link in case it vanishes).
The article is quite long, and includes tables that are hard to reproduce, but here's the essence:
You can detect Unix-style OS with:
#if !defined(_WIN32) && (defined(__unix__) || defined(__unix) || (defined(__APPLE__) && defined(__MACH__)))
/* UNIX-style OS. ------------------------------------------- */
#endif
Once you know it's Unix, you can find if it's POSIX and the POSIX version with:
#include <unistd.h>
#if defined(_POSIX_VERSION)
/* POSIX compliant */
#endif
You can check for BSD-derived systems with:
#if defined(__unix__) || (defined(__APPLE__) && defined(__MACH__))
#include <sys/param.h>
#if defined(BSD)
/* BSD (DragonFly BSD, FreeBSD, OpenBSD, NetBSD). ----------- */
#endif
#endif
and Linux with:
#if defined(__linux__)
/* Linux */
#endif
and Apple's operating systems with
#if defined(__APPLE__) && defined(__MACH__)
/* Apple OSX and iOS (Darwin) */
#include <TargetConditionals.h>
#if TARGET_IPHONE_SIMULATOR == 1
/* iOS in Xcode simulator */
#elif TARGET_OS_IPHONE == 1
/* iOS on iPhone, iPad, etc. */
#elif TARGET_OS_MAC == 1
/* OS X */
#endif
#endif
Windows with Cygwin
#if defined(__CYGWIN__) && !defined(_WIN32)
/* Cygwin POSIX under Microsoft Windows. */
#endif
And non-POSIX Windows with:
#if defined(_WIN64)
/* Microsoft Windows (64-bit) */
#elif defined(_WIN32)
/* Microsoft Windows (32-bit) */
#endif
The full article lists the following symbols, and shows which systems define them and when: _AIX, __APPLE__, __CYGWIN32__, __CYGWIN__, __DragonFly__, __FreeBSD__, __gnu_linux, hpux, __hpux, linux, __linux, __linux__, __MACH__, __MINGW32__, __MINGW64__, __NetBSD__, __OpenBSD__, _POSIX_IPV6, _POSIX_MAPPED_FILES, _POSIX_SEMAPHORES, _POSIX_THREADS, _POSIX_VERSION, sun, __sun, __SunOS, __sun__, __SVR4, __svr4__, TARGET_IPHONE_SIMULATOR, TARGET_OS_EMBEDDED, TARGET_OS_IPHONE, TARGET_OS_MAC, UNIX, unix, __unix, __unix__, WIN32, _WIN32, __WIN32, __WIN32__, WIN64, _WIN64, __WIN64, __WIN64__, WINNT, __WINNT, __WINNT__.
A related article (archive.org link) covers detecting compilers and compiler versions. It lists the following symbols: __clang__, __GNUC__, __GNUG__, __HP_aCC, __HP_cc, __IBMCPP__, __IBMC__, __ICC, __INTEL_COMPILER, _MSC_VER, __PGI, __SUNPRO_C, __SUNPRO_CC for detecting compilers, and __clang_major__, __clang_minor__, __clang_patchlevel__, __clang_version__, __GNUC_MINOR__, __GNUC_PATCHLEVEL__, __GNUC__, __GNUG__, __HP_aCC, __HP_cc, __IBMCPP__, __IBMC__, __ICC, __INTEL_COMPILER, __INTEL_COMPILER_BUILD_DATE, _MSC_BUILD, _MSC_FULL_VER, _MSC_VER, __PGIC_MINOR__, __PGIC_PATCHLEVEL__, __PGIC__, __SUNPRO_C, __SUNPRO_CC, __VERSION__, __xlC_ver__, __xlC__, __xlc__ for detecting compiler versions.
It depends what you are trying to do. You can check the compiler if your program wants to make use of some specific functions (from the gcc toolchain for example). You can check for operating system ( _WINDOWS, __unix__ ) if you want to use some OS specific functions (regardless of compiler - for example CreateProcess on Windows and fork on unix).
Macros for Visual C
Macros for gcc
You must check the documentation of each compiler in order to be able to detect the differences when compiling. I remember that the gnu toolchain(gcc) has some functions in the C library (libc) that are not on other toolchains (like Visual C for example). This way if you want to use those functions out of commodity then you must detect that you are using GCC, so the code you must use would be the following:
#ifdef __GNUC__
// do my gcc specific stuff
#else
// ... handle this for other compilers
#endif
Don't see why you have to. You might have to remember to specify the definition manually on your compiler's commandline, but that's all. For the record, Visual Studio's definition is _WIN32 (with one underscore) rather than __WIN32. If it's not defined then it's not defined, and it won't matter.
I've rebuild my answer... Damn, editing berserk :P:
You don't need to use partical one. And probably for MacOSX, Linux and other Unix-likes you don't need to use any at all.
Most popular one is (as far as Google tells the truth) is _WIN32.
You never define it "by hand" in your source code. It is defined in one of these ways:
as a commandline preprocessor/compiler flag (like g++ -D _WIN32)
or it is predefined by compiler itself (most of Windows compilers predefine _WIN32, and sometimes other like WIN32 or _WIN32_ too. -- Then you don't need to worry about defining it at all, compiler does the whole work.
And my old answer:
You don't 'have to' anything. It's just for multi-platform compatibility. Often version of code for all Unix-likes (including Linux, MacOSX, BSD, Solaris...) and other POSIX platform will be completely the same and there must be some changes for Windows. So people write their code generally for Unix-likes and put some Windows-only (eg. DirectX instructions, Windows-like file paths...) parts between #ifdef _WIN32 and #endif.
If you have some parts eg. X-Window-system only, or MacOS-only, you do similar with something like #ifdef X_WINDOW or #ifdef MACOS. Then, you need set a proper preprocessor definition while compiling (with gcc using -D flag, like eg. gcc -D _WIN32).
If you don't write any platform-dependent code, then you don't need to care for such a #ifdef, #else, #endif blocks. And most of Windows compilers/preprocessors AFAIK have predefined some symbols like _WIN32 (most popular, as far as google tells the truth), WIN32, _WIN32_, etc. So compiling it on Windows most probably you don't need to make anything else than just compiling.
Sigh - don't rely on compiler anything - specify which platform you are building for in your Makefile. Simply put, anything beginning with _ is implementation dependent and not portable.
I tried your method once upon a time, on a very large project, and in between bouncing around between Sun-C++ and GCC we just decided to go with Makefile control rather than trying to deduce what the compilers were going to do.