TARGET_OS_IPHONE and ApplicationTests
Asked Answered
M

6

26

Why doesn't this code work when compiling an ApplicationTests unit test bundle?

#if TARGET_OS_IPHONE
   #import <Foundation/Foundation.h>
   #import <UIKit/UIKit.h>
#else
   #import <Cocoa/Cocoa.h>
#endif

One of my dependencies has this check and compiles just fine in my main application bundles, but it tries to load <Cocoa/Cocoa.h> when compiling my ApplicationTests bundle. It's probably just my lack of understanding of Xcode, but I get nervous when my test bundles don't build. Any suggestions?

Mcfarlane answered 18/9, 2010 at 16:42 Comment(3)
just to add, you don't need to import foundation if you importing uikitSuzerainty
maybe not now, but 5 years ago? maybe.Mcfarlane
Probably even 5 years ago as all elements in the UIKit come from NSObject => Foundation frameworkSuzerainty
N
15

I had a similar problem: TARGET_OS_IPHONE isn't defined when building a static library. My solution was to add "-DTARGET_OS_IPHONE" to the "Other C Flags" section of the target build options.

Nauseate answered 20/9, 2010 at 2:28 Comment(4)
Yup, this ended up working. I'm not sure how I feel about having to force this being true, but I guess it works. Thanks.Mcfarlane
@MattBaker - Same issue here and I agree!Homologize
That sounds like the wrong solution. You should do as antho suggested below and include TargetConditionals.h. Documented here: developer.apple.com/library/ios/#DOCUMENTATION/Xcode/Conceptual/…Colitis
This was the solution that worked for me in a Swift Test Target.Halutz
U
43

You need to add

#include <TargetConditionals.h>

source: https://opensource.apple.com/source/CarbonHeaders/CarbonHeaders-8A428/TargetConditionals.h.auto.html

Ultraism answered 21/6, 2012 at 20:54 Comment(1)
When running on watchOS Scheme, I was getting all TARGET_OS_* being evaluated to 0. Using the above import solved the problemCameroun
B
20

The simplest solution is to move the #import <Foundation/Foundation.h> statement out if the #if condition and replace Cocoa with AppKit like this:

#import <Foundation/Foundation.h>
#if TARGET_OS_IPHONE
   #import <UIKit/UIKit.h>
#else
   #import <AppKit/AppKit.h>
#endif

The Foundation umbrella header imports the NSObjCRuntime header which in turn imports the TargetConditionals header.

Behr answered 28/10, 2015 at 22:9 Comment(1)
Brilliant! This actually should be accepted answer!Arietta
N
15

I had a similar problem: TARGET_OS_IPHONE isn't defined when building a static library. My solution was to add "-DTARGET_OS_IPHONE" to the "Other C Flags" section of the target build options.

Nauseate answered 20/9, 2010 at 2:28 Comment(4)
Yup, this ended up working. I'm not sure how I feel about having to force this being true, but I guess it works. Thanks.Mcfarlane
@MattBaker - Same issue here and I agree!Homologize
That sounds like the wrong solution. You should do as antho suggested below and include TargetConditionals.h. Documented here: developer.apple.com/library/ios/#DOCUMENTATION/Xcode/Conceptual/…Colitis
This was the solution that worked for me in a Swift Test Target.Halutz
C
0

Both work well

  • #import "TargetConditionals.h"
  • #import <Foundation/Foundation.h>
<Foundation/Foundation.h> 
    |
    └-#import <Foundation/NSObjCRuntime.h>
        |
        └- #include <TargetConditionals.h> 
                |
                └- defined TARGET_OS_IPHONE
Crosseye answered 21/5, 2020 at 8:11 Comment(0)
N
0

The solution for me in Xcode 12.5 is to add TARGET_OS_IPHONE or TARGET_OS_IPHONE=1 to GCC_PREPROCESSOR_DEFINITIONS_NOT_USED_IN_PRECOMPS in build settings or in an .xcconfig file.

Details:

After updating to Xcode 12.5 beta, now carthage bootstrap will fail when trying to build iRate 1.12.2. I looked in the carthage build log, and the error responsible for the failure is:

error: 'TARGET_OS_IPHONE' is not defined, evaluates to 0 [-Werror,-Wundef-prefix=TARGET_OS_]

The problem for me is that iRate is no longer under development, and I'd rather not fork iRate it just to override some broken build setting.

However, there is a nifty workaround trick that I learned from the folks over at Carthage: you can override the build settings of any project using any .xcconfig file by setting an environment variable, XCODE_XCCONFIG_FILE=path/to/my.xcconfig before running xcodebuild. Any settings in that .xcconfig file will now override the settings of whatever project you're building with xcodebuild.

Furthermore you can do this dynamically by a script that you call instead of calling xcodebuild, e.g.:

#!/usr/bin/env bash

# Save this script as 'injectXcodeBuild.sh'
# Run it in place of xcodebuild (all arguments get forwarded through)
# The echo'd commands below will override any settings of the
# projects that get built by xcodebuild through this script.

set -euo pipefail

xcconfig=$(mktemp /tmp/static.xcconfig.XXXXXX)
trap 'rm -f "$xcconfig"' INT TERM HUP EXIT

echo 'GCC_PREPROCESSOR_DEFINITIONS_NOT_USED_IN_PRECOMPS=TARGET_OS_IPHONE=1' >> $xcconfig

export XCODE_XCCONFIG_FILE="$xcconfig"

xcodebuild "$@"

Alternatively instead of xcodebuild this script could call carthage if you're needing to override some Carthage dependency's build settings. It might also work for CocoaPods pod command (I'm not sure).

Nigel answered 13/2, 2021 at 23:16 Comment(0)
T
0

Note: in Swift one must use:

#if os(iOS)
Tavis answered 24/11, 2021 at 2:40 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.