3
0
Fork 0
forked from mirrors/nixpkgs

Merge pull request #209870 from amjoseph-nixpkgs/pr/stdenv/external-gcc-bootstrap

This commit is contained in:
Bernardo Meurer 2023-04-03 08:19:03 -07:00 committed by GitHub
commit f1f6ca8bcd
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
16 changed files with 429 additions and 114 deletions

View file

@ -85,7 +85,8 @@ in rec {
stdenv stdenv
subversion subversion
tarball tarball
vim; vim
tests-stdenv-gcc-stageCompare;
}; };
tested = let tested = let
@ -135,6 +136,7 @@ in rec {
"nixos.tests.proxy" "nixos.tests.proxy"
"nixos.tests.simple" "nixos.tests.simple"
"nixpkgs.jdk" "nixpkgs.jdk"
"nixpkgs.tests-stdenv-gcc-stageCompare"
]) ])
]; ];
}; };

View file

@ -62,9 +62,17 @@ assert withXwidgets -> withGTK3 && webkitgtk != null;
assert withTreeSitter -> tree-sitter != null; assert withTreeSitter -> tree-sitter != null;
let
libGccJitLibraryPaths = [
"${lib.getLib libgccjit}/lib/gcc"
"${lib.getLib stdenv.cc.libc}/lib"
] ++ lib.optionals (stdenv.cc?cc.libgcc) [
"${lib.getLib stdenv.cc.cc.libgcc}/lib"
];
in
(if withMacport then llvmPackages_6.stdenv else stdenv).mkDerivation (finalAttrs: (lib.optionalAttrs nativeComp { (if withMacport then llvmPackages_6.stdenv else stdenv).mkDerivation (finalAttrs: (lib.optionalAttrs nativeComp {
NATIVE_FULL_AOT = "1"; NATIVE_FULL_AOT = "1";
LIBRARY_PATH = "${lib.getLib stdenv.cc.libc}/lib"; LIBRARY_PATH = lib.concatStringsSep ":" libGccJitLibraryPaths;
} // { } // {
pname = pname + lib.optionalString ( !withX && !withNS && !withMacport && !withGTK2 && !withGTK3 ) "-nox"; pname = pname + lib.optionalString ( !withX && !withNS && !withMacport && !withGTK2 && !withGTK3 ) "-nox";
inherit version; inherit version;
@ -75,17 +83,15 @@ assert withTreeSitter -> tree-sitter != null;
then ./native-comp-driver-options-28.patch then ./native-comp-driver-options-28.patch
else ./native-comp-driver-options.patch; else ./native-comp-driver-options.patch;
backendPath = (lib.concatStringsSep " " backendPath = (lib.concatStringsSep " "
(builtins.map (x: ''"-B${x}"'') [ (builtins.map (x: ''"-B${x}"'') ([
# Paths necessary so the JIT compiler finds its libraries: # Paths necessary so the JIT compiler finds its libraries:
"${lib.getLib libgccjit}/lib" "${lib.getLib libgccjit}/lib"
"${lib.getLib libgccjit}/lib/gcc" ] ++ libGccJitLibraryPaths ++ [
"${lib.getLib stdenv.cc.libc}/lib"
# Executable paths necessary for compilation (ld, as): # Executable paths necessary for compilation (ld, as):
"${lib.getBin stdenv.cc.cc}/bin" "${lib.getBin stdenv.cc.cc}/bin"
"${lib.getBin stdenv.cc.bintools}/bin" "${lib.getBin stdenv.cc.bintools}/bin"
"${lib.getBin stdenv.cc.bintools.bintools}/bin" "${lib.getBin stdenv.cc.bintools.bintools}/bin"
])); ])));
}) })
]; ];

View file

