Static Objective-C Libraries
While looking for something completely unrelated, I stumbled across the solution to a problem I encountered a while back: how to create a static library containing Objective-C code. Objective-C does not define linker symbols the same way that C and C++ do, due to the dynamic nature of the language. Specifically, a symbol is not created for each method, just each class. The problem manifests itself when trying to create a static library containing categories on existing classes, say NSString
. When compiling against this static library, the code for the categories is not linked into the final executable. The result is a runtime “selector not recognized” exception.
In order to understand why, we must go back to how static libraries are implemented in Unix, and hence OS X. Static libraries are just a collection of object files combined into a single file called an archive. As an optimization, the linker only chooses the object files that are required to resolve symbols. This means that even if a static library contains 100 object files, the linker may only pick one of them, thus reducing the amount of code in the final executable. Back to Objective-C: if I use a class, say NSString
, the compiler generates an undefined symbol for the the class, but not each method I use. Thus if the class and a category are in two different object files, the linker has no way to know it needs to link in the category object file. This is a non-issue for frameworks, which are dynamic libraries, where linking happens at runtime. But for static libraries, this results in code for the category not being included in the final executable. The solution: link the executable with the -ObjC option. The ld(1)
documentation for this option is:
Loads all members of static archive libraries that define an Objective C class or a category.
Aha… just what I want! This forces the linker to pull in the object file with the category into the executable. One downside to this is you lose the optimization the linker typically does with static libraries. If I link against a static library with 100 categories, each in separate object files, and I only use one, the linker pulls them all in. This also puts the burden on the library user to use a non-standard linker flag. It would be nice to link the static library specially such that the library creator could tag this library as containing Objective-C. But due to the limitations of Unix static libraries being a collection of object files, this is not possible. I’ve long been annoyed with static libraries on Unix, and this is just another reason to dislike them. The way Windows does static libraries is actually much nicer. A full rant will have to wait for another post. However, static libraries do have their uses, and it’s nice to know it is possible to put Objective-C code in them.