understanding: macos rpath resolution (wip)

tl;dr

macos has a unique approach to runtime library path resolution (RPATH) that differs from Linux. Understanding how RPATH works in macos is crucial for properly distributing applications with dynamic libraries.

the basics of dylib loading

On macos, dynamic libraries (.dylib files) are loaded at runtime using a set of search paths. When your application needs a library, macos follows a specific resolution order:

┌─ macos dylib resolution order ─────────────────┐
│ 1. LC_RPATH                                    │
│    ↓                                           │
│ 2. LC_LOAD_DYLIB paths                         │
│    ↓                                           │
│ 3. DYLD_LIBRARY_PATH (if not SIP protected)    │
│    ↓                                           │
│ 4. System paths (/usr/lib, etc.)               │
└───────────────────────────────────────────────┘

The key concept here is @rpath, which serves as a placeholder for a list of search paths defined by the executable or libraries. Intention is to provide flexibility and makes your application more portable.

special path variables

macos provides several special path variables that can be used in RPATH entries:

VariableMeaning
@executable_pathDirectory of the main executable
@loader_pathDirectory of the file being loaded
@rpathSearch path list defined by LC_RPATH commands

checking rpath information

You can examine RPATH information using these commands:

otool -L myapp

otool -l myapp | grep -A2 LC_RPATH

install_name_tool -add_rpath @executable_path/../lib myapp

wrap up

Understanding RPATH in macos is essential for creating portable applications. By using @rpath, @executable_path, and @loader_path appropriately, you can ensure your application finds its dynamic dependencies no matter where it’s installed.

For a more detailed explanation, the CMake community wiki provides an excellent reference on RPATH handling across different platforms.