Skip to content

Archive

Tag: XCode

Earlier, I described how to integrate Blender 2.4x assets with XCode build rules. Let’s jump into the present and do the same with Blender 2.6x.

Fundamentally, the solution is the same (see here). I added a new build rule with the described parameters:

Matching rule

*2.5x/assets/*.blend

So, all 2.5x / 2.6x files go under a ###/2.5x/### folder (depending on the file version, I run either Blender 2.49b or Blender 2.6x ). This rule matches a fragment of the path, so it will still work with multiple projects, e.g. :

  • …/foobar/2.5x/assets/foo.blend,
  • …/superfungame/2.5x/assets/funasset.blend
  • (…)

Script invocation

/Applications/blender-2.6x/blender.app/Contents/MacOS/blender -b “${INPUT_FILE_PATH}” -P /Users/xxx/svn/blender-scripts/ox3ich/ox3ich_main.py — “$INPUT_FILE_DIR/../../build/$INPUT_FILE_BASE.blz”

ox3ich_main.py is the script used to export assets, so maybe you’ll invoke a COLLADA export script or such.

Output:

${INPUT_FILE_DIR}/../../build/${INPUT_FILE_BASE}.blz

This just matches the output (in script invocation, specified after “–”, note this is a custom script rule, Blender lets you pass custom parameters after “–” )

Caveats

While testing remember XCode may not re-run the script unless the input file has changed (even if the previous invocation failed).

Blender 2.5x/2.6x has a somewhat complex script registration mechanism. When integrating with XCode, however, what tends to happen is… …nothing. So typically you have a script FOO.py, which is designed to run as a registered blender script; then you should pass a bootstrap script BAR.py to drive FOO when running Blender from cd. This is more or less what I did.

One more thought on this is that, all considered, if the main use of your script is exporting via cd, you don’t need to learn about script registration, you just write your export script and feed it to Blender via the command line.

Note: With a little trickery you can write scripts that will run on both blender 2.5x and 2.63 and later; I’ll cover the changes later. Or you can read the NGons and tesselated faces gotcha (from blender.org).

XCode notes

  • Code generation settings are under project > Build Settings > Code generation
  • The ‘main switch’ is under LLVM GCC 4.2 > Optimization level.
  • You can pass additional flags under LLVM GCC 4.2 > Language > Other C flags
LLVM or GCC?
In the best case scenario you can pick between 3 compilers. I don’t have benchmarks; the overall feel from reading around is that GCC may generate faster apps.
Incidentally, my system stalled while building a C++ library with -O2/-O3/-Os turned on (LLVM GCC, LLVM 3.0). Adding -fno-inline-functions to Other C flags ‘fixed’ the issue. But now, that’s quite note what I wanted to do. Switching to GCC 4.2 solved the problem (the target library wraps basic maths with inlines; enforcing inlining yielded 10-15% gain).
.
Read here?
.
Thumbs up?
.
On ARMv6 ( iPhone 3GS and earlier), turning thumbs off, used to yield a dramatic performance increase on floating point calculations. Well not anymore. Put in a better way, there aren’t many ARMv6 devices around anymore ( ~3.5%? )
.
I tested an FP intensive task and observed a marginal improvement ( maybe less than 3%) with an iPad2.
.
-/O0/O1/O2/O3/Os
.
I was curious to see whether -Os (smallest/fastest) would perform significantly worse than -O3. It doesn’t – well not in my case. I observe about 4% speed increase between -O2/O3/Os and -O0 (-O0 : no optimizations).
.
I tested this on a graphic application running OpenGL ES 1.x . I measure the performance increase by looking at % usage per frame for non GPU tasks (In my case, the CPU/GPU balance is fairly even).
.
Measuring performance
.
Running with GDB or Instruments turned on will slow down your app; a crude way to measure release-grade performance may be to stick a frame rate meter right on top of your UI (now that is common practice, right?) and check with an unplugged device.
This won’t tell you where your overheads are going. For this, I still find Instruments an invaluable help.
.
I’m looking at averaging performance over one or several game sessions to get useful figures. Formal test cases can help solving specific performance issues – keeping in mind that optimization issues and level design strongly interact.
.
Stuff that looks interesting
.
.
Conclusion
.
With a background in Java and other virtual languages, I find that playing with compile time settings is, overall, almost a waste of time. Sadly (cf. the thumbs episode) it isn’t always quite so.
.
Wasting a day on belittling tweaks and flags from time to time isn’t altogether bad.

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 article is a revision of a previous article I wrote about unit testing with XCode.

I describe the steps carried to setup a test target long after a project has been created, so initially the test target will lack most of what’s needed to operate correctly (e.g frameworks, libraries and source files)

Setting up may take up to a few hours.

Creating a test target isn’t a big deal (just go to the project panel, add a new target and follow the steps).

I expect tests to run every time I try to build/run the main target. If the tests won’t pass I’d rather not fire up the simulator.

By default, the test target is not setup to work this way. Maybe it makes sense (after all, how does it know which target to depend on).

  1. Go to project panel => build phases ; add the test target under target dependencies.
  2. In the project panel, open ‘build settings’ for the test target, search for and tick ‘Test After Build’.
Note: You can also edit the scheme for the main target; under ‘testing’, add the test target. However doing it this way won’t action tests every time you run the application; you’d have to select the test action instead of run (top-left of xcode window, press and hold the ‘run’ button).
Up to ‘housekeeping’, the steps described below are likely necessary. Try to build before/after every step and check build messages to help you move on.

1. Adding source files

Maybe the fastest way to add your .m files: go to Build Phases and scroll to ‘source files’, then press add. type *.m as search filter. If you have many groups you may need to do this a few times to include all the required files.

2. Disable/Enable Automated reference counting.

In your test target, under build settings, search for ‘Reference counting’ and tick/untick “Objective-C Automatic Reference Counting”

3. Replace/Edit precompiled headers

In build settings, search for ‘pch’. If possible I just copy the *.pch from my main target settings to the test target settings.

4. Add the required frameworks & libraries

Most of this should be copied from your main target. Opening the assistant editor so you can compare/check both targets at once is useful (see build phases > link binary with libraries).

If you miss a library it will result in countless unresolved dependencies so it’s easy to figure.

5. List additional headers

If you’re pointing at additional headers in build settings, ideally you can share definitions by declaring them in the project’s (not the target’s) build settings – target-specific entries can be overwritten using $(inherited).

Housekeeping

Keep your framework/library references tidy: Checking the list of frameworks/libraries included in your project (there may be some in several places) may be a good idea as (harmless) duplicates may arise.

With frameworks/libraries, getting ‘red files’ is not rare. In many cases this doesn’t mean anything is actually broken (sigh…)

Remove unused files: remove files created by the wizard, if unused (e.g. precompiled headers)

Rename/Regroup: Renaming/Regrouping may cause references to break and need further editing. It’s a bit fidgety so you’ve been warned.

I like using generic names for my source folders (e.g. not MyApp Tests/ , just test/ ) and certain files (info.plist instead of MyAppTests-Info.plist). Renaming the info.plist will require editing in build settings etc… so maybe it’s easier to leave things as they are (XCode can help you rename project items).

Caveats

Beware that some classes in related libraries may rebuild after setting up the test suite; if old files were lingering in the system this may cause errors and confusion. Clean the build if things start looking weird.


We use blender to create game assets; we also use blender as level editor. Blend files are exported to our proprietary format using py scripts.

Exporting files manually is okay… to a point. Soon we find out not only that exporting files manually is a chore, it contributes to creating a beautiful mess.

How to automate the conversion? With XCode, it can be done using build rules. I’m covering the following points:

  • Build integration – add files to your build, automatically translate them using utilities and include the products in your app bundle.
  • Defining useful build rules.
  • Invoking blender from the command line.
  • Modifying blender scripts so that they won’t crash in a windowless environment.
  • Signaling export errors (notably, errors generated by a script running inside blender) using XCode.

While we have a mixed workflow (Blender 2.49 / Blender 2.61), we’re dominantly using 2.49b, so I started with the older version. I’ll be covering 2.61… later.

I used the following articles as a starting point:

This article is not concise; I’ll summarize my findings in a coming article.

The experiment

The first step is to configure build rules to process *.blend files I guess, so in a first approximation I used this:

  • Source files with names matching *.blend
  • Custom Script: /Applications/blender/blender.app/Contents/MacOS/blender ${INPUT_FILE_PATH} (bad)
  • Output Files:
    ${TARGET_BUILD_DIR}/../../${INPUT_FILE_BASE}.scg (bad)
I just thought it would be interesting to try this way although it’s obviously not complete. And indeed, it was.
First surprise, Blender opens in a window. Good for testing (notably because it’s displaying errors already; for a nice smooth build I’ll want to disable this).
Both Blender & XCode are displaying messages in the XCode errors & warnings panel, which is nice.
The initial problem is path related. The file won’t open because spaces in the path are incorrectly interpreted. So the correct form to open the blend is like this:
  • /Applications/blender/blender.app/Contents/MacOS/blender “${INPUT_FILE_PATH}” (good)
Running the script is the next obvious step. For now blender just opens and idles happily until I quit. So I modify my command, like this:
  • /Applications/blender/blender.app/Contents/MacOS/blender -b “${INPUT_FILE_PATH}” -P qwagga.py (bad)

-b to tell blender to ‘render in background’. -P qwagga.py is the wishful step to run my script hoping that scripts are being run from the blender scripts folder. qwagga.py is my export script. There will be a problem with that but let’s try anyway.

Indeed, -b prevents the blender window from opening. Blender is reporting (via XCode) that qwagga.py wasn’t found. Interestingly it would appear that -P could also refer a script included inside the blend file (text node). For now, however, I’ll just provide the full path.

  • /Applications/blender/blender.app/Contents/MacOS/blender -b “${INPUT_FILE_PATH}” -P /Applications/blender/blender.app/Contents/MacOS/.blender/scripts/qwagga.py (good)

Yea this works. As you’d expect since the exporter is trying to pop a file selection panel the script crashes with a fairly explicit message:

File “/Applications/blender/blender.app/Contents/MacOS/.blender/scripts/qwagga.py”, line 213, in <module>   Blender.Window.FileSelector(exportAssets,’Export to File’,PATH)
RuntimeError: the file/image selector is not available in background mode

This error can be patched easily:

    try:
            Blender.Window.FileSelector(exportAssets,’Export to File’,PATH)
    except RuntimeError:
            OUTPUT=Blender.sys.makename(ext=’.scg’)
    exportAssets(OUTPUT)

Telling XCode where the ouptut is located turned out to be a nag. The docs aren’t overly explicit about what environment variables can be used. As it turn out, however, whenever running a custom shell script (like, what we are doing now) the messages window displays a whole batch of setenv commands. That is all we need to know. I adjusted my entry in output files accordingly:

  • ${INPUT_FILE_DIR}/${INPUT_FILE_BASE}.scg

Immediately after I got this work, it seemed there was ‘a bit of weirdness’ in XCode (an error I couldn’t make sense of). For whatever reason this cleared after cleaning the build and re-saving my blend file.

It appears that each file is getting processed/converted whenever building (even if the input file hasn’t changed). I’m a bit worried about how this will turn when I have 200 blend files linked in this way – since blender loads almost instantly I’ll just wait and see.

Single input => multiple output

Now, the above looks quite useful but there are issues:

  • My py scripts don’t output just one file.
  • In fact I have two py scripts used in blender. One outputs a single file, the other outputs a whole lot of files. The names of the files match object names in blender
I would hope that both Blender and XCode can handle this situation gracefully.
For proof of concept, I just hacked a different output file path and created a file hierarchy looking like this :
  • blends
    • car_park.blend
    • build
      • car_park.blz
        • foo.rtf
        • bar.rtf
I added a ‘build’ folder under blends because we don’t want to have output files sprawling around. Then the question is to know whether car_park.blz will be exported along with all its content (for sake, foo.rtf, bar.rtf). The answer is YES.
Not perfect
Using this method I don’t know how to modify the location of the output in the resulting package. Before I would link a ‘blue folder’, so all my media 3D assets would go under [package]/3D/. Controlling the structure of this package is useful in various ways. 
We just demonstrated that we can link a whole folder given a single input file; this means we could input a config file describing which blend files we want to translate and how; then we’d run blender once , translate all the files and producing the correct output.
In the end I think this will turn out to be a better solution, notably because it will avoid translating the same files other and other even if they weren’t modified. Scene files process fast; not the case with files containing large meshes and animations.

For whatever reason, the next steps turned out to be troublesome.
My second py script was symlinked. I didn’t think it would matter (strictly speaking, still don’t think it does) but I found it hard to get the script to refresh (meaning, I would edit the py script and run the build again, find the same error as previously. And again. And again.

An error in the scene export script caused the wrong path to be used.

Passing several scripts on blender command line (-P foo.py -P bar.py) doesn’t work so I ended calling blender twice which is a lesser evil. Maybe.

Complications

  1. I have a mixed workflow using both Blender 2.4x and Blender 2.5x. In theory this means that I would have to go through the motions again, finding out how I can run 2.5x from the command line (likely as not, it won’t work in the same way).
  2. Scene files contain level edits and assets. Asset files do not contain level edits. Both blender 2.4x and 2.5x files are just annotated as *.blend. How do I know which version of blender to run and which scripts to call?

The answer to (1) will be simple for now. Don’t do that. I mainly use 2.4x; the only 2.5x file that really matters so far is the one containing the PC mesh and animations. So I’ll just pass and use the manual workflow for that.

The answer two question (2) will be equally simple. Use a convention. For starters:

  • level file: level.s.blend
  • asset file: asset.a.blend

( and likewise when I get 2.5x scripts working, different conventions may be used )

This is a bit lame. Maybe a better convention might be something like:

  • *2.4x/scenes*.blend
  • *2.5x/assets*.blend

Works – although the build rule does say something like “files with name matching”, the matching rule actually uses the path.

A nag here is that I don’t want to have 2 or 4 ‘build’ folders for my assets. Just one folder (that I can trash as a quick and dirty way to make sure no out of data lingers in the system) would be best. This should be straightforward, matching the output like so:

  • ${INPUT_FILE_DIR}/../../build/${INPUT_FILE_BASE}.blz

Conflating the output from various files (e.g. 2.4x/assets/foo.blend and 2.4x/scenes/foo.blend ) is possible. Collisions are unlikely, however, so I’ll keep it this way.

Polish?

Silencing the output?

When running blender directly from the desktop, getting console output to show up can be tricky. XCode surely doesn’t have this problem. All debug output appears in the messages window. Too much of it, in fact. Worse, something forces the item matching the translation script to expand.

No luck. I was assuming (maybe wrongly) that blender output is displayed because it is sent to stderr. Either way standing messages to stderr or stdout will yield the same result. Until further notice if I want to avoid script messages blotching the output, I need to disable debug output manually.

Displaying errors during the export process

An issue serious enough that putting it under ‘polish’ may be foolish : how to ensure that XCode will alert us when export errors occur? And by the way, what is an export error?

I tried my luck again, this time by looking at the unit test framework output. I thought XCode may be detecting a simple pattern to identify errors, and it is. The pattern is something like this:

  • error: description of error

The space after the colon in error : is required. In python (~2.7), use:

print (“error: something went wrong”)

And XCode will detect the error and display a flamboyant exclamation mark. Neat.

This won’t stop the build from completing but a red exclamation mark is difficult to ignore so it will be enough.

What is an error, then?

A py script failing while running inside blender does NOT cause an error to appear in XCode. This is because blender returns with exit code ‘OK’ regardless. Now that we know how to signal errors to XCode, we can insert validation related errors. But we also want to report an error when our script fails unexpectedly:

    try:
        exportAssets(PATH)
    except:
        print “error: in blender script: “, sys.exc_info()[0], “(see messages window)”
        raise

raise causes the error to propagate, allowing detailed information to appear in the log.

caveat: If the script contains a syntax error, it won’t run. In this case blender will report the error and exit, however we cannot alert XCode since the script didn’t even start running.

(how to cope with) limitations

Limitations with the approach I described derive from the atomicity of the conversion. It has to be done like this:

input file => output file or directory

For level edits, it is fine.

I see a problem when several files want to output to the same deployment directory. For example, it often makes sense to define actors as shared assets (same creatures used in different levels). Although it is a bit messy, it is often convenient to keep several actors in the same blend file. But then what we’ll end up doing is this:

  • myCreatures1 => targetFolderA
  • myCreatures2 => targetFolderA

This is bad in at least two ways:

  • We should cleanup targetFolderA before exporting (to avoid outdated files lingering in the build)
  • When exporting myCreatures2, we’ll end up copying over again data output by myCreatures1.
If we export to separate folders (myCreatures1Out/, myCreatures2Out/) the deployment structure becomes inconvenient. We may end up manually adding every output folder to the path used by a loader, and if we do so retrieving assets will take more time.
For shared assets, we have to choose. Either we start from a file listing all shared asset files and this becomes the input – processed by a special script – or we agree that each file will contain one actor / item. While the first solution is somewhat constraining it does help keeping things neat and requires less work.
So, do what?
Although not ideal, a solution is to modify the way the loader retrieves data blocks. I want to do this conservatively.
Before, a data block would be retrieved by creating a file name against the resource paths (e.g: rabbit => retrieve the mesh called rabbit.dbk)
After, a data block can also be retrieved by matching a file name against a path in a designated shared resource folder (this would have to be the bundle’s root I’m afraid) : rabbit => rabbit.blz/rabbit.dbk

Additionally, the name of the blend file for a shared resource should match the name of the data it contains.

Much easier than editing/adding project wizards, making simple changes to file templates to suit your needs is a breeze.

All you have to do is search for FILEBASENAME under your XCode install path; the filepath for each __FILEBASENAME__ .h / .m file clearly indicates what the template is used for; additionally, templates can be opened directly in XCode.

Nothing’s perfect. XCode is kind of usable but there are ways it could be greatly improved. Instead of posting a rant, I have decided to structure my requests a little and share them with you.

__________________________________________________________________

If you like this article

You’re an XCode user. You agree that this stuff is important.
Feel free to paste this article on your blog and submit bug reports / enhancement requests.
Duplicates help developers understand what is important to their users.

__________________________________________________________________

1. XCode should have a feedback button in the Help menu

We are power users. We know what we want. We know what we need. If I want to provide feedback about XCode I have to poke around the Apple site for ages, fill in forms, and finally ask myself whether it is a bug, an enhancement request or ‘none of the above’ that I want to file.

XCode users are worth money to Apple. Let us help you improve our IDE.

2. Creating and deleting files is slow and error prone

The file creation wizard should guess which folder we want to put a file in using the folder files in the same group are located in. I don’t know how the default location to create a file is determined, I just know it doesn’t do that. So I regularly find misplaced files.

XCode regularly bails out when trying to delete files; typically this happens because it gets confused about what to delete when the file is under version control. Please improve. Additionally, it is rare that somebody wants to delete an *.h file or *.m file without deleting the counterpart. No assistance provided. Please improve.

3. There is no way (I know of) that a ‘folder reference’ can work with source files

… and if there is one, discovering it should be a breeze.

Massive bummer. You can’t create an XCode project integrating a third party library without updating the list of source files yourself. Whenever the guys who make the library add or remove a file, you have to update the project manually.

The last time I tried using the ‘blue folders’ (the ones that track content automatically) to include source files, the sources were simply ignored by the compiler.

4. Auto-completion doesn’t recognize the header path

Objective C encourages verbose, literate function names. Auto-completion is important to XCode users. Given problem (3), adding the library headers to a project only works when the library is ultra-stable. Otherwise we end up having to re-add the headers on a regular basis.

Whenever adding a static library, XCode should help us locate public headers and sort these annoyances for us.

5. Typing is slow. Indexing is slow. Opening a project is slow

I love my mac; not the next mac. My mac. There’s no reason on blooming ancient earth that a dual-core computer couldn’t handle a weeny bunch of strings and let us input code at the speed of type. My mac is 24 months old, looks brand new and does everything well except running XCode 4.0.2.

6. Provide an option to hide definition/declaration files from the project navigator.

A tri-state button would sit nicely at the bottom of the project navigator along with custom and time based filters. The custom filter can sort of do it but it’s too awkward for such use – if anything it’s expanding the whole workspace recursively.

On this note, the ‘related files’ button in the code window is a poor substitute for the XCode 3 counterparts toggle. It’s cartesian. It’s complex. It’s 2 clicks versus 1. It’s a gimmick overriding a much needed shortcut.

Nor is the ‘assistant view’ quite solving the problem either.

The assistant view is this wacky widget that puts your .h file on the right, puts it on the left, then locks over something ‘altogether different’ that we inadvertently requested. It’s nice to have but for now it is convoluted and forever after it’s dependent on having a lot of screen space.

7. Adding a group causes the project navigator viewport to reset

This is a bug. It’s annoying and distracting. Please fix it.

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.

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