diff --git a/pkgs/build-support/trivial-builders/default.nix b/pkgs/build-support/trivial-builders/default.nix index 13cc1fdf77ef..6e812fe8f756 100644 --- a/pkgs/build-support/trivial-builders/default.nix +++ b/pkgs/build-support/trivial-builders/default.nix @@ -80,8 +80,8 @@ rec { inherit buildCommand name; passAsFile = [ "buildCommand" ] ++ (derivationArgs.passAsFile or [ ]); } - // lib.optionalAttrs (!derivationArgs ? meta) { - pos = + // { + ${if !derivationArgs ? meta then "pos" else null} = let args = builtins.attrNames derivationArgs; in @@ -89,11 +89,9 @@ rec { builtins.unsafeGetAttrPos (builtins.head args) derivationArgs else null; + ${if runLocal then "preferLocalBuild" else null} = true; + ${if runLocal then "allowSubstitutes" else null} = false; } - // (lib.optionalAttrs runLocal { - preferLocalBuild = true; - allowSubstitutes = false; - }) // removeAttrs derivationArgs [ "passAsFile" ] ); @@ -567,8 +565,8 @@ rec { ${postBuild} ''; } - // lib.optionalAttrs (!args ? meta) { - pos = + // { + ${if !args ? meta then "pos" else null} = if args ? pname then builtins.unsafeGetAttrPos "pname" args else diff --git a/pkgs/stdenv/generic/make-derivation.nix b/pkgs/stdenv/generic/make-derivation.nix index 5177b2245f1b..4406bef8f908 100644 --- a/pkgs/stdenv/generic/make-derivation.nix +++ b/pkgs/stdenv/generic/make-derivation.nix @@ -1,3 +1,11 @@ +# PERF: This file is evaluated for every derivation in the build closure. +# Avoid `// optionalAttrs` — each call allocates a closure, an intermediate +# attrset, and a `//` merge. Use nullable attribute names instead: +# +# ${if cond then "name" else null} = value; +# +# See https://github.com/NixOS/nixpkgs/pull/430969 for measurements. + { lib, config }: stdenv: @@ -28,7 +36,6 @@ let mapAttrs mapNullable optional - optionalAttrs optionalString optionals pipe @@ -530,220 +537,228 @@ let ] ]; - derivationArg = - removeAttrs attrs removedOrReplacedAttrNames - // { - ${if (attrs ? name || (attrs ? pname && attrs ? version)) then "name" else null} = - let - # Indicate the host platform of the derivation if cross compiling. - # Fixed-output derivations like source tarballs shouldn't get a host - # suffix. But we have some weird ones with run-time deps that are - # just used for their side-affects. Those might as well since the - # hash can't be the same. See #32986. - hostSuffix = optionalString (!dontAddHostSuffix) stdenvHostSuffix; + derivationArg = removeAttrs attrs removedOrReplacedAttrNames // { + ${if (attrs ? name || (attrs ? pname && attrs ? version)) then "name" else null} = + let + # Indicate the host platform of the derivation if cross compiling. + # Fixed-output derivations like source tarballs shouldn't get a host + # suffix. But we have some weird ones with run-time deps that are + # just used for their side-affects. Those might as well since the + # hash can't be the same. See #32986. + hostSuffix = optionalString (!dontAddHostSuffix) stdenvHostSuffix; - # Disambiguate statically built packages. This was originally - # introduce as a means to prevent nix-env to get confused between - # nix and nixStatic. This should be also achieved by moving the - # hostSuffix before the version, so we could contemplate removing - # it again. - staticMarker = stdenvStaticMarker; - in - lib.strings.sanitizeDerivationName ( - if attrs ? name then - attrs.name + hostSuffix - else - # we cannot coerce null to a string below - assert assertMsg ( - attrs ? version && attrs.version != null - ) "The `version` attribute cannot be null."; - "${attrs.pname}${staticMarker}${hostSuffix}-${attrs.version}" - ); - - builder = attrs.realBuilder or stdenvShell; - args = - attrs.args or [ - "-e" - ./source-stdenv.sh - (attrs.builder or ./default-builder.sh) - ]; - inherit stdenv; - - # The `system` attribute of a derivation has special meaning to Nix. - # Derivations set it to choose what sort of machine could be used to - # execute the build, The build platform entirely determines this, - # indeed more finely than Nix knows or cares about. The `system` - # attribute of `buildPlatform` matches Nix's degree of specificity. - # exactly. - system = buildPlatformSystem; - - inherit userHook; - __ignoreNulls = true; - inherit __structuredAttrs strictDeps; - - depsBuildBuild = elemAt (elemAt dependencies 0) 0; - nativeBuildInputs = elemAt (elemAt dependencies 0) 1; - depsBuildTarget = elemAt (elemAt dependencies 0) 2; - depsHostHost = elemAt (elemAt dependencies 1) 0; - buildInputs = elemAt (elemAt dependencies 1) 1; - depsTargetTarget = elemAt (elemAt dependencies 2) 0; - - depsBuildBuildPropagated = elemAt (elemAt propagatedDependencies 0) 0; - propagatedNativeBuildInputs = elemAt (elemAt propagatedDependencies 0) 1; - depsBuildTargetPropagated = elemAt (elemAt propagatedDependencies 0) 2; - depsHostHostPropagated = elemAt (elemAt propagatedDependencies 1) 0; - propagatedBuildInputs = elemAt (elemAt propagatedDependencies 1) 1; - depsTargetTargetPropagated = elemAt (elemAt propagatedDependencies 2) 0; - - # This parameter is sometimes a string, sometimes null, and sometimes a list, yuck - configureFlags = - configureFlags - ++ ( - if configurePlatforms == defaultConfigurePlatforms then - defaultConfigurePlatformsFlags - else - optional (elem "build" configurePlatforms) buildPlatformConfigureFlag - ++ optional (elem "host" configurePlatforms) hostPlatformConfigureFlag - ++ optional (elem "target" configurePlatforms) targetPlatformConfigureFlag - ); - - inherit patches; - - inherit doCheck doInstallCheck; - - inherit outputs; - - # When the derivations is content addressed provide default values - # for outputHashMode and outputHashAlgo because most people won't - # care about these anyways - ${if __contentAddressed then "__contentAddressed" else null} = __contentAddressed; - ${if __contentAddressed then "outputHashAlgo" else null} = attrs.outputHashAlgo or "sha256"; - ${if __contentAddressed then "outputHashMode" else null} = attrs.outputHashMode or "recursive"; - - ${if enableParallelBuilding then "enableParallelBuilding" else null} = enableParallelBuilding; - ${if enableParallelBuilding then "enableParallelChecking" else null} = - attrs.enableParallelChecking or true; - ${if enableParallelBuilding then "enableParallelInstalling" else null} = - attrs.enableParallelInstalling or true; - - ${ - if (hardeningDisable != [ ] || hardeningEnable != [ ] || isMusl) then - "NIX_HARDENING_ENABLE" + # Disambiguate statically built packages. This was originally + # introduce as a means to prevent nix-env to get confused between + # nix and nixStatic. This should be also achieved by moving the + # hostSuffix before the version, so we could contemplate removing + # it again. + staticMarker = stdenvStaticMarker; + in + lib.strings.sanitizeDerivationName ( + if attrs ? name then + attrs.name + hostSuffix else - null - } = - lib.warnIf ((builtins.elem "pie" hardeningEnable) || (builtins.elem "pie" hardeningDisable)) - "The 'pie' hardening flag has been removed in favor of enabling PIE by default in compilers and should no longer be used. PIE can be disabled with the -no-pie compiler flag, but this is usually not necessary as most build systems pass this if needed. Usage of the 'pie' hardening flag will become an error in future." - (builtins.concatStringsSep " " enabledHardeningOptions); + # we cannot coerce null to a string below + assert assertMsg ( + attrs ? version && attrs.version != null + ) "The `version` attribute cannot be null."; + "${attrs.pname}${staticMarker}${hostSuffix}-${attrs.version}" + ); - # TODO: remove platform condition - # Enabling this check could be a breaking change as it requires to edit nix.conf - # NixOS module already sets gccarch, unsure of nix installers and other distributions - ${if requiredSystemFeaturesShouldBeSet then "requiredSystemFeatures" else null} = - attrs.requiredSystemFeatures or [ ] ++ gccArchFeature; - } - // optionalAttrs buildIsDarwin ( + builder = attrs.realBuilder or stdenvShell; + args = + attrs.args or [ + "-e" + ./source-stdenv.sh + (attrs.builder or ./default-builder.sh) + ]; + inherit stdenv; + + # The `system` attribute of a derivation has special meaning to Nix. + # Derivations set it to choose what sort of machine could be used to + # execute the build, The build platform entirely determines this, + # indeed more finely than Nix knows or cares about. The `system` + # attribute of `buildPlatform` matches Nix's degree of specificity. + # exactly. + system = buildPlatformSystem; + + inherit userHook; + __ignoreNulls = true; + inherit __structuredAttrs strictDeps; + + depsBuildBuild = elemAt (elemAt dependencies 0) 0; + nativeBuildInputs = elemAt (elemAt dependencies 0) 1; + depsBuildTarget = elemAt (elemAt dependencies 0) 2; + depsHostHost = elemAt (elemAt dependencies 1) 0; + buildInputs = elemAt (elemAt dependencies 1) 1; + depsTargetTarget = elemAt (elemAt dependencies 2) 0; + + depsBuildBuildPropagated = elemAt (elemAt propagatedDependencies 0) 0; + propagatedNativeBuildInputs = elemAt (elemAt propagatedDependencies 0) 1; + depsBuildTargetPropagated = elemAt (elemAt propagatedDependencies 0) 2; + depsHostHostPropagated = elemAt (elemAt propagatedDependencies 1) 0; + propagatedBuildInputs = elemAt (elemAt propagatedDependencies 1) 1; + depsTargetTargetPropagated = elemAt (elemAt propagatedDependencies 2) 0; + + # This parameter is sometimes a string, sometimes null, and sometimes a list, yuck + configureFlags = + configureFlags + ++ ( + if configurePlatforms == defaultConfigurePlatforms then + defaultConfigurePlatformsFlags + else + optional (elem "build" configurePlatforms) buildPlatformConfigureFlag + ++ optional (elem "host" configurePlatforms) hostPlatformConfigureFlag + ++ optional (elem "target" configurePlatforms) targetPlatformConfigureFlag + ); + + inherit patches; + + inherit doCheck doInstallCheck; + + inherit outputs; + + # When the derivations is content addressed provide default values + # for outputHashMode and outputHashAlgo because most people won't + # care about these anyways + ${if __contentAddressed then "__contentAddressed" else null} = __contentAddressed; + ${if __contentAddressed then "outputHashAlgo" else null} = attrs.outputHashAlgo or "sha256"; + ${if __contentAddressed then "outputHashMode" else null} = attrs.outputHashMode or "recursive"; + + ${if enableParallelBuilding then "enableParallelBuilding" else null} = enableParallelBuilding; + ${if enableParallelBuilding then "enableParallelChecking" else null} = + attrs.enableParallelChecking or true; + ${if enableParallelBuilding then "enableParallelInstalling" else null} = + attrs.enableParallelInstalling or true; + + ${ + if (hardeningDisable != [ ] || hardeningEnable != [ ] || isMusl) then + "NIX_HARDENING_ENABLE" + else + null + } = + lib.warnIf ((builtins.elem "pie" hardeningEnable) || (builtins.elem "pie" hardeningDisable)) + "The 'pie' hardening flag has been removed in favor of enabling PIE by default in compilers and should no longer be used. PIE can be disabled with the -no-pie compiler flag, but this is usually not necessary as most build systems pass this if needed. Usage of the 'pie' hardening flag will become an error in future." + (builtins.concatStringsSep " " enabledHardeningOptions); + + # TODO: remove platform condition + # Enabling this check could be a breaking change as it requires to edit nix.conf + # NixOS module already sets gccarch, unsure of nix installers and other distributions + ${if requiredSystemFeaturesShouldBeSet then "requiredSystemFeatures" else null} = + attrs.requiredSystemFeatures or [ ] ++ gccArchFeature; + + # -- Darwin-specific attrs -- + ${if buildIsDarwin then "__darwinAllowLocalNetworking" else null} = __darwinAllowLocalNetworking; + ${if buildIsDarwin then "__sandboxProfile" else null} = let allDependencies = concatLists (concatLists dependencies); allPropagatedDependencies = concatLists (concatLists propagatedDependencies); - computedSandboxProfile = concatMap (input: input.__propagatedSandboxProfile or [ ]) ( extraNativeBuildInputs ++ extraBuildInputs ++ allDependencies ); - computedPropagatedSandboxProfile = concatMap ( input: input.__propagatedSandboxProfile or [ ] ) allPropagatedDependencies; - + profiles = [ + extraSandboxProfile + ] + ++ computedSandboxProfile + ++ computedPropagatedSandboxProfile + ++ [ + propagatedSandboxProfile + sandboxProfile + ]; + in + # TODO: remove `unique` once nix has a list canonicalization primitive + concatStringsSep "\n" (filter (x: x != "") (unique profiles)); + ${if buildIsDarwin then "__propagatedSandboxProfile" else null} = + let + allPropagatedDependencies = concatLists (concatLists propagatedDependencies); + computedPropagatedSandboxProfile = concatMap ( + input: input.__propagatedSandboxProfile or [ ] + ) allPropagatedDependencies; + in + unique (computedPropagatedSandboxProfile ++ [ propagatedSandboxProfile ]); + ${if buildIsDarwin then "__impureHostDeps" else null} = + let + allDependencies = concatLists (concatLists dependencies); + allPropagatedDependencies = concatLists (concatLists propagatedDependencies); computedImpureHostDeps = unique ( concatMap (input: input.__propagatedImpureHostDeps or [ ]) ( extraNativeBuildInputs ++ extraBuildInputs ++ allDependencies ) ); - computedPropagatedImpureHostDeps = unique ( concatMap (input: input.__propagatedImpureHostDeps or [ ]) allPropagatedDependencies ); in - { - inherit __darwinAllowLocalNetworking; - # TODO: remove `unique` once nix has a list canonicalization primitive - __sandboxProfile = - let - profiles = [ - extraSandboxProfile - ] - ++ computedSandboxProfile - ++ computedPropagatedSandboxProfile - ++ [ - propagatedSandboxProfile - sandboxProfile - ]; - final = concatStringsSep "\n" (filter (x: x != "") (unique profiles)); - in - final; - __propagatedSandboxProfile = unique ( - computedPropagatedSandboxProfile ++ [ propagatedSandboxProfile ] + computedImpureHostDeps + ++ computedPropagatedImpureHostDeps + ++ __propagatedImpureHostDeps + ++ __impureHostDeps + ++ __extraImpureHostDeps + ++ [ + "/dev/zero" + "/dev/random" + "/dev/urandom" + "/bin/sh" + ]; + ${if buildIsDarwin then "__propagatedImpureHostDeps" else null} = + let + allPropagatedDependencies = concatLists (concatLists propagatedDependencies); + computedPropagatedImpureHostDeps = unique ( + concatMap (input: input.__propagatedImpureHostDeps or [ ]) allPropagatedDependencies ); - __impureHostDeps = - computedImpureHostDeps - ++ computedPropagatedImpureHostDeps - ++ __propagatedImpureHostDeps - ++ __impureHostDeps - ++ __extraImpureHostDeps - ++ [ - "/dev/zero" - "/dev/random" - "/dev/urandom" - "/bin/sh" - ]; - __propagatedImpureHostDeps = computedPropagatedImpureHostDeps ++ __propagatedImpureHostDeps; - } - ) - // optionalAttrs (isWindows || isCygwin) { - allowedImpureDLLs = - allowedImpureDLLs - ++ lib.optionals isCygwin [ - "KERNEL32.dll" - ]; - } - // ( + in + computedPropagatedImpureHostDeps ++ __propagatedImpureHostDeps; + + # -- Windows/Cygwin-specific attrs -- + ${if isWindows || isCygwin then "allowedImpureDLLs" else null} = + allowedImpureDLLs + ++ lib.optionals isCygwin [ + "KERNEL32.dll" + ]; + + # -- Output reference checks -- + ${if !__structuredAttrs && attrs ? disallowedReferences then "disallowedReferences" else null} = + map unsafeDerivationToUntrackedOutpath attrs.disallowedReferences; + ${if !__structuredAttrs && attrs ? disallowedRequisites then "disallowedRequisites" else null} = + map unsafeDerivationToUntrackedOutpath attrs.disallowedRequisites; + ${if !__structuredAttrs && attrs ? allowedReferences then "allowedReferences" else null} = + mapNullable unsafeDerivationToUntrackedOutpath attrs.allowedReferences; + ${if !__structuredAttrs && attrs ? allowedRequisites then "allowedRequisites" else null} = + mapNullable unsafeDerivationToUntrackedOutpath attrs.allowedRequisites; + ${if __structuredAttrs then "outputChecks" else null} = let attrsOutputChecks = makeOutputChecks attrs; attrsOutputChecksFiltered = filterAttrs (_: v: v != null) attrsOutputChecks; in - if !__structuredAttrs then - attrsOutputChecks - else - { - outputChecks = builtins.listToAttrs ( - map (name: { - inherit name; - value = - let - raw = zipAttrsWith (_: builtins.concatLists) [ - attrsOutputChecksFiltered - (makeOutputChecks attrs.outputChecks.${name} or { }) - ]; - in - # separateDebugInfo = true will put all sorts of files in - # the debug output which could carry references, but - # that's "normal". Notably it symlinks to the source. - # So disable reference checking for the debug output - if separateDebugInfo' && name == "debug" then - removeAttrs raw [ - "allowedReferences" - "allowedRequisites" - "disallowedReferences" - "disallowedRequisites" - ] - else - raw; - }) outputs - ); - } - ); - + builtins.listToAttrs ( + map (name: { + inherit name; + value = + let + raw = zipAttrsWith (_: builtins.concatLists) [ + attrsOutputChecksFiltered + (makeOutputChecks attrs.outputChecks.${name} or { }) + ]; + in + # separateDebugInfo = true will put all sorts of files in + # the debug output which could carry references, but + # that's "normal". Notably it symlinks to the source. + # So disable reference checking for the debug output + if separateDebugInfo' && name == "debug" then + removeAttrs raw [ + "allowedReferences" + "allowedRequisites" + "disallowedReferences" + "disallowedRequisites" + ] + else + raw; + }) outputs + ); + }; in derivationArg; @@ -806,7 +821,9 @@ let let mainProgram = meta.mainProgram or null; - env' = env // lib.optionalAttrs (mainProgram != null) { NIX_MAIN_PROGRAM = mainProgram; }; + env' = env // { + ${if mainProgram != null then "NIX_MAIN_PROGRAM" else null} = mainProgram; + }; derivationArg = makeDerivationArgument ( removeAttrs attrs [ @@ -815,8 +832,8 @@ let "pos" "env" ] - // lib.optionalAttrs __structuredAttrs { env = checkedEnv; } // { + ${if __structuredAttrs then "env" else null} = checkedEnv; cmakeFlags = makeCMakeFlags attrs; mesonFlags = makeMesonFlags attrs; }