@ -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;
@ -321,7 +352,7 @@ stdenv.mkDerivation {
&& targetPlatform.isLinux && targetPlatform.isLinux
&& !(stdenv.targetPlatform.useAndroidPrebuilt or false) && !(stdenv.targetPlatform.useAndroidPrebuilt or false)
&& !(stdenv.targetPlatform.useLLVM or false) && !(stdenv.targetPlatform.useLLVM or false)
&& gccForLibs != null) '' && gccForLibs != null) (''
echo "--gcc-toolchain=${gccForLibs}" >> $out/nix-support/cc-cflags echo "--gcc-toolchain=${gccForLibs}" >> $out/nix-support/cc-cflags
# Pull in 'cc.out' target to get 'libstdc++fs.a'. It should be in # Pull in 'cc.out' target to get 'libstdc++fs.a'. It should be in
@ -329,6 +360,11 @@ stdenv.mkDerivation {
# TODO(trofi): remove once gcc is fixed to move libraries to .lib output. # TODO(trofi): remove once gcc is fixed to move libraries to .lib output.
echo "-L${gccForLibs}/${optionalString (targetPlatform != hostPlatform) "/${targetPlatform.config}"}/lib" >> $out/nix-support/cc-ldflags echo "-L${gccForLibs}/${optionalString (targetPlatform != hostPlatform) "/${targetPlatform.config}"}/lib" >> $out/nix-support/cc-ldflags
'' ''
# this ensures that when clang passes -lgcc_s to lld (as it does
# when building e.g. firefox), lld is able to find libgcc_s.so
+ lib.optionalString (gccForLibs?libgcc) ''
echo "-L${gccForLibs.libgcc}/lib" >> $out/nix-support/cc-ldflags
'')
## ##
## General libc support ## General libc support

View file

@ -67,10 +67,12 @@ runCommand
# Store all paths we want to add to emacs here, so that we only need to add # Store all paths we want to add to emacs here, so that we only need to add
# one path to the load lists # one path to the load lists
deps = runCommand "emacs-packages-deps" deps = runCommand "emacs-packages-deps"
{ ({
inherit explicitRequires lndir emacs; inherit explicitRequires lndir emacs;
nativeBuildInputs = lib.optional nativeComp gcc; nativeBuildInputs = lib.optional nativeComp gcc;
} } // lib.optionalAttrs nativeComp {
inherit (emacs) LIBRARY_PATH;
})
'' ''
findInputsOld() { findInputsOld() {
local pkg="$1"; shift local pkg="$1"; shift

View file

@ -28,6 +28,8 @@
, buildPackages , buildPackages
, libxcrypt , libxcrypt
, disableGdbPlugin ? !enablePlugin , disableGdbPlugin ? !enablePlugin
, nukeReferences
, callPackage
}: }:
# Make sure we get GNU sed. # Make sure we get GNU sed.
@ -49,7 +51,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;
@ -159,7 +161,7 @@ let majorVersion = "11";
in in
stdenv.mkDerivation ({ lib.pipe (stdenv.mkDerivation ({
pname = "${crossNameAddon}${name}"; pname = "${crossNameAddon}${name}";
inherit version; inherit version;
@ -250,9 +252,8 @@ 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 { })
@ -310,4 +311,8 @@ stdenv.mkDerivation ({
} }
// optionalAttrs (enableMultilib) { dontMoveLib64 = true; } // optionalAttrs (enableMultilib) { dontMoveLib64 = true; }
) ))
[
(callPackage ../common/libgcc.nix { inherit langC langCC langJit; })
(callPackage ../common/checksum.nix { inherit langC langCC; })
]

View file

@ -29,6 +29,8 @@
, buildPackages , buildPackages
, libxcrypt , libxcrypt
, disableGdbPlugin ? !enablePlugin , disableGdbPlugin ? !enablePlugin
, nukeReferences
, callPackage
}: }:
# Make sure we get GNU sed. # Make sure we get GNU sed.
@ -54,7 +56,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;
@ -177,6 +179,7 @@ let majorVersion = "12";
mpfr mpfr
name name
noSysDirs noSysDirs
nukeReferences
patchelf patchelf
perl perl
profiledCompiler profiledCompiler
@ -194,7 +197,7 @@ let majorVersion = "12";
in in
stdenv.mkDerivation ({ lib.pipe (stdenv.mkDerivation ({
pname = "${crossNameAddon}${name}"; pname = "${crossNameAddon}${name}";
inherit version; inherit version;
@ -344,4 +347,9 @@ stdenv.mkDerivation ({
} }
// optionalAttrs (enableMultilib) { dontMoveLib64 = true; } // optionalAttrs (enableMultilib) { dontMoveLib64 = true; }
) ))
[
(callPackage ../common/libgcc.nix { inherit langC langCC langJit; })
(callPackage ../common/checksum.nix { inherit langC langCC; })
]

View file

@ -0,0 +1,40 @@
{ lib
, stdenv
, nukeReferences
, langC
, langCC
, runtimeShell
}:
let
enableChecksum = (with stdenv; buildPlatform == hostPlatform && hostPlatform == targetPlatform) && langC && langCC;
in
(pkg: pkg.overrideAttrs (previousAttrs: lib.optionalAttrs enableChecksum {
outputs = previousAttrs.outputs ++ lib.optionals enableChecksum [ "checksum" ];
# This is a separate phase because gcc assembles its phase scripts
# in bash instead of nix (we should fix that).
preFixupPhases = (previousAttrs.preFixupPhases or []) ++ [ "postInstallSaveChecksumPhase" ];
#
# gcc uses an auxiliary utility `genchecksum` to md5-hash (most of) its
# `.o` and `.a` files prior to linking (in case the linker is
# nondeterministic). Since we want to compare across gccs built from two
# separate derivations, we wrap `genchecksum` with a `nuke-references`
# call. We also stash copies of the inputs to `genchecksum` in
# `$checksum/inputs/` -- this is extremely helpful for debugging since
# it's hard to get Nix to not delete the $NIX_BUILD_TOP of a successful
# build.
#
postInstallSaveChecksumPhase = ''
mv gcc/build/genchecksum gcc/build/.genchecksum-wrapped
cat > gcc/build/genchecksum <<\EOF
#!${runtimeShell}
${nukeReferences}/bin/nuke-refs $@
for INPUT in "$@"; do install -Dt $INPUT $checksum/inputs/; done
exec build/.genchecksum-wrapped $@
EOF
chmod +x gcc/build/genchecksum
rm gcc/*-checksum.*
make -C gcc cc1-checksum.o cc1plus-checksum.o
install -Dt $checksum/checksums/ gcc/cc*-checksum.o
'';
}))

View 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
'');
}))

View file

@ -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"; };
}) })

View file

@ -74,7 +74,8 @@ stdenv.mkDerivation (finalAttrs: {
# A derivation that provides gcc and g++ commands, but that # A derivation that provides gcc and g++ commands, but that
# will end up calling ccache for the given cacheDir # will end up calling ccache for the given cacheDir
links = { unwrappedCC, extraConfig }: stdenv.mkDerivation { links = { unwrappedCC, extraConfig }: stdenv.mkDerivation {
name = "ccache-links"; pname = "ccache-links";
inherit (finalAttrs) version;
passthru = { passthru = {
isClang = unwrappedCC.isClang or false; isClang = unwrappedCC.isClang or false;
isGNU = unwrappedCC.isGNU or false; isGNU = unwrappedCC.isGNU or false;

View file

@ -30,6 +30,13 @@ LD_LIBRARY_PATH=$out/lib $LD_BINARY $out/bin/mv $out/lib/libstdc++.* $LIBSTDCXX_
# use a copy of patchelf. # use a copy of patchelf.
LD_LIBRARY_PATH=$out/lib $LD_BINARY $out/bin/cp $out/bin/patchelf . LD_LIBRARY_PATH=$out/lib $LD_BINARY $out/bin/cp $out/bin/patchelf .
# Older versions of the bootstrap-files did not compile their
# patchelf with -static-libgcc, so we have to be very careful not to
# run patchelf on the same copy of libgcc_s that it links against.
LD_LIBRARY_PATH=$out/lib $LD_BINARY $out/bin/cp $out/lib/libgcc_s.so.1 .
LD_LIBRARY_PATH=.:$out/lib:$LIBSTDCXX_SO_DIR $LD_BINARY \
./patchelf --set-rpath $out/lib --force-rpath $out/lib/libgcc_s.so.1
for i in $out/bin/* $out/libexec/gcc/*/*/*; do for i in $out/bin/* $out/libexec/gcc/*/*/*; do
if [ -L "$i" ]; then continue; fi if [ -L "$i" ]; then continue; fi
if [ -z "${i##*/liblto*}" ]; then continue; fi if [ -z "${i##*/liblto*}" ]; then continue; fi

View file

@ -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
@ -111,6 +108,21 @@ let
isBuiltByBootstrapFilesCompiler = isBuiltByBootstrapFilesCompiler =
pkg: isFromNixpkgs pkg && isFromBootstrapFiles pkg.stdenv.cc.cc; pkg: isFromNixpkgs pkg && isFromBootstrapFiles pkg.stdenv.cc.cc;
commonGccOverrides = {
# Use a deterministically built compiler
# see https://github.com/NixOS/nixpkgs/issues/108475 for context
reproducibleBuild = true;
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 =
'' ''
export NIX_ENFORCE_PURITY="''${NIX_ENFORCE_PURITY-1}" export NIX_ENFORCE_PURITY="''${NIX_ENFORCE_PURITY-1}"
@ -170,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;
@ -184,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; };
}; };
@ -226,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
@ -282,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;
@ -295,6 +312,75 @@ 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 // {
# 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.
@ -303,7 +389,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 {
@ -313,7 +399,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.
@ -378,11 +464,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";
@ -390,25 +477,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 { # 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;
# Use a deterministically built compiler
# see https://github.com/NixOS/nixpkgs/issues/108475 for context
reproducibleBuild = true;
profiledCompiler = false;
};
}; };
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.
@ -422,18 +504,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";
@ -453,11 +528,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; };
@ -495,8 +565,8 @@ in
# 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;
{ {
@ -546,11 +616,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)
@ -580,8 +654,8 @@ in
# 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; })

View file

@ -2,6 +2,10 @@
let let
libc = pkgs.stdenv.cc.libc; libc = pkgs.stdenv.cc.libc;
patchelf = pkgs.patchelf.overrideAttrs(previousAttrs: {
NIX_CFLAGS_COMPILE = (previousAttrs.NIX_CFLAGS_COMPILE or []) ++ [ "-static-libgcc" "-static-libstdc++" ];
NIX_CFLAGS_LINK = (previousAttrs.NIX_CFLAGS_LINK or []) ++ [ "-static-libgcc" "-static-libstdc++" ];
});
in with pkgs; rec { in with pkgs; rec {
@ -127,7 +131,7 @@ in with pkgs; rec {
cp -d ${bootGCC.out}/bin/gcc $out/bin cp -d ${bootGCC.out}/bin/gcc $out/bin
cp -d ${bootGCC.out}/bin/cpp $out/bin cp -d ${bootGCC.out}/bin/cpp $out/bin
cp -d ${bootGCC.out}/bin/g++ $out/bin cp -d ${bootGCC.out}/bin/g++ $out/bin
cp -d ${bootGCC.lib}/lib/libgcc_s.so* $out/lib cp ${bootGCC.lib}/lib/libgcc_s.so* $out/lib
cp -d ${bootGCC.lib}/lib/libstdc++.so* $out/lib cp -d ${bootGCC.lib}/lib/libstdc++.so* $out/lib
cp -d ${bootGCC.out}/lib/libssp.a* $out/lib cp -d ${bootGCC.out}/lib/libssp.a* $out/lib
cp -d ${bootGCC.out}/lib/libssp_nonshared.a $out/lib cp -d ${bootGCC.out}/lib/libssp_nonshared.a $out/lib
@ -149,6 +153,7 @@ in with pkgs; rec {
rm -rf $out/include/c++/*/ext/parallel rm -rf $out/include/c++/*/ext/parallel
cp -d ${gmpxx.out}/lib/libgmp*.so* $out/lib cp -d ${gmpxx.out}/lib/libgmp*.so* $out/lib
cp -d ${isl.out}/lib/libisl*.so* $out/lib
cp -d ${mpfr.out}/lib/libmpfr*.so* $out/lib cp -d ${mpfr.out}/lib/libmpfr*.so* $out/lib
cp -d ${libmpc.out}/lib/libmpc*.so* $out/lib cp -d ${libmpc.out}/lib/libmpc*.so* $out/lib
cp -d ${zlib.out}/lib/libz.so* $out/lib cp -d ${zlib.out}/lib/libz.so* $out/lib

View file

@ -0,0 +1,32 @@
# This test *must* be run prior to releasing any build of either stdenv or the
# gcc that it exports! This check should also be part of CI for any PR that
# causes a rebuild of `stdenv.cc`.
#
# When we used gcc's internal bootstrap it did this check as part of (and
# serially with) the gcc derivation. Now that we bootstrap externally this
# check can be done in parallel with any/all of stdenv's referrers. But we
# must remember to do the check.
#
{ stdenv
, pkgs
, lib
}:
assert stdenv.cc.isGNU;
with pkgs;
# rebuild gcc using the "final" stdenv
let gcc-stageCompare = (gcc-unwrapped.override {
reproducibleBuild = true;
profiledCompiler = false;
stdenv = overrideCC stdenv (wrapCCWith {
cc = stdenv.cc;
});
}).overrideAttrs(_: {
NIX_OUTPATH_USED_AS_RANDOM_SEED = stdenv.cc.cc.out;
});
in (runCommand "gcc-stageCompare" {} ''
diff -sr ${pkgs.gcc-unwrapped.checksum}/checksums ${gcc-stageCompare.checksum}/checksums && touch $out
'').overrideAttrs (a: {
meta = (a.meta or { }) // { platforms = lib.platforms.linux; };
})

View file

@ -34205,6 +34205,8 @@ with pkgs;
testssl = callPackage ../applications/networking/testssl { }; testssl = callPackage ../applications/networking/testssl { };
tests-stdenv-gcc-stageCompare = callPackage ../test/stdenv/gcc-stageCompare.nix { };
lavalauncher = callPackage ../applications/misc/lavalauncher { }; lavalauncher = callPackage ../applications/misc/lavalauncher { };
t-rec = callPackage ../misc/t-rec { t-rec = callPackage ../misc/t-rec {

View file

@ -150,5 +150,5 @@ with import ./release-lib.nix { inherit supportedSystems nixpkgsArgs; };
xfsprogs = linux; xfsprogs = linux;
xkeyboard_config = linux; xkeyboard_config = linux;
zip = all; zip = all;
tests-stdenv-gcc-stageCompare = all;
} )) } ))