1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74
|
#!/bin/bash
# A macOS executable linked to dynamic libraries will either link to a full path
# or an rpath (a series of which will be specified in the binary). In order to
# have a self-contained app bundle, we need to copy the external libraries into
# the bundle, and then update the executable to use @executable_path to point
# within the bundle.
if [[ $(uname) != "Darwin" ]]; then
echo "This script is only useful for macOS"
exit 1
fi
if [[ $# != 1 ]]; then
echo "Usage: $0 path/to/name.app"
exit 1
fi
# Find the path to the actual executable in the app bundle
appBundle=$1
exeDir="$appBundle/Contents/MacOS"
exe=$(find "$exeDir" -type f -perm +111 | grep -v dylib)
if [[ ! -f $exe ]]; then
echo "No executable file in app bundle ($appBundle/Contents/MacOS)"
exit 1
fi
# Find the rpath paths
rpaths=$(otool -l "$exe" | grep "path " | awk '{print $2}')
if [[ $rpaths != "" ]]; then
echo "@rpath:"
for rp in $rpaths; do
echo " $rp"
done
fi
# Set IFS so that newlines don't become spaces; helps parsing the otool -L output
IFS='
'
# Copy any external libraries and change the library paths to @executable_path
libs=$(otool -L "$exe" | grep -v "$exe" | grep -v /usr/lib | grep -v /System | awk '{ print $1; }')
for lib in $libs; do
if [[ ${lib:0:1} != "@" ]]; then # external library with a regular path
libname=$(basename $lib)
# copy the external library, resolve symlink chain
cp -aRL "$lib" "$exeDir/$libname"
# change its path in the executable
newpath="@executable_path/$libname"
echo "$lib -> $newpath"
install_name_tool -change "$lib" "$newpath" "$exe"
elif [[ $lib == @rpath/* ]]; then # external library with @rpath
libname=${lib:7}
# copy the external library. Since it uses an rpath, we need to
# prepend each rpath to see which one gives a valid path
for rp in $rpaths; do
if [[ -f "$rp/$libname" ]]; then
cp -aRL "$rp/$libname" "$exeDir/$libname"
break
fi
done
# change its path in the executable
newpath="@executable_path/$libname"
echo "$lib -> $newpath"
install_name_tool -change "$lib" "$newpath" $exe
fi
done
# Remove rpaths
for rp in $rpaths; do
install_name_tool -delete_rpath "$rp" "$exe"
done
|