Best way to install a custom cocoa framework

12,710

Solution 1

In the past months, I've learned a lot more about frameworks, so I'm rewriting this answer. Please note that I'm talking about installing a framework as part of the development workflow.

The preferred location for installing a public framework (i.e. a framework that will be used by more than one of your apps or bundles) is /Library/Frameworks[link text] because "frameworks in this location are discovered automatically by the compiler at compile time and the dynamic linker at runtime."[Framework Programming Guide]. The most elegant way to do this is in the Deployment section of the Build settings.

As you work on your framework, there are times when you do want to update the framework when you do a build, and times when you don't. For that reason, I change the Deployment settings only in the Release Configuration. So:

  1. Double-click on the framework target to bring up the Target info window and switch to the Build tab.
  2. Select Release in the Configuration selectbox.
  3. Scroll down to the Deployment section and enter the following values:

Deployment Location = YES (click the checkbox)

Installation Build Products Location = /

Installation Directory = /Library/Frameworks

The Installation Build Products Location serves as the root of the installation. Its default value is some /tmp directory: if you don't change it to the system root, you'll never see your installed framework since it's hiding in the /tmp.

Now you can work on your framework as you like in the Debug configuration without upsetting your other projects and when you are ready to publish all you need to do is switch to Release and do a Build.

Xcode 4 Warning Since switching to Xcode 4, I've experienced a number of problems with my custom framework. Mostly, they are linking warnings in GDB that do not really interfere with the usefulness of the framework, except when running the built-in unit-test. I have submitted a technical support ticket to Apple a week ago, and they are still looking into it. When I get a working solution I will update this answer since the question has proven quite popular (1 kViews and counting).

Solution 2

There's not much reason to put a framework into Library/Frameworks, and it's a lot of work: You'd need to either do it for the user in an Installer package, which is a tremendous hassle to create and maintain, or have installation code in your app (which could only install to ~/L/F, unless you expend the time and effort necessary to make your app capable of installing to /L/F with root powers).

Much more common is what Apple calls a “private framework”. You'll bundle this into your application bundle.

Even frameworks intended for general use by any applications (e.g., Sparkle, Growl) are, in practice, built to be used as private frameworks, simply because the “right” way of installing a single copy of the framework to Library/Frameworks is such a hassle.

Solution 3

The conventional way to do this is to have your framework project and its clients share a common build directory. Xcode will search for framework headers and link against framework binaries in the build folder first, before any other location. So an app project that compiles and links against the header will pick up the most-recently-built one, rather than whatever's installed.

You can then remove the cp -r and instead use the Install Location build setting to place your build product in the final location, using xcodebuild install DSTROOT=/ at the command line. But you'll only need to do this when you're finished, not every time you rebuild the framework.

Share:
12,710
Elise van Looij
Author by

Elise van Looij

SOreadytohelp

Updated on June 15, 2022

Comments

  • Elise van Looij
    Elise van Looij almost 2 years

    I have a custom framework that, following the advice in Apple's Framework Programming Guide >> Installing your framework I install in /Library/Frameworks. I do this by adding a Run Script build phase with the following script:

    cp -R  build/Debug/MyFramework.framework /Library/Frameworks
    

    In my projects I then link against /Library/Frameworks/MyFramework and import it in my classes like so:

    #import <MyFramework/MyFramework.h>
    

    This works very well, except that I always see the following message in my debugger console:

    Loading program into debugger… sharedlibrary apply-load-rules all warning: Unable to read symbols for "/Users/elisevanlooij/Library/Frameworks/MyFramework.framework/Versions/A/MyFramework" (file not found). warning: Unable to read symbols from "MyFramework" (not yet mapped into memory). Program loaded.

    Apparently, the compiler first looks in /Users/elisevanlooij/Library/Frameworks, can't find MyFramework, then looks in /Library/Frameworks, does find MyFramework and continues on its merry way. So far this has been more of an annoyance than a real problem, but when runnning unit tests, gdb stops on the (file not found) and refuses to continue. I have solved the problem by adding an extra line to the Run Script Phase

    cp -R  build/Debug/MyFramework.framework ~/Library/Frameworks
    

    but it feels like sello-taping something that shouldn't be broken in the first place. How can I fix this?

  • Elise van Looij
    Elise van Looij over 14 years
    Since the framework is used by several projects, installing it as a private framework is not feasible. I have tried the same thing with the release version (cp -R build/Release/MyFramework.framework /Library/Frameworks) but the result is the same. As for it not mattering where the framework is located as long as ... -- well, words fail me.
  • Elise van Looij
    Elise van Looij over 14 years
    Intriguing, but I found two problems with this approach. First of all, xcodebuild install DSTROOT=/ does cure the "Unable to read symbols" problem. However: 1) When the build directory for the framework was pointed at the common build directory (outside the project folder), xcodebuild somehow would overlook changes made in the framework. The modified date of the framework header files would change, but not hte content(perhaps to do with versioning?). 2) When I changed the build directory back to default build, xcodebuild would install inside the framework another copy of the framework. Weird.
  • NSResponder
    NSResponder over 14 years
    You should consider any answers from cdespinosa regarding the Xcode build system to be authoritative.
  • Elise van Looij
    Elise van Looij over 14 years
    Well, I voted up his answer, so I hope my kneecaps are safe. But I do consider the solution I arrived at more elegant, as it involves fewer changes to the default Xcode settings and eliminates the need for the command line.
  • Elise van Looij
    Elise van Looij over 14 years
    I don't doubt that creating an installer package is a lot of work -- I've never done it and it's not something I look forward to. But since it will need to be done anyway for the apps, I can't see that adding one more for the framework would be such a big deal -- it probably should be bundled into the app installers anyway, unless it proves to be an uncommonly popular framework. All in all, I'm not convinced that keeping the framework private is that important.
  • Raffi Khatchadourian
    Raffi Khatchadourian over 12 years
    I disagree. It's really easy just to copy the .framework bundle to /Library/Frameworks and then import it in other Xcode projects.
  • Nico
    Nico over 12 years
    @RaffiKhatchadourian: But then your application won't work for anyone else. You have to install the framework(s) in L/F on every user's machine; the app won't launch for any user who doesn't have the frameworks in the same location you had them.
  • Raffi Khatchadourian
    Raffi Khatchadourian over 12 years
    @PeterHosey /Library/Frameworks is a standard location for frameworks, so that shouldn't be a problem.
  • Nico
    Nico over 12 years
    @RaffiKhatchadourian: Being a standard location does not ameliorate needing to make an installer of some kind to install the frameworks there on users' machines. It's “really easy to just copy the .framework bundle” there on your own machine, but you need to make an installer for it if you want anyone else to be able to use your app without it crashing on launch. Embedding the framework in the app is simpler for all involved.
  • Raffi Khatchadourian
    Raffi Khatchadourian over 12 years
    @PeterHosey Sometimes it's not possible or ideal to embed a framework in an app. For example, you may have multiple apps using the framework. Also, creating an installation package is very easy with the package creator tool.
  • Nico
    Nico over 12 years
    @RaffiKhatchadourian: Multiple apps using the framework doesn't make /L/F preferable (the installation and uninstallation hassle still outweighs it), and PackageMaker looks easier than it really is and doesn't help users uninstall the framework if they decide they don't want it.
  • Raffi Khatchadourian
    Raffi Khatchadourian about 12 years
    @PeterHosey I disagree with your first statement. In any case, PackageMaker got an update recently with Xcode 4.3. It should be easier to use now. Also, uninstallation on Mac has always been a lacking feature.