Skip to content

Archive

Tag: library

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.

Previous articles

The ‘symbol not found’ error: setting up linkages correctly

Remember that…

  • 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.
After applying changes as described in the first SO item, above, you may see warnings regarding -L paths not being found.
=> Have a look under the relevant build setting “Library Search Paths” – I seem to  find that fixing library locations generates introns in the search path, which later causes the warnings.

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.

 

Now that we’re a little more familiar with targets. How about we actually stopped being lazy and created a shared library?

How to do it

  1. Select File > New > Target (can also click on the project to open the target list and select the (+) symbol at the bottom left)
  2. Pick ‘Framework & Library’ in iOS templates.
  3. Select ‘Cocoa Touch Static Library’

I have a few files that I find useful whatever project I’m working on; for now I have just removed these files from all my existing targets, and added them to my newly created ‘utilities’ library target. This builds without issues.

Next, I opened the Build Phases tab for a target that should use the library. I drag and drop the library in the ‘Link Binary With Libraries’ section. Ordering is sensitive, so I add my library at the bottom of the list, after the frameworks.

Remember that the library should be listed by every target that uses the library. If your main target depends on a test target, and somehow your test code implies using the library as well, then both the main target and the test target should link against the library.

OK, how do I include the headers in my project?

  1. Click on your project (the project that you want to use your library with) to open the build related stuff.
  2. Select the project. It’s especially useful to include headers at project level if you have tests or use several targets.
  3. search for ‘User Header Search Paths’.
  4. Add the path to the library source file. It’s better to add a relative path. So if your project is under foo/myProj.xcodeproj and the library headers are under foo/myLib/myLib, then typically the path would be ../myLib/myLib
  5. You may need to set the matching target settings (the user header search path in each target) to $(inherited). This explicitly tells a target to inherit the setting from project level.

I feel there should be a cleaner way to do it, but I’ve seen it done by other devs, works for me.

Why do it?

Maybe you have qualified reasons for using a static library instead of sharing files across targets. Or maybe you just want to create a library that other developers can use.

However, even if we’re working on small projects and the ‘dev team’ is just one guy, the bottom line is that static libraries are the better way as soon as you want to share code between your apps.

Even if you define your apps using several products in the same project (a lightweight, moderately evil technique I describe in my previous post), that changes little to the fact that editing target associations in xcode is a manual process that requires patience. So rather than having to add every other code file to a new target whenever we start a new project (or removing undesirable files from a cloned target), we just add our files to the library, and link the library against our project, once and for all.

What cannot be included in a static library?

Pictures, text files, nib files and other non code files cannot be included in a library target. Code and header files can be included. It is interesting that Test and Library targets both allow *.h files, whereas product targets do not.

Can I get my static library to build automatically whenever I rebuild my product target?

Yes; it works the same as target dependencies for test targets.

Under ‘build phases’, drag the library target into the ‘target dependencies’ list. Ben Artin explained very nicely (here) that ‘dependencies are orthogonal to linking, if you want both, you need to specify both’

Reading further

You may find this article useful (from “The Carbon Emitter”).

haXe provides several ways to work with the Flash target. For example, you can both export to AS3 and directly compile a swf file.

Since our designers will definitely want to create their UIs with the flash IDE, I need haXe and Flash to work together. While explanations on the haXe site could still be useful, this step by step guide shows how haXe makes it possible to:

  • Separately maintain one or several asset files (just standard swfs) created using Flash CS3/4
  • Write all your code in haXe.
  • Export the result to a unique swf including both the code and imported assets.

If you are new to haXe/never heard of it, discover haXe benefits (link to haXe homepage)

At the moment, FlashDevelop is probably the best IDE to work with haXe (autocompletion, responsive interface, etc…)

Create a Flash file including your assets

  1. Create the test file, eg. assets.fla (new AS3 document or something like that)
  2. Create a movie clip and convert it to a symbol called ‘BlueSquare’
  3. Check Export for ActionScript in the movie clip properties. Ignore the notice telling you that flash will create a class automatically. That’s OK.
  4. The above automatically assigns a ‘BlueSquare’ class to the movie clip.

Create a new haXe project.

  1. Create a haXe project in FlashDevelop (project >> new project or similar)
  2. Create a resources folder along the src and bin folders created by FDevelop.
  3. Set the AS3 test file to publish to the resources folder as ‘assets.swf’.

Link the Assets file to your project

By default, FDevelop compiles your source files using the following command line:

haxe
-cp "C:\Users\tea\haxe_fl_test\src"
-cp "C:\src\ext\haxe"
-cp "C:\Program Files\FlashDevelop\Library\HAXE\classes"
-swf-header 800:600:30:FFFFFF
-main Main
-swf "C:\Users\tea\AppData\Local\Temp\tmpEE3B.tmp"
-swf-version 9
-v
-debug

Add the following setting (in Project Properties > Compiler Options > Additional Compiler Options)

-swf-lib assets.swf

You can also configure the document size and the target (e.g. flash9/10) in project properties, along with quite a few other things.

Don’t forget adding the resources folder path to the classpath, eg:

"C:\MyProject\resources"

Get a movie clip from your assets and show it on-stage

Finally, add the following to your main method:

var panel = flash.Lib.attach("BlueSquare");
panel.x = 20;
panel.y = 20;
flash.Lib.current.addChild(panel);

The above code instantiate the symbol, adding it to the top left corner of the stage – easy?