Preprocessor macro for OS X targets?
As per the documentation in TargetConditionals.h
(it seems, as of 2020; any platform):
+---------------------------------------------------------------------+
| TARGET_OS_MAC |
| +---+ +-----------------------------------------------+ +---------+ |
| | | | TARGET_OS_IPHONE | | | |
| | | | +---------------+ +----+ +-------+ +--------+ | | | |
| | | | | IOS | | | | | | | | | | |
| |OSX| | |+-------------+| | TV | | WATCH | | BRIDGE | | |DRIVERKIT| |
| | | | || MACCATALYST || | | | | | | | | | |
| | | | |+-------------+| | | | | | | | | | |
| | | | +---------------+ +----+ +-------+ +--------+ | | | |
| +---+ +-----------------------------------------------+ +---------+ |
+---------------------------------------------------------------------+
This tells us:
TARGET_OS_MAC
will be1
for (probably) any Cocoa application running on an Apple platform.TARGET_OS_OSX
will only be1
for macOS targetsTARGET_OS_IPHONE
will be1
for any non-Mac Apple productsTARGET_OS_IOS
is just for iOSTARGET_OS_MACCATALYST
is just for Project Catalyst. It seemsTARGET_OS_UIKITFORMAC
will also work.
TARGET_OS_TV
is just for tvOSTARGET_OS_WATCH
is just for watchOSTARGET_OS_BRIDGE
is just for bridgeOS (which currently doesn't even support 3rd-party apps so you'll likely always see that be0
)
TARGET_OS_DRIVERKIT
will be1
when building for DriverKit
⚠️ But wait! ⚠️
I got that from the iOS 14 (macOS 11, watchOS 7) SDK. If I look back into the iOS 13 (macOS 10.15, watchOS 6) SDK, I see this:
+----------------------------------------------------------------+
| TARGET_OS_MAC |
| +---+ +-----------------------------------------------------+ |
| | | | TARGET_OS_IPHONE | |
| |OSX| | +-----+ +----+ +-------+ +--------+ +-------------+ | |
| | | | | IOS | | TV | | WATCH | | BRIDGE | | MACCATALYST | | |
| | | | +-----+ +----+ +-------+ +--------+ +-------------+ | |
| +---+ +-----------------------------------------------------+ |
+----------------------------------------------------------------+
Notably, TARGET_OS_DRIVERKIT
is new in 14, and TARGET_OS_MACCATALYST
is inside IOS
now. This tells me that compiling against the iOS 14 SDK can break some C code written for iOS 13, if it assumes that TARGET_OS_MACCATALYST
and IOS
are completely separate.
Additionally, these are defined:
TARGET_OS_SIMULATOR
is just for iOS, tvOS, and watchOS simulators. You can further refine this using the above#define
sTARGET_OS_WIN32
is in case you wanna use Apple's SDKs to make Windows apps. I don't personally know of any other than Apple's own (like iTunes, Safari, and QuickTime). This might become useful now that Swift has Windows support, if you want to take existing Objective-C code with you.TARGET_OS_UNIX
is for non-Apple UNIX systems
And these are deprecated, and should not be used anymore. That said, you might find them in code you have to maintain, so here's what they meant:
TARGET_IPHONE_SIMULATOR
used to mean the iPhoneOS simulatorTARGET_OS_EMBEDDED
used to mean iOS, tvOS, and watchOS non-simulated devicesTARGET_OS_NANO
probably used to mean iPod Nano (I can't find any historical usage online)
Something else to note is that the TargetConditionals.h
used in swift-corelibs-foundation is significantly different, and includes #define
s for Android, Cygwin, and other not-explicitly-supported-but-they-technically-work platforms.
I'm not entirely sure what to make of this. I would guess it's for compiling the Swift Foundation framework, and not for consuming it, since Swift doesn't consume #define
s.
As of Xcode 8 GM, this is the relevant section of TargetConditionals.h in iOS 10.0:
#define TARGET_OS_MAC 1
#define TARGET_OS_WIN32 0
#define TARGET_OS_UNIX 0
#define TARGET_OS_OSX 0
#define TARGET_OS_IPHONE 1
#define TARGET_OS_IOS 1
#define TARGET_OS_WATCH 0
#define TARGET_OS_BRIDGE 0
#define TARGET_OS_TV 0
#define TARGET_OS_SIMULATOR 0
#define TARGET_OS_EMBEDDED 1
#define TARGET_IPHONE_SIMULATOR TARGET_OS_SIMULATOR /* deprecated */
#define TARGET_OS_NANO TARGET_OS_WATCH /* deprecated */
(In the 'breadcrumb' above the text editor in Xcode, iOS 10.0 > usr/include > TargetConditionals.h
)
...And this is the same file, for macOS:
#define TARGET_OS_MAC 1
#define TARGET_OS_WIN32 0
#define TARGET_OS_UNIX 0
#define TARGET_OS_OSX 1
#define TARGET_OS_IPHONE 0
#define TARGET_OS_IOS 0
#define TARGET_OS_WATCH 0
#define TARGET_OS_BRIDGE 0
#define TARGET_OS_TV 0
#define TARGET_OS_SIMULATOR 0
#define TARGET_OS_EMBEDDED 0
#define TARGET_IPHONE_SIMULATOR TARGET_OS_SIMULATOR /* deprecated */
#define TARGET_OS_NANO TARGET_OS_WATCH /* deprecated */
(In the 'breadcrumb' above the text editor in Xcode, macOS 10.12 > usr/include > TargetConditionals.h
)
TARGET_OS_MAC
is defined as 1 on both platforms, but TARGET_OS_OSX
is 1 only on macOS.
In the file's comments, they are described as follows:
- TARGET_OS_MAC: Generated code will run under Mac OS X variant.
- TARGET_OS_OSX: Generated code will run under OS X devices.
I guess at some point back then (perhaps around when the iPhone was announced?) somebody decided that iOS (né "iPhone OS") fits the definitions of "Mac OS X variant".
That is because TARGET_OS_MAC
is defined when building for iOS as well.
See http://sealiesoftware.com/blog/archive/2010/8/16/TargetConditionalsh.html on that.
I would try and build my own target specific define via build-settings on the target.
If you're using Swift, there's a great language feature for this. If you're using Objective-C, it's often useful to do something like this:
#include <TargetConditionals.h>
#if TARGET_OS_IPHONE
@import UIKit;
#else
@import AppKit;
#endif
Understanding the TARGET_OS_*
defines will make this make a lot more sense. Most notably, TARGET_OS_MAC
is any Apple platform which is pretty unexpected. !TARGET_OS_IPHONE
is macOS and TARGET_OS_IPHONE
is anything besides that. There are more specific defines for iOS, tvOS, and watchOS.
From TargetConditions.h
:
TARGET_OS_*
These conditionals specify in which Operating System the generated code will
run. Indention is used to show which conditionals are evolutionary subclasses.
The MAC/WIN32/UNIX conditionals are mutually exclusive.
The IOS/TV/WATCH conditionals are mutually exclusive.
TARGET_OS_WIN32 - Generated code will run under 32-bit Windows
TARGET_OS_UNIX - Generated code will run under some Unix (not OSX)
TARGET_OS_MAC - Generated code will run under Mac OS X variant
TARGET_OS_IPHONE - Generated code for firmware, devices, or simulator
TARGET_OS_IOS - Generated code will run under iOS
TARGET_OS_TV - Generated code will run under Apple TV OS
TARGET_OS_WATCH - Generated code will run under Apple Watch OS
TARGET_OS_SIMULATOR - Generated code will run under a simulator
TARGET_OS_EMBEDDED - Generated code for firmware
TARGET_IPHONE_SIMULATOR - DEPRECATED: Same as TARGET_OS_SIMULATOR
TARGET_OS_NANO - DEPRECATED: Same as TARGET_OS_WATCH