Skip to content

Archive

Tag: static library

In case you’re not getting it from the title, I may not have learned anything substantial while writing this article. I just created yet another static library, tried linking it against another, and there goes XCode (build 4C104) NYAAAAN.

Since I used to write my own coding tools, I bloody well knew how to compile a java (sigh) program on the command line. I also wrote tools in such a way that they found jars in myland (comforting it was, however restrictive).

XCode workspaces are meant to improve the (sodding) developer experience when dealing with complex projects. Don’t get me wrong, I’m all for wizardry – Clearly, however an ignoramus ex machina is usually at work when I try stringing libraries together.

Useful notes?

Check this article from the Carbon Five blog for useful notes about linking static libraries. I’ll provide a new article on this topic at some point. I just wasted a couple of hours clear because this stuff is having its way. Here’s a lame summary of what I found:

  • Like pixies, build issues appear when you least expect it. Sadly they also disappear mysteriously as soon as you try getting to the root of the problem.
  • You can fix build issues by fiddling:
    • If at first you don’t succeed…
    • Don’t assume a library won’t get found because it appears ‘marked red’
    • Don’t assume a library will get found because it doesn’t appear ‘marked red’
    • Assume duplicate items can easily arise when adding libraries to a project.
    • Remove duplicate items whenever you stumble on them.
    • Play with the ‘Location’ combo (relative to group, relative to project etc…).
  • Don’t be afraid to check build logs. The paths often look infuriatingly convoluted, but while you’re poking around to find what’s really gone wrong, the problem is getting itself fixed (and at least you’re kidding yourself that you have something to do with it).
Need I say this is only the beginning of an idiotic battle? I will get to the bottom of this (if there is one).

The case

Okay, let’s say I made a library called ‘foobar’ (I actually did)

Initially, under ‘products’, libfoobar.a is red. In my file inspector the location is relative to build products (and cannot be changed)

For sake, build (don’t add any source file) and check what happens: nothing. Well that’s good, innit? No source files, no library.

Now, add a source file and rebuild. Check the messages window. We now have 3 items: Precompile…, Compile… and Libtool.

Under Libtool, we can see the intended location of the output:

-o /Users/johndoe/Library/Developer/Xcode/DerivedData/workspace-fdpyddpbphekphdqtzzutyjcagva/Build/Products/Debug-iphonesimulator/libfoobar.a

Feeling paranoid (would Libtool ever lie?) we can verify that the library has been created by browsing to this path (Finder is gracefully setup to overlook whatever path this stuff goes under).

But the item still appears ‘marked red’ under ‘Products’. Suspicious?

Can’t copy libfoobar.a?

Now let’s try linking foobar against a target inside another project (same workspace, right?). Open project settings (yea click on the project in the navigator), go to Build Phases > Link Binary With Libraries, hit the [+] button. A cute browser now appears with libfoobar.a under Workspace (or whatever your workspace is named). Select libfoobar.a, press return and… *build*.

Mind, this operation adds an item to your project, now also visible in the navigator (libfoobar.a, still marked red).

If there is an error, it may look like this:

error: /Users/johndoe/Library/Developer/Xcode/DerivedData/workspace-fdpyddpbphekphdqtzzutyjcagva/Build/Products/Debug-iphonesimulator/../../../../../../../../svn/components/base/build/Release-iphoneos/libfoobar.a: No such file or directory
Command builtin-copy failed with exit code 1

What’s going on here? Let’s go and check the added library item inside our project (select the item and make check sure the inspector is open). I see this:

Location: relative to group

Path: ../../../components/base/build/Release-iphoneos/libfoobar.a

Clearly not right (yet, consistent with the failed copy operation)

Fancy patching the path manually?

Location: relative to build products

Path: ../Debug-iphonesimulator/libfoobar.a

Worked for me, but not right away. Digging around I found yet another duplicate of the same library reference (marked red!). Removed it, cleared (what appears to be) the same item under ‘build phases’ and re-re-re-added it all over again (this time by checking the box I wanted in ‘target memberships’).

