lol

stdenv: support opt-in __structuredAttrs

Co-authored-by: Robin Gloster <mail@glob.in>

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<nix::Store>, 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

Artturin 238a6053 3754f950

+271 -119
+1 -1
pkgs/applications/networking/cluster/nomad-autoscaler/default.nix
··· 45 45 mv bin/nomad-autoscaler $bin/bin 46 46 ln -s $bin/bin/nomad-autoscaler $out/bin/nomad-autoscaler 47 47 48 - for d in $outputs; do 48 + for d in $(getAllOutputNames); do 49 49 mkdir -p ''${!d}/share 50 50 done 51 51 rmdir $bin/share
+2 -2
pkgs/build-support/bintools-wrapper/default.nix
··· 68 68 # The dynamic linker has different names on different platforms. This is a 69 69 # shell glob that ought to match it. 70 70 dynamicLinker = 71 - /**/ if sharedLibraryLoader == null then null 71 + /**/ if sharedLibraryLoader == null then "" 72 72 else if targetPlatform.libc == "musl" then "${sharedLibraryLoader}/lib/ld-musl-*" 73 73 else if targetPlatform.libc == "uclibc" then "${sharedLibraryLoader}/lib/ld*-uClibc.so.1" 74 74 else if (targetPlatform.libc == "bionic" && targetPlatform.is32bit) then "/system/bin/linker" ··· 87 87 else if targetPlatform.isDarwin then "/usr/lib/dyld" 88 88 else if targetPlatform.isFreeBSD then "/libexec/ld-elf.so.1" 89 89 else if lib.hasSuffix "pc-gnu" targetPlatform.config then "ld.so.1" 90 - else null; 90 + else ""; 91 91 92 92 expand-response-params = 93 93 if buildPackages ? stdenv && buildPackages.stdenv.hasCC && buildPackages.stdenv.cc != "/dev/null"
+1 -1
pkgs/build-support/release/nix-build.nix
··· 124 124 echo "$system" > $out/nix-support/system 125 125 126 126 if [ -z "${toString doingAnalysis}" ]; then 127 - for i in $outputs; do 127 + for i in $(getAllOutputNames); do 128 128 if [ "$i" = out ]; then j=none; else j="$i"; fi 129 129 mkdir -p ''${!i}/nix-support 130 130 echo "nix-build $j ''${!i}" >> ''${!i}/nix-support/hydra-build-products
+1 -1
pkgs/build-support/setup-hooks/auto-patchelf.sh
··· 84 84 # (Expressions don't expand in single quotes, use double quotes for that.) 85 85 postFixupHooks+=(' 86 86 if [ -z "${dontAutoPatchelf-}" ]; then 87 - autoPatchelf -- $(for output in $outputs; do 87 + autoPatchelf -- $(for output in $(getAllOutputNames); do 88 88 [ -e "${!output}" ] || continue 89 89 echo "${!output}" 90 90 done)
+9 -3
pkgs/build-support/setup-hooks/move-docs.sh
··· 5 5 preFixupHooks+=(_moveToShare) 6 6 7 7 _moveToShare() { 8 - forceShare=${forceShare:=man doc info} 8 + if [ -n "$__structuredAttrs" ]; then 9 + if [ -z "${forceShare-}" ]; then 10 + forceShare=( man doc info ) 11 + fi 12 + else 13 + forceShare=( ${forceShare:-man doc info} ) 14 + fi 15 + 9 16 if [[ -z "$out" ]]; then return; fi 10 17 11 - for d in $forceShare; do 18 + for d in "${forceShare[@]}"; do 12 19 if [ -d "$out/$d" ]; then 13 20 if [ -d "$out/share/$d" ]; then 14 21 echo "both $d/ and share/$d/ exist!" ··· 20 27 fi 21 28 done 22 29 } 23 -
+15 -17
pkgs/build-support/setup-hooks/multiple-outputs.sh
··· 47 47 48 48 # Add standard flags to put files into the desired outputs. 49 49 _multioutConfig() { 50 - if [ "$outputs" = "out" ] || [ -z "${setOutputFlags-1}" ]; then return; fi; 50 + if [ "$(getAllOutputNames)" = "out" ] || [ -z "${setOutputFlags-1}" ]; then return; fi; 51 51 52 52 # try to detect share/doc/${shareDocName} 53 53 # Note: sadly, $configureScript detection comes later in configurePhase, ··· 66 66 fi 67 67 fi 68 68 69 - configureFlags="\ 70 - --bindir=${!outputBin}/bin --sbindir=${!outputBin}/sbin \ 71 - --includedir=${!outputInclude}/include --oldincludedir=${!outputInclude}/include \ 72 - --mandir=${!outputMan}/share/man --infodir=${!outputInfo}/share/info \ 73 - --docdir=${!outputDoc}/share/doc/${shareDocName} \ 74 - --libdir=${!outputLib}/lib --libexecdir=${!outputLib}/libexec \ 75 - --localedir=${!outputLib}/share/locale \ 76 - $configureFlags" 69 + prependToVar configureFlags \ 70 + --bindir="${!outputBin}"/bin --sbindir="${!outputBin}"/sbin \ 71 + --includedir="${!outputInclude}"/include --oldincludedir="${!outputInclude}"/include \ 72 + --mandir="${!outputMan}"/share/man --infodir="${!outputInfo}"/share/info \ 73 + --docdir="${!outputDoc}"/share/doc/"${shareDocName}" \ 74 + --libdir="${!outputLib}"/lib --libexecdir="${!outputLib}"/libexec \ 75 + --localedir="${!outputLib}"/share/locale 77 76 78 - installFlags="\ 79 - pkgconfigdir=${!outputDev}/lib/pkgconfig \ 80 - m4datadir=${!outputDev}/share/aclocal aclocaldir=${!outputDev}/share/aclocal \ 81 - $installFlags" 77 + prependToVar installFlags \ 78 + pkgconfigdir="${!outputDev}"/lib/pkgconfig \ 79 + m4datadir="${!outputDev}"/share/aclocal aclocaldir="${!outputDev}"/share/aclocal 82 80 } 83 81 84 82 ··· 94 92 local patt="$1" 95 93 local dstOut="$2" 96 94 local output 97 - for output in $outputs; do 95 + for output in $(getAllOutputNames); do 98 96 if [ "${!output}" = "$dstOut" ]; then continue; fi 99 97 local srcPath 100 98 for srcPath in "${!output}"/$patt; do ··· 149 147 150 148 # Move development-only stuff to the desired outputs. 151 149 _multioutDevs() { 152 - if [ "$outputs" = "out" ] || [ -z "${moveToDev-1}" ]; then return; fi; 150 + if [ "$(getAllOutputNames)" = "out" ] || [ -z "${moveToDev-1}" ]; then return; fi; 153 151 moveToOutput include "${!outputInclude}" 154 152 # these files are sometimes provided even without using the corresponding tool 155 153 moveToOutput lib/pkgconfig "${!outputDev}" ··· 166 164 167 165 # Make the "dev" propagate other outputs needed for development. 168 166 _multioutPropagateDev() { 169 - if [ "$outputs" = "out" ]; then return; fi; 167 + if [ "$(getAllOutputNames)" = "out" ]; then return; fi; 170 168 171 169 local outputFirst 172 - for outputFirst in $outputs; do 170 + for outputFirst in $(getAllOutputNames); do 173 171 break 174 172 done 175 173 local propagaterOutput="$outputDev"
+1 -1
pkgs/build-support/setup-hooks/patch-ppd-files/patch-ppd-hook.sh
··· 70 70 # * outputs of current build before buildInputs 71 71 # * `/lib/cups/filter' before `/bin` 72 72 # * add HOST_PATH at end, so we don't miss anything 73 - for path in $outputs; do 73 + for path in $(getAllOutputNames); do 74 74 addToSearchPath cupspath "${!path}/lib/cups/filter" 75 75 addToSearchPath cupspath "${!path}/bin" 76 76 done
+15 -6
pkgs/build-support/setup-hooks/strip.sh
··· 12 12 local -ra stripCmds=(STRIP STRIP_FOR_TARGET) 13 13 local -ra ranlibCmds=(RANLIB RANLIB_FOR_TARGET) 14 14 15 + # TODO(structured-attrs): This doesn't work correctly if one of 16 + # the items in strip*List or strip*Flags contains a space, 17 + # even with structured attrs enabled. This is OK for now 18 + # because very few packages set any of these, and it doesn't 19 + # affect any of them. 20 + # 21 + # After __structuredAttrs = true is universal, come back and 22 + # push arrays all the way through this logic. 23 + 15 24 # Strip only host paths by default. Leave targets as is. 16 - stripDebugList=${stripDebugList:-lib lib32 lib64 libexec bin sbin} 17 - stripDebugListTarget=${stripDebugListTarget:-} 18 - stripAllList=${stripAllList:-} 19 - stripAllListTarget=${stripAllListTarget:-} 25 + stripDebugList=${stripDebugList[*]:-lib lib32 lib64 libexec bin sbin} 26 + stripDebugListTarget=${stripDebugListTarget[*]:-} 27 + stripAllList=${stripAllList[*]:-} 28 + stripAllListTarget=${stripAllListTarget[*]:-} 20 29 21 30 local i 22 31 for i in ${!stripCmds[@]}; do ··· 30 39 if [[ "${dontStrip-}" || "${flag-}" ]] || ! type -f "${stripCmd-}" 2>/dev/null 31 40 then continue; fi 32 41 33 - stripDirs "$stripCmd" "$ranlibCmd" "$debugDirList" "${stripDebugFlags:--S}" 34 - stripDirs "$stripCmd" "$ranlibCmd" "$allDirList" "${stripAllFlags:--s}" 42 + stripDirs "$stripCmd" "$ranlibCmd" "$debugDirList" "${stripDebugFlags[*]:--S}" 43 + stripDirs "$stripCmd" "$ranlibCmd" "$allDirList" "${stripAllFlags[*]:--s}" 35 44 done 36 45 } 37 46
+1 -1
pkgs/build-support/setup-hooks/win-dll-link.sh
··· 15 15 # prefix $PATH by currently-built outputs 16 16 local DLLPATH="" 17 17 local outName 18 - for outName in $outputs; do 18 + for outName in $(getAllOutputNames); do 19 19 addToSearchPath DLLPATH "${!outName}/bin" 20 20 done 21 21 DLLPATH="$DLLPATH:$PATH"
+1 -1
pkgs/build-support/testers/expect-failure.sh
··· 35 35 # ----------------------------------------- 36 36 # Write the build log to the default output 37 37 38 - outs=( $outputs ) 38 + outs=( $(getAllOutputNames) ) 39 39 defOut=${outs[0]} 40 40 defOutPath=${!defOut} 41 41
+1 -1
pkgs/data/icons/catppuccin-cursors/default.nix
··· 50 50 installPhase = '' 51 51 runHook preInstall 52 52 53 - for output in $outputs; do 53 + for output in $(getAllOutputNames); do 54 54 if [ "$output" != "out" ]; then 55 55 local outputDir="''${!output}" 56 56 local iconsDir="$outputDir"/share/icons
+1 -1
pkgs/data/icons/comixcursors/default.nix
··· 52 52 ''; 53 53 54 54 installPhase = '' 55 - for outputName in $outputs ; do 55 + for outputName in $(getAllOutputNames) ; do 56 56 if [ $outputName != out ]; then 57 57 local outputDir=''${!outputName}; 58 58 local iconsDir=$outputDir/share/icons
+1 -1
pkgs/desktops/gnome/core/gdm/default.nix
··· 143 143 # We use rsync to merge the directories. 144 144 rsync --archive "${DESTDIR}/etc" "$out" 145 145 rm --recursive "${DESTDIR}/etc" 146 - for o in $outputs; do 146 + for o in $(getAllOutputNames); do 147 147 if [[ "$o" = "debug" ]]; then continue; fi 148 148 rsync --archive "${DESTDIR}/''${!o}" "$(dirname "''${!o}")" 149 149 rm --recursive "${DESTDIR}/''${!o}"
+2 -2
pkgs/development/compilers/openjdk/11.nix
··· 132 132 postFixup = '' 133 133 # Build the set of output library directories to rpath against 134 134 LIBDIRS="" 135 - for output in $outputs; do 135 + for output in $(getAllOutputNames); do 136 136 if [ "$output" = debug ]; then continue; fi 137 137 LIBDIRS="$(find $(eval echo \$$output) -name \*.so\* -exec dirname {} \+ | sort | uniq | tr '\n' ':'):$LIBDIRS" 138 138 done 139 139 # Add the local library paths to remove dependencies on the bootstrap 140 - for output in $outputs; do 140 + for output in $(getAllOutputNames); do 141 141 if [ "$output" = debug ]; then continue; fi 142 142 OUTPUTDIR=$(eval echo \$$output) 143 143 BINLIBS=$(find $OUTPUTDIR/bin/ -type f; find $OUTPUTDIR -name \*.so\*)
+2 -2
pkgs/development/compilers/openjdk/12.nix
··· 136 136 postFixup = '' 137 137 # Build the set of output library directories to rpath against 138 138 LIBDIRS="" 139 - for output in $outputs; do 139 + for output in $(getAllOutputNames); do 140 140 if [ "$output" = debug ]; then continue; fi 141 141 LIBDIRS="$(find $(eval echo \$$output) -name \*.so\* -exec dirname {} \+ | sort | uniq | tr '\n' ':'):$LIBDIRS" 142 142 done 143 143 # Add the local library paths to remove dependencies on the bootstrap 144 - for output in $outputs; do 144 + for output in $(getAllOutputNames); do 145 145 if [ "$output" = debug ]; then continue; fi 146 146 OUTPUTDIR=$(eval echo \$$output) 147 147 BINLIBS=$(find $OUTPUTDIR/bin/ -type f; find $OUTPUTDIR -name \*.so\*)
+2 -2
pkgs/development/compilers/openjdk/13.nix
··· 136 136 postFixup = '' 137 137 # Build the set of output library directories to rpath against 138 138 LIBDIRS="" 139 - for output in $outputs; do 139 + for output in $(getAllOutputNames); do 140 140 if [ "$output" = debug ]; then continue; fi 141 141 LIBDIRS="$(find $(eval echo \$$output) -name \*.so\* -exec dirname {} \+ | sort | uniq | tr '\n' ':'):$LIBDIRS" 142 142 done 143 143 # Add the local library paths to remove dependencies on the bootstrap 144 - for output in $outputs; do 144 + for output in $(getAllOutputNames); do 145 145 if [ "$output" = debug ]; then continue; fi 146 146 OUTPUTDIR=$(eval echo \$$output) 147 147 BINLIBS=$(find $OUTPUTDIR/bin/ -type f; find $OUTPUTDIR -name \*.so\*)
+2 -2
pkgs/development/compilers/openjdk/14.nix
··· 132 132 postFixup = '' 133 133 # Build the set of output library directories to rpath against 134 134 LIBDIRS="" 135 - for output in $outputs; do 135 + for output in $(getAllOutputNames); do 136 136 if [ "$output" = debug ]; then continue; fi 137 137 LIBDIRS="$(find $(eval echo \$$output) -name \*.so\* -exec dirname {} \+ | sort | uniq | tr '\n' ':'):$LIBDIRS" 138 138 done 139 139 # Add the local library paths to remove dependencies on the bootstrap 140 - for output in $outputs; do 140 + for output in $(getAllOutputNames); do 141 141 if [ "$output" = debug ]; then continue; fi 142 142 OUTPUTDIR=$(eval echo \$$output) 143 143 BINLIBS=$(find $OUTPUTDIR/bin/ -type f; find $OUTPUTDIR -name \*.so\*)
+2 -2
pkgs/development/compilers/openjdk/15.nix
··· 131 131 postFixup = '' 132 132 # Build the set of output library directories to rpath against 133 133 LIBDIRS="" 134 - for output in $outputs; do 134 + for output in $(getAllOutputNames); do 135 135 if [ "$output" = debug ]; then continue; fi 136 136 LIBDIRS="$(find $(eval echo \$$output) -name \*.so\* -exec dirname {} \+ | sort | uniq | tr '\n' ':'):$LIBDIRS" 137 137 done 138 138 # Add the local library paths to remove dependencies on the bootstrap 139 - for output in $outputs; do 139 + for output in $(getAllOutputNames); do 140 140 if [ "$output" = debug ]; then continue; fi 141 141 OUTPUTDIR=$(eval echo \$$output) 142 142 BINLIBS=$(find $OUTPUTDIR/bin/ -type f; find $OUTPUTDIR -name \*.so\*)
+2 -2
pkgs/development/compilers/openjdk/16.nix
··· 138 138 postFixup = '' 139 139 # Build the set of output library directories to rpath against 140 140 LIBDIRS="" 141 - for output in $outputs; do 141 + for output in $(getAllOutputNames); do 142 142 if [ "$output" = debug ]; then continue; fi 143 143 LIBDIRS="$(find $(eval echo \$$output) -name \*.so\* -exec dirname {} \+ | sort | uniq | tr '\n' ':'):$LIBDIRS" 144 144 done 145 145 # Add the local library paths to remove dependencies on the bootstrap 146 - for output in $outputs; do 146 + for output in $(getAllOutputNames); do 147 147 if [ "$output" = debug ]; then continue; fi 148 148 OUTPUTDIR=$(eval echo \$$output) 149 149 BINLIBS=$(find $OUTPUTDIR/bin/ -type f; find $OUTPUTDIR -name \*.so\*)
+2 -2
pkgs/development/compilers/openjdk/17.nix
··· 149 149 postFixup = '' 150 150 # Build the set of output library directories to rpath against 151 151 LIBDIRS="" 152 - for output in $outputs; do 152 + for output in $(getAllOutputNames); do 153 153 if [ "$output" = debug ]; then continue; fi 154 154 LIBDIRS="$(find $(eval echo \$$output) -name \*.so\* -exec dirname {} \+ | sort -u | tr '\n' ':'):$LIBDIRS" 155 155 done 156 156 # Add the local library paths to remove dependencies on the bootstrap 157 - for output in $outputs; do 157 + for output in $(getAllOutputNames); do 158 158 if [ "$output" = debug ]; then continue; fi 159 159 OUTPUTDIR=$(eval echo \$$output) 160 160 BINLIBS=$(find $OUTPUTDIR/bin/ -type f; find $OUTPUTDIR -name \*.so\*)
+2 -2
pkgs/development/compilers/openjdk/18.nix
··· 140 140 postFixup = '' 141 141 # Build the set of output library directories to rpath against 142 142 LIBDIRS="" 143 - for output in $outputs; do 143 + for output in $(getAllOutputNames); do 144 144 if [ "$output" = debug ]; then continue; fi 145 145 LIBDIRS="$(find $(eval echo \$$output) -name \*.so\* -exec dirname {} \+ | sort -u | tr '\n' ':'):$LIBDIRS" 146 146 done 147 147 # Add the local library paths to remove dependencies on the bootstrap 148 - for output in $outputs; do 148 + for output in $(getAllOutputNames); do 149 149 if [ "$output" = debug ]; then continue; fi 150 150 OUTPUTDIR=$(eval echo \$$output) 151 151 BINLIBS=$(find $OUTPUTDIR/bin/ -type f; find $OUTPUTDIR -name \*.so\*)
+2 -2
pkgs/development/compilers/openjdk/19.nix
··· 140 140 postFixup = '' 141 141 # Build the set of output library directories to rpath against 142 142 LIBDIRS="" 143 - for output in $outputs; do 143 + for output in $(getAllOutputNames); do 144 144 if [ "$output" = debug ]; then continue; fi 145 145 LIBDIRS="$(find $(eval echo \$$output) -name \*.so\* -exec dirname {} \+ | sort -u | tr '\n' ':'):$LIBDIRS" 146 146 done 147 147 # Add the local library paths to remove dependencies on the bootstrap 148 - for output in $outputs; do 148 + for output in $(getAllOutputNames); do 149 149 if [ "$output" = debug ]; then continue; fi 150 150 OUTPUTDIR=$(eval echo \$$output) 151 151 BINLIBS=$(find $OUTPUTDIR/bin/ -type f; find $OUTPUTDIR -name \*.so\*)
+2 -2
pkgs/development/compilers/openjdk/8.nix
··· 187 187 postFixup = '' 188 188 # Build the set of output library directories to rpath against 189 189 LIBDIRS="" 190 - for output in $outputs; do 190 + for output in $(getAllOutputNames); do 191 191 if [ "$output" = debug ]; then continue; fi 192 192 LIBDIRS="$(find $(eval echo \$$output) -name \*.so\* -exec dirname {} \+ | sort | uniq | tr '\n' ':'):$LIBDIRS" 193 193 done 194 194 # Add the local library paths to remove dependencies on the bootstrap 195 - for output in $outputs; do 195 + for output in $(getAllOutputNames); do 196 196 if [ "$output" = debug ]; then continue; fi 197 197 OUTPUTDIR=$(eval echo \$$output) 198 198 BINLIBS=$(find $OUTPUTDIR/bin/ -type f; find $OUTPUTDIR -name \*.so\*)
+1 -1
pkgs/development/libraries/polkit/default.nix
··· 167 167 rsync --archive "${DESTDIR}${system}"/* "$out" 168 168 rm --recursive "${DESTDIR}${system}"/* 169 169 rmdir --parents --ignore-fail-on-non-empty "${DESTDIR}${system}" 170 - for o in $outputs; do 170 + for o in $(getAllOutputNames); do 171 171 rsync --archive "${DESTDIR}/''${!o}" "$(dirname "''${!o}")" 172 172 rm --recursive "${DESTDIR}/''${!o}" 173 173 done
+1 -1
pkgs/os-specific/darwin/signing-utils/auto-sign-hook.sh
··· 25 25 signDarwinBinariesInAllOutputs() { 26 26 local output 27 27 28 - for output in $outputs; do 28 + for output in $(getAllOutputNames); do 29 29 signDarwinBinariesIn "${!output}" 30 30 done 31 31 }
+4
pkgs/stdenv/generic/default-builder.sh
··· 1 + if [ -f .attrs.sh ]; then 2 + . .attrs.sh 3 + fi 4 + 1 5 source $stdenv/setup 2 6 genericBuild
+25 -6
pkgs/stdenv/generic/make-derivation.nix
··· 154 154 (! attrs ? outputHash) # Fixed-output drvs can't be content addressed too 155 155 && config.contentAddressedByDefault 156 156 157 + # Experimental. For simple packages mostly just works, 158 + # but for anything complex, be prepared to debug if enabling. 159 + , __structuredAttrs ? false 160 + 161 + , env ? { } 162 + 157 163 , ... } @ attrs: 158 164 159 165 let ··· 259 265 lib.unique (lib.concatMap (input: input.__propagatedImpureHostDeps or []) 260 266 (lib.concatLists propagatedDependencies)); 261 267 268 + envIsExportable = lib.isAttrs env && !lib.isDerivation env; 269 + 262 270 derivationArg = 263 271 (removeAttrs attrs 264 - ["meta" "passthru" "pos" 272 + (["meta" "passthru" "pos" 265 273 "checkInputs" "installCheckInputs" 266 274 "__darwinAllowLocalNetworking" 267 275 "__impureHostDeps" "__propagatedImpureHostDeps" 268 - "sandboxProfile" "propagatedSandboxProfile"]) 276 + "sandboxProfile" "propagatedSandboxProfile"] 277 + ++ lib.optionals envIsExportable [ "env" ])) 269 278 // (lib.optionalAttrs (attrs ? name || (attrs ? pname && attrs ? version)) { 270 279 name = 271 280 let ··· 289 298 then attrs.name + hostSuffix 290 299 else "${attrs.pname}${staticMarker}${hostSuffix}-${attrs.version}" 291 300 ); 292 - }) // { 301 + }) // lib.optionalAttrs (envIsExportable && __structuredAttrs) { env = checkedEnv; } // { 293 302 builder = attrs.realBuilder or stdenv.shell; 294 303 args = attrs.args or ["-e" (attrs.builder or ./default-builder.sh)]; 295 304 inherit stdenv; ··· 304 313 305 314 userHook = config.stdenv.userHook or null; 306 315 __ignoreNulls = true; 307 - 308 - inherit strictDeps; 316 + inherit __structuredAttrs strictDeps; 309 317 310 318 depsBuildBuild = lib.elemAt (lib.elemAt dependencies 0) 0; 311 319 nativeBuildInputs = lib.elemAt (lib.elemAt dependencies 0) 1; ··· 473 481 else true); 474 482 }; 475 483 484 + checkedEnv = 485 + let 486 + overlappingNames = lib.intersectLists (lib.attrNames env) (lib.attrNames derivationArg); 487 + in 488 + assert lib.assertMsg (overlappingNames == [ ]) 489 + "The ‘env’ attribute set cannot contain any attributes passed to derivation. The following attributes are overlapping: ${lib.concatStringsSep ", " overlappingNames}"; 490 + lib.mapAttrs 491 + (n: v: assert lib.assertMsg (lib.isString v || lib.isBool v || lib.isInt v) 492 + "The ‘env’ attribute set can only contain string, boolean or integer attributes. The ‘${n}’ attribute is of type ${builtins.typeOf v}."; v) 493 + env; 494 + 476 495 in 477 496 478 497 lib.extendDerivation ··· 509 528 # should be made available to Nix expressions using the 510 529 # derivation (e.g., in assertions). 511 530 passthru) 512 - (derivation derivationArg); 531 + (derivation (derivationArg // lib.optionalAttrs envIsExportable checkedEnv)); 513 532 514 533 in 515 534 fnOrAttrs:
+169 -53
pkgs/stdenv/generic/setup.sh
··· 15 15 set -x 16 16 fi 17 17 18 - : ${outputs:=out} 18 + if [ -f .attrs.sh ]; then 19 + __structuredAttrs=1 20 + echo "structuredAttrs is enabled" 21 + else 22 + __structuredAttrs= 23 + fi 24 + 25 + if [ -n "$__structuredAttrs" ]; then 26 + for outputName in "${!outputs[@]}"; do 27 + # ex: out=/nix/store/... 28 + export "$outputName=${outputs[$outputName]}" 29 + done 30 + else 31 + : ${outputs:=out} 32 + fi 19 33 34 + getAllOutputNames() { 35 + if [ -n "$__structuredAttrs" ]; then 36 + echo "${!outputs[*]}" 37 + else 38 + echo "$outputs" 39 + fi 40 + } 20 41 21 42 ###################################################################### 22 43 # Hook handling. ··· 175 196 addToSearchPathWithCustomDelimiter ":" "$@" 176 197 } 177 198 199 + # Prepend elements to variable "$1", which may come from an attr. 200 + # 201 + # This is useful in generic setup code, which must (for now) support 202 + # both derivations with and without __structuredAttrs true, so the 203 + # variable may be an array or a space-separated string. 204 + # 205 + # Expressions for individual packages should simply switch to array 206 + # syntax when they switch to setting __structuredAttrs = true. 207 + prependToVar() { 208 + local -n nameref="$1"; shift 209 + if [ -n "$__structuredAttrs" ]; then 210 + nameref=( "$@" ${nameref+"${nameref[@]}"} ) 211 + else 212 + nameref="$* ${nameref-}" 213 + fi 214 + } 215 + 216 + # Same as above 217 + appendToVar() { 218 + local -n nameref="$1"; shift 219 + if [ -n "$__structuredAttrs" ]; then 220 + nameref=( ${nameref+"${nameref[@]}"} "$@" ) 221 + else 222 + nameref="${nameref-} $*" 223 + fi 224 + } 225 + 226 + # Accumulate into `flagsArray` the flags from the named variables. 227 + # 228 + # If __structuredAttrs, the variables are all treated as arrays 229 + # and simply concatenated onto `flagsArray`. 230 + # 231 + # If not __structuredAttrs, then: 232 + # * Each variable is treated as a string, and split on whitespace; 233 + # * except variables whose names end in "Array", which are treated 234 + # as arrays. 235 + _accumFlagsArray() { 236 + local name 237 + if [ -n "$__structuredAttrs" ]; then 238 + for name in "$@"; do 239 + local -n nameref="$name" 240 + flagsArray+=( ${nameref+"${nameref[@]}"} ) 241 + done 242 + else 243 + for name in "$@"; do 244 + local -n nameref="$name" 245 + case "$name" in 246 + *Array) 247 + flagsArray+=( ${nameref+"${nameref[@]}"} ) ;; 248 + *) 249 + flagsArray+=( ${nameref-} ) ;; 250 + esac 251 + done 252 + fi 253 + 254 + } 255 + 178 256 # Add $1/lib* into rpaths. 179 257 # The function is used in multiple-outputs.sh hook, 180 258 # so it is defined here but tried after the hook. ··· 254 332 255 333 ###################################################################### 256 334 # Initialisation. 335 + 336 + # export all vars that should be in the ENV 337 + for envVar in "${!env[@]}"; do 338 + declare -x "${envVar}=${env[${envVar}]}" 339 + done 257 340 258 341 259 342 # Set a fallback default value for SOURCE_DATE_EPOCH, used by some build tools ··· 469 552 done 470 553 } 471 554 555 + # The way we handle deps* and *Inputs works with structured attrs 556 + # either enabled or disabled. For this it's convenient that the items 557 + # in each list must be store paths, and therefore space-free. 558 + 472 559 # Make sure all are at least defined as empty 473 560 : ${depsBuildBuild=} ${depsBuildBuildPropagated=} 474 561 : ${nativeBuildInputs=} ${propagatedNativeBuildInputs=} ${defaultNativeBuildInputs=} ··· 477 564 : ${buildInputs=} ${propagatedBuildInputs=} ${defaultBuildInputs=} 478 565 : ${depsTargetTarget=} ${depsTargetTargetPropagated=} 479 566 480 - for pkg in $depsBuildBuild $depsBuildBuildPropagated; do 567 + for pkg in ${depsBuildBuild[@]} ${depsBuildBuildPropagated[@]}; do 481 568 findInputs "$pkg" -1 -1 482 569 done 483 - for pkg in $nativeBuildInputs $propagatedNativeBuildInputs; do 570 + for pkg in ${nativeBuildInputs[@]} ${propagatedNativeBuildInputs[@]}; do 484 571 findInputs "$pkg" -1 0 485 572 done 486 - for pkg in $depsBuildTarget $depsBuildTargetPropagated; do 573 + for pkg in ${depsBuildTarget[@]} ${depsBuildTargetPropagated[@]}; do 487 574 findInputs "$pkg" -1 1 488 575 done 489 - for pkg in $depsHostHost $depsHostHostPropagated; do 576 + for pkg in ${depsHostHost[@]} ${depsHostHostPropagated[@]}; do 490 577 findInputs "$pkg" 0 0 491 578 done 492 - for pkg in $buildInputs $propagatedBuildInputs ; do 579 + for pkg in ${buildInputs[@]} ${propagatedBuildInputs[@]} ; do 493 580 findInputs "$pkg" 0 1 494 581 done 495 - for pkg in $depsTargetTarget $depsTargetTargetPropagated; do 582 + for pkg in ${depsTargetTarget[@]} ${depsTargetTargetPropagated[@]}; do 496 583 findInputs "$pkg" 1 1 497 584 done 498 585 # Default inputs must be processed last 499 - for pkg in $defaultNativeBuildInputs; do 586 + for pkg in ${defaultNativeBuildInputs[@]}; do 500 587 findInputs "$pkg" -1 0 501 588 done 502 - for pkg in $defaultBuildInputs; do 589 + for pkg in ${defaultBuildInputs[@]}; do 503 590 findInputs "$pkg" 0 1 504 591 done 505 592 ··· 909 996 srcs="$src" 910 997 fi 911 998 999 + local -a srcsArray 1000 + if [ -n "$__structuredAttrs" ]; then 1001 + srcsArray=( "${srcs[@]}" ) 1002 + else 1003 + srcsArray=( $srcs ) 1004 + fi 1005 + 912 1006 # To determine the source directory created by unpacking the 913 1007 # source archives, we record the contents of the current 914 1008 # directory, then look below which directory got added. Yeah, ··· 921 1015 done 922 1016 923 1017 # Unpack all source archives. 924 - for i in $srcs; do 1018 + for i in "${srcsArray[@]}"; do 925 1019 unpackFile "$i" 926 1020 done 927 1021 ··· 971 1065 patchPhase() { 972 1066 runHook prePatch 973 1067 974 - for i in ${patches:-}; do 1068 + local -a patchesArray 1069 + if [ -n "$__structuredAttrs" ]; then 1070 + patchesArray=( ${patches:+"${patches[@]}"} ) 1071 + else 1072 + patchesArray=( ${patches:-} ) 1073 + fi 1074 + 1075 + for i in "${patchesArray[@]}"; do 975 1076 header "applying patch $i" 3 976 1077 local uncompress=cat 977 1078 case "$i" in ··· 988 1089 uncompress="lzma -d" 989 1090 ;; 990 1091 esac 1092 + 1093 + local -a flagsArray 1094 + if [ -n "$__structuredAttrs" ]; then 1095 + flagsArray=( "${patchFlags[@]:--p1}" ) 1096 + else 1097 + # shellcheck disable=SC2086 1098 + flagsArray=( ${patchFlags:--p1} ) 1099 + fi 991 1100 # "2>&1" is a hack to make patch fail if the decompressor fails (nonexistent patch, etc.) 992 1101 # shellcheck disable=SC2086 993 - $uncompress < "$i" 2>&1 | patch ${patchFlags:--p1} 1102 + $uncompress < "$i" 2>&1 | patch "${flagsArray[@]}" 994 1103 done 995 1104 996 1105 runHook postPatch ··· 1018 1127 1019 1128 # set to empty if unset 1020 1129 : ${configureScript=} 1021 - : ${configureFlags=} 1022 1130 1023 1131 if [[ -z "$configureScript" && -x ./configure ]]; then 1024 1132 configureScript=./configure ··· 1049 1157 fi 1050 1158 1051 1159 if [[ -z "${dontAddPrefix:-}" && -n "$prefix" ]]; then 1052 - configureFlags="${prefixKey:---prefix=}$prefix $configureFlags" 1160 + prependToVar configureFlags "${prefixKey:---prefix=}$prefix" 1053 1161 fi 1054 1162 1055 1163 if [[ -f "$configureScript" ]]; then 1056 1164 # Add --disable-dependency-tracking to speed up some builds. 1057 1165 if [ -z "${dontAddDisableDepTrack:-}" ]; then 1058 1166 if grep -q dependency-tracking "$configureScript"; then 1059 - configureFlags="--disable-dependency-tracking $configureFlags" 1167 + prependToVar configureFlags --disable-dependency-tracking 1060 1168 fi 1061 1169 fi 1062 1170 1063 1171 # By default, disable static builds. 1064 1172 if [ -z "${dontDisableStatic:-}" ]; then 1065 1173 if grep -q enable-static "$configureScript"; then 1066 - configureFlags="--disable-static $configureFlags" 1174 + prependToVar configureFlags --disable-static 1067 1175 fi 1068 1176 fi 1069 1177 fi 1070 1178 1071 1179 if [ -n "$configureScript" ]; then 1072 - # Old bash empty array hack 1073 - # shellcheck disable=SC2086 1074 - local flagsArray=( 1075 - $configureFlags "${configureFlagsArray[@]}" 1076 - ) 1180 + local -a flagsArray 1181 + _accumFlagsArray configureFlags configureFlagsArray 1182 + 1077 1183 echoCmd 'configure flags' "${flagsArray[@]}" 1078 1184 # shellcheck disable=SC2086 1079 1185 $configureScript "${flagsArray[@]}" ··· 1089 1195 buildPhase() { 1090 1196 runHook preBuild 1091 1197 1092 - # set to empty if unset 1093 - : ${makeFlags=} 1094 - 1095 - if [[ -z "$makeFlags" && -z "${makefile:-}" && ! ( -e Makefile || -e makefile || -e GNUmakefile ) ]]; then 1198 + if [[ -z "${makeFlags-}" && -z "${makefile:-}" && ! ( -e Makefile || -e makefile || -e GNUmakefile ) ]]; then 1096 1199 echo "no Makefile, doing nothing" 1097 1200 else 1098 1201 foundMakefile=1 1099 1202 1100 - # Old bash empty array hack 1101 1203 # shellcheck disable=SC2086 1102 1204 local flagsArray=( 1103 1205 ${enableParallelBuilding:+-j${NIX_BUILD_CORES}} 1104 1206 SHELL=$SHELL 1105 - $makeFlags "${makeFlagsArray[@]}" 1106 - $buildFlags "${buildFlagsArray[@]}" 1107 1207 ) 1208 + _accumFlagsArray makeFlags makeFlagsArray buildFlags buildFlagsArray 1108 1209 1109 1210 echoCmd 'build flags' "${flagsArray[@]}" 1110 1211 make ${makefile:+-f $makefile} "${flagsArray[@]}" ··· 1141 1242 local flagsArray=( 1142 1243 ${enableParallelChecking:+-j${NIX_BUILD_CORES}} 1143 1244 SHELL=$SHELL 1144 - $makeFlags "${makeFlagsArray[@]}" 1145 - ${checkFlags:-VERBOSE=y} "${checkFlagsArray[@]}" 1146 - ${checkTarget} 1147 1245 ) 1148 1246 1247 + _accumFlagsArray makeFlags makeFlagsArray 1248 + if [ -n "$__structuredAttrs" ]; then 1249 + flagsArray+=( "${checkFlags[@]:-VERBOSE=y}" ) 1250 + else 1251 + flagsArray+=( ${checkFlags:-VERBOSE=y} ) 1252 + fi 1253 + _accumFlagsArray checkFlagsArray 1254 + flagsArray+=( ${checkTarget} ) 1255 + 1149 1256 echoCmd 'check flags' "${flagsArray[@]}" 1150 1257 make ${makefile:+-f $makefile} "${flagsArray[@]}" 1151 1258 ··· 1163 1270 mkdir -p "$prefix" 1164 1271 fi 1165 1272 1166 - # Old bash empty array hack 1167 1273 # shellcheck disable=SC2086 1168 1274 local flagsArray=( 1169 1275 SHELL=$SHELL 1170 - $makeFlags "${makeFlagsArray[@]}" 1171 - $installFlags "${installFlagsArray[@]}" 1172 - ${installTargets:-install} 1173 1276 ) 1277 + _accumFlagsArray makeFlags makeFlagsArray installFlags installFlagsArray 1278 + if [ -n "$__structuredAttrs" ]; then 1279 + flagsArray+=( "${installTargets[@]:-install}" ) 1280 + else 1281 + flagsArray+=( ${installTargets:-install} ) 1282 + fi 1174 1283 1175 1284 echoCmd 'install flags' "${flagsArray[@]}" 1176 1285 make ${makefile:+-f $makefile} "${flagsArray[@]}" ··· 1186 1295 fixupPhase() { 1187 1296 # Make sure everything is writable so "strip" et al. work. 1188 1297 local output 1189 - for output in $outputs; do 1298 + for output in $(getAllOutputNames); do 1190 1299 if [ -e "${!output}" ]; then chmod -R u+w "${!output}"; fi 1191 1300 done 1192 1301 ··· 1194 1303 1195 1304 # Apply fixup to each output. 1196 1305 local output 1197 - for output in $outputs; do 1306 + for output in $(getAllOutputNames); do 1198 1307 prefix="${!output}" runHook fixupOutput 1199 1308 done 1200 1309 ··· 1239 1348 if [ -n "${setupHooks:-}" ]; then 1240 1349 mkdir -p "${!outputDev}/nix-support" 1241 1350 local hook 1242 - for hook in $setupHooks; do 1351 + # have to use ${setupHooks[@]} without quotes because it needs to support setupHooks being a array or a whitespace separated string 1352 + # # values of setupHooks won't have spaces so it won't cause problems 1353 + # shellcheck disable=2068 1354 + for hook in ${setupHooks[@]}; do 1243 1355 local content 1244 1356 consumeEntire content < "$hook" 1245 1357 substituteAllStream content "file '$hook'" >> "${!outputDev}/nix-support/setup-hook" ··· 1275 1387 local flagsArray=( 1276 1388 ${enableParallelChecking:+-j${NIX_BUILD_CORES}} 1277 1389 SHELL=$SHELL 1278 - $makeFlags "${makeFlagsArray[@]}" 1279 - $installCheckFlags "${installCheckFlagsArray[@]}" 1280 - ${installCheckTarget:-installcheck} 1281 1390 ) 1391 + 1392 + _accumFlagsArray makeFlags makeFlagsArray \ 1393 + installCheckFlags installCheckFlagsArray 1394 + flagsArray+=( ${installCheckTarget:-installcheck} ) 1282 1395 1283 1396 echoCmd 'installcheck flags' "${flagsArray[@]}" 1284 1397 make ${makefile:+-f $makefile} "${flagsArray[@]}" ··· 1292 1405 distPhase() { 1293 1406 runHook preDist 1294 1407 1295 - # Old bash empty array hack 1296 - # shellcheck disable=SC2086 1297 - local flagsArray=( 1298 - $distFlags "${distFlagsArray[@]}" ${distTarget:-dist} 1299 - ) 1408 + local flagsArray=() 1409 + _accumFlagsArray distFlags distFlagsArray 1410 + flagsArray+=( ${distTarget:-dist} ) 1300 1411 1301 1412 echo 'dist flags: %q' "${flagsArray[@]}" 1302 1413 make ${makefile:+-f $makefile} "${flagsArray[@]}" ··· 1307 1418 # Note: don't quote $tarballs, since we explicitly permit 1308 1419 # wildcards in there. 1309 1420 # shellcheck disable=SC2086 1310 - cp -pvd ${tarballs:-*.tar.gz} "$out/tarballs" 1421 + cp -pvd ${tarballs[*]:-*.tar.gz} "$out/tarballs" 1311 1422 fi 1312 1423 1313 1424 runHook postDist ··· 1357 1468 return 1358 1469 fi 1359 1470 1360 - if [ -z "${phases:-}" ]; then 1361 - phases="${prePhases:-} unpackPhase patchPhase ${preConfigurePhases:-} \ 1362 - configurePhase ${preBuildPhases:-} buildPhase checkPhase \ 1363 - ${preInstallPhases:-} installPhase ${preFixupPhases:-} fixupPhase installCheckPhase \ 1364 - ${preDistPhases:-} distPhase ${postPhases:-}"; 1471 + if [ -z "${phases[*]:-}" ]; then 1472 + phases="${prePhases[*]:-} unpackPhase patchPhase ${preConfigurePhases[*]:-} \ 1473 + configurePhase ${preBuildPhases[*]:-} buildPhase checkPhase \ 1474 + ${preInstallPhases[*]:-} installPhase ${preFixupPhases[*]:-} fixupPhase installCheckPhase \ 1475 + ${preDistPhases[*]:-} distPhase ${postPhases[*]:-}"; 1365 1476 fi 1366 1477 1367 - for curPhase in $phases; do 1478 + # The use of ${phases[*]} gives the correct behavior both with and 1479 + # without structured attrs. This relies on the fact that each 1480 + # phase name is space-free, which it must be because it's the name 1481 + # of either a shell variable or a shell function. 1482 + for curPhase in ${phases[*]}; do 1368 1483 if [[ "$curPhase" = unpackPhase && -n "${dontUnpack:-}" ]]; then continue; fi 1369 1484 if [[ "$curPhase" = patchPhase && -n "${dontPatch:-}" ]]; then continue; fi 1370 1485 if [[ "$curPhase" = configurePhase && -n "${dontConfigure:-}" ]]; then continue; fi ··· 1413 1528 1414 1529 1415 1530 dumpVars 1531 + 1416 1532 1417 1533 # Restore the original options for nix-shell 1418 1534 [[ $__nixpkgs_setup_set_original == *e* ]] || set +e
+1 -1
pkgs/tools/typesetting/tex/texlive/bin.nix
··· 247 247 "xetex" 248 248 ]; 249 249 postInstall = '' 250 - for output in $outputs; do 250 + for output in $(getAllOutputNames); do 251 251 mkdir -p "''${!output}/bin" 252 252 done 253 253