diff --git a/doc/cross-compilation.xml b/doc/cross-compilation.xml index 06a8919c2a1..728616a9f26 100644 --- a/doc/cross-compilation.xml +++ b/doc/cross-compilation.xml @@ -167,6 +167,11 @@ Because of this, a best-of-both-worlds solution is in the works with no splicing or explicit access of buildPackages needed. For now, feel free to use either method. + + There is also a "backlink" __targetPackages, yielding a package set whose buildPackages is the current package set. + This is a hack, though, to accommodate compilers with lousy build systems. + Please do not use this unless you are absolutely sure you are packaging such a compiler and there is no other way. + diff --git a/pkgs/stdenv/booter.nix b/pkgs/stdenv/booter.nix index 2c82d12da95..d459deb6ab5 100644 --- a/pkgs/stdenv/booter.nix +++ b/pkgs/stdenv/booter.nix @@ -41,6 +41,35 @@ # other words, this does a foldr not foldl. stageFuns: let + /* "dfold" a ternary function `op' between successive elements of `list' as if + it was a doubly-linked list with `lnul' and `rnul` base cases at either + end. In precise terms, `fold op lnul rnul [x_0 x_1 x_2 ... x_n-1]` is the + same as + + let + f_-1 = lnul; + f_0 = op f_-1 x_0 f_1; + f_1 = op f_0 x_1 f_2; + f_2 = op f_1 x_2 f_3; + ... + f_n = op f_n-1 x_n f_n+1; + f_n+1 = rnul; + in + f_0 + */ + dfold = op: lnul: rnul: list: + let + len = builtins.length list; + go = pred: n: + if n == len + then rnul + else let + # Note the cycle -- call-by-need ensures finite fold. + cur = op pred (builtins.elemAt list n) succ; + succ = go cur (n + 1); + in cur; + in go lnul 0; + # Take the list and disallow custom overrides in all but the final stage, # and allow it in the final flag. Only defaults this boolean field if it # isn't already set. @@ -55,19 +84,21 @@ stageFuns: let # Adds the stdenv to the arguments, and sticks in it the previous stage for # debugging purposes. - folder = stageFun: finalSoFar: let - args = stageFun finalSoFar; + folder = nextStage: stageFun: prevStage: let + args = stageFun prevStage; args' = args // { stdenv = args.stdenv // { # For debugging - __bootPackages = finalSoFar; + __bootPackages = prevStage; + __hatPackages = nextStage; }; }; in if args.__raw or false then args' else allPackages ((builtins.removeAttrs args' ["selfBuild"]) // { - buildPackages = if args.selfBuild or true then null else finalSoFar; + buildPackages = if args.selfBuild or true then null else prevStage; + __targetPackages = if args.selfBuild or true then null else nextStage; }); -in lib.lists.fold folder {} withAllowCustomOverrides +in dfold folder {} {} withAllowCustomOverrides diff --git a/pkgs/top-level/splice.nix b/pkgs/top-level/splice.nix index a22587d5b57..43951100de3 100644 --- a/pkgs/top-level/splice.nix +++ b/pkgs/top-level/splice.nix @@ -64,7 +64,11 @@ let splicedPackages = if actuallySplice - then splicer defaultBuildScope defaultRunScope + then splicer defaultBuildScope defaultRunScope // { + # These should never be spliced under any circumstances + inherit (pkgs) pkgs buildPackages __targetPackages + buildPlatform targetPlatform hostPlatform; + } else pkgs // pkgs.xorg; in diff --git a/pkgs/top-level/stage.nix b/pkgs/top-level/stage.nix index 6febedb79f3..d8e190cfd4b 100644 --- a/pkgs/top-level/stage.nix +++ b/pkgs/top-level/stage.nix @@ -46,9 +46,18 @@ ## , # The package set used at build-time. If null, `buildPackages` will - # be defined internally as the produced package set as itself. + # be defined internally as the final produced package set itself. This allows + # us to avoid expensive splicing. buildPackages +, # The package set used in the next stage. If null, `__targetPackages` will be + # defined internally as the final produced package set itself, just like with + # `buildPackages` and for the same reasons. + # + # THIS IS A HACK for compilers that don't think critically about cross- + # compilation. Please do *not* use unless you really know what you are doing. + __targetPackages + , # The standard environment to use for building packages. stdenv @@ -87,6 +96,8 @@ let stdenvBootstappingAndPlatforms = self: super: { buildPackages = (if buildPackages == null then self else buildPackages) // { recurseForDerivations = false; }; + __targetPackages = (if __targetPackages == null then self else __targetPackages) + // { recurseForDerivations = false; }; inherit stdenv buildPlatform hostPlatform targetPlatform; };