编译iPhone时,Xcode设置了哪些#define?
Xcode在为iPhone编译时设置了哪些#define是一个常见的问题。然而,有些回答并不完全正确。问题的核心是平台和硬件与模拟器之间的关系,并不是直接相关的。因此,不能将架构作为检测平台或模拟器的捷径。这种粗心的思维方式多年来给很多程序员带来了很多困扰和头疼。
下面是一个ASCII图表,列出了各种条件定义的名称(由于历史原因,这些名称可能并不总是合乎逻辑):
+--------------------------------------+
| TARGET_OS_MAC |
| +---+ +---------------------------+ |
| | | | TARGET_OS_IPHONE | |
| |OSX| | +-----+ +----+ +-------+ | |
| | | | | IOS | | TV | | WATCH | | |
| | | | +-----+ +----+ +-------+ | |
| +---+ +---------------------------+ |
+--------------------------------------+
设备: TARGET_OS_EMBEDDED
模拟器: TARGET_OS_SIMULATOR
TARGET_OS_MAC对于所有Apple平台都为真。
TARGET_OS_OSX仅对于macOS为真。
TARGET_OS_IPHONE对于iOS、watchOS和tvOS(设备和模拟器)为真。
TARGET_OS_IOS仅对于iOS(设备和模拟器)为真。
TARGET_OS_WATCH仅对于watchOS(设备和模拟器)为真。
TARGET_OS_TV仅对于tvOS(设备和模拟器)为真。
TARGET_OS_EMBEDDED仅对于iOS/watchOS/tvOS硬件为真。
TARGET_OS_SIMULATOR仅对于模拟器为真。
此外,还可以通过平台在xcconfig文件中进行条件设置:
//仅适用于macOS
SOME_SETTING[sdk=macosx] = ...
//iOS(设备和模拟器)
SOME_SETTING[sdk=iphone*] = ...
//iOS(设备)
SOME_SETTING[sdk=iphoneos*] = ...
//iOS(模拟器)
SOME_SETTING[sdk=iphonesimulator*] = ...
//watchOS(设备和模拟器)
SOME_SETTING[sdk=watch*] = ...
//watchOS(设备)
SOME_SETTING[sdk=watchos*] = ...
//watchOS(模拟器)
SOME_SETTING[sdk=watchsimulator*] = ...
//tvOS(设备和模拟器)
SOME_SETTING[sdk=appletv*] = ...
//tvOS(设备)
SOME_SETTING[sdk=appletvos*] = ...
//tvOS(模拟器)
SOME_SETTING[sdk=appletvsimulator*] = ...
//iOS、tvOS或watchOS模拟器
SOME_SETTING[sdk=embeddedsimulator*] = ...
通过这些条件设置,我们可以根据不同的平台来定制化一些设置。
在使用Xcode编译iPhone应用程序时,会自动设置一些宏定义(#defines)。如果想要查看所有的宏定义,可以在构建配置的"Other C Flags"中添加以下内容:
-g3 -save-temps -dD
这样做会导致一些构建错误,但是编译器会将所有的宏定义转储到项目根目录下的.mi文件中。可以使用grep命令来查看它们,例如:
grep define main.mi
完成后,不要忘记从构建设置中删除这些选项。
另外,可以在命令行中执行gcc -dM -E - < /dev/null
,以更简单的方式获取这些宏定义。不论是gcc、g++、clang还是clang++都可以使用这个命令。
当使用Xcode编译iPhone应用程序时,会自动设置一些预定义的宏定义。这些宏定义可以用于在代码中根据条件进行编译。Xcode设置的宏定义主要有TARGET_OS_IPHONE和TARGET_IPHONE_SIMULATOR,它们在iOS框架的/usr/include/TargetConditionals.h文件中被定义。在早期版本的工具链中,需要添加#include "TargetConditionals.h"
来引入这些宏定义,但是在当前的Xcode 6/iOS 8工具链中已经不再需要了。
如果想要只在构建设备时编译某一块代码,可以使用#if !(TARGET_OS_SIMULATOR)
来判断。需要注意的是,应该使用#if而不是#ifdef,因为当不在模拟器上时,TARGET_OS_IPHONE宏定义通常被定义为0,而#ifdef仍然会返回true。
需要注意的是,TARGET_OS_IPHONE并不是用来检测设备的方式,它只表示当前运行在iOS系统上,可以是模拟器或者真机。要检测设备与模拟器的区别,应该使用TARGET_IPHONE_SIMULATOR宏定义。
另外,在Xcode 6.4中,仍然需要手动包含TargetConditionals.h
文件。
如果想要检测是否在设备上运行,可以使用TARGET_OS_EMBEDDED
宏定义。
,Xcode在编译iPhone应用程序时会自动设置一些宏定义,可以根据这些宏定义来条件编译代码,以实现在不同环境下的不同逻辑。