Sunday, June 10, 2012

Xcode workspaces and external libraries.

A lot has been said about Xcode workspaces. Still, when using the xcode workspace feature to add dependencies on external (static) libraries, you might still stumble upon the following error:

clang: error: linker command failed with exit code 1 (use -v to see invocation)

ld: warning: ignoring file /Users/michaeljackson/looma/libs/build/Debug-iphoneos/libMapView.a, missing required architecture i386 in file
Undefined symbols for architecture i386:

...

Let's think about the steps that where taken before this error emerged.

  1. Some external static library project was added to the workspace.
  2. The static library target from that project was added to 'link Binary with Libraries' in 'Build phases'.
    'link Binary with Libraries' in 'Choose frameworks and libraries to add' pane in 'Build phases'

...

???

Very strange, because xcode promised it would put all build products in a shared 'build' directory, so why can't it find the libraries?

It did in fact find the libraries, because they where there when you selected them from the picker pane in 'Build phases' right??!!

It turns out that xcode does not put all build products in a shared build directory. It ONLY does this if all your xcode projects are in the same folder. So if your project looks like this:

looma
├── libs
│   ├── MapView.xcodeproj
│   ├── hoolahoop.xcodeproj
│   └── nostrils.xcodeproj
├── looma.xcodeproj
└── looma.xworkspace

You're in trouble. There will be a looma/libs/build and a looma/build directory.

In that case, when you select the library from 'link Binary with Libraries', you are selecting just a path to one of the platform specific builds in the looma/libs/build directory, which will probably be 'looma/libs/build/Release-iphoneos'.

As soon as you switch to the ios simulator, you will see the linker error, because your build is still being linked against the 'looma/libs/build/Release-iphoneos' build, which is an arm7 build and not i386.

The solution is to manually edit your library search path
library search path and add the following:

"$(SRCROOT)/libs/build/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)"

That will add the build folder in 'libs' to your search path for the current build scheme.

The same trick will work if you are having a lot of git submodules, where each project has a different structure. You can put them all in a folder and add a line to the library search path that adds the build folder for each project.

No comments:

Post a Comment