Including third party framework in Xcode project

1.5k views Asked by At

I'm having a pretty hard time getting a TagLib framework properly included in an OS X Objective-C(++) project in Xcode 6. Ultimately, my goal is to have the framework be distributed with my application bundle so everything is fully self-contained. Since I'm not sure where I went wrong, let me start with what I've done so far, from the very beginning.

I grabbed TagLib from GitHub and built it into a Framework with CMake. These are the build options I used:

cmake -DCMAKE_BUILD_TYPE=Release \
-DBUILD_FRAMEWORK=ON \
-DCMAKE_OSX_DEPLOYMENT_TARGET=10.10 \
-DCMAKE_OSX_ARCHITECTURES="x86_64"

These were what I though were "acceptable minimums" and they came from the TagLib INSTALL readme. After a make and make install the framework ended up in /Library/Frameworks. The framework has 1.14.0 directory inside Versions--this is important (I think) for one of my issues.

After creating my project in Xcode, the next thing I did was add the framework to "Linked Frameworks and Libraries" in my app's target. I then added a new "Copy Files" Build Phase for both my app and test targets, to copy the framework into the bundle's Frameworks directory. From there, I added /Library/Frameworks/tag.framework/Headers to my app and test target's "User Header Search Paths". The last thing I did was add the framework to my test target's "Link Binary With Libraries" Build Phase.

At this point, if I don't codesign anything, my project will build. However, if I try to run the app or tests, I get this error (names removed from paths):

dyld: Library not loaded: /usr/local/lib/tag.framework/Versions/1.14.0/tag
Referenced from: /Users/.../Library/Developer/.../Build/Products/Debug...
Reason: image not found

It makes perfect sense that dyld can't find the framework there because it wasn't installed there. But why is it looking there in the first place? My app target's "Runtime Search Paths" is @executable_path/../Frameworks and my test target's includes that along with @loader_path/../Frameworks.

Now, if I try to codesign my project, I can't even get it to build. I choose "Mac App Store" for "Signing", choose my profile for "Team" and re-check the "Code Sign On Copy" box for my "Copy Files" Build Phase, and codesign spits this back:

/Users/.../Library/Developer/Xcode/DerivedData/.../Build/Products/Debug/.../Contents/Frameworks/tag.framework/Versions/A: No such file or directory
Command /usr/bin/codesign failed with exit code 1

Again, this message makes perfect sense because there's no A directory inside Versions--just 1.14.0 and the Current symlink. But why is it looking for A at all?

So, my question in its most general form is, how do I properly include this framework into an Xcode project so that I can 1) have no external dependencies (ie, framework is in the bundle) and 2) have it codesign? My process was a conglomeration of things I've read on SO and the Apple Developer site, but I'm not at all sure it's even close to being correct. The only other thing I've seen mentioned that I haven't tried is using "install_name_tool" and "otool", but I'm not sure what I need to change or which of those two tools to use.

Any help or advice is greatly appreciated!

1

There are 1 answers

0
Rob Arnold On

This is a well written question. I came across it when looking for an answer to my problem, which was basically the same thing. I figured mine out, and think you are on the right track.

You do need to fix the structure of the framework. Not sure why things are built differently, but basically, the 1.14.0 directory should be A instead, and Current should be a symlink to it. That's what I did, and that handles that part. Others have hacked around it by just deleting the Current symlink and moving the 1.14.0 dir to Current. I frankly don't know why the signing tool doesn't go to sign Current, follow the symlink, and just work. I did notice there is a build setting for framework version under Build Settings->Packaging that is set to A - perhaps it could be changed to Current or 1.14.0? I punted and just moved 1.14.0 to A and deleted and remade the symlink or Current->A (if inside the framework/versions dir, ln -s A Current).

At this point, I think code signing will work for you, and you'll be back to your other problem at runtime. That's because the frameworks install path wasn't set properly at build time. There's different options for that, but the most flexible is to change the build for the framework to use @rpath as the install location, or just fix it after the fact like I did using install_name_tool. For example, if you CD to the dir containing the tag.framework package,

install_name_tool -id @rpath/tag.framework/Versions/A/tag tag.framework/Versions/A/tag 

Make sure to clean before building if you are changing this stuff between builds, unless you are sure you have the dependencies on the framework set up. Good luck. This was annoying for me to work out too.

Tag lib should update their build process too, I suspect, though the way I read the framework docs from Apple, I thought that the dir names A, B, etc. were just examples, not the firm rule, and that the real rule was that Current was a symlink, and there wasn't extra cruft allowed outside of specified things at specified places.

Links that helped me through my wandering path: https://developer.apple.com/library/mac/documentation/MacOSX/Conceptual/BPFrameworks/Concepts/FrameworkAnatomy.html http://blog.gmane.org/gmane.comp.kde.devel.taglib/month=20081001/page=1 (and the mikeash and driben links from the above too! - I can't currently post more than 2 links)