Shipping libical in a Mac Application Bundle
I have been working with the libical library for parsing and manipulating iCal data for a while now, and it works fine (even though we probably don't need it anymore, once Leopard is out). Now that I have finally put my code for semiBlog online, a number of new problems arose. So here is a little summary of what those problems were and how I solved them:
- Making sure the library is a universal binary: Generating universal binaries in Xcode is very simple. However, when you want to turn a configure/make based project (like libical) into a universal binary, things get a little more complicated. Luckily, this document on Apple's developer pages explains it all.
- Bundling a .a-type library with an application bundle: This is actually very easy. You need to do three things.
- Drag and drop the library files (in the case of libical those are libical.a, libicalss.a and libicalva.a) into the "Linked Frameworks" group of your project in Xcode (a little trick if you don't know how to get a finder window for hidden folders like
/usr/local
: move into the folder in the terminal window and then open a finder window for it by typingopen .
). - Set the header search paths correctly: make sure you point the "User Header Search Paths" of your target to the right location (e.g.
/usr/local/include
). - Set the library search paths correctly: make sure you point the "Library Search Paths" of your target to the right location (e.g.
/usr/local/lib
).
- Drag and drop the library files (in the case of libical those are libical.a, libicalss.a and libicalva.a) into the "Linked Frameworks" group of your project in Xcode (a little trick if you don't know how to get a finder window for hidden folders like
- Make sure libical finds those time zone info files: libical needs to have access to a bunch of time zone definition files. They are located in in a
share
sub-directory of the libical install directory. (.../share/libical/zoneinfo
). By default, libical will look for that folder in the location it was first installed, which is fine in many cases. However, when you distribute your project's code or the application bundle, things can get messed up. If libical doesn't find the time zone information, you get errors like those:icalerror.c:99: FILE: An operation on a file failed. Check errno for more detail. icalerror.c:100: failed assertion `0'
That's why you need to callset_zone_directory()
at runtime, and pass it the right path. I copy the zoneinfo folder into the application bundle (using a bunch of Copy Files build phases), and then askNSBundle
for the right path, like so:
NSBundle *pluginBundle = [NSBundle bundleForClass: [SBICalInterface class]]; NSString *zoneinfoPath = [NSString stringWithFormat: @"%@/zoneinfo", [pluginBundle resourcePath]]; set_zone_directory([zoneinfoPath cString]);(note that I use
bundleForClass:
because the zoneinfo folder is actually inside a plugin bundle within the real application bundle. If it was in the application bundle directly, I could just call mainBundle
)
0 Comments:
Post a Comment
<< Home