about summary refs log tree commit diff
path: root/pkgs/stdenv/generic/setup.sh
diff options
context:
space:
mode:
Diffstat (limited to 'pkgs/stdenv/generic/setup.sh')
-rw-r--r--pkgs/stdenv/generic/setup.sh338
1 files changed, 262 insertions, 76 deletions
diff --git a/pkgs/stdenv/generic/setup.sh b/pkgs/stdenv/generic/setup.sh
index 686ed68cedeb..d2c67cce81a2 100644
--- a/pkgs/stdenv/generic/setup.sh
+++ b/pkgs/stdenv/generic/setup.sh
@@ -300,11 +300,83 @@ runHook preHook
 runHook addInputsHook
 
 
-# Recursively find all build inputs.
+# Package accumulators
+
+# shellcheck disable=SC2034
+declare -a pkgsBuildBuild pkgsBuildHost pkgsBuildTarget
+declare -a pkgsHostHost pkgsHostTarget
+declare -a pkgsTargetTarget
+
+declare -ra pkgBuildAccumVars=(pkgsBuildBuild pkgsBuildHost pkgsBuildTarget)
+declare -ra pkgHostAccumVars=(pkgsHostHost pkgsHostTarget)
+declare -ra pkgTargetAccumVars=(pkgsTargetTarget)
+
+declare -ra pkgAccumVarVars=(pkgBuildAccumVars pkgHostAccumVars pkgTargetAccumVars)
+
+
+# Hooks
+
+declare -a envBuildBuildHooks envBuildHostHooks envBuildTargetHooks
+declare -a envHostHostHooks envHostTargetHooks
+declare -a envTargetTargetHooks
+
+declare -ra pkgBuildHookVars=(envBuildBuildHook envBuildHostHook envBuildTargetHook)
+declare -ra pkgHostHookVars=(envHostHostHook envHostTargetHook)
+declare -ra pkgTargetHookVars=(envTargetTargetHook)
+
+declare -ra pkgHookVarVars=(pkgBuildHookVars pkgHostHookVars pkgTargetHookVars)
+
+# Add env hooks for all sorts of deps with the specified host offset.
+addEnvHooks() {
+    local depHostOffset="$1"
+    shift
+    local pkgHookVarsSlice="${pkgHookVarVars[$depHostOffset + 1]}[@]"
+    local pkgHookVar
+    for pkgHookVar in "${!pkgHookVarsSlice}"; do
+        eval "${pkgHookVar}s"'+=("$@")'
+    done
+}
+
+
+# Propagated dep files
+
+declare -ra propagatedBuildDepFiles=(
+    propagated-build-build-deps
+    propagated-native-build-inputs # Legacy name for back-compat
+    propagated-build-target-deps
+)
+declare -ra propagatedHostDepFiles=(
+    propagated-host-host-deps
+    propagated-build-inputs # Legacy name for back-compat
+)
+declare -ra propagatedTargetDepFiles=(
+    propagated-target-target-deps
+)
+declare -ra propagatedDepFilesVars=(
+    propagatedBuildDepFiles
+    propagatedHostDepFiles
+    propagatedTargetDepFiles
+)
+
+# Platform offsets: build = -1, host = 0, target = 1
+declare -ra allPlatOffsets=(-1 0 1)
+
+
+# Mutually-recursively find all build inputs. See the dependency section of the
+# stdenv chapter of the Nixpkgs manual for the specification this algorithm
+# implements.
 findInputs() {
-    local pkg="$1"; shift
-    local var="$1"; shift
-    local propagatedBuildInputsFiles=("$@")
+    local -r pkg="$1"
+    local -ri hostOffset="$2"
+    local -ri targetOffset="$3"
+
+    # Sanity check
+    (( "$hostOffset" <= "$targetOffset" )) || exit -1
+
+    local varVar="${pkgAccumVarVars[$hostOffset + 1]}"
+    local varRef="$varVar[\$targetOffset - \$hostOffset]"
+    local var="${!varRef}"
+    unset -v varVar varRef
 
     # TODO(@Ericson2314): Restore using associative array once Darwin
     # nix-shell doesn't use impure bash. This should replace the O(n)
@@ -324,21 +396,106 @@ findInputs() {
         exit 1
     fi
 
-    local file
-    for file in "${propagatedBuildInputsFiles[@]}"; do
-        file="$pkg/nix-support/$file"
-        [[ -f "$file" ]] || continue
-
-        local pkgNext
-        for pkgNext in $(< "$file"); do
-            findInputs "$pkgNext" "$var" "${propagatedBuildInputsFiles[@]}"
+    # The current package's host and target offset together
+    # provide a <=-preserving homomorphism from the relative
+    # offsets to current offset
+    function mapOffset() {
+        local -ri inputOffset="$1"
+        if (( "$inputOffset" <= 0 )); then
+            local -ri outputOffset="$inputOffset + $hostOffset"
+        else
+            local -ri outputOffset="$inputOffset - 1 + $targetOffset"
+        fi
+        echo "$outputOffset"
+    }
+
+    # Host offset relative to that of the package whose immediate
+    # dependencies we are currently exploring.
+    local -i relHostOffset
+    for relHostOffset in "${allPlatOffsets[@]}"; do
+        # `+ 1` so we start at 0 for valid index
+        local files="${propagatedDepFilesVars[$relHostOffset + 1]}"
+
+        # Host offset relative to the package currently being
+        # built---as absolute an offset as will be used.
+        local -i hostOffsetNext
+        hostOffsetNext="$(mapOffset relHostOffset)"
+
+        # Ensure we're in bounds relative to the package currently
+        # being built.
+        [[ "${allPlatOffsets[*]}" = *"$hostOffsetNext"*  ]] || continue
+
+        # Target offset relative to the *host* offset of the package
+        # whose immediate dependencies we are currently exploring.
+        local -i relTargetOffset
+        for relTargetOffset in "${allPlatOffsets[@]}"; do
+            (( "$relHostOffset" <= "$relTargetOffset" )) || continue
+
+            local fileRef="${files}[$relTargetOffset - $relHostOffset]"
+            local file="${!fileRef}"
+            unset -v fileRef
+
+            # Target offset relative to the package currently being
+            # built.
+            local -i targetOffsetNext
+            targetOffsetNext="$(mapOffset relTargetOffset)"
+
+            # Once again, ensure we're in bounds relative to the
+            # package currently being built.
+            [[ "${allPlatOffsets[*]}" = *"$targetOffsetNext"* ]] || continue
+
+            [[ -f "$pkg/nix-support/$file" ]] || continue
+
+            local pkgNext
+            for pkgNext in $(< "$pkg/nix-support/$file"); do
+                findInputs "$pkgNext" "$hostOffsetNext" "$targetOffsetNext"
+            done
         done
     done
 }
 
+# Make sure all are at least defined as empty
+: ${depsBuildBuild=} ${depsBuildBuildPropagated=}
+: ${nativeBuildInputs=} ${propagatedNativeBuildInputs=} ${defaultNativeBuildInputs=}
+: ${depsBuildTarget=} ${depsBuildTargetPropagated=}
+: ${depsHostHost=} ${depsHostHostPropagated=}
+: ${buildInputs=} ${propagatedBuildInputs=} ${defaultBuildInputs=}
+: ${depsTargetTarget=} ${depsTargetTargetPropagated=}
+
+for pkg in $depsBuildBuild $depsBuildBuildPropagated; do
+    findInputs "$pkg" -1 -1
+done
+for pkg in $nativeBuildInputs $propagatedNativeBuildInputs; do
+    findInputs "$pkg" -1  0
+done
+for pkg in $depsBuildTarget $depsBuildTargetPropagated; do
+    findInputs "$pkg" -1  1
+done
+for pkg in $depsHostHost $depsHostHostPropagated; do
+    findInputs "$pkg"  0  0
+done
+for pkg in $buildInputs $propagatedBuildInputs ; do
+    findInputs "$pkg"  0  1
+done
+for pkg in $depsTargetTarget $depsTargetTargetPropagated; do
+    findInputs "$pkg"  1  1
+done
+# Default inputs must be processed last
+for pkg in $defaultNativeBuildInputs; do
+    findInputs "$pkg" -1  0
+done
+for pkg in $defaultBuildInputs; do
+    findInputs "$pkg"  0  1
+done
+
 # Add package to the future PATH and run setup hooks
 activatePackage() {
     local pkg="$1"
+    local -ri hostOffset="$2"
+    local -ri targetOffset="$3"
+
+    # Sanity check
+    (( "$hostOffset" <= "$targetOffset" )) || exit -1
 
     if [ -f "$pkg" ]; then
         local oldOpts="$(shopt -po nounset)"
@@ -347,11 +504,18 @@ activatePackage() {
         eval "$oldOpts"
     fi
 
-    if [ -d "$pkg/bin" ]; then
+    # Only dependencies whose host platform is guaranteed to match the
+    # build platform are included here. That would be `depsBuild*`,
+    # and legacy `nativeBuildInputs`, in general. If we aren't cross
+    # compiling, however, everything can be put on the PATH. To ease
+    # the transition, we do include everything in thatcase.
+    #
+    # TODO(@Ericson2314): Don't special-case native compilation
+    if [[ ( -z "${crossConfig-}" ||  "$hostOffset" -le -1 ) && -d "$pkg/bin" ]]; then
         addToSearchPath _PATH "$pkg/bin"
     fi
 
-    if [ -f "$pkg/nix-support/setup-hook" ]; then
+    if [[ -f "$pkg/nix-support/setup-hook" ]]; then
         local oldOpts="$(shopt -po nounset)"
         set +u
         source "$pkg/nix-support/setup-hook"
@@ -359,67 +523,72 @@ activatePackage() {
     fi
 }
 
-declare -a nativePkgs crossPkgs
-if [ -z "${crossConfig:-}" ]; then
-    # Not cross-compiling - both buildInputs (and variants like propagatedBuildInputs)
-    # are handled identically to nativeBuildInputs
-    for i in ${nativeBuildInputs:-} ${buildInputs:-} \
-             ${defaultNativeBuildInputs:-} ${defaultBuildInputs:-} \
-             ${propagatedNativeBuildInputs:-} ${propagatedBuildInputs:-}; do
-        findInputs "$i" nativePkgs propagated-native-build-inputs propagated-build-inputs
-    done
-else
-    for i in ${nativeBuildInputs:-} ${defaultNativeBuildInputs:-} ${propagatedNativeBuildInputs:-}; do
-        findInputs "$i" nativePkgs propagated-native-build-inputs
-    done
-    for i in ${buildInputs:-} ${defaultBuildInputs:-} ${propagatedBuildInputs:-}; do
-        findInputs "$i" crossPkgs propagated-build-inputs
+_activatePkgs() {
+    local -i hostOffset targetOffset
+    local pkg
+
+    for hostOffset in "${allPlatOffsets[@]}"; do
+        local pkgsVar="${pkgAccumVarVars[$hostOffset + 1]}"
+        for targetOffset in "${allPlatOffsets[@]}"; do
+            (( "$hostOffset" <= "$targetOffset" )) || continue
+            local pkgsRef="${pkgsVar}[$targetOffset - $hostOffset]"
+            local pkgsSlice="${!pkgsRef}[@]"
+            for pkg in ${!pkgsSlice+"${!pkgsSlice}"}; do
+                activatePackage "$pkg" "$hostOffset" "$targetOffset"
+            done
+        done
     done
-fi
-
-for i in ${nativePkgs+"${nativePkgs[@]}"} ${crossPkgs+"${crossPkgs[@]}"}; do
-    activatePackage "$i"
-done
+}
 
+# Run the package setup hooks and build _PATH
+_activatePkgs
 
 # Set the relevant environment variables to point to the build inputs
 # found above.
 #
-# These `depOffset`s tell the env hook what sort of dependency
-# (ignoring propagatedness) is being passed to the env hook. In a real
-# language, we'd append a closure with this information to the
-# relevant env hook array, but bash doesn't have closures, so it's
-# easier to just pass this in.
-
-_addToNativeEnv() {
-    local pkg="$1"
-    if [[ -n "${crossConfig:-}" ]]; then
-        local -i depOffset=-1
-    else
-        local -i depOffset=0
-    fi
-
-    # Run the package-specific hooks set by the setup-hook scripts.
-    runHook envHook "$pkg"
-}
-
-# Old bash empty array hack
-for i in ${nativePkgs+"${nativePkgs[@]}"}; do
-    _addToNativeEnv "$i"
-done
-
-_addToCrossEnv() {
-    local pkg="$1"
-    local -i depOffset=0
-
-    # Run the package-specific hooks set by the setup-hook scripts.
-    runHook crossEnvHook "$pkg"
+# These `depOffset`s, beyond indexing the arrays, also tell the env
+# hook what sort of dependency (ignoring propagatedness) is being
+# passed to the env hook. In a real language, we'd append a closure
+# with this information to the relevant env hook array, but bash
+# doesn't have closures, so it's easier to just pass this in.
+_addToEnv() {
+    local -i depHostOffset depTargetOffset
+    local pkg
+
+    for depHostOffset in "${allPlatOffsets[@]}"; do
+        local hookVar="${pkgHookVarVars[$depHostOffset + 1]}"
+        local pkgsVar="${pkgAccumVarVars[$depHostOffset + 1]}"
+        for depTargetOffset in "${allPlatOffsets[@]}"; do
+            (( "$depHostOffset" <= "$depTargetOffset" )) || continue
+            local hookRef="${hookVar}[$depTargetOffset - $depHostOffset]"
+            if [[ -z "${crossConfig-}" ]]; then
+                # Apply environment hooks to all packages during native
+                # compilation to ease the transition.
+                #
+                # TODO(@Ericson2314): Don't special-case native compilation
+                for pkg in \
+                    ${pkgsBuildBuild+"${pkgsBuildBuild[@]}"} \
+                    ${pkgsBuildHost+"${pkgsBuildHost[@]}"} \
+                    ${pkgsBuildTarget+"${pkgsBuildTarget[@]}"} \
+                    ${pkgsHostHost+"${pkgsHostHost[@]}"} \
+                    ${pkgsHostTarget+"${pkgsHostTarget[@]}"} \
+                    ${pkgsTargetTarget+"${pkgsTargetTarget[@]}"}
+                do
+                    runHook "${!hookRef}" "$pkg"
+                done
+            else
+                local pkgsRef="${pkgsVar}[$depTargetOffset - $depHostOffset]"
+                local pkgsSlice="${!pkgsRef}[@]"
+                for pkg in ${!pkgsSlice+"${!pkgsSlice}"}; do
+                    runHook "${!hookRef}" "$pkg"
+                done
+            fi
+        done
+    done
 }
 
-# Old bash empty array hack
-for i in ${crossPkgs+"${crossPkgs[@]}"}; do
-    _addToCrossEnv "$i"
-done
+# Run the package-specific hooks set by the setup-hook scripts.
+_addToEnv
 
 
 _addRpathPrefix "$out"
@@ -882,6 +1051,7 @@ installPhase() {
 # propagated-build-inputs.
 fixupPhase() {
     # Make sure everything is writable so "strip" et al. work.
+    local output
     for output in $outputs; do
         if [ -e "${!output}" ]; then chmod -R u+w "${!output}"; fi
     done
@@ -895,19 +1065,35 @@ fixupPhase() {
     done
 
 
-    # Propagate build inputs and setup hook into the development output.
+    # Propagate dependencies & setup hook into the development output.
+    declare -ra flatVars=(
+        # Build
+        depsBuildBuildPropagated
+        propagatedNativeBuildInputs
+        depsBuildTargetPropagated
+        # Host
+        depsHostHostPropagated
+        propagatedBuildInputs
+        # Target
+        depsTargetTargetPropagated
+    )
+    declare -ra flatFiles=(
+        "${propagatedBuildDepFiles[@]}"
+        "${propagatedHostDepFiles[@]}"
+        "${propagatedTargetDepFiles[@]}"
+    )
 
-    if [ -n "${propagatedBuildInputs:-}" ]; then
-        mkdir -p "${!outputDev}/nix-support"
-        # shellcheck disable=SC2086
-        printWords $propagatedBuildInputs > "${!outputDev}/nix-support/propagated-build-inputs"
-    fi
+    local propagatedInputsIndex
+    for propagatedInputsIndex in "${!flatVars[@]}"; do
+        local propagatedInputsSlice="${flatVars[$propagatedInputsIndex]}[@]"
+        local propagatedInputsFile="${flatFiles[$propagatedInputsIndex]}"
+
+        [[ "${!propagatedInputsSlice}" ]] || continue
 
-    if [ -n "${propagatedNativeBuildInputs:-}" ]; then
         mkdir -p "${!outputDev}/nix-support"
         # shellcheck disable=SC2086
-        printWords $propagatedNativeBuildInputs > "${!outputDev}/nix-support/propagated-native-build-inputs"
-    fi
+        printWords ${!propagatedInputsSlice} > "${!outputDev}/nix-support/$propagatedInputsFile"
+    done
 
 
     if [ -n "${setupHook:-}" ]; then