visualboyadvance-m/tools/osx/third_party_libs_tool

312 lines
7.3 KiB
Bash
Executable File
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#!/bin/sh
version=1.2
main() {
# parse options
list=
while [ $# -gt 0 ]; do
case "$1" in
-h|--help|--usage)
usage
quit 0
;;
-v|--version)
echo "third_party_libs_tool $version"
quit 0
;;
-l|--list)
list=1
shift
;;
*)
break
;;
esac
done
if [ $# -ne 1 ]; then
usage
quit 1
fi
mktmp
app_bundle=$(echo "$1" | fully_resolve_links)
case "$app_bundle" in
*.app|*.APP)
if [ ! -d "$app_bundle" ]; then
usage
quit 1
fi
;;
*)
usage
quit 1
;;
esac
set --
OLDIFS=$IFS
IFS='
'
for file in $(find "$app_bundle/Contents/MacOS" -type f); do
case "$file" in
*.dylib)
set -- "$@" "$file"
;;
*)
[ -x "$file" ] && set -- "$@" "$file"
;;
esac
done
IFS=$OLDIFS
frameworks="$app_bundle/Contents/Frameworks"
mkdir -p "$frameworks"
scan_libs "$@" | fully_resolve_links | sort -u | \
while read lib; do
if [ -n "$list" ]; then
echo "$lib"
else
cp -f "$lib" "$frameworks" 2>/dev/null
fi
done
# fix dynamic link info in executables and just copied libs
[ -z "$list" ] && relink_all "$@"
quit 0
}
usage() {
cat <<'EOF'
Usage: third_party_libs_tool [OPTION] BUNDLE.app
Bundle third party dylibs into BUNDLE.app and fix up linkages.
Binaries are searched for in BUNDLE.app/Contents/MacOS .
The dylibs are copied into BUNDLE.app/Contents/Frameworks .
-h, --help, --usage Show this help screen and exit.
-v, --version Show version information and exit.
-l, --list Only list dylibs used by binaries, do not copy or link.
Examples:
third_party_libs_tool ./MyApp.app # bundle and link ./MyApp.app
third_party_libs_tool --list ./MyApp.app # list third party libs used by ./MyApp.app
Project homepage and documentation: <http://github.com/rkitover/mac-third-party-libs-tool>
EOF
}
mktmp() {
tmp="/tmp/third_party_libs_tool_$$"
mkdir "$tmp" || quit 1
chmod 700 "$tmp" 2>/dev/null
trap "quit 1" PIPE HUP INT QUIT ILL TRAP KILL BUS TERM
}
quit() {
[ -n "$tmp" ] && rm -rf "$tmp" 2>/dev/null
exit ${1:-0}
}
scan_libs() {
scratch_dir="$tmp/lib_scan"
mkdir -p "$scratch_dir"
lib_scan "$@"
rm -rf "$scratch_dir"
}
lib_scan() {
for bin in "$@"; do
case "$bin" in
*.dylib)
;;
*)
[ ! -x "$bin" ] && continue
;;
esac
# if binary is already processed, continue
[ -d "$scratch_dir/$bin" ] && continue
# otherwise mark it processed
mkdir -p "$scratch_dir/$bin"
set --
OLDIFS=$IFS
IFS='
'
for lib in $(otool -L "$bin" 2>/dev/null \
| sed -E '1d; s/^[[:space:]]*//; \,^(/System|/usr/lib),d; s/[[:space:]]+\([^()]+\)[[:space:]]*$//'); do
[ "$lib" = "$bin" ] && continue
# check for libs already linked as @rpath/ which usually means /usr/local/lib/
case "$lib" in
'@rpath/'*)
lib='/usr/local/lib'"${lib#@rpath}"
;;
esac
echo "$lib"
set -- "$@" "$lib"
done
IFS=$OLDIFS
# recurse
[ $# -ne 0 ] && lib_scan "$@"
done
}
fully_resolve_links() {
while read -r file; do
# get initial part for non-absolute path, or blank for absolute
path=${file%%/*}
# and set $file to the rest
file=${file#*/}
OLDIFS=$IFS
IFS='/'
for part in $file; do
[ ! -z "$part" ] && path=$(resolve_link "$path/$part")
done
IFS=$OLDIFS
# remove 'foo/..' path parts
while :; do
case "$path" in
*/../*|*/..)
path=$(echo "$path" | sed 's,//*[^/][^/]*//*\.\./*,/,g')
;;
*)
break
;;
esac
done
# remove trailing /s
while [ "$path" != "${path%/}" ]; do
path=${path%/}
done
echo "$path"
done
}
resolve_link() {
file=$1
while [ -h "$file" ]; do
ls0=$(ls -ld "$file")
new_link=$(expr "$ls0" : '.* -> \(.*\)$')
if expr "$new_link" : '/.*' > /dev/null; then
file="$new_link"
else
file="${file%/*}"/"$new_link"
fi
done
echo "$file"
}
relink_all() {
for exe in "$@"; do
# dylib search path for executable
install_name_tool -add_rpath '@loader_path/../Frameworks' "$exe"
OLDIFS=$IFS
IFS='
'
set --
for lib in $(find "$app_bundle/Contents/Frameworks" -name '*.dylib'); do
set -- "$@" "$lib"
done
IFS=$OLDIFS
for lib in "$@"; do
# make lib writable
chmod u+w "$lib"
# change id of lib
install_name_tool -id "@rpath/${lib##*/}" "$lib"
# set search path of lib
install_name_tool -add_rpath '@loader_path/../Frameworks' "$lib"
# relink executable and all other libs to this lib
for target in "$exe" "$@"; do
relink "$lib" "$target"
done
done
done
}
relink() {
lib=$1
target=$2
lib_basename=${lib##*/}
lib_basename_unversioned_re=$(echo "$lib_basename" | sed 's/[0-9.-]*\.dylib$//; s/\./\\./g')
# remove full path and version of lib in executable
lib_link_path=$(
otool -l "$target" 2>/dev/null | \
sed -n 's,^ *name \(.*/*'"$lib_basename_unversioned_re"'[0-9.-]*\.dylib\) (offset .*,\1,p' | \
head -1
)
[ -z "$lib_link_path" ] && return 0
# check that the shorter basename is the prefix of the longer basename
# that is, the lib versions match
lib1=${lib_basename%.dylib}
lib2=${lib_link_path##*/}
lib2=${lib2%.dylib}
if [ "${#lib1}" -le "${#lib2}" ]; then
shorter=$lib1
longer=$lib2
else
shorter=$lib2
longer=$lib1
fi
case "$longer" in
"$shorter"*)
# and if so, relink target to the lib
install_name_tool -change "$lib_link_path" "@rpath/$lib_basename" "$target"
;;
esac
}
# try with sudo in case it fails,
# also suppress duplicate path errors
install_name_tool() {
out_file="$tmp/install_name_tool.out"
if ! command install_name_tool "$@" >"$out_file" 2>&1; then
if grep -Eq -i 'permission denied|bad file descriptor' "$out_file"; then
if ! command sudo install_name_tool "$@"; then
return 1
fi
elif ! grep -Eq -i 'would duplicate path' "$out_file"; then
cat "$out_file" >&2
return 1
fi
fi
return 0
}
main "$@"