How to properly set run paths, search paths, and install names?

BigMacAttack picture BigMacAttack · Mar 21, 2012 · Viewed 26.9k times · Source

I have a collection of projects that I'm compiling as dynamic libraries. Each of these .dylibs depend on other various .dylibs that I would like to place in various other directories (i.e. some at the executable path, some at the loader path, some at a fixed path).

When I run otool -L on the compiled libraries, I get a list of paths to those dependencies but I have know idea how those paths are being set/determined. They almost appear pseudo random. I've spent hours messing with the "Build Settings" in Xcode to try and change these paths (w/ @rpath, @executable_path, @loader_path, etc.) but I can't seem to change anything (as checked by running otool -L). I'm not even entirely sure where to add these flags and don't really understand the difference between the following or how to properly use them:

Linking - "Dynamic Library Install Name"
Linking - "Runpath Search Paths"
Linking - "Other Linking Flags"
Search Paths - "Library Search Paths"

When I run install_name_tool -change on the various libraries, I am able to successfully change the run path search paths (again as verified by running otool -L to confirm).

I'm running Xcode 4.2 and I'm very close to giving up and just using a post-build script that runs install_tool_name to make the changes. But its a kludge hack fix and I'd prefer not to do it.

Where can I see how the search/run paths for the dylib dependencies are being set?
Anyone have any ideas on what I might be doing wrong?

Answer

Kurt Revis picture Kurt Revis · Mar 21, 2012

Typically, in my dylib's target, I set INSTALL_PATH aka "Installation Directory" to the prefix I want (e.g. @executable_path/../Frameworks).

I leave LD_DYLIB_INSTALL_NAME aka "Dynamic Library Install Name" set to its default value, which is $(DYLIB_INSTALL_NAME_BASE:standardizepath)/$(EXECUTABLE_PATH).

Xcode expands that based on your target's name, so it might end up being @executable_path/../Frameworks/MyFramework.framework/Versions/A/MyFramework, for instance.

The important thing to realize is that the install path is built into the dylib, as part of its build process. Later on, when you link B.dylib that refers to A.dylib, A.dylib's install path is copied into B.dylib. (That's what otool is showing you -- those copied install paths.) So it's best to get the correct install path built into the dylib in the first place.

Before trying to get all the dylibs working together, check each one individually. Build it, then otool -L on the built dylib. The first line for each architecture should be what LD_DYLIB_INSTALL_NAME was showing you.

Once you have that organized, try to get the dylibs linking against each other. It should be much more straightforward.