Pending a merge of my related articles, I put together related info and also include interesting finds related to unit testing and setting up linkages.
- Using static libraries is easy as pie. Well not really but this is my original post on the topic.
- If you have projects combining ObjC++, C++ and ObjC, checking this article will save you a migraine.
- When attempting to archive, validate and submit a package including static libraries, you may encounter issues. Refer this article on DoronKatz.com ; it is helpful.
- Unit testing Using XCode 4.2 (but first, look at setting up for unit testing below as I think the setup is a lot smoother, and will dramatically reduce build times compared to my old one).
The ‘symbol not found’ error: setting up linkages correctly
- For each project
- For each target depending on your static library
- You need to add “mylib.a” to the “Link Binary With Libraries”
This typically includes:
- Targets that generate an executable
- Testing targets.
This means that you may encounter this error several times, and fix it in a variety of places. Say you have the following workspace:
- Project MyApp
- Target MyApp (executable) [requires Baselib.a]
- Target MyAppTests (unit tests) [requires Baselib.a]
- Project FunkyStuff
- Target MyFunkyStuff (static lib)
- Target My FunkyStuffTests (unit tests) [requires Baselib.a]
- Project Base
- Target MyBase (static lib)
- Target MyBaseTests
Assuming that FunkyStuff uses a class in Base, I have highlighted places where you probably need to add a dependency.
More linkage errors (important!)
Beyond the above, typically you have setup a workspace and sooner or later you’ll run into cases where you make a change in the library source code, but can’t see the result when running your app unless you do a full clean and rebuild (this is an awesome productivity killer) . I found two SO items that are rather helpful in this case, and they’re probably not the ones everybody’s looking at:
- One possibility is that your libraries rebuild, but the app does not re-link. Read this SO item, here. But in short if you relate a project to libfoo.a, it’s “location” setting in inspector should be “Relative to build products”
(and for this to work you really ought to keep your library projects in a workspace)
- And there is an in-depth answer (notably covering the whimsical question: “Why do the library items in project not turn black, but remain red) here.
Setting up for unit testing
While XCode kindly creates a unit test target for you by default tests will not run when you want them to: unless you have some kind of continuous integration setup (if so, why are you even reading this post?) you want tests to run whenever-after the library is built.
I’m still wrapping my head around exactly what all the related buttons and fidgets do, in the meantime here’s a couple of things that work well:
- Edit scheme for myLib; in Edit Scheme > Build you should see myLib and myLibTests.
- Check the run action for myLibTests. Otherwise your tests won’t run.
- myLib *may* be removed.
(Not recommended – but knowing that this works, and why, is enlightening:
look into the myLibTests target and see that myLib is under ‘target dependencies’ – the library cannot be tested before it is built, so the tests require it, ergo it is redundant as declared in your scheme )
- Build and check messages. You can see “RunUnitTests exited without running tests…” under “TEST_AFTER_BUILD”.
So, look for TEST_AFTER_BUILD in the test target build settings and set this to TRUE
- If you have an app using myLib, you can ensure that tests will run (and the library will rebuild whenever needed) by adding myLibTests to the myApp scheme just like we did for myLib.
For solo dev this is probably the most useful tweak. Assuming you bother maintaining separate projects and libs (I do)…
- You don’t care to switch scheme whenever making a minor change to one of your static libs
- You really want tests to run (and possibly fail) BEFORE the simulator launches.