nixpkgs/pkgs/build-support/setup-hooks/patch-shebangs.sh
Matthew Bauer eb7c50a993 patch-shebangs: use --build for auto patch shebangs
In strictDeps=false, autoPatchshebangs should use
--build (corresponding to PATH) to lookup commands. This restores the
previous behavior of patchshebangs so that we don’t break stuff that
isn’t careful in the buildInputs vs. nativeBuildInputs distinction.
Unfortunately this won’t work under cross compilation.
2018-11-02 00:27:14 -05:00

117 lines
3.9 KiB
Bash

# This setup hook causes the fixup phase to rewrite all script
# interpreter file names (`#! /path') to paths found in $PATH. E.g.,
# /bin/sh will be rewritten to /nix/store/<hash>-some-bash/bin/sh.
# /usr/bin/env gets special treatment so that ".../bin/env python" is
# rewritten to /nix/store/<hash>/bin/python. Interpreters that are
# already in the store are left untouched.
fixupOutputHooks+=(patchShebangsAuto)
# Run patch shebangs on a directory.
# patchShebangs [--build | --host] directory
# Flags:
# --build : Lookup commands available at build-time
# --host : Lookup commands available at runtime
# Example use cases,
# $ patchShebangs --host /nix/store/...-hello-1.0/bin
# $ patchShebangs --build configure
patchShebangs() {
local pathName
if [ "$1" = "--host" ]; then
pathName=HOST_PATH
shift
elif [ "$1" = "--build" ]; then
pathName=PATH
shift
fi
local dir="$1"
header "patching script interpreter paths in $dir"
local f
local oldPath
local newPath
local arg0
local args
local oldInterpreterLine
local newInterpreterLine
[ -e "$dir" ] || return 0
local f
while IFS= read -r -d $'\0' f; do
isScript "$f" || continue
oldInterpreterLine=$(head -1 "$f" | tail -c+3)
read -r oldPath arg0 args <<< "$oldInterpreterLine"
if [ -z "$pathName" ]; then
if [ -n "$strictDeps" ] && [[ "$f" = "$NIX_STORE"* ]]; then
pathName=HOST_PATH
else
pathName=PATH
fi
fi
if $(echo "$oldPath" | grep -q "/bin/env$"); then
# Check for unsupported 'env' functionality:
# - options: something starting with a '-'
# - environment variables: foo=bar
if $(echo "$arg0" | grep -q -- "^-.*\|.*=.*"); then
echo "$f: unsupported interpreter directive \"$oldInterpreterLine\" (set dontPatchShebangs=1 and handle shebang patching yourself)"
exit 1
fi
newPath="$(PATH="${!pathName}" command -v "$arg0" || true)"
else
if [ "$oldPath" = "" ]; then
# If no interpreter is specified linux will use /bin/sh. Set
# oldpath="/bin/sh" so that we get /nix/store/.../sh.
oldPath="/bin/sh"
fi
newPath="$(PATH="${!pathName}" command -v "$(basename "$oldPath")" || true)"
args="$arg0 $args"
fi
# Strip trailing whitespace introduced when no arguments are present
newInterpreterLine="$(echo "$newPath $args" | sed 's/[[:space:]]*$//')"
if [ -n "$oldPath" -a "${oldPath:0:${#NIX_STORE}}" != "$NIX_STORE" ]; then
if [ -n "$newPath" -a "$newPath" != "$oldPath" ]; then
echo "$f: interpreter directive changed from \"$oldInterpreterLine\" to \"$newInterpreterLine\""
# escape the escape chars so that sed doesn't interpret them
escapedInterpreterLine=$(echo "$newInterpreterLine" | sed 's|\\|\\\\|g')
# Preserve times, see: https://github.com/NixOS/nixpkgs/pull/33281
touch -r "$f" "$f.timestamp"
sed -i -e "1 s|.*|#\!$escapedInterpreterLine|" "$f"
touch -r "$f.timestamp" "$f"
rm "$f.timestamp"
fi
fi
done < <(find "$dir" -type f -perm -0100 -print0)
stopNest
}
patchShebangsAuto () {
if [ -z "$dontPatchShebangs" -a -e "$prefix" ]; then
if [ -z "${strictDeps-}"]; then
patchShebangs --build "$prefix"
# Dev output will end up being run on the build platform. An
# example case of this is sdl2-config. Otherwise, we can just
# use the runtime path (--host).
elif [ "$output" != out ] && [ "$output" = "${!outputDev}" ]; then
patchShebangs --build "$prefix"
else
patchShebangs --host "$prefix"
fi
fi
}