14

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

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

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 文件是生产代码,是我的应用程序目标的一部分,因此我不必将它链接到单元测试包中。

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

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

4

4 回答 4

27

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

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

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

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

于 2013-08-10T17:38:56.167 回答
12

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

于 2013-11-14T15:54:24.063 回答
1

一些可能性:

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

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

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

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

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

iOS:虽然 Xcode 可以在模拟器中运行逻辑和应用程序单元测试,但 Xcode 不能在 iOS 设备上运行逻辑单元测试。因此,如果您在一个方案中包含并激活了这两种类型的单元测试,您将无法使用该方案在 iOS 设备上运行单元测试。

于 2013-08-08T22:40:29.257 回答
0

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

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

于 2013-08-09T16:03:23.970 回答