Link error while building a unit test target
Asked Answered
M

5

51

I have a XCode4 / iOS project with a regular target and unit test target. Everything works fine, except when I try to #import one of my classes in my test class and try to use it. If I try to build the unit test target, I get the following link error:

Undefined symbols for architecture i386:
  "_OBJC_CLASS_$_FRRCategory", referenced from:
      objc-class-ref in CategoryTests.o
ld: symbol(s) not found for architecture i386
collect2: ld returned 1 exit status

In CategoryTests.m I'm importing the header file in this way:

#import "../todoro/FRRCategory.h"

What am I doing wrong?

Marbling answered 25/4, 2011 at 21:7 Comment(1)
Is your regular target an application, or a static library?Haggar
B
22

Make sure that the FRRCategory source file has been added to your Compile Sources for your unit test target.

Xcode 4:

Project Navigator -> "[Project Name]" -> Under Targets select your unit test target -> Build Phases -> Expand Compile Sources -> Click + at bottom of Compile sources and add the correct source file.

Batting answered 25/4, 2011 at 21:11 Comment(9)
Adding the files to the compile sources removed the error. What are those "compile sources" anyway and what's the rationale of forcing you to manually adding files from your main target?Marbling
Each target uses an independent set of source files. Either you didn't create the test target as a duplicate of your main target, or during the creation of FRRCategory you didn't select both targets.Gerstein
It depends which unit testing framework you're using. Are you using SenTestingKit that comes with Xcode 4, or something else? …If you're using SenTestingKit, then you don't want to add the code under test to your test target.Haggar
Compile sources are all of your implementation files that you need to have compiled for a target. When you have multiple targets each maintains there own set of compile sources and when you go to add new or existing files to the project you should see a checkbox option for which targets that new file should be included in. This includes resources such as images and interfaces as well code.Batting
This is not the correct answer to this issue imo. Check answer below this one.Madlin
This answer works, but is painful if you're testing more than a couple classes (which I hope you are). See @Martin Wickman's answer.Winery
@Ertai I agree the answer below is now correct and I as well have upvoted it months ago. But do note the difference in dates between to the two answers. Maybe consider convincing the OP to accept the other answer rather than continually downvote this one.Batting
the answer below is by far the best answer, especially if you have many sourcesMccue
THIS IS THE WRONG ANSWER - see below. Don't mean this as rude to the answerer, just trying to save other people any wasted time in case they miss it.Parrish
K
165

Follow the instructions here. It doesn't require you to add any files to compile sources.

I first missed that "Symbols Hidden by Default=NO" should be for your app target, not test target.

It worked for me anyway (tm).

Kalman answered 8/7, 2011 at 12:39 Comment(11)
This the answer most people want to follow imo, not the one the questioner checked. This way the the application build product is build like for standalone use, and the tests link against it. The alternative is to replicate all build settings, linker settings, etc. to build the source separately with the unit test.Keto
Lol, even after reading your comment I still messed up and needed the "Symbols Hidden by Default=NO" on my app target, not the test one. +1Mesosphere
it helps. And I found the sample code of Apple has the same settings.Thanks!Shutin
It worked for me as well! I also think this is the only correct answer! Not the one marked as the correct one above... The one marked as correct is only a hack to get things kind of working.Antiscorbutic
This is indeed the only correct answer. The other answers compile two copies of your sources into what becomes the instantiated test bundle. While generally this will be fine, if there are bugs in the build-toolchain you would get very strange and hard-to-debug side-effects.Please
Since the question specifically relates to Unit Testing, following the guide on the link contradicts Apple's one developer.apple.com/library/mac/#documentation/DeveloperTools/…Actomyosin
While following the list of steps here, just make sure you add a cocoa touch test target (he says cocoa test target). had some issues with architecture type before adding the cocoa touch test target instead of cocoa test targetGibe
The linked post above helped me to resolve this issue in Xcode 6.2 using the Quick framework for tests. In my case, only the BUNDLE_LOADER build setting had to be set.Buitenzorg
Symbols Hidden by default = NO for debug mode solved the problem even for X-Code 6.3 for my newly added test target. Thanks.Denni
this solution does not seem to work for extension unit tests, more solutions are here: stackoverflow.com/questions/24627600Carcinomatosis
not work for me :( I have static library need to write unit test. Code compile and build successfully but test case fail unrecognized selector. It works fine when I add .m file in test targetWakayama
B
22

Make sure that the FRRCategory source file has been added to your Compile Sources for your unit test target.

Xcode 4:

Project Navigator -> "[Project Name]" -> Under Targets select your unit test target -> Build Phases -> Expand Compile Sources -> Click + at bottom of Compile sources and add the correct source file.

Batting answered 25/4, 2011 at 21:11 Comment(9)
Adding the files to the compile sources removed the error. What are those "compile sources" anyway and what's the rationale of forcing you to manually adding files from your main target?Marbling
Each target uses an independent set of source files. Either you didn't create the test target as a duplicate of your main target, or during the creation of FRRCategory you didn't select both targets.Gerstein
It depends which unit testing framework you're using. Are you using SenTestingKit that comes with Xcode 4, or something else? …If you're using SenTestingKit, then you don't want to add the code under test to your test target.Haggar
Compile sources are all of your implementation files that you need to have compiled for a target. When you have multiple targets each maintains there own set of compile sources and when you go to add new or existing files to the project you should see a checkbox option for which targets that new file should be included in. This includes resources such as images and interfaces as well code.Batting
This is not the correct answer to this issue imo. Check answer below this one.Madlin
This answer works, but is painful if you're testing more than a couple classes (which I hope you are). See @Martin Wickman's answer.Winery
@Ertai I agree the answer below is now correct and I as well have upvoted it months ago. But do note the difference in dates between to the two answers. Maybe consider convincing the OP to accept the other answer rather than continually downvote this one.Batting
the answer below is by far the best answer, especially if you have many sourcesMccue
THIS IS THE WRONG ANSWER - see below. Don't mean this as rude to the answerer, just trying to save other people any wasted time in case they miss it.Parrish
D
7

Another gotcha that you may hit is if your unit test is using C functions (or similar) that aren't used in the actual app.

This may be restricted to having a sub-project. In my case

  • App
    • Sub-project
      • A C library embedded (i.e. .c and .h files compiled directly inside)

My unit test used a few of the C functions that were not used anywhere else, and these were stripped from the app binary (NOT from the sub project's .a file).

The fix is to

  1. turn off "Dead Code Stripping" for the app's Debug build.* and
  2. make sure your unit tests are using Debug and not Release, in the Scheme settings.

(* don't do this to the release configs as it'll bloat the app with code that is never called).

Decalogue answered 29/7, 2013 at 20:18 Comment(1)
This was this issue when trying to run unit tests on device architecture arm64. ThanksEnsiform
G
1

You should only refer to a folder inside your import if your file is inside a framework. Otherwise, once you added your file to the project, simply do #import "FRRCategory.h". Well, unless you did something weird with your Header Search Paths.

Gerstein answered 25/4, 2011 at 22:13 Comment(1)
It didn't remove the error, but I had no idea it wasn't necessary to include the folder. Thanks!Marbling
D
0

In my case, the host app was "Custom". I had to change it to an iOS target and set "Allow testing Host Application APIs". You can find it on the General tab of your test target.

Host Application setting

Dissatisfaction answered 9/11, 2021 at 15:19 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.