Search This Blog

Wednesday, May 18, 2011

XCode 4 Static Library Hell

The other day I set about creating some static libraries in XCode4 for a project I was working on.

The project involved a couple of libraries of .CPP (C++) code that I needed to integrate into my iPad project.

Basically the C++ code was a stand-alone library of functionality that I needed to call from my iPad application.  I wanted the libraries to be statically linked, i.e., built into the application, as opposed to becoming dynamic libraries linked at run time.  I also wanted to use the LLVM GCC 4.2 compiler because the rest of my project was built using this compiler.  A final requirement was that the library work on the iPhone, iPad, both iPhone and iPad simulators for debugging, and on Mac OSX.

I started out by building the libraries by hand with some scripts provided by with the library.  Basically the scripts looked like this initially:

    gcc -O2 -fno-rtti -Wall -fno-strict-aliasing -c $(SRCS) $(INCZ) $(DEFS)
    ar rc lib.a *.o


This created lib.a which I could link with a second script that compiled a .c file and linked it to the library:

    g++ -O2 -fno-rtti -o app $(SRCS) $(INCZ) lib.a

Now using XCode 3.2 makes this very easy.  You simply create a new project, select either iOS/Library or Mac OSX/Framework & Library, add your files, check your compiler settings, and build.


In the case of Mac OSX you can set whether you want a build for production or test.  I also needed to create both 32-bit and 64-bit versions of my app.

For 32-bit OSX I could use the existing command line and just change it as follows:

    llvm-gcc -O2 -arch i386 -fno-rtti -Wall -fno-strict-aliasing -c $(SRCS) $(INCZ) $(DEFS)

    ...
    llvm-g++ -O2 -fno-rtti -o app $(SRCS) $(INCZ) lib32.a

Both llvm-gcc and gcc both create the same type of .o output files for the library. 

I then replaced the second command line, llvm-g++, with an XCode4 project for a Mac OSX 32-bit application.  I included the .a library and the second pass .c files and everything linked and ran just fine.

For a 64-bit OS X app I changed "-arch i386" to "-arch x86_64" to create a "lib64.a".

However, now I was left with two libraries in a project where I only wanted one.  That way I could simply toggle the project "scheme" to 32 or 64 bit.


To do this I used lipo.  This app allows you to combine libraries together.  Somehow XCode then knows which architecture (as defined by -arch) to pull out at link time to build the app.  You just say

  lipo -create $(LIB64) $(LIB32) -output commonosxlib.a

Now you can include commonosxlib.a in your projects (XCode 3.2 or 4) and the right library will be linked based on the selected application bit size.

I next tried this same scheme for the iPhone.  I changed "-arch 386" to "-arch armv6" thinking that this would be easy.

No dice.

I got strange errors:

  llvm-gcc-4.2: error trying to exec '/usr/bin/../llvm-gcc-4.2/bin/arm-apple-darwin10-llvm-gcc-4.2': execvp: No such file or directory

Now what?

I went back to XCode 3.2 and created a new project as above (iOS/Library), added the source, targeted the iPhone, and boom - I had a iPhone library.  I also had to make a second build targeting the simulator (because that actually is 386-type architecture as opposed to arm).

I used the same lipo trick to build a common lib for simulator and iphone and I was done - that way I could have one .a in my iPhone/iPad project for both the actual device and the simulator.

The libraries work just fine in XCode4 projects.

Now I figured I could do all of this library work in XCode4 eliminating the need for XCode 3.2.

That's where the fun began.

I found this article which claims to accomplish this.

The only problem was that after hours of thrashing with the XCode4 library stuff I could not get it to produce a .a file no matter how hard I tried.  I was able to follow all the steps but no libraries that I could find ever came out.

I am sure I could create workspaces in XCode4 and import the XCode 3.2 projects in order to cheat and get everything all into one place but at this point I am so pissed off about how ugly the library building is in XCode4 that I probably won't bother.

Fortunately the library is a very static one and I can afford some ugliness just to stay away from the XCode4 nonsense.

Apple's XCode4 is nice if you don't do anything but build your simple project from scratch.  But as soon as you get into all the the "scheme's" and other uglies things quickly fall apart.  There is no good way I have found to see what its actually doing (unlike 3.2 which created logs).  I think 4 creates logs but they are in weird places.

Oh well - I created this post so others would not bother with XCode4 and libraries until Apple comes up with something nicer.  It took me less than one minute to create the iPhone library (and I am not an XCode wiz by any means).  After about four hours with XCode4 I gave up...

No comments:

Post a Comment