I have a project that has both an iOS and an OS X target. Is there a preprocessor macro that is true when I'm compiling for OS X? I tried this:
#if TARGET_OS_MAC
@interface BFNode : NSObject <NSPasteboardReading, NSPasteboardWriting> {
#else
@interface BFNode : NSObject {
#endif
But TARGET_OS_MAC
doesn't seem to work. When I try to run the app on iOS I get a compiler error, because it tries to compile the first line and there is no NSPasteboardReading
protocol defined on iOS.
I know there is TARGET_OS_IPHONE
too. If I use that and swap the @interface
declarations it works.
But there are a lot of places where I have code, that has no iOS version, so I need a macro for OS X too.
SOLUTION:
I ended up defining a new macro in the .pch file:
#define TARGET_OSX TARGET_OS_IPHONE == 0
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
The documentation in TargetConditionals.h
has this diagram (it seems, as of 2022; any platform):
+---------------------------------------------------------------------+
| TARGET_OS_MAC |
| +---+ +-----------------------------------------------+ +---------+ |
| | | | TARGET_OS_IPHONE | | | |
| | | | +---------------+ +----+ +-------+ +--------+ | | | |
| | | | | IOS | | | | | | | | | | |
| |OSX| | |+-------------+| | TV | | WATCH | | BRIDGE | | |DRIVERKIT| |
| | | | || MACCATALYST || | | | | | | | | | |
| | | | |+-------------+| | | | | | | | | | |
| | | | +---------------+ +----+ +-------+ +--------+ | | | |
| +---+ +-----------------------------------------------+ +---------+ |
+---------------------------------------------------------------------+
This tells us:
TARGET_OS_MAC
will be 1
for (probably) any Cocoa application running on an Apple platform.
TARGET_OS_OSX
will only be 1
for macOS targetsTARGET_OS_IPHONE
will be 1
for any non-Mac Apple products
TARGET_OS_IOS
is just for iOS
TARGET_OS_MACCATALYST
is just for Project Catalyst. It seems TARGET_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 be 0
)TARGET_OS_DRIVERKIT
will be 1
when building for DriverKit
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 us that compiling against the iOS 14 / macOS 11 SDK can break some C code written for iOS 13 / macOS 10.15, if it assumes that TARGET_OS_MACCATALYST
and TARGET_OS_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 systemsAnd 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 simulator. Use TARGET_OS_SIMULATOR
instead (along with TARGET_OS_IOS
to target only iOS simulators)TARGET_OS_EMBEDDED
used to mean iOS, tvOS, and watchOS non-simulated devices. Use the standard OS targets instead.TARGET_OS_NANO
probably used to mean iPod Nano (I can't find any historical usage online). Apple advises to use TARGET_OS_WATCH
instead.Something else to note is that the TargetConditionals.h
which is 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.
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 love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With