diff --git a/pkgs/build-support/setup-hooks/move-docs.sh b/pkgs/build-support/setup-hooks/move-docs.sh index ef31dcdce2747..6cfa82cddb700 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 "$forceShare" -o -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 2e95495c96fdc..939348b107e54 100644 --- a/pkgs/build-support/setup-hooks/multiple-outputs.sh +++ b/pkgs/build-support/setup-hooks/multiple-outputs.sh @@ -66,19 +66,18 @@ _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" - - installFlags="\ - pkgconfigdir=${!outputDev}/lib/pkgconfig \ - m4datadir=${!outputDev}/share/aclocal aclocaldir=${!outputDev}/share/aclocal \ - $installFlags" + _prepend 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 + + _prepend installFlags \ + pkgconfigdir="${!outputDev}"/lib/pkgconfig \ + m4datadir="${!outputDev}"/share/aclocal aclocaldir="${!outputDev}"/share/aclocal + } diff --git a/pkgs/build-support/setup-hooks/strip.sh b/pkgs/build-support/setup-hooks/strip.sh index f5fa9378fd7e6..57e270053d3dc 100644 --- a/pkgs/build-support/setup-hooks/strip.sh +++ b/pkgs/build-support/setup-hooks/strip.sh @@ -23,14 +23,23 @@ _doStrip() { if [[ "${dontStrip-}" || "${flag-}" ]] || ! type -f "${stripCmd-}" 2>/dev/null then continue; fi - stripDebugList=${stripDebugList:-lib lib32 lib64 libexec bin sbin} + # 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. + + stripDebugList=${stripDebugList[*]:-lib lib32 lib64 libexec bin sbin} if [ -n "$stripDebugList" ]; then - stripDirs "$stripCmd" "$stripDebugList" "${stripDebugFlags:--S}" + stripDirs "$stripCmd" "$stripDebugList" "${stripDebugFlags[*]:--S}" fi - stripAllList=${stripAllList:-} + stripAllList=${stripAllList[*]:-} if [ -n "$stripAllList" ]; then - stripDirs "$stripCmd" "$stripAllList" "${stripAllFlags:--s}" + stripDirs "$stripCmd" "$stripAllList" "${stripAllFlags[*]:--s}" fi done } diff --git a/pkgs/stdenv/generic/default-builder.sh b/pkgs/stdenv/generic/default-builder.sh index 273fc55c75523..0e555b81023f2 100644 --- a/pkgs/stdenv/generic/default-builder.sh +++ b/pkgs/stdenv/generic/default-builder.sh @@ -1,2 +1,6 @@ +if [ -e .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 a11b280b047ee..4d3891680d96c 100644 --- a/pkgs/stdenv/generic/make-derivation.nix +++ b/pkgs/stdenv/generic/make-derivation.nix @@ -88,6 +88,10 @@ in rec { , patches ? [] + # Experimental. For simple packages mostly just works, + # but for anything complex, be prepared to debug if enabling. + , __structuredAttrs ? false + , ... } @ attrs: let @@ -210,6 +214,7 @@ in rec { userHook = config.stdenv.userHook or null; __ignoreNulls = true; + inherit __structuredAttrs; inherit strictDeps; diff --git a/pkgs/stdenv/generic/setup.sh b/pkgs/stdenv/generic/setup.sh index 5b8fdde579612..4f2e19b5fb95c 100644 --- a/pkgs/stdenv/generic/setup.sh +++ b/pkgs/stdenv/generic/setup.sh @@ -5,7 +5,24 @@ if (( "${NIX_DEBUG:-0}" >= 6 )); then set -x fi -: ${outputs:=out} +if [ -f .attrs.sh ]; then + __structuredAttrs=1 +else + __structuredAttrs= +fi + +# Set up shell-style variables for outputs. +# +# Output names are identifiers and values are store paths, +# so they're all space-free and this style works cleanly. +if [ -n "$__structuredAttrs" ]; then + for outputName in "${!outputs[@]}"; do + eval export\ "$outputName"="${outputs[$outputName]}" + done + export outputs="${!outputs[*]}" +else + : ${outputs:=out} +fi ###################################################################### @@ -166,6 +183,52 @@ 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. +_prepend() { + local varName="$1"; shift + if [ -n "$__structuredAttrs" ]; then + # e.g., buildFlags=( "$@" ${buildFlags+"${buildFlags[@]}"} ) + eval $varName'=( "$@" ${'$varName'+"${'$varName'[@]}"} )' + else + # e.g., buildFlags="$* $buildFlags" + eval $varName'="$* ${'$varName'-}"' + 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 + eval 'flagsArray+=( ${'$name'+"${'$name'[@]}"} )' + done + else + for name in "$@"; do + case "$name" in + *Array) + eval 'flagsArray+=( ${'$name'+"${'$name'[@]}"} )' ;; + *) + eval 'flagsArray+=( ${'$name'-} )' ;; + 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. @@ -428,6 +491,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=} @@ -436,29 +503,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 @@ -855,6 +922,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, @@ -867,7 +941,7 @@ unpackPhase() { done # Unpack all source archives. - for i in $srcs; do + for i in "${srcsArray[@]}"; do unpackFile "$i" done @@ -917,7 +991,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 @@ -934,9 +1015,15 @@ 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 @@ -953,7 +1040,6 @@ configurePhase() { # set to empty if unset : ${configureScript=} - : ${configureFlags=} if [[ -z "$configureScript" && -x ./configure ]]; then configureScript=./configure @@ -968,29 +1054,27 @@ configurePhase() { fi if [[ -z "${dontAddPrefix:-}" && -n "$prefix" ]]; then - configureFlags="${prefixKey:---prefix=}$prefix $configureFlags" + _prepend configureFlags "${prefixKey:---prefix=}$prefix" fi # Add --disable-dependency-tracking to speed up some builds. if [ -z "${dontAddDisableDepTrack:-}" ]; then if [ -f "$configureScript" ] && grep -q dependency-tracking "$configureScript"; then - configureFlags="--disable-dependency-tracking $configureFlags" + _prepend configureFlags --disable-dependency-tracking fi fi # By default, disable static builds. if [ -z "${dontDisableStatic:-}" ]; then if [ -f "$configureScript" ] && grep -q enable-static "$configureScript"; then - configureFlags="--disable-static $configureFlags" + _prepend configureFlags --disable-static fi fi if [ -n "$configureScript" ]; then - # Old bash empty array hack - # shellcheck disable=SC2086 - local flagsArray=( - $configureFlags ${configureFlagsArray+"${configureFlagsArray[@]}"} - ) + local -a flagsArray + _accumFlagsArray configureFlags configureFlagsArray + echoCmd 'configure flags' "${flagsArray[@]}" # shellcheck disable=SC2086 $configureScript "${flagsArray[@]}" @@ -1006,22 +1090,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} -l${NIX_BUILD_CORES}} SHELL=$SHELL - $makeFlags ${makeFlagsArray+"${makeFlagsArray[@]}"} - $buildFlags ${buildFlagsArray+"${buildFlagsArray[@]}"} ) + _accumFlagsArray makeFlags makeFlagsArray buildFlags buildFlagsArray echoCmd 'build flags' "${flagsArray[@]}" make ${makefile:+-f $makefile} "${flagsArray[@]}" @@ -1058,10 +1137,15 @@ checkPhase() { local flagsArray=( ${enableParallelChecking:+-j${NIX_BUILD_CORES} -l${NIX_BUILD_CORES}} SHELL=$SHELL - $makeFlags ${makeFlagsArray+"${makeFlagsArray[@]}"} - ${checkFlags:-VERBOSE=y} ${checkFlagsArray+"${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[@]}" @@ -1080,14 +1164,16 @@ installPhase() { mkdir -p "$prefix" fi - # Old bash empty array hack # shellcheck disable=SC2086 local flagsArray=( SHELL=$SHELL - $makeFlags ${makeFlagsArray+"${makeFlagsArray[@]}"} - $installFlags ${installFlagsArray+"${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[@]}" @@ -1187,15 +1273,14 @@ installCheckPhase() { && ! make -n ${makefile:+-f $makefile} ${installCheckTarget:-installcheck} >/dev/null 2>&1; then echo "no installcheck target in ${makefile:-Makefile}, doing nothing" else - # Old bash empty array hack # shellcheck disable=SC2086 local flagsArray=( ${enableParallelChecking:+-j${NIX_BUILD_CORES} -l${NIX_BUILD_CORES}} SHELL=$SHELL - $makeFlags ${makeFlagsArray+"${makeFlagsArray[@]}"} - $installCheckFlags ${installCheckFlagsArray+"${installCheckFlagsArray[@]}"} - ${installCheckTarget:-installcheck} ) + _accumFlagsArray makeFlags makeFlagsArray \ + installCheckFlags installCheckFlagsArray + flagsArray+=( ${installCheckTarget:-installcheck} ) echoCmd 'installcheck flags' "${flagsArray[@]}" make ${makefile:+-f $makefile} "${flagsArray[@]}" @@ -1209,11 +1294,9 @@ installCheckPhase() { distPhase() { runHook preDist - # Old bash empty array hack - # shellcheck disable=SC2086 - local flagsArray=( - $distFlags ${distFlagsArray+"${distFlagsArray[@]}"} ${distTarget:-dist} - ) + local flagsArray=() + _accumFlagsArray distFlags distFlagsArray + flagsArray+=( ${distTarget:-dist} ) echo 'dist flags: %q' "${flagsArray[@]}" make ${makefile:+-f $makefile} "${flagsArray[@]}" @@ -1224,7 +1307,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 @@ -1257,14 +1340,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" = configurePhase && -n "${dontConfigure:-}" ]]; then continue; fi if [[ "$curPhase" = buildPhase && -n "${dontBuild:-}" ]]; then continue; fi diff --git a/pkgs/tools/networking/netmask/default.nix b/pkgs/tools/networking/netmask/default.nix index 864838bdd3902..63e87e1d20c8d 100644 --- a/pkgs/tools/networking/netmask/default.nix +++ b/pkgs/tools/networking/netmask/default.nix @@ -3,6 +3,7 @@ stdenv.mkDerivation rec { pname = "netmask"; version = "2.4.4"; + __structuredAttrs = true; src = fetchFromGitHub { owner = "tlby";