Recently, in my infinite wisdom, I decided I wanted to have a framework that embeds a private framework. Frameworks, are those are uber-cool versions of DLLs complete with multiple versions, public headers, dynamically linked object code, etc for you recent Cocoa converts following along at home.
Before I get started, you may be asking, why ever would I want to do this?
Well, my application is distributed (err, planned to be distributed) with a set of plug-ins that live in the application’s bundle. One of the plug-ins wants to use a framework common to my organization, but not public. I don’t want to develop an installer to put the framework the plug-in needs in the system or user’s library, especially because it’s private to my plug-in’s implementation.
Ok, now that THAT’s out of the way, let’s get back to the subject at hand. When I first started splitting my code up into frameworks I was surprised to learn that the dynamic library at the heart of a framework actually embeds the path it expects to be installed at. Generally speaking having the absolute path of where the framework expects to be installed is not that big a deal, and helps lift OS X out of DLL hell. There are only a handful of standard places you should be putting your framework (such as $HOME/Library/Frameworks, etc).
Since frameworks can contain multiple versions of their code, the DLL hell that .NET helps clean up with the GAC is largely obviated. The main downside to installing your framework in a standard location is well, just that, the installation part.
If your framework is unlikely (or not intended) to be used by more than your one application, a nice alternative to installing it in a standard location is to embed it in your application’s bundle. The standard place for this is in the MyApp.app/Contents/Frameworks directory inside your bundle.
The catch is that you don’t really know where the application is going to be copied by the user (when they say drag/drop it from the .dmg disk image that you distributed it in). The problem with not knowing where it’s going to be copied, is that pesky hard coded path inside of the dynamic library (the one used by the linker to bake references to it into your application).
Fortunately, starting with OS X Tiger, you can use a the string “@executable_path” in the hard coded installation path of your framework. Assuming that you plan to put your private framework in the standard place in your application bundle (the MyApp.app/Contents/Frameworks directory) that path is typically “@executable_path/../Frameworks”. When the dynamic linker attempts to locate the library at runtime, it substitutes the path of the current executable in place of, you guessed it, “@executable_path”. That’s likely to be something like /Applications/MyApp.app/Contents/MacOS.
So far so good. And so far, pretty reasonably documented by Apple.
Now, back to those plug-ins. The plug-ins are themselves frameworks; frameworks that uses other frameworks. Both the standard Cocoa ones, and also the private one-off kind. The symbolic constant “@executable_path” isn’t too much help to us here because we can’t say for sure where the plug-ins are going to live relative to the application. I suppose for my originally stated “plug-ins distributed in the bundle of my application” case I could come up with some really knarly relative path, but what about user installed plug-ins?
There are a few different reasonable places (and I’m sure quite a few unreasonable places) that plug-ins might live on the user’s system. Here again Apple provides nice documentation to describe the details and best practices. So really, “@executable_path” is not quite what we’re looking for.
Thankfully, “@executable_path” has a little less well known friend named “@loader_path”. This friend is exactly the kind of friend we need to implement frameworks with private frameworks. As you may already be able to guess, “@loader_path” is resolved by the dynamic linker at load time to the path of the dynamic library inside the framework bundle (i.e. my plug-in) that is actually doing the loading.
The standard place to put a private framework inside of another framework is “MyCoolPlugin.framework/Versions/Current/Frameworks” (although as per the Apple documentation, your plug-in should pick a unique extension, and not be named with the “.framework” extension). Since the actual dynamic library lives as a direct peer to the “Frameworks” path (rather than under a sub-directory like “MacOS”) the typical installation path for the private framework used by another framework is “@loader_path/Frameworks”.
And there you have it, frameworks with private frameworks!

One caveat here: @loader_path is relative to the first place that will cause the framework to be loaded – the first use of a symbol from the embedded framework. So if you have the following: App.app, A.framework, and B.framework. App.app links to A.framework as well as B.framework. A.framework links to B.framework as well. Now the question is where to embed these frameworks.
Using @loader_path for frameworks A and B means A should get copied to App.app/Contents/Frameworks/A.framework (and A should have its install path set to @loader_path/../Frameworks).
B, however, is used by both the application and framework A. So you could put it in framework A. Going with this assumption, B would have an install location as described above of @loader_path/Frameworks – a slightly different install location from from A (it doesn’t use .. to go up one directory). This is so B can be copied to A.framework/Versions/A/Frameworks/B.framework. In this scenario, the first use of a symbol from the B framework must be done by A.framework. If App.app uses a symbol first, the dynamic linker would look for the framework at App.app/Contents/MacOS/Frameworks/B.framework (and wouldn’t find it there).
You could easily fix this situation by using a symlink from App.app to A.framework’s copy of B.framework. Using a symlink would ensure that regardless of which code path your application takes, it can load B.framework. Using this suggestion, though, I would recommend an install path of @loader_path/../Frameworks for B as well and installing it in A at A.framework/Versions/Frameworks/B.framework instead. It makes things a little more standardized since all private frameworks would have the same install path (and doesn’t really hurt anything for A.framework either). App.app then just makes a symlink to A.framework/Versions/Frameworks/B.framework in App.app/Contents/Frameworks/.
Of course you could also just use @executable_path instead and instruct App.app that it needs to copy B.framework in order to use A.framework.
Why plugins as frameworks?
Hey Pat! My main reason for supporting frameworks for plug-ins (rather than just naked dylibs) is so that the plug-ins can contain their own resources, such as images or scripts. Additionally, it provides a convenient place for the plug-ins to store any dependent private libraries or frameworks (rather than having to install them in the standard system directories).
You should actually use bundles, rather than frameworks, for your plug-ins. In terms of coding it won’t matter much, but you can actually associate an arbitrary path extension with a bundle, and even mark it as another document type for your application so your plug-ins can have their own icons etc.
There’s a standard place for plug-ins inside applications; Xcode has a Copy Files build phase destination for the plug-ins directory as well. And there’s even a method on NSBundle to get the default plug-ins directory for the bundle (for plug-ins embedded in your application).
If you’re publishing your plug-in API, you should also look outside your app for plug-ins, since you don’t want people messing around inside your app since that will do things like break the code-signing seal (if any).
Finally, if you can target Mac OS X 10.5 or later, instead of either @executable_path or @loader_path you can make your frameworks relative to @rpath. Then anything that links them can supply a set of Runpath Search Paths that will be searched for the framework: For example, the app can specify @executable_path/../Frameworks in its Runpath Search Paths, and a plug-in that includes its own Frameworks directory can specify @loader_path/../Frameworks. This should be a lot more like the search mechanisms supported on other operating systems, and also provide as much flexibility as you need for your plug-in architecture.
hi
I used the load_path but my framework can’t archive… It shows me success archive…but no archive file.
how could i solve that problem?
thanks so much