From d7aad245314ef6b026707bf41c36461d450ef3ab Mon Sep 17 00:00:00 2001 From: Adam Joseph Date: Tue, 10 Jan 2023 02:19:17 -0800 Subject: [PATCH] express #208478 as assertions PR #208478 added a lot of documentation about which packages were rebuilt in each stage of the stdenv bootstrap. However nothing checks that these comments agree with reality; they can bitrot over time. This PR rewrites those comments as assertions, so they cannot bitrot. This conversion did expose some ambiguity in our scheme for naming the stages. Suppose that `pkgs.stdenv.name=="stdenv-stage4", then which of these is "the stage4 coreutils"? ``` pkgs.coreutils pkgs.stdenv.__bootPackages.coreutils ``` The choice is arbitrary, and both choices have confusing corner cases. We should revisit this at some point. --- pkgs/stdenv/linux/default.nix | 124 +++++++++++++++++++++------------- 1 file changed, 76 insertions(+), 48 deletions(-) diff --git a/pkgs/stdenv/linux/default.nix b/pkgs/stdenv/linux/default.nix index 5c7dfcceec644..46eac56cc004b 100644 --- a/pkgs/stdenv/linux/default.nix +++ b/pkgs/stdenv/linux/default.nix @@ -100,6 +100,14 @@ assert crossSystem == localSystem; let inherit (localSystem) system; + isFromNixpkgs = pkg: !(isFromBootstrapFiles pkg); + isFromBootstrapFiles = + pkg: pkg.passthru.isFromBootstrapFiles or false; + isBuiltByNixpkgsCompiler = + pkg: isFromNixpkgs pkg && isFromNixpkgs pkg.stdenv.cc.cc; + isBuiltByBootstrapFilesCompiler = + pkg: isFromNixpkgs pkg && isFromBootstrapFiles pkg.stdenv.cc.cc; + commonPreHook = '' export NIX_ENFORCE_PURITY="''${NIX_ENFORCE_PURITY-1}" @@ -117,16 +125,14 @@ let # Download and unpack the bootstrap tools (coreutils, GCC, Glibc, ...). - bootstrapTools = import (if localSystem.libc == "musl" then ./bootstrap-tools-musl else ./bootstrap-tools) { + bootstrapTools = (import (if localSystem.libc == "musl" then ./bootstrap-tools-musl else ./bootstrap-tools) { inherit system bootstrapFiles; - extraAttrs = lib.optionalAttrs - config.contentAddressedByDefault - { - __contentAddressed = true; - outputHashAlgo = "sha256"; - outputHashMode = "recursive"; - }; - }; + extraAttrs = lib.optionalAttrs config.contentAddressedByDefault { + __contentAddressed = true; + outputHashAlgo = "sha256"; + outputHashMode = "recursive"; + }; + }) // { passthru.isFromBootstrapFiles = true; }; getLibc = stage: stage.${localSystem.libc}; @@ -186,7 +192,7 @@ let }; in - + assert bootstrapTools.passthru.isFromBootstrapFiles or false; # sanity check [ ({}: { @@ -200,9 +206,6 @@ in # Build a dummy stdenv with no GCC or working fetchurl. This is # because we need a stdenv to build the GCC wrapper and fetchurl. - # - # resulting stage0 stdenv: - # - coreutils, binutils, glibc, gcc: from bootstrapFiles (prevStage: stageFun prevStage { name = "bootstrap-stage0"; @@ -230,6 +233,7 @@ in '' + lib.optionalString (localSystem.libc == "musl") '' ln -s ${bootstrapTools}/include-libc $out/include ''; + passthru.isFromBootstrapFiles = true; }; gcc-unwrapped = bootstrapTools; binutils = import ../../build-support/bintools-wrapper { @@ -258,10 +262,14 @@ in # If we ever need to use a package from more than one stage back, we # simply re-export those packages in the middle stage(s) using the # overrides attribute and the inherit syntax. - # - # resulting stage1 stdenv: - # - coreutils, binutils, glibc, gcc: from bootstrapFiles - (prevStage: stageFun prevStage { + (prevStage: + # previous stage0 stdenv: + assert isFromBootstrapFiles prevStage.binutils.bintools; + assert isFromBootstrapFiles prevStage."${localSystem.libc}"; + assert isFromBootstrapFiles prevStage.gcc-unwrapped; + assert isFromBootstrapFiles prevStage.coreutils; + assert isFromBootstrapFiles prevStage.gnugrep; + stageFun prevStage { name = "bootstrap-stage1"; # Rebuild binutils to use from stage2 onwards. @@ -288,10 +296,14 @@ in # 2nd stdenv that contains our own rebuilt binutils and is used for # compiling our own Glibc. # - # resulting stage2 stdenv: - # - coreutils, glibc, gcc: from bootstrapFiles - # - binutils: from nixpkgs, built by bootstrapFiles toolchain - (prevStage: stageFun prevStage { + (prevStage: + # previous stage1 stdenv: + assert isBuiltByBootstrapFilesCompiler prevStage.binutils-unwrapped; + assert isFromBootstrapFiles prevStage."${localSystem.libc}"; + assert isFromBootstrapFiles prevStage.gcc-unwrapped; + assert isFromBootstrapFiles prevStage.coreutils; + assert isFromBootstrapFiles prevStage.gnugrep; + stageFun prevStage { name = "bootstrap-stage2"; overrides = self: super: { @@ -334,6 +346,7 @@ in bintools = self.stdenvNoCC.mkDerivation { pname = prevStage.bintools.bintools.pname + "-patchelfed-ld"; inherit (prevStage.bintools.bintools) version; + passthru = { inherit (prevStage.bintools.passthru) isFromBootstrapFiles; }; enableParallelBuilding = true; dontUnpack = true; dontBuild = true; @@ -360,11 +373,14 @@ in # Construct a third stdenv identical to the 2nd, except that this # one uses the rebuilt Glibc from stage2. It still uses the recent # binutils and rest of the bootstrap tools, including GCC. - # - # resulting stage3 stdenv: - # - coreutils, gcc: from bootstrapFiles - # - glibc, binutils: from nixpkgs, built by bootstrapFiles toolchain - (prevStage: stageFun prevStage { + (prevStage: + # previous stage2 stdenv: + assert isBuiltByBootstrapFilesCompiler prevStage.binutils-unwrapped; + assert isBuiltByBootstrapFilesCompiler prevStage.${localSystem.libc}; + assert isFromBootstrapFiles prevStage.gcc-unwrapped; + assert isFromBootstrapFiles prevStage.coreutils; + assert isFromBootstrapFiles prevStage.gnugrep; + stageFun prevStage { name = "bootstrap-stage3"; overrides = self: super: rec { @@ -401,17 +417,21 @@ in # Construct a fourth stdenv that uses the new GCC. But coreutils is # still from the bootstrap tools. # - # resulting stage4 stdenv: - # - coreutils: from bootstrapFiles - # - glibc, binutils: from nixpkgs, built by bootstrapFiles toolchain - # - gcc: from nixpkgs, built by bootstrapFiles toolchain. Can assume - # it has almost no code from bootstrapTools as gcc bootstraps - # internally. The only exceptions are crt files from glibc - # built by bootstrapTools used to link executables and libraries, - # and the bootstrapTools-built, statically-linked - # lib{mpfr,mpc,gmp,isl}.a which are linked into the final gcc - # (see commit cfde88976ba4cddd01b1bb28b40afd12ea93a11d). - (prevStage: stageFun prevStage { + (prevStage: + # previous stage3 stdenv: + assert isBuiltByBootstrapFilesCompiler prevStage.binutils-unwrapped; + assert isBuiltByBootstrapFilesCompiler prevStage.${localSystem.libc}; + assert isBuiltByBootstrapFilesCompiler prevStage.gcc-unwrapped; + assert isFromBootstrapFiles prevStage.coreutils; + assert isFromBootstrapFiles prevStage.gnugrep; + # Can assume prevStage.gcc-unwrapped has almost no code from + # bootstrapTools as gcc bootstraps internally. The only + # exceptions are crt files from glibc built bybootstrapTools + # used to link executables and libraries, and the + # bootstrapTools-built, statically-linked + # lib{mpfr,mpc,gmp,isl}.a which are linked into the final gcc + # (see commit cfde88976ba4cddd01b1bb28b40afd12ea93a11d). + stageFun prevStage { name = "bootstrap-stage4"; overrides = self: super: { @@ -468,17 +488,15 @@ in # dependency (`nix-store -qR') on bootstrapTools or the first # binutils built. # - # resulting stage5 (final) stdenv: - # - coreutils, binutils: from nixpkgs, built by nixpkgs toolchain - # - glibc: from nixpkgs, built by bootstrapFiles toolchain - # - gcc: from nixpkgs, built by bootstrapFiles toolchain. Can assume - # it has almost no code from bootstrapTools as gcc bootstraps - # internally. The only exceptions are crt files from glibc - # built by bootstrapTools used to link executables and libraries, - # and the bootstrapTools-built, statically-linked - # lib{mpfr,mpc,gmp,isl}.a which are linked into the final gcc - # (see commit cfde88976ba4cddd01b1bb28b40afd12ea93a11d). - (prevStage: { + (prevStage: + # previous stage4 stdenv; see stage3 comment regarding gcc, + # which applies here as well. + assert isBuiltByNixpkgsCompiler prevStage.binutils-unwrapped; + assert isBuiltByBootstrapFilesCompiler prevStage.${localSystem.libc}; + assert isBuiltByBootstrapFilesCompiler prevStage.gcc-unwrapped; + assert isBuiltByNixpkgsCompiler prevStage.coreutils; + assert isBuiltByNixpkgsCompiler prevStage.gnugrep; + { inherit config overlays; stdenv = import ../generic rec { name = "stdenv-linux"; @@ -554,4 +572,14 @@ in }; }) + # This "no-op" stage is just a place to put the assertions about stage5. + (prevStage: + # previous stage5 stdenv; see stage3 comment regarding gcc, + # which applies here as well. + assert isBuiltByNixpkgsCompiler prevStage.binutils-unwrapped; + assert isBuiltByBootstrapFilesCompiler prevStage.${localSystem.libc}; + assert isBuiltByBootstrapFilesCompiler prevStage.gcc-unwrapped; + assert isBuiltByNixpkgsCompiler prevStage.coreutils; + assert isBuiltByNixpkgsCompiler prevStage.gnugrep; + { inherit (prevStage) config overlays stdenv; }) ]