From 349b2a4232e2a3dfe25b7509cb9d77c7d2a10377 Mon Sep 17 00:00:00 2001 From: aszlig Date: Thu, 1 Feb 2018 21:49:49 +0100 Subject: auto-patchelf: Move into pkgs/build-support This is really not game-specific, so let's put it at the top-level and also make sure we substitute all the commands we're using there, even though a few of them are in PATH of stdenv so that it will always work even when the programs available in stdenv should change someday. Signed-off-by: aszlig --- pkgs/build-support/auto-patchelf/default.nix | 16 +++ pkgs/build-support/auto-patchelf/setup-hook.sh | 149 +++++++++++++++++++++ pkgs/default.nix | 3 +- pkgs/games/build-support/build-game.nix | 6 +- pkgs/games/build-support/default.nix | 2 - .../build-support/setup-hooks/auto-patchelf.sh | 149 --------------------- 6 files changed, 169 insertions(+), 156 deletions(-) create mode 100644 pkgs/build-support/auto-patchelf/default.nix create mode 100644 pkgs/build-support/auto-patchelf/setup-hook.sh delete mode 100644 pkgs/games/build-support/setup-hooks/auto-patchelf.sh diff --git a/pkgs/build-support/auto-patchelf/default.nix b/pkgs/build-support/auto-patchelf/default.nix new file mode 100644 index 00000000..c7a055cb --- /dev/null +++ b/pkgs/build-support/auto-patchelf/default.nix @@ -0,0 +1,16 @@ +{ stdenv, substituteAll, patchelf, binutils-unwrapped, findutils, file, glibc +, gnugrep, gnused +}: + +substituteAll { + src = ./setup-hook.sh; + + inherit (stdenv) shell; + file = "${file}/bin/file"; + find = "${findutils}/bin/find"; + grep = "${gnugrep}/bin/grep"; + ldd = "${glibc.bin}/bin/ldd"; + objdump = "${binutils-unwrapped}/bin/objdump"; + patchelf = "${patchelf}/bin/patchelf"; + sed = "${gnused}/bin/sed"; +} diff --git a/pkgs/build-support/auto-patchelf/setup-hook.sh b/pkgs/build-support/auto-patchelf/setup-hook.sh new file mode 100644 index 00000000..6e34b4ef --- /dev/null +++ b/pkgs/build-support/auto-patchelf/setup-hook.sh @@ -0,0 +1,149 @@ +declare -a autoPatchelfLibs + +gatherLibraries() { + autoPatchelfLibs+=("$1/lib") +} + +addEnvHooks "$targetOffset" 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" 2> /dev/null)" + 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 + 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 +} + +getSoArch() { + @objdump@ -f "$1" | @sed@ -ne 's/^architecture: *\([^,]\+\).*/\1/p' +} + +findDependency() { + local filename="$1" + local arch="$2" + 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 + if [ "$(getSoArch "$dep")" = "$arch" ]; then + foundDependency="$dep" + return 0 + fi + fi + done + + if [ $doneRecursiveSearch -eq 0 ]; then + populateCacheWithRecursiveDeps + doneRecursiveSearch=1 + findDependency "$filename" "$arch" || return 1 + return 0 + fi + return 1 +} + +autoPatchelfFile() { + local dep rpath="" toPatch="$1" + + local interpreter="$(< "$NIX_CC/nix-support/dynamic-linker")" + if isExecutable "$toPatch"; then + @patchelf@ --set-interpreter "$interpreter" "$toPatch" + if [ -n "$runtimeDependencies" ]; then + for dep in $runtimeDependencies; do + rpath="$rpath${rpath:+:}$dep/lib" + done + fi + fi + + echo "searching for dependencies of $toPatch:" >&2 + + @patchelf@ --remove-rpath "$toPatch" + + local missing="$( + @ldd@ "$toPatch" 2> /dev/null | \ + @sed@ -n -e 's/^[\t ]*\([^ ]\+\) => not found.*/\1/p' + )" + + for dep in $missing; do + echo -n " $dep -> " >&2 + if findDependency "$dep" "$(getSoArch "$toPatch")"; then + rpath="$rpath${rpath:+:}${foundDependency%/*}" + echo "found: $foundDependency" >&2 + else + echo "not found!" >&2 + fi + done + + if [ -n "$rpath" ]; then + echo "setting RPATH to: $rpath" >&2 + @patchelf@ --set-rpath "$rpath" "$toPatch" + fi +} + +autoPatchelf() { + echo "automatically fixing dependencies for ELF files" >&2 + + cachedDependencies+=( + $(find "$out" \! -type d \( -name '*.so' -o -name '*.so.*' \)) + ) + local elffile + findElfs "$prefix" | while read -r elffile; do + autoPatchelfFile "$elffile" + done +} + +postInstallHooks+=(autoPatchelf) diff --git a/pkgs/default.nix b/pkgs/default.nix index 5e6530ab..cd4eb76c 100644 --- a/pkgs/default.nix +++ b/pkgs/default.nix @@ -13,11 +13,12 @@ let self.vuizvui = pkgs.recurseIntoAttrs { mkChannel = callPackage ./build-support/channel.nix { }; buildSandbox = callPackage build-support/build-sandbox {}; + autoPatchelfHook = callPackage build-support/auto-patchelf {}; list-gamecontrollers = callPackage ./list-gamecontrollers { }; games = import ./games { - inherit pkgs; + pkgs = pkgs // self.vuizvui; config = pkgs.config.vuizvui.games or null; }; diff --git a/pkgs/games/build-support/build-game.nix b/pkgs/games/build-support/build-game.nix index b04309a5..e4d019af 100644 --- a/pkgs/games/build-support/build-game.nix +++ b/pkgs/games/build-support/build-game.nix @@ -1,4 +1,4 @@ -{ stdenv, lib, file, unzip, buildSandbox +{ stdenv, lib, file, unzip, buildSandbox, autoPatchelfHook , withPulseAudio ? true, libpulseaudio ? null , alsaLib @@ -19,9 +19,7 @@ assert withPulseAudio -> libpulseaudio != null; buildSandbox (stdenv.mkDerivation ({ buildInputs = [ stdenv.cc.cc ] ++ buildInputs; - nativeBuildInputs = [ - unzip file ./setup-hooks/auto-patchelf.sh - ] ++ nativeBuildInputs; + nativeBuildInputs = [ unzip autoPatchelfHook ] ++ nativeBuildInputs; preUnpack = preUnpack + '' mkdir "$name" diff --git a/pkgs/games/build-support/default.nix b/pkgs/games/build-support/default.nix index e739c25f..8e227afc 100644 --- a/pkgs/games/build-support/default.nix +++ b/pkgs/games/build-support/default.nix @@ -4,7 +4,5 @@ buildGame = callPackage ./build-game.nix { withPulseAudio = config.pulseaudio or true; }; - # XXX: Pass through from parent scope! - buildSandbox = callPackage ../../build-support/build-sandbox {}; buildUnity = callPackage ./build-unity.nix {}; } diff --git a/pkgs/games/build-support/setup-hooks/auto-patchelf.sh b/pkgs/games/build-support/setup-hooks/auto-patchelf.sh deleted file mode 100644 index e24e278f..00000000 --- a/pkgs/games/build-support/setup-hooks/auto-patchelf.sh +++ /dev/null @@ -1,149 +0,0 @@ -declare -a autoPatchelfLibs - -gatherLibraries() { - autoPatchelfLibs+=("$1/lib") -} - -addEnvHooks "$targetOffset" 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" 2> /dev/null)" - 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 - 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 -} - -getSoArch() { - objdump -f "$1" | sed -ne 's/^architecture: *\([^,]\+\).*/\1/p' -} - -findDependency() { - local filename="$1" - local arch="$2" - 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 - if [ "$(getSoArch "$dep")" = "$arch" ]; then - foundDependency="$dep" - return 0 - fi - fi - done - - if [ $doneRecursiveSearch -eq 0 ]; then - populateCacheWithRecursiveDeps - doneRecursiveSearch=1 - findDependency "$filename" "$arch" || return 1 - return 0 - fi - return 1 -} - -autoPatchelfFile() { - local dep rpath="" toPatch="$1" - - local interpreter="$(< "$NIX_CC/nix-support/dynamic-linker")" - if isExecutable "$toPatch"; then - patchelf --set-interpreter "$interpreter" "$toPatch" - if [ -n "$runtimeDependencies" ]; then - for dep in $runtimeDependencies; do - rpath="$rpath${rpath:+:}$dep/lib" - done - fi - fi - - echo "searching for dependencies of $toPatch:" >&2 - - patchelf --remove-rpath "$toPatch" - - local missing="$( - ldd "$toPatch" 2> /dev/null | \ - sed -n -e 's/^[\t ]*\([^ ]\+\) => not found.*/\1/p' - )" - - for dep in $missing; do - echo -n " $dep -> " >&2 - if findDependency "$dep" "$(getSoArch "$toPatch")"; then - rpath="$rpath${rpath:+:}${foundDependency%/*}" - echo "found: $foundDependency" >&2 - else - echo "not found!" >&2 - fi - done - - if [ -n "$rpath" ]; then - echo "setting RPATH to: $rpath" >&2 - patchelf --set-rpath "$rpath" "$toPatch" - fi -} - -autoPatchelf() { - echo "automatically fixing dependencies for ELF files" >&2 - - cachedDependencies+=( - $(find "$out" \! -type d \( -name '*.so' -o -name '*.so.*' \)) - ) - local elffile - findElfs "$prefix" | while read -r elffile; do - autoPatchelfFile "$elffile" - done -} - -postInstallHooks+=(autoPatchelf) -- cgit 1.4.1