Xcode 单元测试 - 仅为设备构建时出现链接错误

Posted

技术标签:

【中文标题】Xcode 单元测试 - 仅为设备构建时出现链接错误【英文标题】:Xcode Unit Tests - Link error when building for device only 【发布时间】:2013-06-17 22:47:22 【问题描述】:

我的应用程序单元测试在模拟器中运行时构建和测试,但在构建和测试到设备时失败并出现链接器错误。

在我的应用程序目标上,我设置了以下构建设置:

DEPLOYMENT_POSTPROCESSING = NO
GCC_SYMBOLS_PRIVATE_EXTERN = NO

在我的单元测试中,我设置了以下构建设置:

BUNDLE_LOADER = $(BUILT_PRODUCTS_DIR)/<app name>.app/<app>
TEST_HOST = $(BUNDLE_LOADER)

链接器错误是:

Undefined symbols for architecture armv7s:
"_<An NSString * const>", referenced from:
      -[UnitTestClassA setUp] in UnitTestClassA.o
"_<Another NSString * const>", referenced from:
      -[UnitTestClassB helperMethod:] in UnitTestClassB.o
      -[UnitTestClassB anotherHelperMethod:] in UnitTestClassB.o
ld: symbol(s) not found for architecture armv7s
clang: error: linker command failed with exit code 1 (use -v to see invocation)

...我在 Xcode 的首选项中打开了“构建错误后继续”,但我没有收到大量抱怨 NSString * const 的链接器错误。如果我做错了什么,那么由于我在整个生产代码中使用字符串常量,因此预计链接错误会比我得到的少数链接错误更多。

我正在创建这样的字符串常量:

.h 文件...

extern NSString * const ReallyGoodString;

.m 文件...

NSString * const ReallyGoodString = @"This string is great!";

....m 文件是生产代码,是我的应用程序目标的一部分,因此我不必将它链接到单元测试包中。

那么,这里发生了什么?为什么这在模拟器上运行得很好,而不是在设备上?

我已经发布了一个sample project to Github 来说明问题。您可以在示例项目中看到这个问题是不一致的:有些符号链接得很好,有些则没有。

【问题讨论】:

你有没有想过这个问题?我有同样的问题。更奇怪的是,它以前可以正常工作,链接器只抱怨头文件中的一个字符串常量,从中可以找到其他符号。 @JonGrall 还没弄明白 【参考方案1】:

当链接器创建Linker-Error 可执行文件时,它会丢弃FHKViewControllerThisSymbolWontLink,因为可执行文件中没有任何内容使用它。链接器不知道它应该保留符号以供单元测试包(在运行时动态加载)使用。

您可以通过使用used 属性标记它来告诉链接器不要剥离未使用的符号,如下所示:

NSString * const FHKViewControllerThisSymbolWontLink __attribute__((used)) = @"name";

您需要为您定义的每个符号执行此操作,这些符号不被主可执行文件使用,但被测试套件使用。

【讨论】:

【参考方案2】:

这很可能是因为您的测试套件正在使用主应用程序未使用的符号,并且启用了Dead Code Stripping。您可以在每个配置的基础上禁用 Dead Code Stripping 选项。我修复了一个类似的问题,通过将选项切换为 No 仅用于 Debug 构建,使测试能够在我的设备上运行。

【讨论】:

这可能是更好的选择,因为它适用于所有代码,而不仅仅是带有 __attribute__((used)) 注释的语句。【参考方案3】:

一些可能性:

    您导入了标头,但未链接到正确的库。这很常见,尤其是对于像 QuartzCore 这样的库的头文件,因为默认情况下它不包含在项目中。解决方法:

    A.在 Build Phases 的 Link Binary With Libraries 部分添加正确的库。

    您将文件复制到项目中,但忘记检查要添加文件的目标。解决方法:

    A.打开正确目标的构建阶段,展开编译源并添加缺少的 .m 文件。

    如果您使用逻辑测试,ios 设备不支持它们,而仅在模拟器中支持。应用程序测试可以在设备上运行。相关文档:

iOS:虽然 Xcode 可以在 模拟器,Xcode 无法在 iOS 设备上运行逻辑单元测试。 因此,如果您在 一个方案,您将无法使用该方案来运行单元测试 iOS 设备。

【讨论】:

回复:1 - 这些符号由我在我的生产代码中声明和定义,回复:2 - .m 文件是应用程序目标的一部分,回复:3 - 单元测试是“应用程序测试” “ ...所有这些绝对是朝着正确方向发展的想法,谢谢! 应用程序和逻辑测试是单元测试的类型?您知道您使用的是逻辑测试还是应用测试? 您可以在问题中看到我专门调用了 Build Setting 的 Bundle Loader 和 Test Host 设置 (developer.apple.com/library/ios/documentation/developertools/…)。此外,稍后在问题中提到我在一个全新的 Xcode 项目中完全重新创建了我的问题;应用程序测试是任何新项目中单元测试的默认设置。 对不起,我错过了。祝你的问题好运。【参考方案4】:

我曾经遇到过类似的问题,解决方法就像清理项目一样简单,我猜你已经尝试过了,但也许没有。我至少会试一试。只需转到顶部导航栏中的“产品”->“清洁”,或使用快捷方式:“shift”“command”“K”

(我会把它写成评论而不是答案,因为它不仅仅是一个简单的建议。但我没有足够的评论点,抱歉)。

【讨论】:

该死的。希望它是那么容易。感谢您的建议! 您是否尝试过开始一个全新的项目并将旧项目中的所有代码和数据复制到新项目中? (所谓的完全重启)? 那种。我刚刚开始了一个新项目,其中包含一个链接静态全局变量的类和测试套件。 "我使用 Xcode 4.6.3 的默认单元测试启动了一个项目,在生产代码中声明并定义了一个静态字符串,并在我的单元测试中引用它 - 相同的行为:在模拟器中可以,无法在设备上链接。” 这真的很奇怪,很抱歉,但我想我不能帮你解决这个问题,抱歉

以上是关于Xcode 单元测试 - 仅为设备构建时出现链接错误的主要内容,如果未能解决你的问题,请参考以下文章

单元测试 Xcode 4 的链接器错误

尝试在模拟器或设备上构建 React Native 项目时出现 Xcode 错误

Xcode:尝试在iOS模拟器中运行应用程序时出现无效的符号链接错误

升级到 XCTest 时出现链接器错误

从 Xcode 6 重新构建应用程序时出现 OSStatus 错误 2003334207

为通用 iOS 设备创建产品存档时出现 SDWebImage 错误