diff options
author | aszlig <aszlig@redmoonstudios.org> | 2017-09-13 05:06:32 +0200 |
---|---|---|
committer | aszlig <aszlig@redmoonstudios.org> | 2017-09-13 15:26:28 +0200 |
commit | ef6c66560175e4b5a798bd09caa31cd5ebad8127 (patch) | |
tree | ffa44ce33da4d3f28c52248076c948e3aee1b63e /pkgs/games/build-support/setup-hooks | |
parent | 370f8a5e5215e4f1ff34e05b7094bf08eb5cf643 (diff) |
pkgs/games: Add a new buildGame function
The main functionality for this function is to gather missing dependencies in ELF executables and shared libraries and using patchelf to set the right RPATH. All of the dependencies are searched based on what we have in one of the buildInputs variables, so all we need to do is list them in there. One thing that's still left to solve is adding libraries to the RPATH which are only required at runtime. An example for this would be the pulseaudio library. Signed-off-by: aszlig <aszlig@redmoonstudios.org>
Diffstat (limited to 'pkgs/games/build-support/setup-hooks')
-rw-r--r-- | pkgs/games/build-support/setup-hooks/auto-patchelf.sh | 135 |
1 files changed, 135 insertions, 0 deletions
diff --git a/pkgs/games/build-support/setup-hooks/auto-patchelf.sh b/pkgs/games/build-support/setup-hooks/auto-patchelf.sh new file mode 100644 index 00000000..b0982a45 --- /dev/null +++ b/pkgs/games/build-support/setup-hooks/auto-patchelf.sh @@ -0,0 +1,135 @@ +declare -a autoPatchelfLibs + +gatherLibraries() { + autoPatchelfLibs+=("$1/lib") +} + +envHooks+=(gatherLibraries) + +isExecutable() { + [ "$(file -b -N --mime-type "$1")" = application/x-executable ] +} + +findElfs() { + find "$1" -type f -exec "$SHELL" -c ' + while [ -n "$1" ]; do + mimeType="$(file -b -N --mime-type "$1")" + if [ "$mimeType" = application/x-executable \ + -o "$mimeType" = application/x-sharedlib ]; then + echo "$1" + fi + shift + done + ' -- {} + +} + +declare -a cachedDependencies + +addToDepCache() { + local existing + for existing in "${cachedDependencies[@]}"; do + if [ "$existing" = "$1" ]; then return; fi + done + cachedDependencies+=("$1") +} + +declare -gi depCacheInitialised=0 +declare -gi doneRecursiveSearch=0 +declare -g foundDependency + +getDepsFromSo() { + ldd "$1" 2> /dev/null | sed -n -e 's/[^=]*=> *\(.\+\) \+([^)]*)$/\1/p' +} + +checkElfDep() { + local errors ldout="$(ldd "$1")" + if errors="$(echo "$ldout" | grep -F "not found")"; then + echo -e "Library dependencies missing for $1:\n$errors" + fi +} + +populateCacheWithRecursiveDeps() { + local so found foundso + for so in "${cachedDependencies[@]}"; do + local IFS=$'\n' + for found in $(getDepsFromSo "$so"); do + local libdir="${found%/*}" + local base="${found##*/}" + local soname="${base%.so*}" + for foundso in "${found%/*}/$soname".so*; do + addToDepCache "$foundso" + done + done + done +} + +findDependency() { + local filename="$1" + local lib dep + + if [ $depCacheInitialised -eq 0 ]; then + for lib in "${autoPatchelfLibs[@]}"; do + for so in "$lib/"*.so*; do addToDepCache "$so"; done + done + depCacheInitialised=1 + fi + + for dep in "${cachedDependencies[@]}"; do + if [ "$filename" = "${dep##*/}" ]; then + foundDependency="$dep" + return 0 + fi + done + + if [ $doneRecursiveSearch -eq 0 ]; then + populateCacheWithRecursiveDeps + doneRecursiveSearch=1 + findDependency "$filename" || return 1 + return 0 + fi + return 1 +} + +autoPatchelfFile() { + local toPatch="$1" + local dep + + local interpreter="$(cat $NIX_CC/nix-support/dynamic-linker)" + if isExecutable "$toPatch"; then + patchelf --set-interpreter "$interpreter" "$toPatch" + fi + + patchelf --remove-rpath "$toPatch" + + local rpath="" + local missing="$( + ldd "$toPatch" | sed -n -e 's/^[\t ]*\([^ ]\+\) => not found.*/\1/p' + )" + local IFS=$'\n' + for dep in $missing; do + echo -n "searching for dependency $dep..." >&2 + if findDependency "$dep"; then + rpath="$rpath${rpath:+:}${foundDependency%/*}" + echo " found: $foundDependency" >&2 + else + echo " not found" >&2 + fi + done + + if [ -n "$rpath" ]; then + echo "setting RPATH of $toPatch to $rpath" >&2 + patchelf --set-rpath "$rpath" "$toPatch" + fi +} + +autoPatchelf() { + echo "automatically fixing dependencies for ELF files" >&2 + + local i IFS=$'\n' + cachedDependencies+=( + $(find "$out" \! -type d \( -name '*.so' -o -name '*.so.*' \)) + ) + for i in $(findElfs "$prefix"); do autoPatchelfFile "$i"; done +} + +postInstallHooks+=(autoPatchelf) |