I want to change the rpath of an executable using install_name_tool
, but I can't figure out what the rpath is right now. install_name_tool
requires both the old and the new rpath's to be given on the commandline. What command can I use to print the rpath of an executable under macOS?
@rpath stands for Runpath Search Path. In the Xcode, it's set with LD_RUNPATH_SEARCH_PATH setting. In ld command tool it's set with -rpath parameter when linking. So it's a search path for the linker. Runtime Search Path instructs the dynamic linker to search a list of paths in order, to locate the dynamic library.
In computing, rpath designates the run-time search path hard-coded in an executable file or library. Dynamic linking loaders use the rpath to find required libraries. Specifically, it encodes a path to shared libraries into the header of an executable (or another shared library).
First of all, understand that an executable doesn't contain a single rpath
entry, but an array of one or more entries.
Second, you can use otool
to list an image's rpath
entries. Using otool -l
, you'll get output like the following, at the very end of which are the rpath
entries:
Load command 34 cmd LC_LOAD_DYLIB cmdsize 88 name /System/Library/Frameworks/AppKit.framework/Versions/C/AppKit (offset 24) time stamp 2 Wed Dec 31 19:00:02 1969 current version 1038.32.0 compatibility version 45.0.0 Load command 35 cmd LC_RPATH cmdsize 40 path @loader_path/../Frameworks (offset 12)
Look for the LC_RPATH
commands and note the path under the path
entry.
EDIT: regarding what @loader_path
is: it's a generic and dynamic way to refer to the Mach-O object that wants to do the loading of the framework.
While this is a rather contrived example, I think it should get the point across. Let's say we have an app MyApp.app
that uses a framework MyFramework.framework
. We'll also say that to function properly, I require that my app is installed in the /Applications and nowhere else. So the structure of said app and framework would be the following:
/Applications/MyApp.app/Contents/MacOS/MyApp
(executable) /Applications/MyApp.app/Contents/Frameworks/MyFramework.framework/MyFramework
(Mach-O dylib)
If we were to run otool -L
(note the capital L) on the executable it would show the following regarding MyFramework:
@rpath/MyFramework.framework/Versions/A/MyFramework /System/Library/Frameworks/Cocoa.framework/Versions/A/Cocoa /System/Library/Frameworks/Foundation.framework/Versions/C/Foundation /usr/lib/libobjc.A.dylib /usr/lib/libSystem.B.dylib ....
Note that because the MyFramework.framework uses an @rpath
install name/path, we'll need to have runtime search path entries that will be substituted in place of @rpath
at runtime. Now, I could have a single rpath entry of:
/Applications/MyApp.app/Contents/Frameworks
That would work, and at runtime the two parts would be put together:
/Applications/MyApp.app/Contents/Frameworks
+ /MyFramework.framework/Versions/A/MyFramework
==
/Applications/MyApp.app/Contents/Frameworks/MyFramework.framework/Versions/A/MyFramework
Obviously, hard-coding a path like this is not ideal, as simply moving the app to a different folder or renaming the app itself would cause linking to fail.
@loader_path
is simply a dynamic way to refer to the app's executable wherever it may exist on the filesystem. In this particular case, at runtime it will be filled in with the path to the running executable: /Applications/MyApp.app/Contents/MacOS/MyApp
. Then we can say that to find the MyFramework.framework, you simply go up a directory and over to Frameworks
.
You can use otool -l myexecutable
, but this prints a lot of unnecessary information if you are interested only in the list of rpaths.
You can filter the output of otool -l
to the relevant rpath entries by
otool -l myexecutable | grep RPATH -A2
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With