342

If there's some cross-platform C/C++ code that should be compiled on Mac OS X, iOS, Linux, Windows, how can I detect them reliably during preprocessor process?

Brian Tompsett - 汤莱恩
  • 5,753
  • 72
  • 57
  • 129
eonil
  • 83,476
  • 81
  • 317
  • 516

3 Answers3

599

There are predefined macros that are used by most compilers, you can find the list here. GCC compiler predefined macros can be found here. Here is an example for gcc:

#if defined(WIN32) || defined(_WIN32) || defined(__WIN32__) || defined(__NT__)
   //define something for Windows (32-bit and 64-bit, this part is common)
   #ifdef _WIN64
      //define something for Windows (64-bit only)
   #else
      //define something for Windows (32-bit only)
   #endif
#elif __APPLE__
    #include <TargetConditionals.h>
    #if TARGET_IPHONE_SIMULATOR
         // iOS, tvOS, or watchOS Simulator
    #elif TARGET_OS_MACCATALYST
         // Mac's Catalyst (ports iOS API into Mac, like UIKit).
    #elif TARGET_OS_IPHONE
        // iOS, tvOS, or watchOS device
    #elif TARGET_OS_MAC
        // Other kinds of Apple platforms
    #else
    #   error "Unknown Apple platform"
    #endif
#elif __ANDROID__
    // Below __linux__ check should be enough to handle Android,
    // but something may be unique to Android.
#elif __linux__
    // linux
#elif __unix__ // all unices not caught above
    // Unix
#elif defined(_POSIX_VERSION)
    // POSIX
#else
#   error "Unknown compiler"
#endif

The defined macros depend on the compiler that you are going to use.

The _WIN64 #ifdef can be nested into the _WIN32 #ifdef because _WIN32 is even defined when targeting the Windows x64 version. This prevents code duplication if some header includes are common to both (also WIN32 without underscore allows IDE to highlight the right partition of code).

Top-Master
  • 7,611
  • 5
  • 39
  • 71
Evgeny Gavrin
  • 7,627
  • 1
  • 22
  • 27
  • 1
    The OP specifically asked about `Mac OS X` versus `iOS` – Paul R May 07 '11 at 09:12
  • 6
    @Paul, "code should be compiled on Mac OS X, iOS, Linux, Windows" – Evgeny Gavrin May 07 '11 at 09:21
  • Note: People are saying that "__unix" is a catch-all, but it does not appear to be defined for me on Mac OS 10.7.5 with gcc 4.2.1 (gcc provided by Apple with Xcode) – AlcubierreDrive Dec 22 '13 at 02:51
  • 5
    @jdknight yes `__linux__` is the supported macro on all linux distributions, `__linux` is not supported on all linux distributions, `__unix__` should also be used in place of `__unix` for the same reason, since all platforms that follow the unix guidelines support `__unix__`, and not `__unix`, here is a more in depth description http://nadeausoftware.com/articles/2012/01/c_c_tip_how_use_compiler_predefined_macros_detect_operating_system – daniel Oct 06 '15 at 21:02
  • For QNX, `__QNX__` can be added. More Ref: https://github.com/emrainey/Concerto/wiki/Predefined-Macros-for-Code + https://users.pja.edu.pl/~jms/qnx/help/watcom/compiler-tools/cpwcc.html – parasrish Oct 11 '17 at 13:02
  • Aren't Linux and Macintosh actually POSIX? – Kadam Parikh Apr 17 '20 at 11:03
36

As Jake points out, TARGET_IPHONE_SIMULATOR is a subset of TARGET_OS_IPHONE.

Also, TARGET_OS_IPHONE is a subset of TARGET_OS_MAC.

So a better approach might be:

#ifdef _WIN64
   //define something for Windows (64-bit)
#elif _WIN32
   //define something for Windows (32-bit)
#elif __APPLE__
    #include "TargetConditionals.h"
    #if TARGET_OS_IPHONE && TARGET_OS_SIMULATOR
        // define something for simulator
        // (although, checking for TARGET_OS_IPHONE should not be required).
    #elif TARGET_OS_IPHONE && TARGET_OS_MACCATALYST
        // define something for Mac's Catalyst
    #elif TARGET_OS_IPHONE
        // define something for iphone  
    #else
        #define TARGET_OS_OSX 1
        // define something for OSX
    #endif
#elif __linux
    // linux
#elif __unix // all unices not caught above
    // Unix
#elif __posix
    // POSIX
#endif

Note that above checks TARGET_OS_SIMULATOR macro because TARGET_IPHONE_SIMULATOR macro got deprecated since iOS 14.

Top-Master
  • 7,611
  • 5
  • 39
  • 71
PatchyFog
  • 1,551
  • 16
  • 17
  • I would also add `__ANDROID__` above `__linux__` as it has its own specifics compared to Linux. – 4LegsDrivenCat Nov 22 '16 at 11:23
  • 1
    Wouldn't this require that any code specific to Windows, that is the same for both 32- and 64-bit, be duplicated in the `_WIN64` and `_WIN32` blocks? It's going to skip the `_WIN32` one if it detects `_WIN64`, which may not be desirable. Something like [this](http://pastebin.com/4qTShCq1) might work better. – Justin Time - Reinstate Monica Jan 05 '17 at 07:56
  • My Linux only defines `__linux__`, `__gnu_linux__` and `linux`, but not `__linux` – Mecki Apr 24 '17 at 13:39
  • What is `#define TARGET_OS_OSX 1`? Apple and OS X defines its own macros. – jww Feb 17 '18 at 01:32
12

5 Jan 2021: link update thanks to @Sadap's comment.

Kind of a corollary answer: the people on this site have taken the time to make tables of macros defined for every OS/compiler pair.

For example, you can see that _WIN32 is NOT defined on Windows with Cygwin (POSIX), while it IS defined for compilation on Windows, Cygwin (non-POSIX), and MinGW with every available compiler (Clang, GNU, Intel, etc.).

Anyway, I found the tables quite informative and thought I'd share here.

houtanb
  • 3,852
  • 20
  • 21