Not happy

I felt somewhat unconvinced (notably, I’m not happy with the Debug-iphonesimulator part of the relative-to-build-products-path – how’s that supposed to backfire?).

So I removed the library altogether and started over. Just repeated the initial steps going by the book… sadly it… worked.

Until next time.

This is a flag you can pass along with ‘other linker flags’ in XCode build settings. It tells the linker that your project requires the C++ standard library.

If your project contains *.mm files this is set automatically (implicitly, rather). But what if you wrapped a C++ library using Objective C++ and carefully make sure that no C++ leaks into client code. Now you have a static library wrappedcpp.lib (speaks C++, OC++) and your app tries to link against this but doesn’t contain even one *.mm file?

What then? A bunch of ridiculously obscure linkage errors.

Thanks to Rob Napier, I can go back to my debugging (check the QA on stack overflow)

Last time I documented a rough setup for Bullet on iOS. I think this is much cleaner and would highly recommend you try it. It should take no more than an hour. If you have problems with this, please drop a comment and I’ll try to help you out.

Recipe for building bullet as an iOS ready static library

  1. Grab the archive. I used the *.tgz version (=> download page; Bullet physics engine homepage)
  2. Extract this somewhere you like; I put this under trunk/ext/bullet, thus renaming from bullet-x.xx to bullet
  3. Go to bullet/Extras/AllBulletDemosOSX; find a project named AllBulletDemos.xcodeproj
  4. Drag the project in your xcode workspace (requires XCode 4 or later). At the time of writing the OS X demos build correctly with XCode  4.0.2. Note that this is a MacOS project, not an iOS project – if you build and run you should see a window with lots of attractive demos. If you don’t see this window try to fix the project first(!).
  5. Create a new project (static library) in the same workspace. If you create this project inside the bullet folder, you could name it ios, then rename the project to bullet. You may let XCode create a unit tests target for you.
  6. Use the project navigator to find a group under AllBulletDemosOSX/src/src. Drag this group to the newly created bullet project.
  7. At project level in build settings, set the header search path to ../src and check ‘recursive’
  8. build.
  9. At this point you can remove AllBulletDemosOSX from your workspace if you wish.
  10. (strongly recommended) use the ‘hello world’ code from the bullet wiki to write a simple test, and make sure you get the test to build and run correctly. You probably need to add files that were not under AllBulletDemosOSX/src/src. This is likely to happen because there is no automation that reliably tells xcode to include new source files as they are added to the underlying src folder (sigh).
    In practice you will see a lot of linkage errors that can be easily fixed by adding the missing files from src/LinearMath/, src/BulletSoftBody, src/BulletCollision etc…
  11. (optional) fix the warnings that appear here and there and spoil the build.

Why do it this way?

There are several assumptions underlying this approach:

  • You won’t update very often and would like to check in the source in your own repository, or maybe you don’t use version control but want to keep tidy. I use the so called ‘ext’ folder for third party stuff.
  • You want a separate library; for this to work with iOS it has to be a static library.
  • You don’t want to ‘rearrange’ the archive content. You just want to refer the files you need. Using the archive ‘as is’ makes it easier to setup on several computers (you can check in your project along with the archive so anybody on your team can build it).
  • You want to have ‘unit tests’ handy so you can write tests while you’re learning how to use the library. I like to write tests to make sure I understand how the library works, and later the same tests can help me update to a newer version of the same library. Plus I find it much easier to write a few tests that output to the command line, rather than doing a big upfront integration with my software.
  • If you look at the sources it should become clear that you don’t need everything. I use AllBulletDemosOSX because it already contains references to most of the source files we need, so it saves time and effort (thanks to the bullet forums for the tip)

Is there a better way to do it?

I guess if you have the right make file or know how to create one and are willing to spend the time, maybe it would be better. Especially if it can automatically detect changes when you update to a more recent version of the library.

