TARGET_OS_IPHONE and ApplicationTests

Viewed 16977

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?

6 Answers

Both work well

  • #import "TargetConditionals.h"
  • #import <Foundation/Foundation.h>
<Foundation/Foundation.h> 
    |
    └-#import <Foundation/NSObjCRuntime.h>
        |
        └- #include <TargetConditionals.h> 
                |
                └- defined TARGET_OS_IPHONE

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).

Note: in Swift one must use:

#if os(iOS)
Related