diff --git a/pkgs/stdenv/booter.nix b/pkgs/stdenv/booter.nix index 7fc1fa42b965c23..d21277c81475264 100644 --- a/pkgs/stdenv/booter.nix +++ b/pkgs/stdenv/booter.nix @@ -98,20 +98,26 @@ stageFuns: let thisStage = if args.__raw or false then args' - else allPackages ((builtins.removeAttrs args' ["selfBuild"]) // { - adjacentPackages = if args.selfBuild or true then null else rec { - pkgsBuildBuild = prevStage.buildPackages; - pkgsBuildHost = prevStage; - pkgsBuildTarget = - if args.stdenv.targetPlatform == args.stdenv.hostPlatform - then pkgsBuildHost - else assert args.stdenv.hostPlatform == args.stdenv.buildPlatform; thisStage; - pkgsHostHost = - if args.stdenv.hostPlatform == args.stdenv.targetPlatform - then thisStage - else assert args.stdenv.buildPlatform == args.stdenv.hostPlatform; pkgsBuildHost; - pkgsTargetTarget = nextStage; - }; + else allPackages (args' // { + # Technically we only need to check `build!=target` since nixpkgs currently doesn't allow + # both `build!=host` and `host!=target` at the same time, but we check both in order to be + # future-proof. + actuallySplice = with thisStage.stdenv; buildPlatform != hostPlatform || hostPlatform != targetPlatform; + adjacentPackages = + let + # search backwards from `stage` for the most recent stage containing packages which execute on `on` and target `for` + seek = stage: { on, for }@args: + if on == stage.stdenv.hostPlatform && + for == stage.stdenv.targetPlatform + then stage + else seek stage.stdenv.__bootPackages or (throw "nixpkgs internal error: Bootstrapping stage with requested host and target platform not found.") args; + in rec { + pkgsBuildBuild = seek thisStage { on = thisStage.stdenv.buildPlatform; for = thisStage.stdenv.buildPlatform; }; + pkgsBuildHost = seek thisStage { on = thisStage.stdenv.buildPlatform; for = thisStage.stdenv.hostPlatform; }; + pkgsBuildTarget = seek thisStage { on = thisStage.stdenv.buildPlatform; for = thisStage.stdenv.targetPlatform; }; + pkgsHostHost = seek thisStage { on = thisStage.stdenv.hostPlatform; for = thisStage.stdenv.hostPlatform; }; + pkgsTargetTarget = nextStage; + }; }); in thisStage; diff --git a/pkgs/stdenv/cross/default.nix b/pkgs/stdenv/cross/default.nix index cf6a55fec208c51..9ff2c1b683e05f0 100644 --- a/pkgs/stdenv/cross/default.nix +++ b/pkgs/stdenv/cross/default.nix @@ -24,7 +24,6 @@ in lib.init bootStages ++ [ # Build tool Packages (vanillaPackages: { inherit config overlays; - selfBuild = false; stdenv = assert vanillaPackages.stdenv.buildPlatform == localSystem; assert vanillaPackages.stdenv.hostPlatform == localSystem; @@ -34,6 +33,27 @@ in lib.init bootStages ++ [ allowCustomOverrides = true; }) + # Prevent (some) unwanted assumptions about the number of stages + # from creeping in. Previously, nixpkgs contained code which + # assumed that `pkgs.stdenv.__bootPackages == pkgs.stdenv.pkgsBuildHost`. + # + # We add this no-op stage here, between pkgsBuildHost and + # pkgsHostHost, in order to deliberately break any code which + # makes that assumption -- such code will likely fail since + # `pkgs.stdenv.__bootPackages.hostPlatform != + # pkgs.stdenv.pkgsBuildHost.hostPlatform`, and will end up trying + # to run `hostPlatform` binaries during the build. + # + # We previously had two additional no-op stages: one before + # `pkgsBuildHost`, and one after `pkgsHostHost`. However these + # appeared to increase eval-time CPU usage by 1%, which was deemed + # undesirable. See https://github.com/NixOS/nixpkgs/pull/251299 + # + (prevStage: { + inherit config overlays; + inherit (prevStage) stdenv; + }) + # Run Packages (buildPackages: let adaptStdenv = @@ -43,7 +63,6 @@ in lib.init bootStages ++ [ in { inherit config; overlays = overlays ++ crossOverlays; - selfBuild = false; stdenv = adaptStdenv (buildPackages.stdenv.override (old: rec { buildPlatform = localSystem; hostPlatform = crossSystem; diff --git a/pkgs/top-level/stage.nix b/pkgs/top-level/stage.nix index 1f37bbb70bda648..064337208304e42 100644 --- a/pkgs/top-level/stage.nix +++ b/pkgs/top-level/stage.nix @@ -45,6 +45,7 @@ in # avoid expensive splicing. `pkgsHostTarget` is skipped because it is always # defined as the current stage. adjacentPackages +, actuallySplice , # The standard environment to use for building packages. stdenv @@ -117,7 +118,7 @@ let stdenvBootstappingAndPlatforms = self: super: let withFallback = thisPkgs: - (if adjacentPackages == null then self else thisPkgs) + (if actuallySplice then thisPkgs else self) // { recurseForDerivations = false; }; in { # Here are package sets of from related stages. They are all in the form @@ -145,7 +146,7 @@ let inherit stdenv; }; - splice = self: super: import ./splice.nix lib self (adjacentPackages != null); + splice = self: super: import ./splice.nix lib self actuallySplice; allPackages = self: super: let res = import ./all-packages.nix