XCode 构建系统:弄乱预处理器定义和包含的 header 文件?
XCode Build System: Messing up preprocessors definitions and included header files?
这里是第一个问题。
我在使用 XCode 构建系统时遇到了一些问题,特别是在预处理器定义方面。
我正在尝试为 objective-c 运行时定义一个宏,以避免强制将调度函数强制转换为适当的函数指针类型。通常的做法是使用 #define OBJC_OLD_DISPATCH_PROTOTYPES
,然后在下一行包含 header。一旦 header 被包含,宏就已经被定义并且 header 被相应地配置。
但这就是它开始变得奇怪的地方!
宏根本无法识别,header 被包含,就好像 #define
语句不存在一样,所以它无法 #define OBJC_OLD_DISPATCH_PROTOTYPES
并且它被(重新?)定义作为 0.
main.c
#include <stdio.h>
#define OBJC_OLD_DISPATCH_PROTOTYPES 1
#include <objc/objc-runtime.h>
int main(int argc, const char * argv[]) {
// From there:
// - Build System: OBJC_OLD_DISPATCH_PROTOTYPES is always 0, except if defined in build settings
// - Clang (only): OBJC_OLD_DISPATCH_PROTOTYPES is 1
printf("%d\n", OBJC_OLD_DISPATCH_PROTOTYPES);
}
当在“Apple Clang - 预处理”部分下的项目构建设置中定义预处理器宏时,构建系统将按预期运行。它使用 clang
的 -D
参数定义全局宏,使其可用于项目使用的任何文件。
但是,当我使用 clang main.c
.
从终端使用 clang 时,源代码编译正确
有人能告诉我构建系统正常运行需要配置什么吗?
使用 Xcode IDE:
构建时会发出警告
Ambiguous expansion of macro 'OBJC_OLD_DISPATCH_PROTOTYPES'
并且直接使用 Xcode 输出确实是 0,但是使用 clang main.c
输出是 1。不同之处在于 Xcode 默认情况下将 clang 与已启用的模块一起使用:如果您在此处启用模块,则会在命令行上收到相同的警告:
clang -fmodules main.c
解决方案
在 Xcode、select 目标中,转到“构建设置”选项卡,然后在“Apple Clang - 语言 - 模块”部分,切换“启用模块(C 和 Objective-C)" 进入 'NO':
那么无论您在命令行中使用 Xcode 还是 Clang,在这两种情况下您都会得到预期的结果。
解释:
如果您使用模块,会发生以下情况:
- 使用模块的二进制表示代替包括文本和编译结果的预处理器
- 模块是(独立地)预编译的,即它们使用模块预编译时的定义
- 因此,include/import 语句之前代码中的预处理定义对模块(或其他导入的模块)没有影响。
- 如果启用了模块,不仅@imports 会受到影响,#includes 也会在后台转换为模块导入
所以你对 OBJC_OLD_DISPATCH_PROTOTYPES 的定义是矛盾的。
预编译模块使用 0 作为 OBJC_OLD_DISPATCH_PROTOTYPES,您将其重新定义为 1.
顺便说一句:如果你使用
#define OBJC_OLD_DISPATCH_PROTOTYPES 0
然后您使用预编译模块正在使用的相同定义,因此即使启用了模块,也不会出现有关宏扩展不明确的警告。
没有启用的模块,预处理器包括文本,编译结果和returns预期结果,即在objc.h中使用所需的typedef。
这里是第一个问题。
我在使用 XCode 构建系统时遇到了一些问题,特别是在预处理器定义方面。
我正在尝试为 objective-c 运行时定义一个宏,以避免强制将调度函数强制转换为适当的函数指针类型。通常的做法是使用 #define OBJC_OLD_DISPATCH_PROTOTYPES
,然后在下一行包含 header。一旦 header 被包含,宏就已经被定义并且 header 被相应地配置。
但这就是它开始变得奇怪的地方!
宏根本无法识别,header 被包含,就好像 #define
语句不存在一样,所以它无法 #define OBJC_OLD_DISPATCH_PROTOTYPES
并且它被(重新?)定义作为 0.
main.c
#include <stdio.h>
#define OBJC_OLD_DISPATCH_PROTOTYPES 1
#include <objc/objc-runtime.h>
int main(int argc, const char * argv[]) {
// From there:
// - Build System: OBJC_OLD_DISPATCH_PROTOTYPES is always 0, except if defined in build settings
// - Clang (only): OBJC_OLD_DISPATCH_PROTOTYPES is 1
printf("%d\n", OBJC_OLD_DISPATCH_PROTOTYPES);
}
当在“Apple Clang - 预处理”部分下的项目构建设置中定义预处理器宏时,构建系统将按预期运行。它使用 clang
的 -D
参数定义全局宏,使其可用于项目使用的任何文件。
但是,当我使用 clang main.c
.
有人能告诉我构建系统正常运行需要配置什么吗?
使用 Xcode IDE:
构建时会发出警告Ambiguous expansion of macro 'OBJC_OLD_DISPATCH_PROTOTYPES'
并且直接使用 Xcode 输出确实是 0,但是使用 clang main.c
输出是 1。不同之处在于 Xcode 默认情况下将 clang 与已启用的模块一起使用:如果您在此处启用模块,则会在命令行上收到相同的警告:
clang -fmodules main.c
解决方案
在 Xcode、select 目标中,转到“构建设置”选项卡,然后在“Apple Clang - 语言 - 模块”部分,切换“启用模块(C 和 Objective-C)" 进入 'NO':
那么无论您在命令行中使用 Xcode 还是 Clang,在这两种情况下您都会得到预期的结果。
解释:
如果您使用模块,会发生以下情况:
- 使用模块的二进制表示代替包括文本和编译结果的预处理器
- 模块是(独立地)预编译的,即它们使用模块预编译时的定义
- 因此,include/import 语句之前代码中的预处理定义对模块(或其他导入的模块)没有影响。
- 如果启用了模块,不仅@imports 会受到影响,#includes 也会在后台转换为模块导入
所以你对 OBJC_OLD_DISPATCH_PROTOTYPES 的定义是矛盾的。 预编译模块使用 0 作为 OBJC_OLD_DISPATCH_PROTOTYPES,您将其重新定义为 1.
顺便说一句:如果你使用
#define OBJC_OLD_DISPATCH_PROTOTYPES 0
然后您使用预编译模块正在使用的相同定义,因此即使启用了模块,也不会出现有关宏扩展不明确的警告。
没有启用的模块,预处理器包括文本,编译结果和returns预期结果,即在objc.h中使用所需的typedef。