Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Xcode Unit Tests - Link error when building for device only

My application unit tests build and test when running in the simulator, but fails with a linker error when building and testing to device.

On my application target I've set the following build settings:

DEPLOYMENT_POSTPROCESSING = NO
GCC_SYMBOLS_PRIVATE_EXTERN = NO

On my unit test I've set the following build settings:

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

The linker error is:

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)

... I have "continue after building errors" turned on in Xcode's preferences, but I don't receive a ton of linker errors complaining about NSString * const's. If I'm doing something wrong, then would expect more link errors than the handful I'm getting since I use string constants throughout my production code.

I'm creating my string constants like this:

.h file...

extern NSString * const ReallyGoodString;

.m file...

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

... the .m file is production code, and part of my application target, and so I do not have to link it into the unit test bundle.

So, what is going on here? Why does this work just fine in the simulator and not on device?

I've posted a sample project to Github that illustrates the problem. You can see in the sample project that this problem is inconsistent: some symbols link just fine others do not.

like image 562
edelaney05 Avatar asked Jun 17 '13 22:06

edelaney05


2 Answers

When the linker is creating the Linker-Error executable, it discards FHKViewControllerThisSymbolWontLink because nothing in the executable uses it. The linker doesn't know that it should keep the symbol around to be used by the unit test bundle (which is dynamically loaded at runtime).

You can tell the linker not to strip the unused symbol by tagging it with the used attribute, like this:

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

You will need to do that for each symbol you define that's not used by the main executable but is used by the test suite.

like image 149
rob mayoff Avatar answered Oct 14 '22 04:10

rob mayoff


This is most likely because you have symbols that are in use by your test suite that are not used by the main application and Dead Code Stripping is enabled. You can disable the Dead Code Stripping option on a per-configuration basis. I fixed a similar issue to enable tests to run on my device by flipping the option to No for Debug builds only.

like image 12
Blake Watters Avatar answered Oct 14 '22 02:10

Blake Watters