Change Mach-O Rpaths Safely with llvm-install-name-tool-20
You will finish with a checked workflow for changing install names or rpaths in a Mach-O binary, while keeping an untouched copy for recovery. The examples use llvm-install-name-tool-20 from Ubuntu package llvm-20, version 20.1.8.
The route
Jump straight to the step you need, or tick off Done means at the end.
Allow about fifteen minutes for a small edit and verification. You need the LLVM 20 tool, a Mach-O executable or shared library that you are allowed to modify, and enough free space for a backup and a temporary output. This is normally an unprivileged operation when the file is in your working tree. Use elevated privileges only if the file is deliberately owned by root, and prefer copying it to a workspace first.
1. Check the installed tool
Start with read-only checks. They confirm the executable and the version before you build a script around its options:
$ command -v llvm-install-name-tool-20
/usr/bin/llvm-install-name-tool-20
$ llvm-install-name-tool-20 --version
llvm-install-name-tool, compatible with cctools install_name_tool
Ubuntu LLVM version 20.1.8
Optimized build.
$ dpkg-query -W -f='${Package} ${Version}\n' llvm-20
llvm-20 1:20.1.8~++20250804090239+87f0227cb601-1~exp1~20250804210352.139
The package revision is longer than the tool's displayed version. Record both when a build must be reproduced. The command is for Mach-O binaries, not ELF files produced by an ordinary Linux build.
Checkpoint
Stop here if command -v finds a different binary or the version is not the one you intended.
2. Read the operation you are about to perform
The input is the final argument. At least one editing option is required, and the documented operations are:
-change OLD NEWreplaces a dependent shared library install name. IfOLDis absent, the option is ignored.-id NAMEchanges theLC_ID_DYLIBidentification name of a dynamic shared library. If repeated, only the last-idis selected.-add_rpath PATHadds a path and fails if that path is already present.-delete_rpath PATHremoves one existing path and fails if it is absent.-rpath OLD NEWrenames an existing rpath and fails ifOLDis absent orNEWalready exists.-delete_all_rpathsremoves every rpath from the binary.
Options can be combined, but add, delete and rename operations must not share the same rpath value in one invocation. Do not use -delete_all_rpaths as a tidy-up shortcut until you have listed every runtime path that the application needs.
The installed executable's --help also exposes -prepend_rpath and response files in the form @FILE, although they are not described by this installed manpage. Treat those as version-specific interface details: check this executable's help and test them separately before putting them into a portable script.
3. Preserve the original before editing
These options modify the named binary in place. Make a metadata-preserving copy, then check that both files exist:
$ INPUT='/path/to/MyApp'
$ BACKUP='/path/to/MyApp.before-install-name-tool'
$ test -f "$INPUT" && cp --preserve=all -- "$INPUT" "$BACKUP"
$ ls -l -- "$INPUT" "$BACKUP"
Replace both placeholder paths with real paths. The test prevents a missing input from being copied under the backup name, but it does not protect you from choosing the wrong file. Check the path and ownership yourself before running an edit.
Warning
Do not overwrite the only copy of a signed, shipped or production binary. Changing Mach-O load commands can invalidate a code signature, and a changed library path can stop an application starting. Work on a build artefact or a disposable copy first.
4. Change one dependent library name
Use -change when the binary refers to a library under the wrong install name. This example changes one absolute name to an @rpath-based name:
$ llvm-install-name-tool-20 \
-change /old/prefix/lib/libwidget.dylib @rpath/libwidget.dylib \
"$INPUT"
$ test "$?" -eq 0 && echo 'install name change completed'
install name change completed
A zero exit status means the tool completed without reporting an error. It does not prove that the application can now find the library. The old name is ignored if it is not listed, so verify the binary with a Mach-O inspection tool available in your toolchain, then run the application or its test suite.
5. Add or rename an rpath
An rpath is a search location used by the loader when a dependency refers to @rpath. Add a required location only when it is not already present:
$ llvm-install-name-tool-20 \
-add_rpath '@loader_path/../Frameworks' \
"$INPUT"
$ test "$?" -eq 0 && echo 'rpath added'
rpath added
If the path already exists, the command reports an error and returns non-zero. In that case, do not keep retrying or switch to -delete_all_rpaths. Inspect the binary and decide whether the existing value is correct.
To replace a stale path, use the old and new values in one operation:
$ llvm-install-name-tool-20 \
-rpath '/old/prefix/lib' '@loader_path/../Frameworks' \
"$INPUT"
$ test "$?" -eq 0 && echo 'rpath changed'
rpath changed
The old value must be present and the new value must not already be listed. If either condition is false, restore the backup before trying a different plan.
6. Verify and recover
Use your platform's Mach-O inspection command to check the result. On an Apple development host, for example, otool -L lists dependent install names and otool -l shows load commands, but those tools are not part of this LLVM manpage and may not be installed on Linux. The useful verification is a before-and-after comparison showing the intended name or rpath changed and unrelated load commands preserved.
If the edit was wrong, restore the original copy. This is a state-changing command, so check both paths first:
$ test -f "$INPUT" && test -f "$BACKUP"
$ cp --preserve=all -- "$BACKUP" "$INPUT"
$ cmp -s -- "$BACKUP" "$INPUT" && echo 'original restored'
original restored
Restoring the file does not restore a previously invalidated code signature or undo a copy that has already been deployed elsewhere. Re-sign or rebuild through the normal release process when the binary is shipped.
Done means
- The executable and package version were checked before editing.
- The input was confirmed to be the intended Mach-O file.
- An untouched backup remains available.
- Only the required install name or rpath operation was used.
- The command returned zero and an independent Mach-O inspection confirmed the intended change.
- You know how to restore the original before deploying the result.