free love frustration

Either I’m missing something or it’s ridiculously hard to build a self-contained plugin architecture for an OS X app.

In particular, getting all the dynamic libraries to look for their dependencies in the right place is much harder than it should be. The “install” location of a library (INSTALL_PATH, aka “Installation Directory” in XCode 3’s build options pane) is set at build time on the library itself. Then, when a client links to a library, the linker statically writes that install path into the client of the library. Then the client knows where to look for its libraries at runtime.

That makes sense if all your libraries can live in one big collection at some absolute path on everyone’s system, like /usr/blah/blah or /Library/Application Support/MyApp/. But hard-coded absolute paths just give me the willies. Furthermore, I want people to be able to drag and drop my application (or plugin) and have everything go with it. That is more valuable to me than the remote possibility that these particular frameworks will be updated independently of the app/plugin using them.

Thankfully, in OS 10.4, Apple provided the aliases @executable_path and @loader_path. Put them at the front of your INSTALL_PATH in cases where you know your library will be living relative to some executable, or relative to some other library, respectively. They resolve, at load time, to the path to the executable or library image.

I find it amazing that it took until Tiger for Apple to provide those options. Did I mention that it’s also weirdly hard to find information about them? And that in 10.5 there’s a new option, @rpath? It just seems like such an obvious thing to want to do, I guess I’d think it would be more front and center, more easily accessible.

But so. I have a plugin that wants to depend on two private frameworks. Call them Bob and Ted. And … uhhh, let’s call my plugin Alice.*

This is what it seems I have to do. I have to set the INSTALL_PATH variable when the frameworks are built to @loader_path/../Frameworks so that Alice can find them when she decides she wants them. That’s fine, but it turns out that Ted also depends on Bob. That is, Ted will want to load Bob, and Alice will want to load both Bob and Ted. So unless I’m missing something, I have to set Bob’s INSTALL_PATH to be relative to Ted’s eventual image location, build Bob, then build Ted, then use install_name_tool to change Bob’s INSTALL_PATH to be relative to Alice before building Alice.

Why can’t I just tell Alice to always look for Bob and Ted where I know they’re going to be, relative to her? Why do I have to tell Bob to tell Ted where he’ll be, then tell Bob to tell Alice where he’ll be, and most annoyingly, why the heck do I have to write a shell script to do all of this in version 3 of XCode?

Complicating all of this, of course, is the fact that my app (Carol, natch) will have to dynamically load Alice, who’s got to load Bob and Ted (who also has to load Bob), at run-time, and so Carol is the one who winds up complaining when Alice can’t find Bob because I can’t get Bob to tell Alice where is he after I told him to tell Ted where he is because install_name_tool insists on knowing the old INSTALL_NAME path before it will change to the new one.

Or something. At any rate, it’s not working. Meh.

update: OK, it turns out that I misunderstood how install_name_tool works: the -id argument lets you set the install path on the library image without having to know its current value. The -change argument lets you set the this-dependent-library-lives-here value (like what you get from the -L switch passed to otool) on the client of the library. So it makes sense that you have to give it the old value.

Uh, that is, you can tell Ted and Alice where to find Bob; you don’t have to tell Bob to tell Ted and Alice where he is before they try to load him.

* Cultural reference: Bob & Carol & Ted & Alice … which I’ve never seen.

Leave a Reply

You must be logged in to post a comment.