A few caveats

  • To rename a project, you can use the project navigator or the file inspector. You can rename a project the same way you rename a file in your xcode workspace and xcode will try to help you rename various entries. It’s easier than renaming the *.xcodeproj file yourself.
  • You may need help to setup unit tests. If you’ve never done it please consider doing it as it’s well worth it and there are good articles about this lying around.

All in all, there’s no game engine until you see that game engine supporting a couple of separate executables. Paradoxically, even if you’re working on ‘just one game’, it’s better to have a game engine and it’s better to have two or three executables than one.

I don’t exactly remember when I started piecing things out. It took a few weeks already and I’m not done yet. Now I have a bunch of static libraries:

  1. utilities. This doesn’t do much. Sound and string utilities, a tiny parser and some support for talkback. I put there essential things that I’d see running in any game I make. I
  2. shell. An MVC template for game containers. It provides basic support for stuff people do when they’re not playing: starting a new game, checking out ‘more games’, mailing support and the like. In other words, the ‘little extras’ that indies don’t think about when they start making a game. This is meant to be reusable and can be customized easily.
  3. rendering engine. this is directly derived from Antistar code. This library knows how to import stuff from blender (via ox3ich/qwagga) and render scenes using OpenGL ES 1.0
  4. game engine. derived from Antistar code, its scope is narrow compared with open source and commercial counterparts. Includes support for walking, game physics, qualified actors and items etc…

Aside, I also have the following:

  • Unit testing for all my libraries. It’s not that I use it that much (less than I should) but I want to have it handy when I need it (seriously, I do have more than zero tests, and for solo work it’s a lot more valuable than version control, which gives me chronical pains and zero rewards).
  • Two sandboxes. The sandboxes are used to play-test and develop features. One sandbox targets core3d (for your eyes only), the other targets a3dsfx to try out game features. I consider that the sandboxes are a big improvement over messing with level design ‘just for testing’, then finding that nothing’s where it should.
  • 3 game projects. Antistar, and other stuff I may or may not be working on.

How did it happen?

It all happened mainly because I thought the Antistar project took way too long, and I’m getting better at designing smaller games. I managed to kickstart a mini-project, and the good news is, I’m not working on it now (somebody else is). The mini project spawned the shell, utilities and a rather tiny game engine for 2D stuff (not quoted above).

Then it looked like the mini project might take a while. So I started looking at the 3D content in Antistar, thinking I’m much better at 3D graphics than 2D. So I extracted the rendering library and spawned another mini project (not something I’m too concerned about). And finally I pulled a3dsfx from the antistar equation, because I wanted a sandbox for that.

Is it good?

It depends how you look at it. From a short term perspective, it’s wasteful. Building with unstable libraries (most of them are) is much slower. Creating standalone libraries requires breaking undesirable dependencies. None of this hurt a lot (which still shows the code massively improved since last year), but it takes time.

If we look ahead a little, I think it’s great. I’ve been rushing forward, then thrashing forward, I wrote code that’s valuable to me, and code that takes that long to write shouldn’t be used in just one product.
A static library gives ‘strong separation’. Yes, I could import whatever headers I fancy. But no, I don’t, and I don’t feel like it.

Aside, although I’m not evenly committed to the side projects I started, going through the motions helped me look at things in a different light. As a result I already improved my rendering engine and blender scene support. This clearly brought improvements that will support the next Antistar release.

Integrations

Another thing that’s coming up with the static libraries and the sandboxes is ‘easy to use integrations’. So now I have the following:

  • World3D – this is basically a no fuss blender scene viewer.
  • Stage3D – also a scene loader, but it relies on conventions to extract terrain, physics, actors, items and such.

What’s next?

I’m still validating Stage3D using the sandbox. Separating the game engine from the game itself is a little bit like making an omelette (break an egg) but it makes game logic clearer and more manageable.

Yeah, whatever…

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”).