diff options
Diffstat (limited to 'pkgs/build-support/setup-hooks')
4 files changed, 98 insertions, 32 deletions
diff --git a/pkgs/build-support/setup-hooks/auto-patchelf.sh b/pkgs/build-support/setup-hooks/auto-patchelf.sh index 4f7c0c14304c9..49e84f84ceb33 100644 --- a/pkgs/build-support/setup-hooks/auto-patchelf.sh +++ b/pkgs/build-support/setup-hooks/auto-patchelf.sh @@ -1,9 +1,16 @@ declare -a autoPatchelfLibs +declare -Ag autoPatchelfFailedDeps gatherLibraries() { autoPatchelfLibs+=("$1/lib") } +# wrapper around patchelf to raise proper error messages +# containing the tried file name and command +runPatchelf() { + patchelf "$@" || (echo "Command failed: patchelf $*" && exit 1) +} + addEnvHooks "$targetOffset" gatherLibraries isExecutable() { @@ -23,14 +30,19 @@ isExecutable() { # We cache dependencies so that we don't need to search through all of them on # every consecutive call to findDependency. -declare -a cachedDependencies +declare -Ag autoPatchelfCachedDepsAssoc +declare -ag autoPatchelfCachedDeps + addToDepCache() { - local existing - for existing in "${cachedDependencies[@]}"; do - if [ "$existing" = "$1" ]; then return; fi - done - cachedDependencies+=("$1") + if [[ ${autoPatchelfCachedDepsAssoc[$1]+f} ]]; then return; fi + + # store deps in an assoc. array for efficient lookups + # otherwise findDependency would have quadratic complexity + autoPatchelfCachedDepsAssoc["$1"]="" + + # also store deps in normal array to maintain their order + autoPatchelfCachedDeps+=("$1") } declare -gi depCacheInitialised=0 @@ -43,9 +55,8 @@ getDepsFromSo() { populateCacheWithRecursiveDeps() { local so found foundso - for so in "${cachedDependencies[@]}"; do + for so in "${autoPatchelfCachedDeps[@]}"; do for found in $(getDepsFromSo "$so"); do - local libdir="${found%/*}" local base="${found##*/}" local soname="${base%.so*}" for foundso in "${found%/*}/$soname".so*; do @@ -76,7 +87,7 @@ findDependency() { depCacheInitialised=1 fi - for dep in "${cachedDependencies[@]}"; do + for dep in "${autoPatchelfCachedDeps[@]}"; do if [ "$filename" = "${dep##*/}" ]; then if [ "$(getSoArch "$dep")" = "$arch" ]; then foundDependency="$dep" @@ -101,9 +112,10 @@ findDependency() { autoPatchelfFile() { local dep rpath="" toPatch="$1" - local interpreter="$(< "$NIX_CC/nix-support/dynamic-linker")" + local interpreter + interpreter="$(< "$NIX_CC/nix-support/dynamic-linker")" if isExecutable "$toPatch"; then - patchelf --set-interpreter "$interpreter" "$toPatch" + runPatchelf --set-interpreter "$interpreter" "$toPatch" if [ -n "$runtimeDependencies" ]; then for dep in $runtimeDependencies; do rpath="$rpath${rpath:+:}$dep/lib" @@ -115,9 +127,10 @@ autoPatchelfFile() { # We're going to find all dependencies based on ldd output, so we need to # clear the RPATH first. - patchelf --remove-rpath "$toPatch" + runPatchelf --remove-rpath "$toPatch" - local missing="$( + local missing + missing="$( ldd "$toPatch" 2> /dev/null | \ sed -n -e 's/^[\t ]*\([^ ]\+\) => not found.*/\1/p' )" @@ -125,7 +138,6 @@ autoPatchelfFile() { # This ensures that we get the output of all missing dependencies instead # of failing at the first one, because it's more useful when working on a # new package where you don't yet know its dependencies. - local -i depNotFound=0 for dep in $missing; do echo -n " $dep -> " >&2 @@ -134,18 +146,13 @@ autoPatchelfFile() { echo "found: $foundDependency" >&2 else echo "not found!" >&2 - depNotFound=1 + autoPatchelfFailedDeps["$dep"]="$toPatch" fi done - # This makes sure the builder fails if we didn't find a dependency, because - # the stdenv setup script is run with set -e. The actual error is emitted - # earlier in the previous loop. - [ $depNotFound -eq 0 -o -n "$autoPatchelfIgnoreMissingDeps" ] - if [ -n "$rpath" ]; then echo "setting RPATH to: $rpath" >&2 - patchelf --set-rpath "$rpath" "$toPatch" + runPatchelf --set-rpath "$rpath" "$toPatch" fi } @@ -168,10 +175,10 @@ addAutoPatchelfSearchPath() { esac done - cachedDependencies+=( - $(find "$@" "${findOpts[@]}" \! -type d \ - \( -name '*.so' -o -name '*.so.*' \)) - ) + for file in \ + $(find "$@" "${findOpts[@]}" \! -type d \ + \( -name '*.so' -o -name '*.so.*' \)) + do addToDepCache "$file"; done } autoPatchelf() { @@ -197,14 +204,9 @@ autoPatchelf() { echo "automatically fixing dependencies for ELF files" >&2 # Add all shared objects of the current output path to the start of - # cachedDependencies so that it's choosen first in findDependency. + # autoPatchelfCachedDeps so that it's chosen first in findDependency. addAutoPatchelfSearchPath ${norecurse:+--no-recurse} -- "$@" - # Here we actually have a subshell, which also means that - # $cachedDependencies is final at this point, so whenever we want to run - # findDependency outside of this, the dependency cache needs to be rebuilt - # from scratch, so keep this in mind if you want to run findDependency - # outside of this function. while IFS= read -r -d $'\0' file; do isELF "$file" || continue segmentHeaders="$(LANG=C $READELF -l "$file")" @@ -215,8 +217,24 @@ autoPatchelf() { # Skip if the executable is statically linked. [ -n "$(echo "$segmentHeaders" | grep "^ *INTERP\\>")" ] || continue fi + # Jump file if patchelf is unable to parse it + # Some programs contain binary blobs for testing, + # which are identified as ELF but fail to be parsed by patchelf + patchelf "$file" || continue autoPatchelfFile "$file" done < <(find "$@" ${norecurse:+-maxdepth 1} -type f -print0) + + # fail if any dependencies were not found and + # autoPatchelfIgnoreMissingDeps is not set + local depsMissing=0 + for failedDep in "${!autoPatchelfFailedDeps[@]}"; do + echo "autoPatchelfHook could not satisfy dependency $failedDep wanted by ${autoPatchelfFailedDeps[$failedDep]}" + depsMissing=1 + done + if [[ $depsMissing == 1 && -z "$autoPatchelfIgnoreMissingDeps" ]]; then + echo "Add the missing dependencies to the build inputs or set autoPatchelfIgnoreMissingDeps=true" + exit 1 + fi } # XXX: This should ultimately use fixupOutputHooks but we currently don't have diff --git a/pkgs/build-support/setup-hooks/copy-desktop-items.sh b/pkgs/build-support/setup-hooks/copy-desktop-items.sh new file mode 100644 index 0000000000000..f96a10f33d5cb --- /dev/null +++ b/pkgs/build-support/setup-hooks/copy-desktop-items.sh @@ -0,0 +1,42 @@ +# shellcheck shell=bash + +# Setup hook that installs specified desktop items. +# +# Example usage in a derivation: +# +# { …, makeDesktopItem, copyDesktopItems, … }: +# +# let desktopItem = makeDesktopItem { … }; in +# stdenv.mkDerivation { +# … +# nativeBuildInputs = [ copyDesktopItems ]; +# +# desktopItems = [ desktopItem ]; +# … +# } +# +# This hook will copy files which are either given by full path +# or all '*.desktop' files placed inside the 'share/applications' +# folder of each `desktopItems` argument. + +postInstallHooks+=(copyDesktopItems) + +copyDesktopItems() { + if [ "${dontCopyDesktopItems-}" = 1 ]; then return; fi + + if [ -z "$desktopItems" ]; then + return + fi + + for desktopItem in $desktopItems; do + if [[ -f "$desktopItem" ]]; then + echo "Copying '$f' into '$out/share/applications'" + install -D -m 444 -t "$out"/share/applications "$f" + else + for f in "$desktopItem"/share/applications/*.desktop; do + echo "Copying '$f' into '$out/share/applications'" + install -D -m 444 -t "$out"/share/applications "$f" + done + fi + done +} diff --git a/pkgs/build-support/setup-hooks/reproducible-builds.sh b/pkgs/build-support/setup-hooks/reproducible-builds.sh new file mode 100644 index 0000000000000..2d8db6ff7d3cf --- /dev/null +++ b/pkgs/build-support/setup-hooks/reproducible-builds.sh @@ -0,0 +1,4 @@ +# Use the last part of the out path as hash input for the build. +# This should ensure that it is deterministic across rebuilds of the same +# derivation and not easily collide with other builds. +export NIX_CFLAGS_COMPILE+=" -frandom-seed=${out##*/}" diff --git a/pkgs/build-support/setup-hooks/wrap-gapps-hook/default.nix b/pkgs/build-support/setup-hooks/wrap-gapps-hook/default.nix index 5a87893d9726f..d0ea088bf71e8 100644 --- a/pkgs/build-support/setup-hooks/wrap-gapps-hook/default.nix +++ b/pkgs/build-support/setup-hooks/wrap-gapps-hook/default.nix @@ -3,6 +3,7 @@ , makeSetupHook , makeWrapper , gobject-introspection +, isGraphical ? true , gtk3 , librsvg , dconf @@ -21,7 +22,7 @@ makeSetupHook { # Unfortunately, it also requires the user to have dconf # D-Bus service enabled globally (e.g. through a NixOS module). dconf.lib - ] ++ [ + ] ++ lib.optionals isGraphical [ # TODO: remove this, packages should depend on GTK explicitly. gtk3 @@ -30,6 +31,7 @@ makeSetupHook { # graphics in GTK (e.g. cross for closing window in window title bar) # so it is pretty much required for applications using GTK. librsvg + ] ++ [ # We use the wrapProgram function. makeWrapper |