From 238a6053c43f7ac2e3dcc3d3c7f29f1e0c0be589 Mon Sep 17 00:00:00 2001 From: Artturin Date: Wed, 1 Jun 2022 00:34:59 +0300 Subject: [PATCH] stdenv: support opt-in __structuredAttrs Co-authored-by: Robin Gloster stdenv: print message if structuredAttrs is enabled stdenv: add _append reduces the chance of a user doing it wrong fix nix develop issue output hooks don't work yet in nix develop though making $outputs be the same on non-structuredAttrs and structuredAttrs is too much trouble. lets instead make a function that gets the output names reading environment file '/nix/store/2x7m69a2sm2kh0r6v0q5s9z1dh41m4xf-xz-5.2.5-env-bin' nix: src/nix/develop.cc:299: std::string Common::makeRcScript(nix::ref, const BuildEnvironment&, const Path&): Assertion `outputs != buildEnvironment.vars.end()' failed. use a function to get all output names instead of using $outputs copy env functionality from https://github.com/NixOS/nixpkgs/pull/76732/commits --- .../cluster/nomad-autoscaler/default.nix | 2 +- .../bintools-wrapper/default.nix | 4 +- pkgs/build-support/release/nix-build.nix | 2 +- .../setup-hooks/auto-patchelf.sh | 2 +- pkgs/build-support/setup-hooks/move-docs.sh | 12 +- .../setup-hooks/multiple-outputs.sh | 32 ++- .../patch-ppd-files/patch-ppd-hook.sh | 2 +- pkgs/build-support/setup-hooks/strip.sh | 21 +- .../build-support/setup-hooks/win-dll-link.sh | 2 +- pkgs/build-support/testers/expect-failure.sh | 2 +- .../data/icons/catppuccin-cursors/default.nix | 2 +- pkgs/data/icons/comixcursors/default.nix | 2 +- pkgs/desktops/gnome/core/gdm/default.nix | 2 +- pkgs/development/compilers/openjdk/11.nix | 4 +- pkgs/development/compilers/openjdk/12.nix | 4 +- pkgs/development/compilers/openjdk/13.nix | 4 +- pkgs/development/compilers/openjdk/14.nix | 4 +- pkgs/development/compilers/openjdk/15.nix | 4 +- pkgs/development/compilers/openjdk/16.nix | 4 +- pkgs/development/compilers/openjdk/17.nix | 4 +- pkgs/development/compilers/openjdk/18.nix | 4 +- pkgs/development/compilers/openjdk/19.nix | 4 +- pkgs/development/compilers/openjdk/8.nix | 4 +- pkgs/development/libraries/polkit/default.nix | 2 +- .../darwin/signing-utils/auto-sign-hook.sh | 2 +- pkgs/stdenv/generic/default-builder.sh | 4 + pkgs/stdenv/generic/make-derivation.nix | 31 ++- pkgs/stdenv/generic/setup.sh | 222 +++++++++++++----- pkgs/tools/typesetting/tex/texlive/bin.nix | 2 +- 29 files changed, 271 insertions(+), 119 deletions(-) diff --git a/pkgs/applications/networking/cluster/nomad-autoscaler/default.nix b/pkgs/applications/networking/cluster/nomad-autoscaler/default.nix index 6329ff9ed11c..eb185f9743c1 100644 --- a/pkgs/applications/networking/cluster/nomad-autoscaler/default.nix +++ b/pkgs/applications/networking/cluster/nomad-autoscaler/default.nix @@ -45,7 +45,7 @@ let mv bin/nomad-autoscaler $bin/bin ln -s $bin/bin/nomad-autoscaler $out/bin/nomad-autoscaler - for d in $outputs; do + for d in $(getAllOutputNames); do mkdir -p ''${!d}/share done rmdir $bin/share diff --git a/pkgs/build-support/bintools-wrapper/default.nix b/pkgs/build-support/bintools-wrapper/default.nix index 121b50fe0f52..ea925e90fa47 100644 --- a/pkgs/build-support/bintools-wrapper/default.nix +++ b/pkgs/build-support/bintools-wrapper/default.nix @@ -68,7 +68,7 @@ let # The dynamic linker has different names on different platforms. This is a # shell glob that ought to match it. dynamicLinker = - /**/ if sharedLibraryLoader == null then null + /**/ if sharedLibraryLoader == null then "" else if targetPlatform.libc == "musl" then "${sharedLibraryLoader}/lib/ld-musl-*" else if targetPlatform.libc == "uclibc" then "${sharedLibraryLoader}/lib/ld*-uClibc.so.1" else if (targetPlatform.libc == "bionic" && targetPlatform.is32bit) then "/system/bin/linker" @@ -87,7 +87,7 @@ let else if targetPlatform.isDarwin then "/usr/lib/dyld" else if targetPlatform.isFreeBSD then "/libexec/ld-elf.so.1" else if lib.hasSuffix "pc-gnu" targetPlatform.config then "ld.so.1" - else null; + else ""; expand-response-params = if buildPackages ? stdenv && buildPackages.stdenv.hasCC && buildPackages.stdenv.cc != "/dev/null" diff --git a/pkgs/build-support/release/nix-build.nix b/pkgs/build-support/release/nix-build.nix index ac51b90e0163..5ed2b0752efc 100644 --- a/pkgs/build-support/release/nix-build.nix +++ b/pkgs/build-support/release/nix-build.nix @@ -124,7 +124,7 @@ stdenv.mkDerivation ( echo "$system" > $out/nix-support/system if [ -z "${toString doingAnalysis}" ]; then - for i in $outputs; do + for i in $(getAllOutputNames); do if [ "$i" = out ]; then j=none; else j="$i"; fi mkdir -p ''${!i}/nix-support echo "nix-build $j ''${!i}" >> ''${!i}/nix-support/hydra-build-products diff --git a/pkgs/build-support/setup-hooks/auto-patchelf.sh b/pkgs/build-support/setup-hooks/auto-patchelf.sh index 7f5ff146e30b..8a74a69bdceb 100644 --- a/pkgs/build-support/setup-hooks/auto-patchelf.sh +++ b/pkgs/build-support/setup-hooks/auto-patchelf.sh @@ -84,7 +84,7 @@ autoPatchelf() { # (Expressions don't expand in single quotes, use double quotes for that.) postFixupHooks+=(' if [ -z "${dontAutoPatchelf-}" ]; then - autoPatchelf -- $(for output in $outputs; do + autoPatchelf -- $(for output in $(getAllOutputNames); do [ -e "${!output}" ] || continue echo "${!output}" done) diff --git a/pkgs/build-support/setup-hooks/move-docs.sh b/pkgs/build-support/setup-hooks/move-docs.sh index e4460f98816d..833113aa0fc8 100644 --- a/pkgs/build-support/setup-hooks/move-docs.sh +++ b/pkgs/build-support/setup-hooks/move-docs.sh @@ -5,10 +5,17 @@ preFixupHooks+=(_moveToShare) _moveToShare() { - forceShare=${forceShare:=man doc info} + if [ -n "$__structuredAttrs" ]; then + if [ -z "${forceShare-}" ]; then + forceShare=( man doc info ) + fi + else + forceShare=( ${forceShare:-man doc info} ) + fi + if [[ -z "$out" ]]; then return; fi - for d in $forceShare; do + for d in "${forceShare[@]}"; do if [ -d "$out/$d" ]; then if [ -d "$out/share/$d" ]; then echo "both $d/ and share/$d/ exist!" @@ -20,4 +27,3 @@ _moveToShare() { fi done } - diff --git a/pkgs/build-support/setup-hooks/multiple-outputs.sh b/pkgs/build-support/setup-hooks/multiple-outputs.sh index 881cf6c90f48..8a2fc2f915e9 100644 --- a/pkgs/build-support/setup-hooks/multiple-outputs.sh +++ b/pkgs/build-support/setup-hooks/multiple-outputs.sh @@ -47,7 +47,7 @@ _overrideFirst outputInfo "info" "$outputBin" # Add standard flags to put files into the desired outputs. _multioutConfig() { - if [ "$outputs" = "out" ] || [ -z "${setOutputFlags-1}" ]; then return; fi; + if [ "$(getAllOutputNames)" = "out" ] || [ -z "${setOutputFlags-1}" ]; then return; fi; # try to detect share/doc/${shareDocName} # Note: sadly, $configureScript detection comes later in configurePhase, @@ -66,19 +66,17 @@ _multioutConfig() { fi fi - configureFlags="\ - --bindir=${!outputBin}/bin --sbindir=${!outputBin}/sbin \ - --includedir=${!outputInclude}/include --oldincludedir=${!outputInclude}/include \ - --mandir=${!outputMan}/share/man --infodir=${!outputInfo}/share/info \ - --docdir=${!outputDoc}/share/doc/${shareDocName} \ - --libdir=${!outputLib}/lib --libexecdir=${!outputLib}/libexec \ - --localedir=${!outputLib}/share/locale \ - $configureFlags" + prependToVar configureFlags \ + --bindir="${!outputBin}"/bin --sbindir="${!outputBin}"/sbin \ + --includedir="${!outputInclude}"/include --oldincludedir="${!outputInclude}"/include \ + --mandir="${!outputMan}"/share/man --infodir="${!outputInfo}"/share/info \ + --docdir="${!outputDoc}"/share/doc/"${shareDocName}" \ + --libdir="${!outputLib}"/lib --libexecdir="${!outputLib}"/libexec \ + --localedir="${!outputLib}"/share/locale - installFlags="\ - pkgconfigdir=${!outputDev}/lib/pkgconfig \ - m4datadir=${!outputDev}/share/aclocal aclocaldir=${!outputDev}/share/aclocal \ - $installFlags" + prependToVar installFlags \ + pkgconfigdir="${!outputDev}"/lib/pkgconfig \ + m4datadir="${!outputDev}"/share/aclocal aclocaldir="${!outputDev}"/share/aclocal } @@ -94,7 +92,7 @@ moveToOutput() { local patt="$1" local dstOut="$2" local output - for output in $outputs; do + for output in $(getAllOutputNames); do if [ "${!output}" = "$dstOut" ]; then continue; fi local srcPath for srcPath in "${!output}"/$patt; do @@ -149,7 +147,7 @@ _multioutDocs() { # Move development-only stuff to the desired outputs. _multioutDevs() { - if [ "$outputs" = "out" ] || [ -z "${moveToDev-1}" ]; then return; fi; + if [ "$(getAllOutputNames)" = "out" ] || [ -z "${moveToDev-1}" ]; then return; fi; moveToOutput include "${!outputInclude}" # these files are sometimes provided even without using the corresponding tool moveToOutput lib/pkgconfig "${!outputDev}" @@ -166,10 +164,10 @@ _multioutDevs() { # Make the "dev" propagate other outputs needed for development. _multioutPropagateDev() { - if [ "$outputs" = "out" ]; then return; fi; + if [ "$(getAllOutputNames)" = "out" ]; then return; fi; local outputFirst - for outputFirst in $outputs; do + for outputFirst in $(getAllOutputNames); do break done local propagaterOutput="$outputDev" diff --git a/pkgs/build-support/setup-hooks/patch-ppd-files/patch-ppd-hook.sh b/pkgs/build-support/setup-hooks/patch-ppd-files/patch-ppd-hook.sh index a450ecd7f963..77322b245b27 100644 --- a/pkgs/build-support/setup-hooks/patch-ppd-files/patch-ppd-hook.sh +++ b/pkgs/build-support/setup-hooks/patch-ppd-files/patch-ppd-hook.sh @@ -70,7 +70,7 @@ patchPpdFileCommands () { # * outputs of current build before buildInputs # * `/lib/cups/filter' before `/bin` # * add HOST_PATH at end, so we don't miss anything - for path in $outputs; do + for path in $(getAllOutputNames); do addToSearchPath cupspath "${!path}/lib/cups/filter" addToSearchPath cupspath "${!path}/bin" done diff --git a/pkgs/build-support/setup-hooks/strip.sh b/pkgs/build-support/setup-hooks/strip.sh index 9bd7b24cab54..104b5515b3db 100644 --- a/pkgs/build-support/setup-hooks/strip.sh +++ b/pkgs/build-support/setup-hooks/strip.sh @@ -12,11 +12,20 @@ _doStrip() { local -ra stripCmds=(STRIP STRIP_FOR_TARGET) local -ra ranlibCmds=(RANLIB RANLIB_FOR_TARGET) + # TODO(structured-attrs): This doesn't work correctly if one of + # the items in strip*List or strip*Flags contains a space, + # even with structured attrs enabled. This is OK for now + # because very few packages set any of these, and it doesn't + # affect any of them. + # + # After __structuredAttrs = true is universal, come back and + # push arrays all the way through this logic. + # Strip only host paths by default. Leave targets as is. - stripDebugList=${stripDebugList:-lib lib32 lib64 libexec bin sbin} - stripDebugListTarget=${stripDebugListTarget:-} - stripAllList=${stripAllList:-} - stripAllListTarget=${stripAllListTarget:-} + stripDebugList=${stripDebugList[*]:-lib lib32 lib64 libexec bin sbin} + stripDebugListTarget=${stripDebugListTarget[*]:-} + stripAllList=${stripAllList[*]:-} + stripAllListTarget=${stripAllListTarget[*]:-} local i for i in ${!stripCmds[@]}; do @@ -30,8 +39,8 @@ _doStrip() { if [[ "${dontStrip-}" || "${flag-}" ]] || ! type -f "${stripCmd-}" 2>/dev/null then continue; fi - stripDirs "$stripCmd" "$ranlibCmd" "$debugDirList" "${stripDebugFlags:--S}" - stripDirs "$stripCmd" "$ranlibCmd" "$allDirList" "${stripAllFlags:--s}" + stripDirs "$stripCmd" "$ranlibCmd" "$debugDirList" "${stripDebugFlags[*]:--S}" + stripDirs "$stripCmd" "$ranlibCmd" "$allDirList" "${stripAllFlags[*]:--s}" done } diff --git a/pkgs/build-support/setup-hooks/win-dll-link.sh b/pkgs/build-support/setup-hooks/win-dll-link.sh index 6130f32bef86..ca4cbb349b6c 100644 --- a/pkgs/build-support/setup-hooks/win-dll-link.sh +++ b/pkgs/build-support/setup-hooks/win-dll-link.sh @@ -15,7 +15,7 @@ _linkDLLs() { # prefix $PATH by currently-built outputs local DLLPATH="" local outName - for outName in $outputs; do + for outName in $(getAllOutputNames); do addToSearchPath DLLPATH "${!outName}/bin" done DLLPATH="$DLLPATH:$PATH" diff --git a/pkgs/build-support/testers/expect-failure.sh b/pkgs/build-support/testers/expect-failure.sh index 0e1bbe9a678c..052ee8527176 100644 --- a/pkgs/build-support/testers/expect-failure.sh +++ b/pkgs/build-support/testers/expect-failure.sh @@ -35,7 +35,7 @@ echo "testBuildFailure: Original builder produced exit code: $r" # ----------------------------------------- # Write the build log to the default output -outs=( $outputs ) +outs=( $(getAllOutputNames) ) defOut=${outs[0]} defOutPath=${!defOut} diff --git a/pkgs/data/icons/catppuccin-cursors/default.nix b/pkgs/data/icons/catppuccin-cursors/default.nix index d9eccc96a029..4559705c169b 100644 --- a/pkgs/data/icons/catppuccin-cursors/default.nix +++ b/pkgs/data/icons/catppuccin-cursors/default.nix @@ -50,7 +50,7 @@ stdenvNoCC.mkDerivation { installPhase = '' runHook preInstall - for output in $outputs; do + for output in $(getAllOutputNames); do if [ "$output" != "out" ]; then local outputDir="''${!output}" local iconsDir="$outputDir"/share/icons diff --git a/pkgs/data/icons/comixcursors/default.nix b/pkgs/data/icons/comixcursors/default.nix index b63877b28209..1c4fdc195180 100644 --- a/pkgs/data/icons/comixcursors/default.nix +++ b/pkgs/data/icons/comixcursors/default.nix @@ -52,7 +52,7 @@ stdenvNoCC.mkDerivation rec { ''; installPhase = '' - for outputName in $outputs ; do + for outputName in $(getAllOutputNames) ; do if [ $outputName != out ]; then local outputDir=''${!outputName}; local iconsDir=$outputDir/share/icons diff --git a/pkgs/desktops/gnome/core/gdm/default.nix b/pkgs/desktops/gnome/core/gdm/default.nix index f1fbe7e49d30..a2265387e1ef 100644 --- a/pkgs/desktops/gnome/core/gdm/default.nix +++ b/pkgs/desktops/gnome/core/gdm/default.nix @@ -143,7 +143,7 @@ stdenv.mkDerivation rec { # We use rsync to merge the directories. rsync --archive "${DESTDIR}/etc" "$out" rm --recursive "${DESTDIR}/etc" - for o in $outputs; do + for o in $(getAllOutputNames); do if [[ "$o" = "debug" ]]; then continue; fi rsync --archive "${DESTDIR}/''${!o}" "$(dirname "''${!o}")" rm --recursive "${DESTDIR}/''${!o}" diff --git a/pkgs/development/compilers/openjdk/11.nix b/pkgs/development/compilers/openjdk/11.nix index 95abb373272c..33c3177d2927 100644 --- a/pkgs/development/compilers/openjdk/11.nix +++ b/pkgs/development/compilers/openjdk/11.nix @@ -132,12 +132,12 @@ let postFixup = '' # Build the set of output library directories to rpath against LIBDIRS="" - for output in $outputs; do + for output in $(getAllOutputNames); do if [ "$output" = debug ]; then continue; fi LIBDIRS="$(find $(eval echo \$$output) -name \*.so\* -exec dirname {} \+ | sort | uniq | tr '\n' ':'):$LIBDIRS" done # Add the local library paths to remove dependencies on the bootstrap - for output in $outputs; do + for output in $(getAllOutputNames); do if [ "$output" = debug ]; then continue; fi OUTPUTDIR=$(eval echo \$$output) BINLIBS=$(find $OUTPUTDIR/bin/ -type f; find $OUTPUTDIR -name \*.so\*) diff --git a/pkgs/development/compilers/openjdk/12.nix b/pkgs/development/compilers/openjdk/12.nix index 60100a5ecc16..f56cf4a79220 100644 --- a/pkgs/development/compilers/openjdk/12.nix +++ b/pkgs/development/compilers/openjdk/12.nix @@ -136,12 +136,12 @@ let postFixup = '' # Build the set of output library directories to rpath against LIBDIRS="" - for output in $outputs; do + for output in $(getAllOutputNames); do if [ "$output" = debug ]; then continue; fi LIBDIRS="$(find $(eval echo \$$output) -name \*.so\* -exec dirname {} \+ | sort | uniq | tr '\n' ':'):$LIBDIRS" done # Add the local library paths to remove dependencies on the bootstrap - for output in $outputs; do + for output in $(getAllOutputNames); do if [ "$output" = debug ]; then continue; fi OUTPUTDIR=$(eval echo \$$output) BINLIBS=$(find $OUTPUTDIR/bin/ -type f; find $OUTPUTDIR -name \*.so\*) diff --git a/pkgs/development/compilers/openjdk/13.nix b/pkgs/development/compilers/openjdk/13.nix index 68a0a9fa7007..ce84d334b426 100644 --- a/pkgs/development/compilers/openjdk/13.nix +++ b/pkgs/development/compilers/openjdk/13.nix @@ -136,12 +136,12 @@ let postFixup = '' # Build the set of output library directories to rpath against LIBDIRS="" - for output in $outputs; do + for output in $(getAllOutputNames); do if [ "$output" = debug ]; then continue; fi LIBDIRS="$(find $(eval echo \$$output) -name \*.so\* -exec dirname {} \+ | sort | uniq | tr '\n' ':'):$LIBDIRS" done # Add the local library paths to remove dependencies on the bootstrap - for output in $outputs; do + for output in $(getAllOutputNames); do if [ "$output" = debug ]; then continue; fi OUTPUTDIR=$(eval echo \$$output) BINLIBS=$(find $OUTPUTDIR/bin/ -type f; find $OUTPUTDIR -name \*.so\*) diff --git a/pkgs/development/compilers/openjdk/14.nix b/pkgs/development/compilers/openjdk/14.nix index 37c3a6a3de3a..8e92b906189c 100644 --- a/pkgs/development/compilers/openjdk/14.nix +++ b/pkgs/development/compilers/openjdk/14.nix @@ -132,12 +132,12 @@ let postFixup = '' # Build the set of output library directories to rpath against LIBDIRS="" - for output in $outputs; do + for output in $(getAllOutputNames); do if [ "$output" = debug ]; then continue; fi LIBDIRS="$(find $(eval echo \$$output) -name \*.so\* -exec dirname {} \+ | sort | uniq | tr '\n' ':'):$LIBDIRS" done # Add the local library paths to remove dependencies on the bootstrap - for output in $outputs; do + for output in $(getAllOutputNames); do if [ "$output" = debug ]; then continue; fi OUTPUTDIR=$(eval echo \$$output) BINLIBS=$(find $OUTPUTDIR/bin/ -type f; find $OUTPUTDIR -name \*.so\*) diff --git a/pkgs/development/compilers/openjdk/15.nix b/pkgs/development/compilers/openjdk/15.nix index 6ea1d0b1dd31..c33e937f9f24 100644 --- a/pkgs/development/compilers/openjdk/15.nix +++ b/pkgs/development/compilers/openjdk/15.nix @@ -131,12 +131,12 @@ let postFixup = '' # Build the set of output library directories to rpath against LIBDIRS="" - for output in $outputs; do + for output in $(getAllOutputNames); do if [ "$output" = debug ]; then continue; fi LIBDIRS="$(find $(eval echo \$$output) -name \*.so\* -exec dirname {} \+ | sort | uniq | tr '\n' ':'):$LIBDIRS" done # Add the local library paths to remove dependencies on the bootstrap - for output in $outputs; do + for output in $(getAllOutputNames); do if [ "$output" = debug ]; then continue; fi OUTPUTDIR=$(eval echo \$$output) BINLIBS=$(find $OUTPUTDIR/bin/ -type f; find $OUTPUTDIR -name \*.so\*) diff --git a/pkgs/development/compilers/openjdk/16.nix b/pkgs/development/compilers/openjdk/16.nix index 0e1911bb1a70..461cd724144e 100644 --- a/pkgs/development/compilers/openjdk/16.nix +++ b/pkgs/development/compilers/openjdk/16.nix @@ -138,12 +138,12 @@ let postFixup = '' # Build the set of output library directories to rpath against LIBDIRS="" - for output in $outputs; do + for output in $(getAllOutputNames); do if [ "$output" = debug ]; then continue; fi LIBDIRS="$(find $(eval echo \$$output) -name \*.so\* -exec dirname {} \+ | sort | uniq | tr '\n' ':'):$LIBDIRS" done # Add the local library paths to remove dependencies on the bootstrap - for output in $outputs; do + for output in $(getAllOutputNames); do if [ "$output" = debug ]; then continue; fi OUTPUTDIR=$(eval echo \$$output) BINLIBS=$(find $OUTPUTDIR/bin/ -type f; find $OUTPUTDIR -name \*.so\*) diff --git a/pkgs/development/compilers/openjdk/17.nix b/pkgs/development/compilers/openjdk/17.nix index bc92b1393fdb..6d8087d7e948 100644 --- a/pkgs/development/compilers/openjdk/17.nix +++ b/pkgs/development/compilers/openjdk/17.nix @@ -149,12 +149,12 @@ let postFixup = '' # Build the set of output library directories to rpath against LIBDIRS="" - for output in $outputs; do + for output in $(getAllOutputNames); do if [ "$output" = debug ]; then continue; fi LIBDIRS="$(find $(eval echo \$$output) -name \*.so\* -exec dirname {} \+ | sort -u | tr '\n' ':'):$LIBDIRS" done # Add the local library paths to remove dependencies on the bootstrap - for output in $outputs; do + for output in $(getAllOutputNames); do if [ "$output" = debug ]; then continue; fi OUTPUTDIR=$(eval echo \$$output) BINLIBS=$(find $OUTPUTDIR/bin/ -type f; find $OUTPUTDIR -name \*.so\*) diff --git a/pkgs/development/compilers/openjdk/18.nix b/pkgs/development/compilers/openjdk/18.nix index 5be60eb94875..fd620aaaf9a5 100644 --- a/pkgs/development/compilers/openjdk/18.nix +++ b/pkgs/development/compilers/openjdk/18.nix @@ -140,12 +140,12 @@ let postFixup = '' # Build the set of output library directories to rpath against LIBDIRS="" - for output in $outputs; do + for output in $(getAllOutputNames); do if [ "$output" = debug ]; then continue; fi LIBDIRS="$(find $(eval echo \$$output) -name \*.so\* -exec dirname {} \+ | sort -u | tr '\n' ':'):$LIBDIRS" done # Add the local library paths to remove dependencies on the bootstrap - for output in $outputs; do + for output in $(getAllOutputNames); do if [ "$output" = debug ]; then continue; fi OUTPUTDIR=$(eval echo \$$output) BINLIBS=$(find $OUTPUTDIR/bin/ -type f; find $OUTPUTDIR -name \*.so\*) diff --git a/pkgs/development/compilers/openjdk/19.nix b/pkgs/development/compilers/openjdk/19.nix index 11b2fa60c733..9537b0d3ce52 100644 --- a/pkgs/development/compilers/openjdk/19.nix +++ b/pkgs/development/compilers/openjdk/19.nix @@ -140,12 +140,12 @@ let postFixup = '' # Build the set of output library directories to rpath against LIBDIRS="" - for output in $outputs; do + for output in $(getAllOutputNames); do if [ "$output" = debug ]; then continue; fi LIBDIRS="$(find $(eval echo \$$output) -name \*.so\* -exec dirname {} \+ | sort -u | tr '\n' ':'):$LIBDIRS" done # Add the local library paths to remove dependencies on the bootstrap - for output in $outputs; do + for output in $(getAllOutputNames); do if [ "$output" = debug ]; then continue; fi OUTPUTDIR=$(eval echo \$$output) BINLIBS=$(find $OUTPUTDIR/bin/ -type f; find $OUTPUTDIR -name \*.so\*) diff --git a/pkgs/development/compilers/openjdk/8.nix b/pkgs/development/compilers/openjdk/8.nix index c232b1f01f16..5558a77ad90b 100644 --- a/pkgs/development/compilers/openjdk/8.nix +++ b/pkgs/development/compilers/openjdk/8.nix @@ -187,12 +187,12 @@ let postFixup = '' # Build the set of output library directories to rpath against LIBDIRS="" - for output in $outputs; do + for output in $(getAllOutputNames); do if [ "$output" = debug ]; then continue; fi LIBDIRS="$(find $(eval echo \$$output) -name \*.so\* -exec dirname {} \+ | sort | uniq | tr '\n' ':'):$LIBDIRS" done # Add the local library paths to remove dependencies on the bootstrap - for output in $outputs; do + for output in $(getAllOutputNames); do if [ "$output" = debug ]; then continue; fi OUTPUTDIR=$(eval echo \$$output) BINLIBS=$(find $OUTPUTDIR/bin/ -type f; find $OUTPUTDIR -name \*.so\*) diff --git a/pkgs/development/libraries/polkit/default.nix b/pkgs/development/libraries/polkit/default.nix index a0344d68a12b..6ab7a4bb9c3a 100644 --- a/pkgs/development/libraries/polkit/default.nix +++ b/pkgs/development/libraries/polkit/default.nix @@ -167,7 +167,7 @@ stdenv.mkDerivation rec { rsync --archive "${DESTDIR}${system}"/* "$out" rm --recursive "${DESTDIR}${system}"/* rmdir --parents --ignore-fail-on-non-empty "${DESTDIR}${system}" - for o in $outputs; do + for o in $(getAllOutputNames); do rsync --archive "${DESTDIR}/''${!o}" "$(dirname "''${!o}")" rm --recursive "${DESTDIR}/''${!o}" done diff --git a/pkgs/os-specific/darwin/signing-utils/auto-sign-hook.sh b/pkgs/os-specific/darwin/signing-utils/auto-sign-hook.sh index cca65661f8a9..6a254cd82123 100644 --- a/pkgs/os-specific/darwin/signing-utils/auto-sign-hook.sh +++ b/pkgs/os-specific/darwin/signing-utils/auto-sign-hook.sh @@ -25,7 +25,7 @@ signDarwinBinariesIn() { signDarwinBinariesInAllOutputs() { local output - for output in $outputs; do + for output in $(getAllOutputNames); do signDarwinBinariesIn "${!output}" done } diff --git a/pkgs/stdenv/generic/default-builder.sh b/pkgs/stdenv/generic/default-builder.sh index 273fc55c7552..8c6fec7873b6 100644 --- a/pkgs/stdenv/generic/default-builder.sh +++ b/pkgs/stdenv/generic/default-builder.sh @@ -1,2 +1,6 @@ +if [ -f .attrs.sh ]; then + . .attrs.sh +fi + source $stdenv/setup genericBuild diff --git a/pkgs/stdenv/generic/make-derivation.nix b/pkgs/stdenv/generic/make-derivation.nix index 510537aac9f3..09a71da93b6e 100644 --- a/pkgs/stdenv/generic/make-derivation.nix +++ b/pkgs/stdenv/generic/make-derivation.nix @@ -154,6 +154,12 @@ let (! attrs ? outputHash) # Fixed-output drvs can't be content addressed too && config.contentAddressedByDefault +# Experimental. For simple packages mostly just works, +# but for anything complex, be prepared to debug if enabling. +, __structuredAttrs ? false + +, env ? { } + , ... } @ attrs: let @@ -259,13 +265,16 @@ else let lib.unique (lib.concatMap (input: input.__propagatedImpureHostDeps or []) (lib.concatLists propagatedDependencies)); + envIsExportable = lib.isAttrs env && !lib.isDerivation env; + derivationArg = (removeAttrs attrs - ["meta" "passthru" "pos" + (["meta" "passthru" "pos" "checkInputs" "installCheckInputs" "__darwinAllowLocalNetworking" "__impureHostDeps" "__propagatedImpureHostDeps" - "sandboxProfile" "propagatedSandboxProfile"]) + "sandboxProfile" "propagatedSandboxProfile"] + ++ lib.optionals envIsExportable [ "env" ])) // (lib.optionalAttrs (attrs ? name || (attrs ? pname && attrs ? version)) { name = let @@ -289,7 +298,7 @@ else let then attrs.name + hostSuffix else "${attrs.pname}${staticMarker}${hostSuffix}-${attrs.version}" ); - }) // { + }) // lib.optionalAttrs (envIsExportable && __structuredAttrs) { env = checkedEnv; } // { builder = attrs.realBuilder or stdenv.shell; args = attrs.args or ["-e" (attrs.builder or ./default-builder.sh)]; inherit stdenv; @@ -304,8 +313,7 @@ else let userHook = config.stdenv.userHook or null; __ignoreNulls = true; - - inherit strictDeps; + inherit __structuredAttrs strictDeps; depsBuildBuild = lib.elemAt (lib.elemAt dependencies 0) 0; nativeBuildInputs = lib.elemAt (lib.elemAt dependencies 0) 1; @@ -473,6 +481,17 @@ else let else true); }; + checkedEnv = + let + overlappingNames = lib.intersectLists (lib.attrNames env) (lib.attrNames derivationArg); + in + assert lib.assertMsg (overlappingNames == [ ]) + "The ‘env’ attribute set cannot contain any attributes passed to derivation. The following attributes are overlapping: ${lib.concatStringsSep ", " overlappingNames}"; + lib.mapAttrs + (n: v: assert lib.assertMsg (lib.isString v || lib.isBool v || lib.isInt v) + "The ‘env’ attribute set can only contain string, boolean or integer attributes. The ‘${n}’ attribute is of type ${builtins.typeOf v}."; v) + env; + in lib.extendDerivation @@ -509,7 +528,7 @@ lib.extendDerivation # should be made available to Nix expressions using the # derivation (e.g., in assertions). passthru) - (derivation derivationArg); + (derivation (derivationArg // lib.optionalAttrs envIsExportable checkedEnv)); in fnOrAttrs: diff --git a/pkgs/stdenv/generic/setup.sh b/pkgs/stdenv/generic/setup.sh index c6cdb6c3df75..de1dad5a1697 100644 --- a/pkgs/stdenv/generic/setup.sh +++ b/pkgs/stdenv/generic/setup.sh @@ -15,8 +15,29 @@ if (( "${NIX_DEBUG:-0}" >= 6 )); then set -x fi -: ${outputs:=out} +if [ -f .attrs.sh ]; then + __structuredAttrs=1 + echo "structuredAttrs is enabled" +else + __structuredAttrs= +fi +if [ -n "$__structuredAttrs" ]; then + for outputName in "${!outputs[@]}"; do + # ex: out=/nix/store/... + export "$outputName=${outputs[$outputName]}" + done +else + : ${outputs:=out} +fi + +getAllOutputNames() { + if [ -n "$__structuredAttrs" ]; then + echo "${!outputs[*]}" + else + echo "$outputs" + fi +} ###################################################################### # Hook handling. @@ -175,6 +196,63 @@ addToSearchPath() { addToSearchPathWithCustomDelimiter ":" "$@" } +# Prepend elements to variable "$1", which may come from an attr. +# +# This is useful in generic setup code, which must (for now) support +# both derivations with and without __structuredAttrs true, so the +# variable may be an array or a space-separated string. +# +# Expressions for individual packages should simply switch to array +# syntax when they switch to setting __structuredAttrs = true. +prependToVar() { + local -n nameref="$1"; shift + if [ -n "$__structuredAttrs" ]; then + nameref=( "$@" ${nameref+"${nameref[@]}"} ) + else + nameref="$* ${nameref-}" + fi +} + +# Same as above +appendToVar() { + local -n nameref="$1"; shift + if [ -n "$__structuredAttrs" ]; then + nameref=( ${nameref+"${nameref[@]}"} "$@" ) + else + nameref="${nameref-} $*" + fi +} + +# Accumulate into `flagsArray` the flags from the named variables. +# +# If __structuredAttrs, the variables are all treated as arrays +# and simply concatenated onto `flagsArray`. +# +# If not __structuredAttrs, then: +# * Each variable is treated as a string, and split on whitespace; +# * except variables whose names end in "Array", which are treated +# as arrays. +_accumFlagsArray() { + local name + if [ -n "$__structuredAttrs" ]; then + for name in "$@"; do + local -n nameref="$name" + flagsArray+=( ${nameref+"${nameref[@]}"} ) + done + else + for name in "$@"; do + local -n nameref="$name" + case "$name" in + *Array) + flagsArray+=( ${nameref+"${nameref[@]}"} ) ;; + *) + flagsArray+=( ${nameref-} ) ;; + esac + done + fi + +} + # Add $1/lib* into rpaths. # The function is used in multiple-outputs.sh hook, # so it is defined here but tried after the hook. @@ -255,6 +333,11 @@ printWords() { ###################################################################### # Initialisation. +# export all vars that should be in the ENV +for envVar in "${!env[@]}"; do + declare -x "${envVar}=${env[${envVar}]}" +done + # Set a fallback default value for SOURCE_DATE_EPOCH, used by some build tools # to provide a deterministic substitute for the "current" time. Note that @@ -469,6 +552,10 @@ findInputs() { done } +# The way we handle deps* and *Inputs works with structured attrs +# either enabled or disabled. For this it's convenient that the items +# in each list must be store paths, and therefore space-free. + # Make sure all are at least defined as empty : ${depsBuildBuild=} ${depsBuildBuildPropagated=} : ${nativeBuildInputs=} ${propagatedNativeBuildInputs=} ${defaultNativeBuildInputs=} @@ -477,29 +564,29 @@ findInputs() { : ${buildInputs=} ${propagatedBuildInputs=} ${defaultBuildInputs=} : ${depsTargetTarget=} ${depsTargetTargetPropagated=} -for pkg in $depsBuildBuild $depsBuildBuildPropagated; do +for pkg in ${depsBuildBuild[@]} ${depsBuildBuildPropagated[@]}; do findInputs "$pkg" -1 -1 done -for pkg in $nativeBuildInputs $propagatedNativeBuildInputs; do +for pkg in ${nativeBuildInputs[@]} ${propagatedNativeBuildInputs[@]}; do findInputs "$pkg" -1 0 done -for pkg in $depsBuildTarget $depsBuildTargetPropagated; do +for pkg in ${depsBuildTarget[@]} ${depsBuildTargetPropagated[@]}; do findInputs "$pkg" -1 1 done -for pkg in $depsHostHost $depsHostHostPropagated; do +for pkg in ${depsHostHost[@]} ${depsHostHostPropagated[@]}; do findInputs "$pkg" 0 0 done -for pkg in $buildInputs $propagatedBuildInputs ; do +for pkg in ${buildInputs[@]} ${propagatedBuildInputs[@]} ; do findInputs "$pkg" 0 1 done -for pkg in $depsTargetTarget $depsTargetTargetPropagated; do +for pkg in ${depsTargetTarget[@]} ${depsTargetTargetPropagated[@]}; do findInputs "$pkg" 1 1 done # Default inputs must be processed last -for pkg in $defaultNativeBuildInputs; do +for pkg in ${defaultNativeBuildInputs[@]}; do findInputs "$pkg" -1 0 done -for pkg in $defaultBuildInputs; do +for pkg in ${defaultBuildInputs[@]}; do findInputs "$pkg" 0 1 done @@ -909,6 +996,13 @@ unpackPhase() { srcs="$src" fi + local -a srcsArray + if [ -n "$__structuredAttrs" ]; then + srcsArray=( "${srcs[@]}" ) + else + srcsArray=( $srcs ) + fi + # To determine the source directory created by unpacking the # source archives, we record the contents of the current # directory, then look below which directory got added. Yeah, @@ -921,7 +1015,7 @@ unpackPhase() { done # Unpack all source archives. - for i in $srcs; do + for i in "${srcsArray[@]}"; do unpackFile "$i" done @@ -971,7 +1065,14 @@ unpackPhase() { patchPhase() { runHook prePatch - for i in ${patches:-}; do + local -a patchesArray + if [ -n "$__structuredAttrs" ]; then + patchesArray=( ${patches:+"${patches[@]}"} ) + else + patchesArray=( ${patches:-} ) + fi + + for i in "${patchesArray[@]}"; do header "applying patch $i" 3 local uncompress=cat case "$i" in @@ -988,9 +1089,17 @@ patchPhase() { uncompress="lzma -d" ;; esac + + local -a flagsArray + if [ -n "$__structuredAttrs" ]; then + flagsArray=( "${patchFlags[@]:--p1}" ) + else + # shellcheck disable=SC2086 + flagsArray=( ${patchFlags:--p1} ) + fi # "2>&1" is a hack to make patch fail if the decompressor fails (nonexistent patch, etc.) # shellcheck disable=SC2086 - $uncompress < "$i" 2>&1 | patch ${patchFlags:--p1} + $uncompress < "$i" 2>&1 | patch "${flagsArray[@]}" done runHook postPatch @@ -1018,7 +1127,6 @@ configurePhase() { # set to empty if unset : ${configureScript=} - : ${configureFlags=} if [[ -z "$configureScript" && -x ./configure ]]; then configureScript=./configure @@ -1049,31 +1157,29 @@ configurePhase() { fi if [[ -z "${dontAddPrefix:-}" && -n "$prefix" ]]; then - configureFlags="${prefixKey:---prefix=}$prefix $configureFlags" + prependToVar configureFlags "${prefixKey:---prefix=}$prefix" fi if [[ -f "$configureScript" ]]; then # Add --disable-dependency-tracking to speed up some builds. if [ -z "${dontAddDisableDepTrack:-}" ]; then if grep -q dependency-tracking "$configureScript"; then - configureFlags="--disable-dependency-tracking $configureFlags" + prependToVar configureFlags --disable-dependency-tracking fi fi # By default, disable static builds. if [ -z "${dontDisableStatic:-}" ]; then if grep -q enable-static "$configureScript"; then - configureFlags="--disable-static $configureFlags" + prependToVar configureFlags --disable-static fi fi fi if [ -n "$configureScript" ]; then - # Old bash empty array hack - # shellcheck disable=SC2086 - local flagsArray=( - $configureFlags "${configureFlagsArray[@]}" - ) + local -a flagsArray + _accumFlagsArray configureFlags configureFlagsArray + echoCmd 'configure flags' "${flagsArray[@]}" # shellcheck disable=SC2086 $configureScript "${flagsArray[@]}" @@ -1089,22 +1195,17 @@ configurePhase() { buildPhase() { runHook preBuild - # set to empty if unset - : ${makeFlags=} - - if [[ -z "$makeFlags" && -z "${makefile:-}" && ! ( -e Makefile || -e makefile || -e GNUmakefile ) ]]; then + if [[ -z "${makeFlags-}" && -z "${makefile:-}" && ! ( -e Makefile || -e makefile || -e GNUmakefile ) ]]; then echo "no Makefile, doing nothing" else foundMakefile=1 - # Old bash empty array hack # shellcheck disable=SC2086 local flagsArray=( ${enableParallelBuilding:+-j${NIX_BUILD_CORES}} SHELL=$SHELL - $makeFlags "${makeFlagsArray[@]}" - $buildFlags "${buildFlagsArray[@]}" ) + _accumFlagsArray makeFlags makeFlagsArray buildFlags buildFlagsArray echoCmd 'build flags' "${flagsArray[@]}" make ${makefile:+-f $makefile} "${flagsArray[@]}" @@ -1141,11 +1242,17 @@ checkPhase() { local flagsArray=( ${enableParallelChecking:+-j${NIX_BUILD_CORES}} SHELL=$SHELL - $makeFlags "${makeFlagsArray[@]}" - ${checkFlags:-VERBOSE=y} "${checkFlagsArray[@]}" - ${checkTarget} ) + _accumFlagsArray makeFlags makeFlagsArray + if [ -n "$__structuredAttrs" ]; then + flagsArray+=( "${checkFlags[@]:-VERBOSE=y}" ) + else + flagsArray+=( ${checkFlags:-VERBOSE=y} ) + fi + _accumFlagsArray checkFlagsArray + flagsArray+=( ${checkTarget} ) + echoCmd 'check flags' "${flagsArray[@]}" make ${makefile:+-f $makefile} "${flagsArray[@]}" @@ -1163,14 +1270,16 @@ installPhase() { mkdir -p "$prefix" fi - # Old bash empty array hack # shellcheck disable=SC2086 local flagsArray=( SHELL=$SHELL - $makeFlags "${makeFlagsArray[@]}" - $installFlags "${installFlagsArray[@]}" - ${installTargets:-install} ) + _accumFlagsArray makeFlags makeFlagsArray installFlags installFlagsArray + if [ -n "$__structuredAttrs" ]; then + flagsArray+=( "${installTargets[@]:-install}" ) + else + flagsArray+=( ${installTargets:-install} ) + fi echoCmd 'install flags' "${flagsArray[@]}" make ${makefile:+-f $makefile} "${flagsArray[@]}" @@ -1186,7 +1295,7 @@ installPhase() { fixupPhase() { # Make sure everything is writable so "strip" et al. work. local output - for output in $outputs; do + for output in $(getAllOutputNames); do if [ -e "${!output}" ]; then chmod -R u+w "${!output}"; fi done @@ -1194,7 +1303,7 @@ fixupPhase() { # Apply fixup to each output. local output - for output in $outputs; do + for output in $(getAllOutputNames); do prefix="${!output}" runHook fixupOutput done @@ -1239,7 +1348,10 @@ fixupPhase() { if [ -n "${setupHooks:-}" ]; then mkdir -p "${!outputDev}/nix-support" local hook - for hook in $setupHooks; do + # have to use ${setupHooks[@]} without quotes because it needs to support setupHooks being a array or a whitespace separated string + # # values of setupHooks won't have spaces so it won't cause problems + # shellcheck disable=2068 + for hook in ${setupHooks[@]}; do local content consumeEntire content < "$hook" substituteAllStream content "file '$hook'" >> "${!outputDev}/nix-support/setup-hook" @@ -1275,11 +1387,12 @@ installCheckPhase() { local flagsArray=( ${enableParallelChecking:+-j${NIX_BUILD_CORES}} SHELL=$SHELL - $makeFlags "${makeFlagsArray[@]}" - $installCheckFlags "${installCheckFlagsArray[@]}" - ${installCheckTarget:-installcheck} ) + _accumFlagsArray makeFlags makeFlagsArray \ + installCheckFlags installCheckFlagsArray + flagsArray+=( ${installCheckTarget:-installcheck} ) + echoCmd 'installcheck flags' "${flagsArray[@]}" make ${makefile:+-f $makefile} "${flagsArray[@]}" unset flagsArray @@ -1292,11 +1405,9 @@ installCheckPhase() { distPhase() { runHook preDist - # Old bash empty array hack - # shellcheck disable=SC2086 - local flagsArray=( - $distFlags "${distFlagsArray[@]}" ${distTarget:-dist} - ) + local flagsArray=() + _accumFlagsArray distFlags distFlagsArray + flagsArray+=( ${distTarget:-dist} ) echo 'dist flags: %q' "${flagsArray[@]}" make ${makefile:+-f $makefile} "${flagsArray[@]}" @@ -1307,7 +1418,7 @@ distPhase() { # Note: don't quote $tarballs, since we explicitly permit # wildcards in there. # shellcheck disable=SC2086 - cp -pvd ${tarballs:-*.tar.gz} "$out/tarballs" + cp -pvd ${tarballs[*]:-*.tar.gz} "$out/tarballs" fi runHook postDist @@ -1357,14 +1468,18 @@ genericBuild() { return fi - if [ -z "${phases:-}" ]; then - phases="${prePhases:-} unpackPhase patchPhase ${preConfigurePhases:-} \ - configurePhase ${preBuildPhases:-} buildPhase checkPhase \ - ${preInstallPhases:-} installPhase ${preFixupPhases:-} fixupPhase installCheckPhase \ - ${preDistPhases:-} distPhase ${postPhases:-}"; + if [ -z "${phases[*]:-}" ]; then + phases="${prePhases[*]:-} unpackPhase patchPhase ${preConfigurePhases[*]:-} \ + configurePhase ${preBuildPhases[*]:-} buildPhase checkPhase \ + ${preInstallPhases[*]:-} installPhase ${preFixupPhases[*]:-} fixupPhase installCheckPhase \ + ${preDistPhases[*]:-} distPhase ${postPhases[*]:-}"; fi - for curPhase in $phases; do + # The use of ${phases[*]} gives the correct behavior both with and + # without structured attrs. This relies on the fact that each + # phase name is space-free, which it must be because it's the name + # of either a shell variable or a shell function. + for curPhase in ${phases[*]}; do if [[ "$curPhase" = unpackPhase && -n "${dontUnpack:-}" ]]; then continue; fi if [[ "$curPhase" = patchPhase && -n "${dontPatch:-}" ]]; then continue; fi if [[ "$curPhase" = configurePhase && -n "${dontConfigure:-}" ]]; then continue; fi @@ -1414,6 +1529,7 @@ runHook userHook dumpVars + # Restore the original options for nix-shell [[ $__nixpkgs_setup_set_original == *e* ]] || set +e [[ $__nixpkgs_setup_set_original == *u* ]] || set +u diff --git a/pkgs/tools/typesetting/tex/texlive/bin.nix b/pkgs/tools/typesetting/tex/texlive/bin.nix index 6c7d8880a316..d874f443f4a3 100644 --- a/pkgs/tools/typesetting/tex/texlive/bin.nix +++ b/pkgs/tools/typesetting/tex/texlive/bin.nix @@ -247,7 +247,7 @@ core-big = stdenv.mkDerivation { #TODO: upmendex "xetex" ]; postInstall = '' - for output in $outputs; do + for output in $(getAllOutputNames); do mkdir -p "''${!output}/bin" done