264 lines
6.3 KiB
Bash
Executable File
264 lines
6.3 KiB
Bash
Executable File
# Quote the given arguement
|
|
#
|
|
VGL_quote() {
|
|
printf '%s' "${*@Q}"
|
|
}
|
|
|
|
|
|
# Stream producers
|
|
#
|
|
# These produce a stream of escaped new-line terminated items
|
|
#
|
|
|
|
# Stream the given arguments
|
|
#
|
|
VGL_sourceS() {
|
|
(( $# == 0 )) || printf '%q\n' "$@"
|
|
}
|
|
|
|
# Stream the results of find (correctly escapes all filenames)
|
|
#
|
|
VGL_findS() {
|
|
declare options=("$@") file
|
|
find "${options[@]}" -print0 |
|
|
while read -d '' -r file; do
|
|
VGL_sourceS "$file"
|
|
done
|
|
}
|
|
|
|
# Stream the list of directly required libraries from an elf file
|
|
#
|
|
VGL_elfLibsS() {
|
|
patchelf --print-needed "$1"
|
|
}
|
|
|
|
# Stream the resolved libraries from an elf file
|
|
#
|
|
VGL_elfLibsResolvedS() {
|
|
declare file=$1 line
|
|
ldd "$file" |
|
|
while read line; do
|
|
line=${line#$'\t'}
|
|
case "$line" in
|
|
*' => not found')
|
|
line=${line% => not found}
|
|
;;
|
|
*' => '*' ('*')')
|
|
line=${line#* => }
|
|
line=${line% (*)}
|
|
;;
|
|
*' ('*')')
|
|
line=${line% (*)}
|
|
;;
|
|
esac
|
|
VGL_sourceS "$line"
|
|
done
|
|
}
|
|
|
|
# Stream the list of rpaths from an elf file
|
|
#
|
|
VGL_elfRPathS() {
|
|
declare file=$1 entry
|
|
patchelf --print-rpath "$file" |
|
|
while read -d ':' -r entry; do
|
|
[[ -z $entry ]] || VGL_sourceS "$entry"
|
|
done
|
|
[[ -z $entry ]] || VGL_sourceS "$entry"
|
|
}
|
|
|
|
|
|
|
|
# Stream transformers
|
|
#
|
|
# Take in a set of options and transform to a stream of new-line terminated items
|
|
#
|
|
|
|
# Remove all items for which the given command returns false
|
|
#
|
|
VGL_testKeepS() {
|
|
declare command=$1 next
|
|
while read next; do
|
|
set -- "$next"
|
|
if (eval "$command"); then
|
|
VGL_sourceS "$next"
|
|
fi
|
|
done
|
|
}
|
|
|
|
# Remove all items which match one of the given values
|
|
#
|
|
VGL_valuesRemoveS() {
|
|
declare -A values
|
|
declare value
|
|
for value in "$@"; do
|
|
values[$value]=
|
|
done
|
|
while read value; do
|
|
[[ ${values[$value]+yes} ]] \
|
|
|| VGL_sourceS "$value"
|
|
done
|
|
}
|
|
|
|
# Add addition to end unless test succeeds on at least one
|
|
#
|
|
VGL_testSuffixNoneS() {
|
|
declare command=$1 addition=$2
|
|
eval "declare items=($(cat))"
|
|
VGL_sourceS "${items[@]}"
|
|
VGL_sourceS "${items[@]}" | VGL_isTestAnyS "$command" \
|
|
|| VGL_sourceS "$addition"
|
|
}
|
|
|
|
|
|
# Stream consumers
|
|
#
|
|
# These consume a stream of escaped new-line terminated items (termination is required for processing)
|
|
#
|
|
|
|
# Return true iff given command returns true for some item
|
|
#
|
|
VGL_isTestAnyS() {
|
|
declare command="$1" next
|
|
while read next; do
|
|
set -- "$next"
|
|
if (eval "$command"); then
|
|
return 0
|
|
fi
|
|
done
|
|
return 1
|
|
}
|
|
|
|
|
|
# Return true iff given command returns true for all item
|
|
#
|
|
VGL_isTestAllS() {
|
|
declare command="$1" next
|
|
while read next; do
|
|
set -- "$next"
|
|
if ! (eval "$command"); then
|
|
return 1
|
|
fi
|
|
done
|
|
return 0
|
|
}
|
|
|
|
|
|
# Tests for the filter transformer
|
|
#
|
|
|
|
# Check for an elf file (binary or library)
|
|
#
|
|
VGL_isElfBin() {
|
|
declare file=$1
|
|
patchelf --print-interpreter "$file" &>/dev/null
|
|
}
|
|
|
|
# Check for libGL
|
|
#
|
|
VGL_isLibGL() {
|
|
declare file=$1
|
|
case "$file" in
|
|
libGL.so* | */libGL.so*)
|
|
return 0 ;;
|
|
*)
|
|
return 1 ;;
|
|
esac
|
|
}
|
|
|
|
|
|
|
|
# Update elf files
|
|
#
|
|
|
|
# Run given stream element on rpath stream and write result to file if differs from original
|
|
#
|
|
VGL_elfFilterRPathS() {
|
|
declare file=$1 command=$2
|
|
eval "declare pathsOld=($(VGL_elfRPathS "$file"))"
|
|
eval "declare pathsNew=($(VGL_sourceS "${pathsOld[@]}" | eval "$command"))"
|
|
[[ ${pathsNew[@]@Q} = ${pathsOld[@]@Q} ]] \
|
|
|| if (( ${#pathsNew[@]} > 0 ));
|
|
then ( IFS=:; patchelf --set-rpath "${pathsNew[*]}" "$file" )
|
|
else ( patchelf --remove-rpath "$file" )
|
|
fi
|
|
}
|
|
|
|
# Run given stream element on directly required libraries stream and write result to file if differs from original
|
|
#
|
|
VGL_elfFilterLibsS() {
|
|
declare file=$1 command=$2
|
|
eval "declare libsOld=($(VGL_elfLibsS "$file"))"
|
|
eval "declare libsNew=($(VGL_sourceS "${libsOld[@]}" | eval "$command"))"
|
|
eval "declare libs=($(VGL_sourceS "${libsOld[@]}" | VGL_valuesRemoveS "${libsNew[@]}"))"
|
|
(( ${#libs[@]} < 1 )) \
|
|
|| ( eval "patchelf$(printf ' --remove-needed %q' "${libs[@]}") ${file@Q}")
|
|
eval "declare libs=($(VGL_sourceS "${libsNew[@]}" | VGL_valuesRemoveS "${libsOld[@]}"))"
|
|
(( ${#libs[@]} < 1 )) \
|
|
|| ( eval "patchelf$(printf ' --add-needed %q' "${libs[@]}") ${file@Q}")
|
|
}
|
|
|
|
# Patch elf file to be able to use OpenGL properly (not a stream function so can be called in normal way)
|
|
#
|
|
VGL_patch() {
|
|
declare files=("$@") file
|
|
for file in "${files[@]}"; do
|
|
# glibc 2.3 ld.so supports a --preload option that would make this just a simple wrapper
|
|
#
|
|
# mv "$file" "${file%/*}/.${file##*/}.vgl"
|
|
# cat > "$file" <<EOF
|
|
#! @bash@
|
|
# exec -a "\$0" "$(patchelf --print-interpreter "${file%/*}/.${file##*/}.vgl")" \${VGL_DISPLAY:+--preload "@virtualglLib@"} "${file%/*}/.${file##*/}.vgl" "\$@"
|
|
# EOF
|
|
# chmod +x "$file"
|
|
|
|
# VGL version may need fixing up to ensure libglfaker.so gets loaded at the start
|
|
printf 'Wrapping and patching for VirtualGL: %q\n' "$file" >&2
|
|
cp -a "$file" "${file%/*}/.${file##*/}.vgl-yes"
|
|
VGL_elfFilterLibsS "${file%/*}/.${file##*/}.vgl-yes" 'VGL_testSuffixNoneS '"$(VGL_quote '[[ $1 =~ ^(.*/)?libvglfaker.so ]]')"' @virtualglLib@'
|
|
|
|
# Non-VGL is fine as we link it against mesa_glxgallium
|
|
mv "$file" "${file%/*}/.${file##*/}.vgl-no"
|
|
|
|
# Replace with chooser script based on whether VGL_DISPLAY is set or not
|
|
cat > "$file" <<EOF
|
|
#! @bash@
|
|
|
|
if [ -z "\$VGL_DISPLAY" ]; then
|
|
exec -a "\$0" "${file%/*}/.${file##*/}.vgl-no" "\$@"
|
|
else
|
|
exec -a "\$0" "${file%/*}/.${file##*/}.vgl-yes" "\$@"
|
|
fi
|
|
EOF
|
|
chmod +x "$file"
|
|
done
|
|
}
|
|
|
|
|
|
# Setup hook
|
|
#
|
|
|
|
# Find all executables that depend on libGL and replace with a wrapper script that either executes the original
|
|
# executable or a copy with an added libvglfaker.so dependency depending on whether VGL_DISPLAY is set or not.
|
|
#
|
|
# Only run when we are a runtime dependency (i.e., our host matches).
|
|
#
|
|
VGL_autoAddVGL() {
|
|
declare opts=$(shopt -p) output
|
|
set +o pipefail
|
|
|
|
echo "Inserting VirtualGL into OpenGL executables in $prefix..." >&2
|
|
for output in $outputs; do
|
|
VGL_findS "${!output}" -type f \
|
|
| VGL_testKeepS 'VGL_isElfBin "$1" && ! [[ ${1##*/} == .*.vgl-* ]] && ! [[ ${1##*/} == ?*.so ]]' \
|
|
| VGL_testKeepS 'VGL_elfLibsResolvedS "$1" | VGL_isTestAnyS '"$(VGL_quote 'VGL_isLibGL "$1"')" \
|
|
| VGL_isTestAllS 'VGL_patch "$1"'
|
|
done
|
|
|
|
eval "$opts"
|
|
}
|
|
|
|
|
|
if (( hostOffset == 0 )); then
|
|
fixupOutputHooks+=(VGL_autoAddVGL)
|
|
fi
|