stdenv: Nix-driven bootstrap of gcc
#### Summary By default, when you type `make`, GCC will compile itself three times. This PR inhibits that behavior by configuring GCC with `--disable-bootstrap`, and reimplements the triple-rebuild using Nix rather than `make`/`sh`. #### Immediate Benefits - Allow `gcc11` and `gcc12` on `aarch64` (without needing new `bootstrapFiles`) - Faster stdenv rebuilds: the third compilation of gcc (i.e. stageCompare) is no longer a `drvInput` of the final stdenv. This allows Nix to build stageCompare in parallel with the rest of nixpkgs instead of in series. - No more copying `libgcc_s` out of the bootstrap-files or other derivations - No more Frankenstein compiler: the final gcc and the libraries it links against (mpfr, mpc, isl, glibc) are all built by the same compiler (xgcc) instead of a mixture of the bootstrapFiles' compiler and xgcc. - No more [static lib{mpfr,mpc,gmp,isl}.a hack] - Many other small `stdenv` hacks eliminated - `gcc` and `clang` share the same codepath for more of `cc-wrapper`. #### Future Benefits - This should allow using a [foreign] `bootstrap-files` so long as `hostPlatform.canExecute bootstrapFiles`. - This should allow each of the libraries that ship with `gcc` (lib{backtrace, atomic, cc1, decnumber, ffi, gomp, iberty, offloadatomic, quadmath, sanitizer, ssp, stdc++-v3, vtv}) to be built in separate (one-liner) derivations which `inherit src;` from `gcc`, much like https://github.com/NixOS/nixpkgs/pull/132343 #### Incorporates - https://github.com/NixOS/nixpkgs/pull/210004 - https://github.com/NixOS/nixpkgs/pull/36948 (unreverted) - https://github.com/NixOS/nixpkgs/pull/210325 - https://github.com/NixOS/nixpkgs/pull/210118 - https://github.com/NixOS/nixpkgs/pull/210132 - https://github.com/NixOS/nixpkgs/pull/210109 - https://github.com/NixOS/nixpkgs/pull/213909 - https://github.com/NixOS/nixpkgs/pull/216136 - https://github.com/NixOS/nixpkgs/pull/216237 - https://github.com/NixOS/nixpkgs/pull/210019 - https://github.com/NixOS/nixpkgs/pull/216232 - https://github.com/NixOS/nixpkgs/pull/216016 - https://github.com/NixOS/nixpkgs/pull/217977 - https://github.com/NixOS/nixpkgs/pull/217995 #### Closes - Closes #108305 - Closes #108111 - Closes #201254 - Closes #208412 #### Credits This project was made possible by three important insights, none of which were mine: 1. @ericson2314 was the first to advocate for this change, and probably the first to appreciate its advantages. Nix-driven (external) bootstrap is "cross by default". 2. @trofi has figured out a lot about how to get gcc to not mix up the copy of `libstdc++` that it depends on with the copy that it builds, by moving the `bootstrapFiles`' `libstdc++` into a [versioned directory]. This allows a Nix-driven bootstrap of gcc without the final gcc would still having references to the `bootstrapFiles`. 3. Using the undocumented variable [`user-defined-trusted-dirs`] when building glibc. When glibc `dlopen()`s `libgcc_s.so`, it uses a completely different and totally special set of rules for finding `libgcc_s.so`. This trick is the only way we can put `libgcc_s.so` in its own separate outpath without creating circular dependencies or dependencies on the bootstrapFiles. I would never have guessed to use this (or that it existed!) if it were not for a [comment in guix] which @Mic92 [mentioned]. My own role in this PR was basically: being available to go on a coding binge at an opportune moment, so we wouldn't waste a [crisis]. [aarch64-compare-ofborg]: https://github.com/NixOS/nixpkgs/pull/209870/checks?check_run_id=10662822938 [amd64-compare-ofborg]: https://github.com/NixOS/nixpkgs/pull/209870/checks?check_run_id=10662825857 [nonexistent sysroot]: https://github.com/NixOS/nixpkgs/pull/210004 [versioned directory]: https://github.com/NixOS/nixpkgs/pull/209054 [`user-defined-trusted-dirs`]: https://sourceware.org/legacy-ml/libc-help/2013-11/msg00026.html [comment in guix]:5e4ec82181/gnu/packages/gcc.scm (L253)
[mentioned]: https://github.com/NixOS/nixpkgs/pull/210112#issuecomment-1379608483 [crisis]: https://github.com/NixOS/nixpkgs/issues/108305 [foreign]: https://github.com/NixOS/nixpkgs/pull/170857#issuecomment-1170558348 [static lib{mpfr,mpc,gmp,isl}.a hack]:2f1948af9c/pkgs/stdenv/linux/default.nix (L380)
This commit is contained in:
parent
fdd49f1bcd
commit
7553d0fe29
6 changed files with 293 additions and 93 deletions
|
@ -17,9 +17,40 @@
|
||||||
, isGNU ? false, isClang ? cc.isClang or false, gnugrep ? null
|
, isGNU ? false, isClang ? cc.isClang or false, gnugrep ? null
|
||||||
, buildPackages ? {}
|
, buildPackages ? {}
|
||||||
, libcxx ? null
|
, libcxx ? null
|
||||||
|
|
||||||
|
# Whether or not to add `-B` and `-L` to `nix-support/cc-{c,ld}flags`
|
||||||
|
, useCcForLibs ?
|
||||||
|
|
||||||
|
# Always add these flags for Clang, because in order to compile (most
|
||||||
|
# software) it needs libraries that are shipped and compiled with gcc.
|
||||||
|
if isClang then true
|
||||||
|
|
||||||
|
# Never add these flags for a build!=host cross-compiler or a host!=target
|
||||||
|
# ("cross-built-native") compiler; currently nixpkgs has a special build
|
||||||
|
# path for these (`crossStageStatic`). Hopefully at some point that build
|
||||||
|
# path will be merged with this one and this conditional will be removed.
|
||||||
|
else if (with stdenvNoCC; buildPlatform != hostPlatform || hostPlatform != targetPlatform) then false
|
||||||
|
|
||||||
|
# Never add these flags when wrapping the bootstrapFiles' compiler; it has a
|
||||||
|
# /usr/-like layout with everything smashed into a single outpath, so it has
|
||||||
|
# no trouble finding its own libraries.
|
||||||
|
else if (cc.passthru.isFromBootstrapFiles or false) then false
|
||||||
|
|
||||||
|
# Add these flags when wrapping `xgcc` (the first compiler that nixpkgs builds)
|
||||||
|
else if (cc.passthru.isXgcc or false) then true
|
||||||
|
|
||||||
|
# Add these flags when wrapping `stdenv.cc`
|
||||||
|
else if (cc.stdenv.cc.cc.passthru.isXgcc or false) then true
|
||||||
|
|
||||||
|
# Do not add these flags in any other situation. This is `false` mainly to
|
||||||
|
# prevent these flags from being added when wrapping *old* versions of gcc
|
||||||
|
# (e.g. `gcc6Stdenv`), since they will cause the old gcc to get `-B` and
|
||||||
|
# `-L` flags pointing at the new gcc's libstdc++ headers. Example failure:
|
||||||
|
# https://hydra.nixos.org/build/213125495
|
||||||
|
else false
|
||||||
|
|
||||||
|
# the derivation at which the `-B` and `-L` flags added by `useCcForLibs` will point
|
||||||
, gccForLibs ? if useCcForLibs then cc else null
|
, gccForLibs ? if useCcForLibs then cc else null
|
||||||
# same as `gccForLibs`, but generalized beyond clang
|
|
||||||
, useCcForLibs ? isClang
|
|
||||||
}:
|
}:
|
||||||
|
|
||||||
with lib;
|
with lib;
|
||||||
|
|
|
@ -49,7 +49,7 @@ with builtins;
|
||||||
|
|
||||||
let majorVersion = "11";
|
let majorVersion = "11";
|
||||||
version = "${majorVersion}.3.0";
|
version = "${majorVersion}.3.0";
|
||||||
disableBootstrap = !(with stdenv; targetPlatform == hostPlatform && hostPlatform == buildPlatform);
|
disableBootstrap = true;
|
||||||
|
|
||||||
inherit (stdenv) buildPlatform hostPlatform targetPlatform;
|
inherit (stdenv) buildPlatform hostPlatform targetPlatform;
|
||||||
|
|
||||||
|
@ -250,9 +250,8 @@ lib.pipe (stdenv.mkDerivation ({
|
||||||
targetConfig = if targetPlatform != hostPlatform then targetPlatform.config else null;
|
targetConfig = if targetPlatform != hostPlatform then targetPlatform.config else null;
|
||||||
|
|
||||||
buildFlags =
|
buildFlags =
|
||||||
let target =
|
let target = lib.optionalString (profiledCompiler) "profiled"
|
||||||
lib.optionalString (profiledCompiler) "profiled" +
|
+ lib.optionalString (targetPlatform == hostPlatform && hostPlatform == buildPlatform && !disableBootstrap) "bootstrap";
|
||||||
lib.optionalString (targetPlatform == hostPlatform && hostPlatform == buildPlatform && !disableBootstrap) "bootstrap";
|
|
||||||
in lib.optional (target != "") target;
|
in lib.optional (target != "") target;
|
||||||
|
|
||||||
inherit (callFile ../common/strip-attributes.nix { })
|
inherit (callFile ../common/strip-attributes.nix { })
|
||||||
|
@ -312,4 +311,5 @@ lib.pipe (stdenv.mkDerivation ({
|
||||||
// optionalAttrs (enableMultilib) { dontMoveLib64 = true; }
|
// optionalAttrs (enableMultilib) { dontMoveLib64 = true; }
|
||||||
))
|
))
|
||||||
[
|
[
|
||||||
|
(callPackage ../common/libgcc.nix { inherit langC langCC langJit; })
|
||||||
]
|
]
|
||||||
|
|
|
@ -54,7 +54,7 @@ with builtins;
|
||||||
|
|
||||||
let majorVersion = "12";
|
let majorVersion = "12";
|
||||||
version = "${majorVersion}.2.0";
|
version = "${majorVersion}.2.0";
|
||||||
disableBootstrap = !(with stdenv; targetPlatform == hostPlatform && hostPlatform == buildPlatform);
|
disableBootstrap = true;
|
||||||
|
|
||||||
inherit (stdenv) buildPlatform hostPlatform targetPlatform;
|
inherit (stdenv) buildPlatform hostPlatform targetPlatform;
|
||||||
|
|
||||||
|
@ -346,5 +346,6 @@ lib.pipe (stdenv.mkDerivation ({
|
||||||
// optionalAttrs (enableMultilib) { dontMoveLib64 = true; }
|
// optionalAttrs (enableMultilib) { dontMoveLib64 = true; }
|
||||||
))
|
))
|
||||||
[
|
[
|
||||||
|
(callPackage ../common/libgcc.nix { inherit langC langCC langJit; })
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
96
pkgs/development/compilers/gcc/common/libgcc.nix
Normal file
96
pkgs/development/compilers/gcc/common/libgcc.nix
Normal file
|
@ -0,0 +1,96 @@
|
||||||
|
{ lib
|
||||||
|
, stdenv
|
||||||
|
, langC
|
||||||
|
, langCC
|
||||||
|
, langJit
|
||||||
|
}:
|
||||||
|
|
||||||
|
let
|
||||||
|
enableLibGccOutput = (with stdenv; targetPlatform == hostPlatform) && !langJit;
|
||||||
|
in
|
||||||
|
(pkg: pkg.overrideAttrs (previousAttrs: lib.optionalAttrs ((!langC) || langJit || enableLibGccOutput) {
|
||||||
|
outputs = previousAttrs.outputs ++ lib.optionals enableLibGccOutput [ "libgcc" ];
|
||||||
|
# This is a separate phase because gcc assembles its phase scripts
|
||||||
|
# in bash instead of nix (we should fix that).
|
||||||
|
preFixupPhases = (previousAttrs.preFixupPhases or []) ++ [ "preFixupLibGccPhase" ];
|
||||||
|
preFixupLibGccPhase =
|
||||||
|
# delete extra/unused builds of libgcc_s in non-langC builds
|
||||||
|
# (i.e. libgccjit, gnat, etc) to avoid potential confusion
|
||||||
|
lib.optionalString (!langC) ''
|
||||||
|
rm -f $out/lib/libgcc_s.so*
|
||||||
|
''
|
||||||
|
|
||||||
|
# TODO(amjoseph): remove the `libgcc_s.so` symlinks below and replace them
|
||||||
|
# with a `-L${gccForLibs.libgcc}/lib` in cc-wrapper's
|
||||||
|
# `$out/nix-support/cc-flags`. See also:
|
||||||
|
# - https://github.com/NixOS/nixpkgs/pull/209870#discussion_r1130614895
|
||||||
|
# - https://github.com/NixOS/nixpkgs/pull/209870#discussion_r1130635982
|
||||||
|
# - https://github.com/NixOS/nixpkgs/commit/404155c6acfa59456aebe6156b22fe385e7dec6f
|
||||||
|
#
|
||||||
|
# move `libgcc_s.so` into its own output, `$libgcc`
|
||||||
|
+ lib.optionalString enableLibGccOutput (''
|
||||||
|
# move libgcc from lib to its own output (libgcc)
|
||||||
|
mkdir -p $libgcc/lib
|
||||||
|
mv $lib/lib/libgcc_s.so $libgcc/lib/
|
||||||
|
mv $lib/lib/libgcc_s.so.1 $libgcc/lib/
|
||||||
|
ln -s $libgcc/lib/libgcc_s.so $lib/lib/
|
||||||
|
ln -s $libgcc/lib/libgcc_s.so.1 $lib/lib/
|
||||||
|
''
|
||||||
|
#
|
||||||
|
# Nixpkgs ordinarily turns dynamic linking into pseudo-static linking:
|
||||||
|
# libraries are still loaded dynamically, exactly which copy of each
|
||||||
|
# library is loaded is permanently fixed at compile time (via RUNPATH).
|
||||||
|
# For libgcc_s we must revert to the "impure dynamic linking" style found
|
||||||
|
# in imperative software distributions. We must do this because
|
||||||
|
# `libgcc_s` calls `malloc()` and therefore has a `DT_NEEDED` for `libc`,
|
||||||
|
# which creates two problems:
|
||||||
|
#
|
||||||
|
# 1. A circular package dependency `glibc`<-`libgcc`<-`glibc`
|
||||||
|
#
|
||||||
|
# 2. According to the `-Wl,-rpath` flags added by Nixpkgs' `ld-wrapper`,
|
||||||
|
# the two versions of `glibc` in the cycle above are actually
|
||||||
|
# different packages. The later one is compiled by this `gcc`, but
|
||||||
|
# the earlier one was compiled by the compiler *that compiled* this
|
||||||
|
# `gcc` (usually the bootstrapFiles). In any event, the `glibc`
|
||||||
|
# dynamic loader won't honor that specificity without namespaced
|
||||||
|
# manual loads (`dlmopen()`). Once a `libc` is present in the address
|
||||||
|
# space of a process, that `libc` will be used to satisfy all
|
||||||
|
# `DT_NEEDED`s for `libc`, regardless of `RUNPATH`s.
|
||||||
|
#
|
||||||
|
# So we wipe the RUNPATH using `patchelf --set-rpath ""`. We can't use
|
||||||
|
# `patchelf --remove-rpath`, because at least as of patchelf 0.15.0 it
|
||||||
|
# will leave the old RUNPATH string in the file where the reference
|
||||||
|
# scanner can still find it:
|
||||||
|
#
|
||||||
|
# https://github.com/NixOS/patchelf/issues/453
|
||||||
|
#
|
||||||
|
# Note: we might be using the bootstrapFiles' copy of patchelf, so we have
|
||||||
|
# to keep doing it this way until both the issue is fixed *and* all the
|
||||||
|
# bootstrapFiles are regenerated, on every platform.
|
||||||
|
#
|
||||||
|
# This patchelfing is *not* effectively equivalent to copying
|
||||||
|
# `libgcc_s` into `glibc`'s outpath. There is one minor and one
|
||||||
|
# major difference:
|
||||||
|
#
|
||||||
|
# 1. (Minor): multiple builds of `glibc` (say, with different
|
||||||
|
# overrides or parameters) will all reference a single store
|
||||||
|
# path:
|
||||||
|
#
|
||||||
|
# /nix/store/xxx...xxx-gcc-libgcc/lib/libgcc_s.so.1
|
||||||
|
#
|
||||||
|
# This many-to-one referrer relationship will be visible in the store's
|
||||||
|
# dependency graph, and will be available to `nix-store -q` queries.
|
||||||
|
# Copying `libgcc_s` into each of its referrers would lose that
|
||||||
|
# information.
|
||||||
|
#
|
||||||
|
# 2. (Major): by referencing `libgcc_s.so.1`, rather than copying it, we
|
||||||
|
# are still able to run `nix-store -qd` on it to find out how it got
|
||||||
|
# built! Most importantly, we can see from that deriver which compiler
|
||||||
|
# was used to build it (or if it is part of the unpacked
|
||||||
|
# bootstrap-files). Copying `libgcc_s.so.1` from one outpath to
|
||||||
|
# another eliminates the ability to make these queries.
|
||||||
|
#
|
||||||
|
+ ''
|
||||||
|
patchelf --set-rpath "" $libgcc/lib/libgcc_s.so.1
|
||||||
|
'');
|
||||||
|
}))
|
|
@ -66,33 +66,26 @@ in
|
||||||
]);
|
]);
|
||||||
};
|
};
|
||||||
|
|
||||||
# When building glibc from bootstrap-tools, we need libgcc_s at RPATH for
|
# glibc needs to `dlopen()` `libgcc_s.so` but does not link
|
||||||
# any program we run, because the gcc will have been placed at a new
|
# against it. Furthermore, glibc doesn't use the ordinary
|
||||||
# store path than that determined when built (as a source for the
|
# `dlopen()` call to do this; instead it uses one which ignores
|
||||||
# bootstrap-tools tarball)
|
# most paths:
|
||||||
# Building from a proper gcc staying in the path where it was installed,
|
#
|
||||||
# libgcc_s will now be at {gcc}/lib, and gcc's libgcc will be found without
|
# https://sourceware.org/legacy-ml/libc-help/2013-11/msg00026.html
|
||||||
# any special hack.
|
#
|
||||||
# TODO: remove this hack. Things that rely on this hack today:
|
# In order to get it to not ignore `libgcc_s.so`, we have to add its path to
|
||||||
# - dejagnu: during linux bootstrap tcl SIGSEGVs
|
# `user-defined-trusted-dirs`:
|
||||||
# - clang-wrapper in cross-compilation
|
#
|
||||||
# Last attempt: https://github.com/NixOS/nixpkgs/pull/36948
|
# https://sourceware.org/git/?p=glibc.git;a=blob;f=elf/Makefile;h=b509b3eada1fb77bf81e2a0ca5740b94ad185764#l1355
|
||||||
preInstall = lib.optionalString (stdenv.hostPlatform == stdenv.buildPlatform) ''
|
#
|
||||||
if [ -f ${lib.getLib stdenv.cc.cc}/lib/libgcc_s.so.1 ]; then
|
# Conveniently, this will also inform Nix of the fact that glibc depends on
|
||||||
mkdir -p $out/lib
|
# gcc.libgcc, since the path will be embedded in the resulting binary.
|
||||||
cp ${lib.getLib stdenv.cc.cc}/lib/libgcc_s.so.1 $out/lib/libgcc_s.so.1
|
#
|
||||||
# the .so It used to be a symlink, but now it is a script
|
makeFlags =
|
||||||
cp -a ${lib.getLib stdenv.cc.cc}/lib/libgcc_s.so $out/lib/libgcc_s.so
|
(previousAttrs.makeFlags or [])
|
||||||
# wipe out reference to previous libc it was built against
|
++ lib.optionals (stdenv.cc.cc?libgcc) [
|
||||||
chmod +w $out/lib/libgcc_s.so.1
|
"user-defined-trusted-dirs=${stdenv.cc.cc.libgcc}/lib"
|
||||||
# rely on default RUNPATHs of the binary and other libraries
|
];
|
||||||
# Do no force-pull wrong glibc.
|
|
||||||
patchelf --remove-rpath $out/lib/libgcc_s.so.1
|
|
||||||
# 'patchelf' does not remove the string itself. Wipe out
|
|
||||||
# string reference to avoid possible link to bootstrapTools
|
|
||||||
${buildPackages.nukeReferences}/bin/nuke-refs $out/lib/libgcc_s.so.1
|
|
||||||
fi
|
|
||||||
'';
|
|
||||||
|
|
||||||
postInstall = (if stdenv.hostPlatform == stdenv.buildPlatform then ''
|
postInstall = (if stdenv.hostPlatform == stdenv.buildPlatform then ''
|
||||||
echo SUPPORTED-LOCALES=C.UTF-8/UTF-8 > ../glibc-2*/localedata/SUPPORTED
|
echo SUPPORTED-LOCALES=C.UTF-8/UTF-8 > ../glibc-2*/localedata/SUPPORTED
|
||||||
|
@ -164,6 +157,12 @@ in
|
||||||
|
|
||||||
separateDebugInfo = true;
|
separateDebugInfo = true;
|
||||||
|
|
||||||
|
passthru =
|
||||||
|
(previousAttrs.passthru or {})
|
||||||
|
// lib.optionalAttrs (stdenv.cc.cc?libgcc) {
|
||||||
|
inherit (stdenv.cc.cc) libgcc;
|
||||||
|
};
|
||||||
|
|
||||||
meta = (previousAttrs.meta or {}) // { description = "The GNU C Library"; };
|
meta = (previousAttrs.meta or {}) // { description = "The GNU C Library"; };
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
|
@ -10,13 +10,10 @@
|
||||||
#
|
#
|
||||||
# Goals of the bootstrap process:
|
# Goals of the bootstrap process:
|
||||||
# 1. final stdenv must not reference any of the bootstrap files.
|
# 1. final stdenv must not reference any of the bootstrap files.
|
||||||
# 2. final stdenv must not contain any of the bootstrap files
|
# 2. final stdenv must not contain any of the bootstrap files.
|
||||||
# (the only current violation is libgcc_s.so in glibc).
|
|
||||||
# 3. final stdenv must not contain any of the files directly
|
# 3. final stdenv must not contain any of the files directly
|
||||||
# generated by the bootstrap code generators (assembler, linker,
|
# generated by the bootstrap code generators (assembler, linker,
|
||||||
# compiler). The only current violations are: libgcc_s.so in glibc,
|
# compiler).
|
||||||
# the lib{mpfr,mpc,gmp,isl} which are statically linked
|
|
||||||
# into the final gcc).
|
|
||||||
#
|
#
|
||||||
# These goals ensure that final packages and final stdenv are built
|
# These goals ensure that final packages and final stdenv are built
|
||||||
# exclusively using nixpkgs package definitions and don't depend
|
# exclusively using nixpkgs package definitions and don't depend
|
||||||
|
@ -116,6 +113,14 @@ let
|
||||||
# see https://github.com/NixOS/nixpkgs/issues/108475 for context
|
# see https://github.com/NixOS/nixpkgs/issues/108475 for context
|
||||||
reproducibleBuild = true;
|
reproducibleBuild = true;
|
||||||
profiledCompiler = false;
|
profiledCompiler = false;
|
||||||
|
|
||||||
|
# It appears that libcc1 (which is not a g++ plugin; it is a gdb plugin) gets linked against
|
||||||
|
# the libstdc++ from the compiler that *built* g++, not the libstdc++ which was just built.
|
||||||
|
# This causes a reference chain from stdenv to the bootstrapFiles:
|
||||||
|
#
|
||||||
|
# stdenv -> gcc-lib -> xgcc-lib -> bootstrapFiles
|
||||||
|
#
|
||||||
|
disableGdbPlugin = true;
|
||||||
};
|
};
|
||||||
|
|
||||||
commonPreHook =
|
commonPreHook =
|
||||||
|
@ -177,7 +182,7 @@ let
|
||||||
|
|
||||||
cc = if prevStage.gcc-unwrapped == null
|
cc = if prevStage.gcc-unwrapped == null
|
||||||
then null
|
then null
|
||||||
else lib.makeOverridable (import ../../build-support/cc-wrapper) {
|
else (lib.makeOverridable (import ../../build-support/cc-wrapper) {
|
||||||
name = "${name}-gcc-wrapper";
|
name = "${name}-gcc-wrapper";
|
||||||
nativeTools = false;
|
nativeTools = false;
|
||||||
nativeLibc = false;
|
nativeLibc = false;
|
||||||
|
@ -191,7 +196,12 @@ let
|
||||||
inherit lib;
|
inherit lib;
|
||||||
inherit (prevStage) coreutils gnugrep;
|
inherit (prevStage) coreutils gnugrep;
|
||||||
stdenvNoCC = prevStage.ccWrapperStdenv;
|
stdenvNoCC = prevStage.ccWrapperStdenv;
|
||||||
};
|
}).overrideAttrs(a: lib.optionalAttrs (prevStage.gcc-unwrapped.passthru.isXgcc or false) {
|
||||||
|
# This affects only `xgcc` (the compiler which compiles the final compiler).
|
||||||
|
postFixup = (a.postFixup or "") + ''
|
||||||
|
echo "--sysroot=${lib.getDev (getLibc prevStage)}" >> $out/nix-support/cc-cflags
|
||||||
|
'';
|
||||||
|
});
|
||||||
|
|
||||||
overrides = self: super: (overrides self super) // { fetchurl = thisStdenv.fetchurlBoot; };
|
overrides = self: super: (overrides self super) // { fetchurl = thisStdenv.fetchurlBoot; };
|
||||||
};
|
};
|
||||||
|
@ -233,7 +243,7 @@ in
|
||||||
${localSystem.libc} = self.stdenv.mkDerivation {
|
${localSystem.libc} = self.stdenv.mkDerivation {
|
||||||
pname = "bootstrap-stage0-${localSystem.libc}";
|
pname = "bootstrap-stage0-${localSystem.libc}";
|
||||||
strictDeps = true;
|
strictDeps = true;
|
||||||
version = "bootstrap";
|
version = "bootstrapFiles";
|
||||||
enableParallelBuilding = true;
|
enableParallelBuilding = true;
|
||||||
buildCommand = ''
|
buildCommand = ''
|
||||||
mkdir -p $out
|
mkdir -p $out
|
||||||
|
@ -289,7 +299,7 @@ in
|
||||||
};
|
};
|
||||||
inherit (prevStage)
|
inherit (prevStage)
|
||||||
ccWrapperStdenv
|
ccWrapperStdenv
|
||||||
gcc-unwrapped coreutils gnugrep;
|
gcc-unwrapped coreutils gnugrep binutils;
|
||||||
|
|
||||||
${localSystem.libc} = getLibc prevStage;
|
${localSystem.libc} = getLibc prevStage;
|
||||||
|
|
||||||
|
@ -302,6 +312,77 @@ in
|
||||||
};
|
};
|
||||||
})
|
})
|
||||||
|
|
||||||
|
# First rebuild of gcc; this is linked against all sorts of junk
|
||||||
|
# from the bootstrap-files, but we only care about the code that
|
||||||
|
# this compiler *emits*. The `gcc` binary produced in this stage
|
||||||
|
# is not part of the final stdenv.
|
||||||
|
(prevStage:
|
||||||
|
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-stage-xgcc";
|
||||||
|
overrides = final: prev: {
|
||||||
|
inherit (prevStage) ccWrapperStdenv coreutils gnugrep gettext bison texinfo zlib gnum4 perl;
|
||||||
|
patchelf = bootstrapTools;
|
||||||
|
${localSystem.libc} = getLibc prevStage;
|
||||||
|
gmp = prev.gmp.override { cxx = false; };
|
||||||
|
gcc-unwrapped =
|
||||||
|
(prev.gcc-unwrapped.override (commonGccOverrides // {
|
||||||
|
enablePlugins = false;
|
||||||
|
|
||||||
|
# The most logical name for this package would be something like
|
||||||
|
# "gcc-stage1". Unfortunately "stage" is already reserved for the
|
||||||
|
# layers of stdenv, so using "stage" in the name of this package
|
||||||
|
# would cause massive confusion.
|
||||||
|
#
|
||||||
|
# Gcc calls its "stage1" compiler `xgcc` (--disable-bootstrap results
|
||||||
|
# in `xgcc` being copied to $prefix/bin/gcc). So we imitate that.
|
||||||
|
#
|
||||||
|
name = "xgcc";
|
||||||
|
|
||||||
|
})).overrideAttrs (a: {
|
||||||
|
|
||||||
|
# This signals to cc-wrapper (as overridden above in this file) to add `--sysroot`
|
||||||
|
# to `$out/nix-support/cc-cflags`.
|
||||||
|
passthru = a.passthru // { isXgcc = true; };
|
||||||
|
|
||||||
|
# Gcc will look for the C library headers in
|
||||||
|
#
|
||||||
|
# ${with_build_sysroot}${native_system_header_dir}
|
||||||
|
#
|
||||||
|
# The ordinary gcc expression sets `--with-build-sysroot=/` and sets
|
||||||
|
# `native-system-header-dir` to `"${lib.getDev stdenv.cc.libc}/include`.
|
||||||
|
#
|
||||||
|
# Unfortunately the value of "--with-native-system-header-dir=" gets "burned in" to the
|
||||||
|
# compiler, and it is quite difficult to get the compiler to change or ignore it
|
||||||
|
# afterwards. On the other hand, the `sysroot` is very easy to change; you can just pass
|
||||||
|
# a `--sysroot` flag to `gcc`.
|
||||||
|
#
|
||||||
|
# So we override the expression to remove the default settings for these flags, and
|
||||||
|
# replace them such that the concatenated value will be the same as before, but we split
|
||||||
|
# the value between the two variables differently: `--native-system-header-dir=/include`,
|
||||||
|
# and `--with-build-sysroot=${lib.getDev stdenv.cc.libc}`.
|
||||||
|
#
|
||||||
|
configureFlags = (a.configureFlags or []) ++ [
|
||||||
|
"--with-native-system-header-dir=/include"
|
||||||
|
"--with-build-sysroot=${lib.getDev final.stdenv.cc.libc}"
|
||||||
|
];
|
||||||
|
|
||||||
|
# This is a separate phase because gcc assembles its phase scripts
|
||||||
|
# in bash instead of nix (we should fix that).
|
||||||
|
preFixupPhases = (a.preFixupPhases or []) ++ [ "preFixupXgccPhase" ];
|
||||||
|
|
||||||
|
# This is needed to prevent "error: cycle detected in build of '...-xgcc-....drv'
|
||||||
|
# in the references of output 'lib' from output 'out'"
|
||||||
|
preFixupXgccPhase = ''
|
||||||
|
find $lib/lib/ -name \*.so\* -exec patchelf --shrink-rpath {} \; || true
|
||||||
|
'';
|
||||||
|
});
|
||||||
|
};
|
||||||
|
})
|
||||||
|
|
||||||
# 2nd stdenv that contains our own rebuilt binutils and is used for
|
# 2nd stdenv that contains our own rebuilt binutils and is used for
|
||||||
# compiling our own Glibc.
|
# compiling our own Glibc.
|
||||||
|
@ -310,7 +391,7 @@ in
|
||||||
# previous stage1 stdenv:
|
# previous stage1 stdenv:
|
||||||
assert isBuiltByBootstrapFilesCompiler prevStage.binutils-unwrapped;
|
assert isBuiltByBootstrapFilesCompiler prevStage.binutils-unwrapped;
|
||||||
assert isFromBootstrapFiles prevStage."${localSystem.libc}";
|
assert isFromBootstrapFiles prevStage."${localSystem.libc}";
|
||||||
assert isFromBootstrapFiles prevStage.gcc-unwrapped;
|
assert isBuiltByBootstrapFilesCompiler prevStage.gcc-unwrapped;
|
||||||
assert isFromBootstrapFiles prevStage.coreutils;
|
assert isFromBootstrapFiles prevStage.coreutils;
|
||||||
assert isFromBootstrapFiles prevStage.gnugrep;
|
assert isFromBootstrapFiles prevStage.gnugrep;
|
||||||
stageFun prevStage {
|
stageFun prevStage {
|
||||||
|
@ -320,7 +401,7 @@ in
|
||||||
inherit (prevStage)
|
inherit (prevStage)
|
||||||
ccWrapperStdenv gettext
|
ccWrapperStdenv gettext
|
||||||
gcc-unwrapped coreutils gnugrep
|
gcc-unwrapped coreutils gnugrep
|
||||||
perl gnum4 bison;
|
perl gnum4 bison texinfo which;
|
||||||
dejagnu = super.dejagnu.overrideAttrs (a: { doCheck = false; } );
|
dejagnu = super.dejagnu.overrideAttrs (a: { doCheck = false; } );
|
||||||
|
|
||||||
# We need libidn2 and its dependency libunistring as glibc dependency.
|
# We need libidn2 and its dependency libunistring as glibc dependency.
|
||||||
|
@ -385,11 +466,12 @@ in
|
||||||
# binutils and rest of the bootstrap tools, including GCC.
|
# binutils and rest of the bootstrap tools, including GCC.
|
||||||
(prevStage:
|
(prevStage:
|
||||||
# previous stage2 stdenv:
|
# previous stage2 stdenv:
|
||||||
assert isBuiltByBootstrapFilesCompiler prevStage.binutils-unwrapped;
|
assert isBuiltByNixpkgsCompiler prevStage.binutils-unwrapped;
|
||||||
assert isBuiltByBootstrapFilesCompiler prevStage.${localSystem.libc};
|
assert isBuiltByNixpkgsCompiler prevStage.${localSystem.libc};
|
||||||
assert isFromBootstrapFiles prevStage.gcc-unwrapped;
|
assert isBuiltByBootstrapFilesCompiler prevStage.gcc-unwrapped;
|
||||||
assert isFromBootstrapFiles prevStage.coreutils;
|
assert isFromBootstrapFiles prevStage.coreutils;
|
||||||
assert isFromBootstrapFiles prevStage.gnugrep;
|
assert isFromBootstrapFiles prevStage.gnugrep;
|
||||||
|
assert lib.all isBuiltByNixpkgsCompiler (with prevStage; [ gmp isl_0_20 libmpc mpfr ]);
|
||||||
stageFun prevStage {
|
stageFun prevStage {
|
||||||
name = "bootstrap-stage3";
|
name = "bootstrap-stage3";
|
||||||
|
|
||||||
|
@ -397,21 +479,20 @@ in
|
||||||
inherit (prevStage)
|
inherit (prevStage)
|
||||||
ccWrapperStdenv
|
ccWrapperStdenv
|
||||||
binutils coreutils gnugrep gettext
|
binutils coreutils gnugrep gettext
|
||||||
perl patchelf linuxHeaders gnum4 bison libidn2 libunistring;
|
perl patchelf linuxHeaders gnum4 bison libidn2 libunistring libxcrypt;
|
||||||
|
# We build a special copy of libgmp which doesn't use libstdc++, because
|
||||||
|
# xgcc++'s libstdc++ references the bootstrap-files (which is what
|
||||||
|
# compiles xgcc++).
|
||||||
|
gmp = super.gmp.override { cxx = false; };
|
||||||
|
} // {
|
||||||
${localSystem.libc} = getLibc prevStage;
|
${localSystem.libc} = getLibc prevStage;
|
||||||
gcc-unwrapped =
|
gcc-unwrapped = (super.gcc-unwrapped.override (commonGccOverrides // {
|
||||||
let makeStaticLibrariesAndMark = pkg:
|
inherit (prevStage) which;
|
||||||
lib.makeOverridable (pkg.override { stdenv = self.makeStaticLibraries self.stdenv; })
|
}
|
||||||
.overrideAttrs (a: { pname = "${a.pname}-stage3"; });
|
)).overrideAttrs (a: {
|
||||||
in super.gcc-unwrapped.override (commonGccOverrides // {
|
# so we can add them to allowedRequisites below
|
||||||
# Link GCC statically against GMP etc. This makes sense because
|
passthru = a.passthru // { inherit (self) gmp mpfr libmpc isl; };
|
||||||
# these builds of the libraries are only used by GCC, so it
|
});
|
||||||
# reduces the size of the stdenv closure.
|
|
||||||
gmp = makeStaticLibrariesAndMark super.gmp;
|
|
||||||
mpfr = makeStaticLibrariesAndMark super.mpfr;
|
|
||||||
libmpc = makeStaticLibrariesAndMark super.libmpc;
|
|
||||||
isl = makeStaticLibrariesAndMark super.isl_0_20;
|
|
||||||
});
|
|
||||||
};
|
};
|
||||||
extraNativeBuildInputs = [ prevStage.patchelf ] ++
|
extraNativeBuildInputs = [ prevStage.patchelf ] ++
|
||||||
# Many tarballs come with obsolete config.sub/config.guess that don't recognize aarch64.
|
# Many tarballs come with obsolete config.sub/config.guess that don't recognize aarch64.
|
||||||
|
@ -425,18 +506,11 @@ in
|
||||||
#
|
#
|
||||||
(prevStage:
|
(prevStage:
|
||||||
# previous stage3 stdenv:
|
# previous stage3 stdenv:
|
||||||
assert isBuiltByBootstrapFilesCompiler prevStage.binutils-unwrapped;
|
assert isBuiltByNixpkgsCompiler prevStage.binutils-unwrapped;
|
||||||
assert isBuiltByBootstrapFilesCompiler prevStage.${localSystem.libc};
|
assert isBuiltByNixpkgsCompiler prevStage.${localSystem.libc};
|
||||||
assert isBuiltByBootstrapFilesCompiler prevStage.gcc-unwrapped;
|
assert isBuiltByNixpkgsCompiler prevStage.gcc-unwrapped;
|
||||||
assert isFromBootstrapFiles prevStage.coreutils;
|
assert isFromBootstrapFiles prevStage.coreutils;
|
||||||
assert isFromBootstrapFiles prevStage.gnugrep;
|
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 {
|
stageFun prevStage {
|
||||||
name = "bootstrap-stage4";
|
name = "bootstrap-stage4";
|
||||||
|
|
||||||
|
@ -456,11 +530,6 @@ in
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
# force gmp to rebuild so we have the option of dynamically linking
|
|
||||||
# libgmp without creating a reference path from:
|
|
||||||
# stage5.gcc -> stage4.coreutils -> stage3.glibc -> bootstrap
|
|
||||||
gmp = lib.makeOverridable (super.gmp.override { stdenv = self.stdenv; }).overrideAttrs (a: { pname = "${a.pname}-stage4"; });
|
|
||||||
|
|
||||||
# To allow users' overrides inhibit dependencies too heavy for
|
# To allow users' overrides inhibit dependencies too heavy for
|
||||||
# bootstrap, like guile: https://github.com/NixOS/nixpkgs/issues/181188
|
# bootstrap, like guile: https://github.com/NixOS/nixpkgs/issues/181188
|
||||||
gnumake = super.gnumake.override { inBootstrap = true; };
|
gnumake = super.gnumake.override { inBootstrap = true; };
|
||||||
|
@ -497,11 +566,11 @@ in
|
||||||
(prevStage:
|
(prevStage:
|
||||||
# previous stage4 stdenv; see stage3 comment regarding gcc,
|
# previous stage4 stdenv; see stage3 comment regarding gcc,
|
||||||
# which applies here as well.
|
# which applies here as well.
|
||||||
assert isBuiltByNixpkgsCompiler prevStage.binutils-unwrapped;
|
assert isBuiltByNixpkgsCompiler prevStage.binutils-unwrapped;
|
||||||
assert isBuiltByBootstrapFilesCompiler prevStage.${localSystem.libc};
|
assert isBuiltByNixpkgsCompiler prevStage.${localSystem.libc};
|
||||||
assert isBuiltByBootstrapFilesCompiler prevStage.gcc-unwrapped;
|
assert isBuiltByNixpkgsCompiler prevStage.gcc-unwrapped;
|
||||||
assert isBuiltByNixpkgsCompiler prevStage.coreutils;
|
assert isBuiltByNixpkgsCompiler prevStage.coreutils;
|
||||||
assert isBuiltByNixpkgsCompiler prevStage.gnugrep;
|
assert isBuiltByNixpkgsCompiler prevStage.gnugrep;
|
||||||
{
|
{
|
||||||
inherit config overlays;
|
inherit config overlays;
|
||||||
stdenv = import ../generic rec {
|
stdenv = import ../generic rec {
|
||||||
|
@ -549,11 +618,15 @@ in
|
||||||
)
|
)
|
||||||
# More complicated cases
|
# More complicated cases
|
||||||
++ (map (x: getOutput x (getLibc prevStage)) [ "out" "dev" "bin" ] )
|
++ (map (x: getOutput x (getLibc prevStage)) [ "out" "dev" "bin" ] )
|
||||||
++ [ /*propagated from .dev*/ linuxHeaders
|
++ [ linuxHeaders # propagated from .dev
|
||||||
binutils gcc gcc.cc gcc.cc.lib gcc.expand-response-params
|
binutils gcc gcc.cc gcc.cc.lib gcc.expand-response-params gcc.cc.libgcc glibc.passthru.libgcc
|
||||||
]
|
]
|
||||||
++ lib.optionals (!localSystem.isx86 || localSystem.libc == "musl")
|
++ lib.optionals (!localSystem.isx86 || localSystem.libc == "musl")
|
||||||
[ prevStage.updateAutotoolsGnuConfigScriptsHook prevStage.gnu-config ];
|
[ prevStage.updateAutotoolsGnuConfigScriptsHook prevStage.gnu-config ]
|
||||||
|
++ (with gcc-unwrapped.passthru; [
|
||||||
|
gmp libmpc mpfr isl
|
||||||
|
])
|
||||||
|
;
|
||||||
|
|
||||||
overrides = self: super: {
|
overrides = self: super: {
|
||||||
inherit (prevStage)
|
inherit (prevStage)
|
||||||
|
@ -582,10 +655,10 @@ in
|
||||||
(prevStage:
|
(prevStage:
|
||||||
# previous stage5 stdenv; see stage3 comment regarding gcc,
|
# previous stage5 stdenv; see stage3 comment regarding gcc,
|
||||||
# which applies here as well.
|
# which applies here as well.
|
||||||
assert isBuiltByNixpkgsCompiler prevStage.binutils-unwrapped;
|
assert isBuiltByNixpkgsCompiler prevStage.binutils-unwrapped;
|
||||||
assert isBuiltByBootstrapFilesCompiler prevStage.${localSystem.libc};
|
assert isBuiltByNixpkgsCompiler prevStage.${localSystem.libc};
|
||||||
assert isBuiltByBootstrapFilesCompiler prevStage.gcc-unwrapped;
|
assert isBuiltByNixpkgsCompiler prevStage.gcc-unwrapped;
|
||||||
assert isBuiltByNixpkgsCompiler prevStage.coreutils;
|
assert isBuiltByNixpkgsCompiler prevStage.coreutils;
|
||||||
assert isBuiltByNixpkgsCompiler prevStage.gnugrep;
|
assert isBuiltByNixpkgsCompiler prevStage.gnugrep;
|
||||||
{ inherit (prevStage) config overlays stdenv; })
|
{ inherit (prevStage) config overlays stdenv; })
|
||||||
]
|
]
|
||||||
|
|
Loading…
Reference in a new issue