在 ONLY_ACTIVE_ARCH = NO 的本地计算机上编译时未遇到编译警告



我有一个小问题,我不知道如何解决。

在我们的多个项目中,我们希望将"将警告视为错误"(GCC_TREAT_WARNINGS_AS_ERRORS)更改为YES

我们还希望将 Xcode 默认项目设置"仅构建活动架构"(ONLY_ACTIVE_ARCH)保留为"调试"YESNO"发布"。

然而,这有一个主要缺点。 代码如...

NSUInteger bob = 12234;
NSLog(@"bob %lu", bob);

应该产生以下类型的警告(因此在我们的例子中是错误的):

类型为"NSUInteger"的值不应用作格式参数; 改为将显式强制转换添加到"无符号长"

但是,

当开发人员在本地构建和测试时,他们不会遇到此警告/错误,但是当他们提交到我们的存储库并且我们的持续集成从命令行xcodebuild运行时,会遇到警告并且他们的构建失败。 这显然是相当令人沮丧的。

我认为这与使用 Xcode 时构建的架构与从命令行使用 xcodebuild 时构建的体系结构之间的差异有关。

我在这里上传了一个示例项目...

https://github.com/OliverPearmain/ArchitectureDependantCompileWarning

我包括了 2 个方案。 如果您使用"ArchitectureDependantCompileWarning"(使用调试构建配置,因此ONLY_ACTIVE_ARCH==YES)为iPhone 6S模拟器进行编译,则不会收到警告,并且编译正常。 如果使用"ArchitectureDependantCompileWarning-FAILED"方案(该方案使用发布构建配置,因此ONLY_ACTIVE_ARCH==NO),则会遇到警告并且编译失败。

我想以某种方式确保在使用ONLY_ACTIVE_ARCH==NO模拟器构建模拟器时始终会遇到此警告。 这可能吗?

造成这种情况的原因是 5s 出现时单词长度的变化。 换句话说,5s及以上的iPhone具有64位处理器,而所有以前的iPhone都具有32位处理器。

这是NSUInteger的实际类型定义

#if __LP64__ || (TARGET_OS_EMBEDDED && !TARGET_OS_IPHONE) || TARGET_OS_WIN32 || NS_BUILD_32_LIKE_64
typedef long NSInteger;
typedef unsigned long NSUInteger;
#else
typedef int NSInteger;
typedef unsigned int NSUInteger;
#endif

您可以看到,对于 32 位处理器,NSUInteger被明确定义为unsigned int而对于 64 位处理器,NSUInteger被明确定义为unsigned long

所以,看看这个代码...

NSUInteger bob = 12234;
NSLog(@"bob %lu", bob);

对于 4s,此NSLog不匹配,因为NSUInteger被显式定义为unsigned int,而格式说明符%luunsigned long。 这种非常明显的不匹配是 32 位处理器存在警告的原因。 对于 64 位处理器,没有不匹配,因此没有警告。

警告中建议的修复假定您打算使用 unsigned long 。 但是,这里有一个替代解决方案。

NSUInteger bob = 12234;
#if __LP64__ || (TARGET_OS_EMBEDDED && !TARGET_OS_IPHONE) || TARGET_OS_WIN32 || NS_BUILD_32_LIKE_64
NSLog(@"bob %lu", bob);
#else
NSLog(@"bob %u", bob);
#endif

底线是,您要做的是在没有不匹配时生成不匹配警告,这既不合适也不可能。

编辑:

这不是不匹配错误无法

表现为警告/错误的情况。从字面上看,没有不匹配。显示此错误的唯一方法是实际上存在不匹配。仅当您针对体系结构进行构建时,才会存在不匹配,而NSUInteger的定义会在您提到的特定代码中创建不匹配。已经有一种标准方法可以实现这一点:为所有方案设置"仅构建活动架构"为"否"。

最新更新