Last week, Mike Ash wrote a post describing the different install name keywords recognized by the Mac OS X dynamic linker: @executable_path, @loader_path, and @rpath. I wanted to chime in with a bit of advice: if at all possible use @rpath.

This gist is, if you’re targeting 10.5 or later, use @rpath. There’s no reason I can think of to still use @loader_path. If you’re still on 10.4, use @loader_path. And let’s hope that you’re still not targeting 10.3 and earlier, so forget that @executable_path ever existed. There’s really never a good reason to use @executable_path on 10.4 and later.

As Mike wrote, @rpath is the most flexible of the three options. The big benefit that I see is that the same binary of a framework or dynamic library can be used embedded in a app bundle, by a command line tool, or put in ~/Library/Frameworks/. Basically, it allows you to use the framework wherever you want by putting the onus on the linking app or bundle to define where to find it.

The only major downside is that @rpath requires 10.5 or later; however, with 10.6 already shipping, there’s increasingly fewer reasons to support anything earlier than 10.5.

So how do you actually use @rpath? Ideally, I think that targets should be setup to use @rpath out of the box (see rdar://7396127), but unfortunately it takes a bit of legwork.

As of Xcode 3.x, you set the Installation Directory build setting of the framework (or library) target to just @rpath:

This will set the install name to something like this for frameworks:

@rpath/SpiffyKit.framework/Versions/A/SpiffyKit

And something like this for dynamic libraries:

@rpath/libspiffy.dylib

The linking application now needs to define what the @rpath expands out to. For any bundle, such as an application, framework, or plugin, you’d add @loader_path/../Frameworks to the Runtime Search Paths build setting to find embedded frameworks:

Note that you’re still using @loader_path here,as it’s still useful to find the framework relative to the actual binary.

If you want to embed dynamic libraries, it’s probably a good idea to put them in their own directory, say Libraries along side the Frameworks directory in the bundle. If you do this, add @loader_path/../Libraries to the Runtime Search Paths build setting, too. Remember, you can have more than one Runtime Search Path.

I’ve created a sample app project with an embedded framework project, both setup to use @rpath, on BitBucket called rpath-demo

% hg clone http://bitbucket.org/ddribin/rpath-demo/

It should compile and run on 10.5 and 10.6 using Xcode 3.0 or newer.