From f445f64207c41c8cb0f6bae31296ac10a561928f Mon Sep 17 00:00:00 2001 From: Adam Joseph Date: Mon, 7 Aug 2023 21:51:23 -0700 Subject: [PATCH 01/15] libgcc: (re)init at 12.3.0 This commit restores the pkgs/development/libraries/gcc/libgcc package, which was deleted by commit 9818d120be614c478f569c21d4b9d358632e651e. We need to be able to build libgcc separately from gcc in order to avoid a circular dependency. Nixpkgs is unusual -- unlike any other distribution, it cannot tolerate circular dependencies between dynamically linked libraries. Because of this, upstream is extremely unsympathetic to the trouble that the glibc<->gcc circular dependency causes for us; if we don't solve it ourselves it will not be solved. --- .../libraries/gcc/libgcc/default.nix | 156 ++++++++++++++++++ pkgs/top-level/aliases.nix | 1 - pkgs/top-level/all-packages.nix | 4 + 3 files changed, 160 insertions(+), 1 deletion(-) create mode 100644 pkgs/development/libraries/gcc/libgcc/default.nix diff --git a/pkgs/development/libraries/gcc/libgcc/default.nix b/pkgs/development/libraries/gcc/libgcc/default.nix new file mode 100644 index 000000000000..835956055448 --- /dev/null +++ b/pkgs/development/libraries/gcc/libgcc/default.nix @@ -0,0 +1,156 @@ +{ lib, stdenvNoLibs, buildPackages +, gcc, glibc +, libiberty +}: + +stdenvNoLibs.mkDerivation rec { + pname = "libgcc"; + inherit (gcc.cc) src version; + + outputs = [ "out" "dev" ]; + + strictDeps = true; + depsBuildBuild = [ buildPackages.stdenv.cc ]; + nativeBuildInputs = [ libiberty ]; + + postUnpack = '' + mkdir -p ./build + buildRoot=$(readlink -e "./build") + ''; + + postPatch = '' + sourceRoot=$(readlink -e "./libgcc") + ''; + + hardeningDisable = [ "pie" ]; + + preConfigure = '' + cd "$buildRoot" + '' + + # Drop in libiberty, as external builds are not expected + + '' + ( + mkdir -p build-${stdenvNoLibs.buildPlatform.config}/libiberty/ + cd build-${stdenvNoLibs.buildPlatform.config}/libiberty/ + ln -s ${buildPackages.libiberty}/lib/libiberty.a ./ + ) + '' + # A few misc bits of gcc need to be built. + # + # - We "shift" the tools over to fake platforms perspective from the previous + # stage. + # + # - We define GENERATOR_FILE so nothing bothers looking for GNU GMP. + # + # - We remove the `libgcc.mvar` deps so that the bootstrap xgcc isn't built. + + '' + mkdir -p "$buildRoot/gcc" + cd "$buildRoot/gcc" + ( + export AS_FOR_BUILD=${buildPackages.stdenv.cc}/bin/$AS_FOR_BUILD + export CC_FOR_BUILD=${buildPackages.stdenv.cc}/bin/$CC_FOR_BUILD + export CPP_FOR_BUILD=${buildPackages.stdenv.cc}/bin/$CPP_FOR_BUILD + export CXX_FOR_BUILD=${buildPackages.stdenv.cc}/bin/$CXX_FOR_BUILD + export LD_FOR_BUILD=${buildPackages.stdenv.cc.bintools}/bin/$LD_FOR_BUILD + + export AS=$AS_FOR_BUILD + export CC=$CC_FOR_BUILD + export CPP=$CPP_FOR_BUILD + export CXX=$CXX_FOR_BUILD + export LD=$LD_FOR_BUILD + + export AS_FOR_TARGET=${stdenvNoLibs.cc}/bin/$AS + export CC_FOR_TARGET=${stdenvNoLibs.cc}/bin/$CC + export CPP_FOR_TARGET=${stdenvNoLibs.cc}/bin/$CPP + export LD_FOR_TARGET=${stdenvNoLibs.cc.bintools}/bin/$LD + + export NIX_CFLAGS_COMPILE_FOR_BUILD+=' -DGENERATOR_FILE=1' + + "$sourceRoot/../gcc/configure" $gccConfigureFlags + + sed -e 's,libgcc.mvars:.*$,libgcc.mvars:,' -i Makefile + + make \ + config.h \ + libgcc.mvars \ + tconfig.h \ + tm.h \ + options.h \ + insn-constants.h \ + insn-modes.h + ) + mkdir -p "$buildRoot/gcc/include" + '' + # Preparing to configure + build libgcc itself + + '' + mkdir -p "$buildRoot/gcc/${stdenvNoLibs.hostPlatform.config}/libgcc" + cd "$buildRoot/gcc/${stdenvNoLibs.hostPlatform.config}/libgcc" + configureScript=$sourceRoot/configure + chmod +x "$configureScript" + + export AS_FOR_BUILD=${buildPackages.stdenv.cc}/bin/$AS_FOR_BUILD + export CC_FOR_BUILD=${buildPackages.stdenv.cc}/bin/$CC_FOR_BUILD + export CPP_FOR_BUILD=${buildPackages.stdenv.cc}/bin/$CPP_FOR_BUILD + export CXX_FOR_BUILD=${buildPackages.stdenv.cc}/bin/$CXX_FOR_BUILD + export LD_FOR_BUILD=${buildPackages.stdenv.cc.bintools}/bin/$LD_FOR_BUILD + + export AS=${stdenvNoLibs.cc}/bin/$AS + export CC=${stdenvNoLibs.cc}/bin/$CC + export CPP=${stdenvNoLibs.cc}/bin/$CPP + export CXX=${stdenvNoLibs.cc}/bin/$CXX + export LD=${stdenvNoLibs.cc.bintools}/bin/$LD + + export AS_FOR_TARGET=${stdenvNoLibs.cc}/bin/$AS_FOR_TARGET + export CC_FOR_TARGET=${stdenvNoLibs.cc}/bin/$CC_FOR_TARGET + export CPP_FOR_TARGET=${stdenvNoLibs.cc}/bin/$CPP_FOR_TARGET + export LD_FOR_TARGET=${stdenvNoLibs.cc.bintools}/bin/$LD_FOR_TARGET + ''; + + gccConfigureFlags = [ + "--build=${stdenvNoLibs.buildPlatform.config}" + "--host=${stdenvNoLibs.buildPlatform.config}" + "--target=${stdenvNoLibs.hostPlatform.config}" + + "--disable-bootstrap" + "--disable-multilib" "--with-multilib-list=" + "--enable-languages=c" + + "--disable-fixincludes" + "--disable-intl" + "--disable-lto" + "--disable-libatomic" + "--disable-libbacktrace" + "--disable-libcpp" + "--disable-libssp" + "--disable-libquadmath" + "--disable-libgomp" + "--disable-libvtv" + "--disable-vtable-verify" + + "--with-system-zlib" + ] ++ lib.optional (stdenvNoLibs.hostPlatform.libc == "glibc") + "--with-glibc-version=${glibc.version}"; + + configurePlatforms = [ "build" "host" ]; + configureFlags = [ + "--disable-dependency-tracking" + # $CC cannot link binaries, let alone run then + "cross_compiling=true" + # Do not have dynamic linker without libc + "--enable-static" + "--disable-shared" + + # Avoid dependency on gcc. + "--disable-gcov" + ]; + + makeFlags = [ "MULTIBUILDTOP:=../" ]; + + postInstall = '' + moveToOutput "lib/gcc/${stdenvNoLibs.hostPlatform.config}/${version}/include" "$dev" + mkdir -p "$out/lib" "$dev/include" + ln -s "$out/lib/gcc/${stdenvNoLibs.hostPlatform.config}/${version}"/* "$out/lib" + ln -s "$dev/lib/gcc/${stdenvNoLibs.hostPlatform.config}/${version}/include"/* "$dev/include/" + ''; +} diff --git a/pkgs/top-level/aliases.nix b/pkgs/top-level/aliases.nix index 04273984e81d..1dc91abc1938 100644 --- a/pkgs/top-level/aliases.nix +++ b/pkgs/top-level/aliases.nix @@ -879,7 +879,6 @@ mapAliases ({ liberation_ttf_v1_from_source = throw "'liberation_ttf_v1_from_source' has been renamed to/replaced by 'liberation_ttf_v1'"; # Converted to throw 2022-02-22 liberation_ttf_v2_from_source = throw "'liberation_ttf_v2_from_source' has been renamed to/replaced by 'liberation_ttf_v2'"; # Converted to throw 2022-02-22 liberationsansnarrow = throw "'liberationsansnarrow' has been renamed to/replaced by 'liberation-sans-narrow'"; # Converted to throw 2022-02-22 - libgcc = throw "libgcc was removed, use gcc.cc.libgcc if needed"; # added 2023-05-13 libgksu = throw "libgksu has been removed"; # Added 2022-01-16 libgme = game-music-emu; # Added 2022-07-20 libgnome_keyring = throw "'libgnome_keyring' has been renamed to/replaced by 'libgnome-keyring'"; # Converted to throw 2022-02-22 diff --git a/pkgs/top-level/all-packages.nix b/pkgs/top-level/all-packages.nix index 1613c7a2f075..1b6f36b8d2af 100644 --- a/pkgs/top-level/all-packages.nix +++ b/pkgs/top-level/all-packages.nix @@ -18911,6 +18911,10 @@ with pkgs; librarian-puppet-go = callPackage ../development/tools/librarian-puppet-go { }; + libgcc = callPackage ../development/libraries/gcc/libgcc { + stdenvNoLibs = gccStdenvNoLibs; # cannot be built with clang it seems + }; + # This is for e.g. LLVM libraries on linux. gccForLibs = if stdenv.targetPlatform == stdenv.hostPlatform && targetPackages.stdenv.cc.isGNU From fcaa5a7556760d520dc78d99ada5a58fc13c7894 Mon Sep 17 00:00:00 2001 From: Adam Joseph Date: Tue, 8 Aug 2023 01:40:31 -0700 Subject: [PATCH 02/15] libgcc: take from gcc unless explicitly overridden --- pkgs/top-level/all-packages.nix | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/pkgs/top-level/all-packages.nix b/pkgs/top-level/all-packages.nix index 1b6f36b8d2af..7314a8c9f89a 100644 --- a/pkgs/top-level/all-packages.nix +++ b/pkgs/top-level/all-packages.nix @@ -18911,9 +18911,7 @@ with pkgs; librarian-puppet-go = callPackage ../development/tools/librarian-puppet-go { }; - libgcc = callPackage ../development/libraries/gcc/libgcc { - stdenvNoLibs = gccStdenvNoLibs; # cannot be built with clang it seems - }; + libgcc = stdenv.cc.cc.libgcc or null; # This is for e.g. LLVM libraries on linux. gccForLibs = From 72fa5978fd45925df9e09b829e23bb429250b898 Mon Sep 17 00:00:00 2001 From: Adam Joseph Date: Tue, 8 Aug 2023 01:59:55 -0700 Subject: [PATCH 03/15] libgcc: minor formatting adjustments --- .../libraries/gcc/libgcc/default.nix | 26 ++++++------------- 1 file changed, 8 insertions(+), 18 deletions(-) diff --git a/pkgs/development/libraries/gcc/libgcc/default.nix b/pkgs/development/libraries/gcc/libgcc/default.nix index 835956055448..c505d69d573d 100644 --- a/pkgs/development/libraries/gcc/libgcc/default.nix +++ b/pkgs/development/libraries/gcc/libgcc/default.nix @@ -24,30 +24,19 @@ stdenvNoLibs.mkDerivation rec { hardeningDisable = [ "pie" ]; - preConfigure = '' - cd "$buildRoot" + preConfigure = '' - - # Drop in libiberty, as external builds are not expected - + '' + # Drop in libiberty, as external builds are not expected + cd "$buildRoot" ( mkdir -p build-${stdenvNoLibs.buildPlatform.config}/libiberty/ cd build-${stdenvNoLibs.buildPlatform.config}/libiberty/ ln -s ${buildPackages.libiberty}/lib/libiberty.a ./ ) - '' - # A few misc bits of gcc need to be built. - # - # - We "shift" the tools over to fake platforms perspective from the previous - # stage. - # - # - We define GENERATOR_FILE so nothing bothers looking for GNU GMP. - # - # - We remove the `libgcc.mvar` deps so that the bootstrap xgcc isn't built. - + '' mkdir -p "$buildRoot/gcc" cd "$buildRoot/gcc" ( + # We "shift" the tools over to fake platforms perspective from the previous stage. export AS_FOR_BUILD=${buildPackages.stdenv.cc}/bin/$AS_FOR_BUILD export CC_FOR_BUILD=${buildPackages.stdenv.cc}/bin/$CC_FOR_BUILD export CPP_FOR_BUILD=${buildPackages.stdenv.cc}/bin/$CPP_FOR_BUILD @@ -65,10 +54,12 @@ stdenvNoLibs.mkDerivation rec { export CPP_FOR_TARGET=${stdenvNoLibs.cc}/bin/$CPP export LD_FOR_TARGET=${stdenvNoLibs.cc.bintools}/bin/$LD + # We define GENERATOR_FILE so nothing bothers looking for GNU GMP. export NIX_CFLAGS_COMPILE_FOR_BUILD+=' -DGENERATOR_FILE=1' "$sourceRoot/../gcc/configure" $gccConfigureFlags + # We remove the `libgcc.mvar` deps so that the bootstrap xgcc isn't built. sed -e 's,libgcc.mvars:.*$,libgcc.mvars:,' -i Makefile make \ @@ -81,9 +72,8 @@ stdenvNoLibs.mkDerivation rec { insn-modes.h ) mkdir -p "$buildRoot/gcc/include" - '' - # Preparing to configure + build libgcc itself - + '' + + # Preparing to configure + build libgcc itself mkdir -p "$buildRoot/gcc/${stdenvNoLibs.hostPlatform.config}/libgcc" cd "$buildRoot/gcc/${stdenvNoLibs.hostPlatform.config}/libgcc" configureScript=$sourceRoot/configure From 2ecf2d954becdd97d78d41d663d0007d72714a5e Mon Sep 17 00:00:00 2001 From: Adam Joseph Date: Tue, 8 Aug 2023 02:00:33 -0700 Subject: [PATCH 04/15] libgcc: use finalAttrs instead of rec --- pkgs/development/libraries/gcc/libgcc/default.nix | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/pkgs/development/libraries/gcc/libgcc/default.nix b/pkgs/development/libraries/gcc/libgcc/default.nix index c505d69d573d..be1e3a682579 100644 --- a/pkgs/development/libraries/gcc/libgcc/default.nix +++ b/pkgs/development/libraries/gcc/libgcc/default.nix @@ -3,7 +3,7 @@ , libiberty }: -stdenvNoLibs.mkDerivation rec { +stdenvNoLibs.mkDerivation (finalAttrs: { pname = "libgcc"; inherit (gcc.cc) src version; @@ -138,9 +138,9 @@ stdenvNoLibs.mkDerivation rec { makeFlags = [ "MULTIBUILDTOP:=../" ]; postInstall = '' - moveToOutput "lib/gcc/${stdenvNoLibs.hostPlatform.config}/${version}/include" "$dev" + moveToOutput "lib/gcc/${stdenvNoLibs.hostPlatform.config}/${finalAttrs.version}/include" "$dev" mkdir -p "$out/lib" "$dev/include" - ln -s "$out/lib/gcc/${stdenvNoLibs.hostPlatform.config}/${version}"/* "$out/lib" - ln -s "$dev/lib/gcc/${stdenvNoLibs.hostPlatform.config}/${version}/include"/* "$dev/include/" + ln -s "$out/lib/gcc/${stdenvNoLibs.hostPlatform.config}/${finalAttrs.version}"/* "$out/lib" + ln -s "$dev/lib/gcc/${stdenvNoLibs.hostPlatform.config}/${finalAttrs.version}/include"/* "$dev/include/" ''; -} +}) From b5893e70468246bcd0062631c0cde3fc5687b362 Mon Sep 17 00:00:00 2001 From: Adam Joseph Date: Tue, 8 Aug 2023 02:01:43 -0700 Subject: [PATCH 05/15] libgcc: let-float gccConfigureFlags out of the derivation attrs --- .../libraries/gcc/libgcc/default.nix | 55 ++++++++++--------- 1 file changed, 28 insertions(+), 27 deletions(-) diff --git a/pkgs/development/libraries/gcc/libgcc/default.nix b/pkgs/development/libraries/gcc/libgcc/default.nix index be1e3a682579..382140fd80c5 100644 --- a/pkgs/development/libraries/gcc/libgcc/default.nix +++ b/pkgs/development/libraries/gcc/libgcc/default.nix @@ -3,7 +3,33 @@ , libiberty }: -stdenvNoLibs.mkDerivation (finalAttrs: { +let + gccConfigureFlags = gcc.cc.configureFlags ++ [ + "--build=${stdenvNoLibs.buildPlatform.config}" + "--host=${stdenvNoLibs.buildPlatform.config}" + "--target=${stdenvNoLibs.hostPlatform.config}" + + "--disable-bootstrap" + "--disable-multilib" "--with-multilib-list=" + "--enable-languages=c" + + "--disable-fixincludes" + "--disable-intl" + "--disable-lto" + "--disable-libatomic" + "--disable-libbacktrace" + "--disable-libcpp" + "--disable-libssp" + "--disable-libquadmath" + "--disable-libgomp" + "--disable-libvtv" + "--disable-vtable-verify" + + "--with-system-zlib" + ] ++ lib.optional (stdenvNoLibs.hostPlatform.libc == "glibc") + "--with-glibc-version=${glibc.version}"; + +in stdenvNoLibs.mkDerivation (finalAttrs: { pname = "libgcc"; inherit (gcc.cc) src version; @@ -57,7 +83,7 @@ stdenvNoLibs.mkDerivation (finalAttrs: { # We define GENERATOR_FILE so nothing bothers looking for GNU GMP. export NIX_CFLAGS_COMPILE_FOR_BUILD+=' -DGENERATOR_FILE=1' - "$sourceRoot/../gcc/configure" $gccConfigureFlags + "$sourceRoot/../gcc/configure" ${lib.concatStringsSep " " gccConfigureFlags} # We remove the `libgcc.mvar` deps so that the bootstrap xgcc isn't built. sed -e 's,libgcc.mvars:.*$,libgcc.mvars:,' -i Makefile @@ -97,31 +123,6 @@ stdenvNoLibs.mkDerivation (finalAttrs: { export LD_FOR_TARGET=${stdenvNoLibs.cc.bintools}/bin/$LD_FOR_TARGET ''; - gccConfigureFlags = [ - "--build=${stdenvNoLibs.buildPlatform.config}" - "--host=${stdenvNoLibs.buildPlatform.config}" - "--target=${stdenvNoLibs.hostPlatform.config}" - - "--disable-bootstrap" - "--disable-multilib" "--with-multilib-list=" - "--enable-languages=c" - - "--disable-fixincludes" - "--disable-intl" - "--disable-lto" - "--disable-libatomic" - "--disable-libbacktrace" - "--disable-libcpp" - "--disable-libssp" - "--disable-libquadmath" - "--disable-libgomp" - "--disable-libvtv" - "--disable-vtable-verify" - - "--with-system-zlib" - ] ++ lib.optional (stdenvNoLibs.hostPlatform.libc == "glibc") - "--with-glibc-version=${glibc.version}"; - configurePlatforms = [ "build" "host" ]; configureFlags = [ "--disable-dependency-tracking" From 383d62d94c31a8094154a4b5346679d204a2f0f8 Mon Sep 17 00:00:00 2001 From: Adam Joseph Date: Tue, 8 Aug 2023 02:02:04 -0700 Subject: [PATCH 06/15] libgcc: add glibc as a buildInput This is necessary in order to prevent gcc from switching on `inhibit_libc`, which cripples the `libgcc_s.so` unwinder. --- pkgs/development/libraries/gcc/libgcc/default.nix | 1 + 1 file changed, 1 insertion(+) diff --git a/pkgs/development/libraries/gcc/libgcc/default.nix b/pkgs/development/libraries/gcc/libgcc/default.nix index 382140fd80c5..d3f1ce2a27d6 100644 --- a/pkgs/development/libraries/gcc/libgcc/default.nix +++ b/pkgs/development/libraries/gcc/libgcc/default.nix @@ -38,6 +38,7 @@ in stdenvNoLibs.mkDerivation (finalAttrs: { strictDeps = true; depsBuildBuild = [ buildPackages.stdenv.cc ]; nativeBuildInputs = [ libiberty ]; + buildInputs = [ glibc ]; postUnpack = '' mkdir -p ./build From 92186a49bf72a74e507549669cde90977c977efe Mon Sep 17 00:00:00 2001 From: Adam Joseph Date: Mon, 14 Aug 2023 02:02:31 -0700 Subject: [PATCH 07/15] gcc: factor out forceLibgccToBuildCrtStuff --- .../compilers/gcc/common/builder.nix | 6 +++ .../gcc/common/libgcc-buildstuff.nix | 37 +++++++++++++++++++ .../compilers/gcc/common/libgcc.nix | 14 +++---- .../compilers/gcc/common/pre-configure.nix | 36 +----------------- 4 files changed, 51 insertions(+), 42 deletions(-) create mode 100644 pkgs/development/compilers/gcc/common/libgcc-buildstuff.nix diff --git a/pkgs/development/compilers/gcc/common/builder.nix b/pkgs/development/compilers/gcc/common/builder.nix index cd8d4572a158..6df4e32ddb76 100644 --- a/pkgs/development/compilers/gcc/common/builder.nix +++ b/pkgs/development/compilers/gcc/common/builder.nix @@ -3,7 +3,13 @@ , enableMultilib }: +let + forceLibgccToBuildCrtStuff = + import ./libgcc-buildstuff.nix { inherit lib stdenv; }; +in + originalAttrs: (stdenv.mkDerivation (finalAttrs: originalAttrs // { + passthru = (originalAttrs.passthru or {}) // { inherit forceLibgccToBuildCrtStuff; }; preUnpack = '' oldOpts="$(shopt -po nounset)" || true set -euo pipefail diff --git a/pkgs/development/compilers/gcc/common/libgcc-buildstuff.nix b/pkgs/development/compilers/gcc/common/libgcc-buildstuff.nix new file mode 100644 index 000000000000..e7dc570a560c --- /dev/null +++ b/pkgs/development/compilers/gcc/common/libgcc-buildstuff.nix @@ -0,0 +1,37 @@ +{ lib +, stdenv +}: + +# Trick to build a gcc that is capable of emitting shared libraries *without* having the +# targetPlatform libc available beforehand. Taken from: +# https://web.archive.org/web/20170222224855/http://frank.harvard.edu/~coldwell/toolchain/ +# https://web.archive.org/web/20170224235700/http://frank.harvard.edu/~coldwell/toolchain/t-linux.diff +let + # crt{i,n}.o are the first and last (respectively) object file + # linked when producing an executable. Traditionally these + # files are delivered as part of the C library, but on GNU + # systems they are in fact built by GCC. Since libgcc needs to + # build before glibc, we can't wait for them to be copied by + # glibc. At this early pre-glibc stage these files sometimes + # have different names. + crtstuff-ofiles = + if stdenv.targetPlatform.isPower + then "ecrti.o ecrtn.o ncrti.o ncrtn.o" + else "crti.o crtn.o"; + + # Normally, `SHLIB_LC` is set to `-lc`, which means that + # `libgcc_s.so` cannot be built until `libc.so` is available. + # The assignment below clobbers this variable, removing the + # `-lc`. + # + # On PowerPC we add `-mnewlib`, which means "libc has not been + # built yet". This causes libgcc's Makefile to use the + # gcc-built `{e,n}crt{n,i}.o` instead of failing to find the + # versions which have been repackaged in libc as `crt{n,i}.o` + # + SHLIB_LC = lib.optionalString stdenv.targetPlatform.isPower "-mnewlib"; + +in '' + echo 'libgcc.a: ${crtstuff-ofiles}' >> libgcc/Makefile.in + echo 'SHLIB_LC=${SHLIB_LC}' >> libgcc/Makefile.in + '' diff --git a/pkgs/development/compilers/gcc/common/libgcc.nix b/pkgs/development/compilers/gcc/common/libgcc.nix index b14d111e361f..4ab6eb2b3b44 100644 --- a/pkgs/development/compilers/gcc/common/libgcc.nix +++ b/pkgs/development/compilers/gcc/common/libgcc.nix @@ -44,14 +44,14 @@ lib.optional (lib.versionAtLeast version "11.0") !langJit && !stdenv.hostPlatform.isDarwin && enableShared - ; + ; - # For some reason libgcc_s.so has major-version "2" on m68k but - # "1" everywhere else. Might be worth changing this to "*". - libgcc_s-version-major = - if targetPlatform.isM68k - then "2" - else "1"; + # For some reason libgcc_s.so has major-version "2" on m68k but + # "1" everywhere else. Might be worth changing this to "*". + libgcc_s-version-major = + if targetPlatform.isM68k + then "2" + else "1"; in (pkg: pkg.overrideAttrs (previousAttrs: lib.optionalAttrs ((!langC) || langJit || enableLibGccOutput) { diff --git a/pkgs/development/compilers/gcc/common/pre-configure.nix b/pkgs/development/compilers/gcc/common/pre-configure.nix index 933a132ce4d1..5cb2f186fd1d 100644 --- a/pkgs/development/compilers/gcc/common/pre-configure.nix +++ b/pkgs/development/compilers/gcc/common/pre-configure.nix @@ -112,39 +112,5 @@ in lib.optionalString (hostPlatform.isSunOS && hostPlatform.is64bit) '' export inhibit_libc=true '' -# Trick to build a gcc that is capable of emitting shared libraries *without* having the -# targetPlatform libc available beforehand. Taken from: -# https://web.archive.org/web/20170222224855/http://frank.harvard.edu/~coldwell/toolchain/ -# https://web.archive.org/web/20170224235700/http://frank.harvard.edu/~coldwell/toolchain/t-linux.diff + lib.optionalString (targetPlatform != hostPlatform && withoutTargetLibc && enableShared) - (let - - # crt{i,n}.o are the first and last (respectively) object file - # linked when producing an executable. Traditionally these - # files are delivered as part of the C library, but on GNU - # systems they are in fact built by GCC. Since libgcc needs to - # build before glibc, we can't wait for them to be copied by - # glibc. At this early pre-glibc stage these files sometimes - # have different names. - crtstuff-ofiles = - if targetPlatform.isPower - then "ecrti.o ecrtn.o ncrti.o ncrtn.o" - else "crti.o crtn.o"; - - # Normally, `SHLIB_LC` is set to `-lc`, which means that - # `libgcc_s.so` cannot be built until `libc.so` is available. - # The assignment below clobbers this variable, removing the - # `-lc`. - # - # On PowerPC we add `-mnewlib`, which means "libc has not been - # built yet". This causes libgcc's Makefile to use the - # gcc-built `{e,n}crt{n,i}.o` instead of failing to find the - # versions which have been repackaged in libc as `crt{n,i}.o` - # - SHLIB_LC = lib.optionalString targetPlatform.isPower "-mnewlib"; - - in '' - echo 'libgcc.a: ${crtstuff-ofiles}' >> libgcc/Makefile.in - echo 'SHLIB_LC=${SHLIB_LC}' >> libgcc/Makefile.in - '') - + (import ./libgcc-buildstuff.nix { inherit lib stdenv; }) From da371c7c5a57a8a34c8bb3ec5336ff97977360de Mon Sep 17 00:00:00 2001 From: Adam Joseph Date: Tue, 8 Aug 2023 02:02:46 -0700 Subject: [PATCH 08/15] libgcc: use forceLibgccToBuildCrtStuff This duplicates (by reference) the two-line adjustment to libgcc's Makefile needed in order to get crtstuff to build without a full build of gcc. --- pkgs/development/libraries/gcc/libgcc/default.nix | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/pkgs/development/libraries/gcc/libgcc/default.nix b/pkgs/development/libraries/gcc/libgcc/default.nix index d3f1ce2a27d6..929e7e47f17f 100644 --- a/pkgs/development/libraries/gcc/libgcc/default.nix +++ b/pkgs/development/libraries/gcc/libgcc/default.nix @@ -45,9 +45,11 @@ in stdenvNoLibs.mkDerivation (finalAttrs: { buildRoot=$(readlink -e "./build") ''; - postPatch = '' - sourceRoot=$(readlink -e "./libgcc") - ''; + postPatch = + gcc.cc.passthru.forceLibgccToBuildCrtStuff + + '' + sourceRoot=$(readlink -e "./libgcc") + ''; hardeningDisable = [ "pie" ]; From fa0ebe80f1e7b3d872b3814bfcb25f991217a5ef Mon Sep 17 00:00:00 2001 From: Adam Joseph Date: Tue, 8 Aug 2023 02:03:40 -0700 Subject: [PATCH 09/15] libgcc: configureFlags: minimize A lot of these flags were unnecessary. --- pkgs/development/libraries/gcc/libgcc/default.nix | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/pkgs/development/libraries/gcc/libgcc/default.nix b/pkgs/development/libraries/gcc/libgcc/default.nix index 929e7e47f17f..d3d91616f6b6 100644 --- a/pkgs/development/libraries/gcc/libgcc/default.nix +++ b/pkgs/development/libraries/gcc/libgcc/default.nix @@ -128,15 +128,9 @@ in stdenvNoLibs.mkDerivation (finalAttrs: { configurePlatforms = [ "build" "host" ]; configureFlags = [ - "--disable-dependency-tracking" - # $CC cannot link binaries, let alone run then "cross_compiling=true" - # Do not have dynamic linker without libc - "--enable-static" - "--disable-shared" - - # Avoid dependency on gcc. "--disable-gcov" + "--with-glibc-version=${glibc.version}" ]; makeFlags = [ "MULTIBUILDTOP:=../" ]; From 8c37dae9adf2c73cbd750566fef244398d5f87e9 Mon Sep 17 00:00:00 2001 From: Adam Joseph Date: Tue, 8 Aug 2023 02:04:08 -0700 Subject: [PATCH 10/15] libgcc: gccConfigureFlags: minimize, fix This commit minimizes libgcc's gccConfigureFlags, and -- importantly -- includes the three flags needed in order to prevent `inhibit_libc` from becoming active. --- .../libraries/gcc/libgcc/default.nix | 29 ++++++------------- 1 file changed, 9 insertions(+), 20 deletions(-) diff --git a/pkgs/development/libraries/gcc/libgcc/default.nix b/pkgs/development/libraries/gcc/libgcc/default.nix index d3d91616f6b6..dd67c2c28da5 100644 --- a/pkgs/development/libraries/gcc/libgcc/default.nix +++ b/pkgs/development/libraries/gcc/libgcc/default.nix @@ -5,29 +5,18 @@ let gccConfigureFlags = gcc.cc.configureFlags ++ [ - "--build=${stdenvNoLibs.buildPlatform.config}" - "--host=${stdenvNoLibs.buildPlatform.config}" - "--target=${stdenvNoLibs.hostPlatform.config}" - - "--disable-bootstrap" - "--disable-multilib" "--with-multilib-list=" - "--enable-languages=c" - "--disable-fixincludes" "--disable-intl" - "--disable-lto" - "--disable-libatomic" - "--disable-libbacktrace" - "--disable-libcpp" - "--disable-libssp" - "--disable-libquadmath" - "--disable-libgomp" - "--disable-libvtv" - "--disable-vtable-verify" + "--enable-threads=posix" + "--with-glibc-version=${glibc.version}" - "--with-system-zlib" - ] ++ lib.optional (stdenvNoLibs.hostPlatform.libc == "glibc") - "--with-glibc-version=${glibc.version}"; + # these are required in order to prevent inhibit_libc=true, + # which will cripple libgcc's unwinder; see: + # https://github.com/NixOS/nixpkgs/issues/213453#issuecomment-1616346163 + "--with-headers=${lib.getDev glibc}/include" + "--with-native-system-header-dir=${lib.getDev glibc}${glibc.incdir or "/include"}" + "--with-build-sysroot=/" + ]; in stdenvNoLibs.mkDerivation (finalAttrs: { pname = "libgcc"; From 17ce8682d67de1977c0a9bc1ef9258a905aa5a1c Mon Sep 17 00:00:00 2001 From: Adam Joseph Date: Mon, 14 Aug 2023 02:05:16 -0700 Subject: [PATCH 11/15] libgcc: let-rename stdenvNoLibs to stdenv --- .../libraries/gcc/libgcc/default.nix | 43 ++++++++++--------- 1 file changed, 22 insertions(+), 21 deletions(-) diff --git a/pkgs/development/libraries/gcc/libgcc/default.nix b/pkgs/development/libraries/gcc/libgcc/default.nix index dd67c2c28da5..e3ae86d21eef 100644 --- a/pkgs/development/libraries/gcc/libgcc/default.nix +++ b/pkgs/development/libraries/gcc/libgcc/default.nix @@ -4,6 +4,7 @@ }: let + stdenv = stdenvNoLibs; gccConfigureFlags = gcc.cc.configureFlags ++ [ "--disable-fixincludes" "--disable-intl" @@ -18,7 +19,7 @@ let "--with-build-sysroot=/" ]; -in stdenvNoLibs.mkDerivation (finalAttrs: { +in stdenv.mkDerivation (finalAttrs: { pname = "libgcc"; inherit (gcc.cc) src version; @@ -47,8 +48,8 @@ in stdenvNoLibs.mkDerivation (finalAttrs: { # Drop in libiberty, as external builds are not expected cd "$buildRoot" ( - mkdir -p build-${stdenvNoLibs.buildPlatform.config}/libiberty/ - cd build-${stdenvNoLibs.buildPlatform.config}/libiberty/ + mkdir -p build-${stdenv.buildPlatform.config}/libiberty/ + cd build-${stdenv.buildPlatform.config}/libiberty/ ln -s ${buildPackages.libiberty}/lib/libiberty.a ./ ) mkdir -p "$buildRoot/gcc" @@ -67,10 +68,10 @@ in stdenvNoLibs.mkDerivation (finalAttrs: { export CXX=$CXX_FOR_BUILD export LD=$LD_FOR_BUILD - export AS_FOR_TARGET=${stdenvNoLibs.cc}/bin/$AS - export CC_FOR_TARGET=${stdenvNoLibs.cc}/bin/$CC - export CPP_FOR_TARGET=${stdenvNoLibs.cc}/bin/$CPP - export LD_FOR_TARGET=${stdenvNoLibs.cc.bintools}/bin/$LD + export AS_FOR_TARGET=${stdenv.cc}/bin/$AS + export CC_FOR_TARGET=${stdenv.cc}/bin/$CC + export CPP_FOR_TARGET=${stdenv.cc}/bin/$CPP + export LD_FOR_TARGET=${stdenv.cc.bintools}/bin/$LD # We define GENERATOR_FILE so nothing bothers looking for GNU GMP. export NIX_CFLAGS_COMPILE_FOR_BUILD+=' -DGENERATOR_FILE=1' @@ -92,8 +93,8 @@ in stdenvNoLibs.mkDerivation (finalAttrs: { mkdir -p "$buildRoot/gcc/include" # Preparing to configure + build libgcc itself - mkdir -p "$buildRoot/gcc/${stdenvNoLibs.hostPlatform.config}/libgcc" - cd "$buildRoot/gcc/${stdenvNoLibs.hostPlatform.config}/libgcc" + mkdir -p "$buildRoot/gcc/${stdenv.hostPlatform.config}/libgcc" + cd "$buildRoot/gcc/${stdenv.hostPlatform.config}/libgcc" configureScript=$sourceRoot/configure chmod +x "$configureScript" @@ -103,16 +104,16 @@ in stdenvNoLibs.mkDerivation (finalAttrs: { export CXX_FOR_BUILD=${buildPackages.stdenv.cc}/bin/$CXX_FOR_BUILD export LD_FOR_BUILD=${buildPackages.stdenv.cc.bintools}/bin/$LD_FOR_BUILD - export AS=${stdenvNoLibs.cc}/bin/$AS - export CC=${stdenvNoLibs.cc}/bin/$CC - export CPP=${stdenvNoLibs.cc}/bin/$CPP - export CXX=${stdenvNoLibs.cc}/bin/$CXX - export LD=${stdenvNoLibs.cc.bintools}/bin/$LD + export AS=${stdenv.cc}/bin/$AS + export CC=${stdenv.cc}/bin/$CC + export CPP=${stdenv.cc}/bin/$CPP + export CXX=${stdenv.cc}/bin/$CXX + export LD=${stdenv.cc.bintools}/bin/$LD - export AS_FOR_TARGET=${stdenvNoLibs.cc}/bin/$AS_FOR_TARGET - export CC_FOR_TARGET=${stdenvNoLibs.cc}/bin/$CC_FOR_TARGET - export CPP_FOR_TARGET=${stdenvNoLibs.cc}/bin/$CPP_FOR_TARGET - export LD_FOR_TARGET=${stdenvNoLibs.cc.bintools}/bin/$LD_FOR_TARGET + export AS_FOR_TARGET=${stdenv.cc}/bin/$AS_FOR_TARGET + export CC_FOR_TARGET=${stdenv.cc}/bin/$CC_FOR_TARGET + export CPP_FOR_TARGET=${stdenv.cc}/bin/$CPP_FOR_TARGET + export LD_FOR_TARGET=${stdenv.cc.bintools}/bin/$LD_FOR_TARGET ''; configurePlatforms = [ "build" "host" ]; @@ -125,9 +126,9 @@ in stdenvNoLibs.mkDerivation (finalAttrs: { makeFlags = [ "MULTIBUILDTOP:=../" ]; postInstall = '' - moveToOutput "lib/gcc/${stdenvNoLibs.hostPlatform.config}/${finalAttrs.version}/include" "$dev" + moveToOutput "lib/gcc/${stdenv.hostPlatform.config}/${finalAttrs.version}/include" "$dev" mkdir -p "$out/lib" "$dev/include" - ln -s "$out/lib/gcc/${stdenvNoLibs.hostPlatform.config}/${finalAttrs.version}"/* "$out/lib" - ln -s "$dev/lib/gcc/${stdenvNoLibs.hostPlatform.config}/${finalAttrs.version}/include"/* "$dev/include/" + ln -s "$out/lib/gcc/${stdenv.hostPlatform.config}/${finalAttrs.version}"/* "$out/lib" + ln -s "$dev/lib/gcc/${stdenv.hostPlatform.config}/${finalAttrs.version}/include"/* "$dev/include/" ''; }) From c0e4121ba537c10ef0a5132777bb35ae94735658 Mon Sep 17 00:00:00 2001 From: Adam Joseph Date: Mon, 14 Aug 2023 02:04:39 -0700 Subject: [PATCH 12/15] libgcc: make needed architecture-specific targets if isM68k --- pkgs/development/libraries/gcc/libgcc/default.nix | 3 +++ 1 file changed, 3 insertions(+) diff --git a/pkgs/development/libraries/gcc/libgcc/default.nix b/pkgs/development/libraries/gcc/libgcc/default.nix index e3ae86d21eef..afc42bccfb53 100644 --- a/pkgs/development/libraries/gcc/libgcc/default.nix +++ b/pkgs/development/libraries/gcc/libgcc/default.nix @@ -88,6 +88,9 @@ in stdenv.mkDerivation (finalAttrs: { tm.h \ options.h \ insn-constants.h \ + '' + lib.optionalString stdenv.targetPlatform.isM68k '' + sysroot-suffix.h \ + '' + '' insn-modes.h ) mkdir -p "$buildRoot/gcc/include" From 18c52d09bcd6c60bc60db81fe1a37d7663acaf27 Mon Sep 17 00:00:00 2001 From: Adam Joseph Date: Mon, 14 Aug 2023 13:34:42 -0700 Subject: [PATCH 13/15] libgcc: make needed architecture-specific targets if isArmv7 --- pkgs/development/libraries/gcc/libgcc/default.nix | 3 +++ pkgs/test/cross/default.nix | 1 + 2 files changed, 4 insertions(+) diff --git a/pkgs/development/libraries/gcc/libgcc/default.nix b/pkgs/development/libraries/gcc/libgcc/default.nix index afc42bccfb53..e2fbf55876fa 100644 --- a/pkgs/development/libraries/gcc/libgcc/default.nix +++ b/pkgs/development/libraries/gcc/libgcc/default.nix @@ -90,6 +90,9 @@ in stdenv.mkDerivation (finalAttrs: { insn-constants.h \ '' + lib.optionalString stdenv.targetPlatform.isM68k '' sysroot-suffix.h \ + '' + lib.optionalString stdenv.targetPlatform.isArmv7 '' + arm-isa.h \ + arm-cpu.h \ '' + '' insn-modes.h ) diff --git a/pkgs/test/cross/default.nix b/pkgs/test/cross/default.nix index 46bb3c8d522d..0b037b6057ec 100644 --- a/pkgs/test/cross/default.nix +++ b/pkgs/test/cross/default.nix @@ -134,6 +134,7 @@ let pkgs.pkgsLLVM.stdenv pkgs.pkgsStatic.bash pkgs.pkgsCross.arm-embedded.stdenv + pkgs.pkgsCross.armv7l-hf-multiplatform.stdenv pkgs.pkgsCross.m68k.stdenv pkgs.pkgsCross.aarch64-multiplatform.pkgsBuildTarget.gcc pkgs.pkgsCross.powernv.pkgsBuildTarget.gcc From 64046f019103677f9539b303bf7be0f9be12d29f Mon Sep 17 00:00:00 2001 From: Adam Joseph Date: Mon, 7 Aug 2023 21:50:24 -0700 Subject: [PATCH 14/15] glibcCross: use a libgcc built separately from gcc ### Summary This PR completely and finally solves the gcc<->glibc circular `buildInputs` problem, for cross compilation. The same technique can be applied to native builds in the future. Closes #213453 ### Motivation Prior to this PR, we had the following circular `buildInputs` problem: 1. gcc has glibc in its `buildInputs` - a compiled copy of glibc must be present before building gcc; if it isn't, gcc cripples itself (`inhibit_libc`) and refuses to build libgcc_s.so 2. glibc has libgcc_s.so in its `buildInputs` - glibc `dlopen()`s libgcc_s.so in order to implement POSIX thread cancellation. For security reasons `glibc` requires that the path to `libgcc_s.so` is [hardwired] into `glibc` at compile time, so it's technically not a true dynamic link -- it just pretends to be one. 3. libgcc_s.so is built in the same derivation as gcc - libgcc_s.so is built as part of the gcc build process We must cut one of these three links in the loop. ### Previous Attempts Previously https://github.com/NixOS/nixpkgs/pull/238154 had attempted to cut link (1) by building `gcc` without `glibc`, and using the `libgcc_s` which emerges from that build. Unfortunately this just doesn't work. GCC's configure script extracts quite a lot of information from the glibc headers (which are a build artifact -- you can't just copy them out of the source tarball) and various `./configure`-driven linking attempts. If `glibc` isn't around at build time you wind up with a `libgcc_s.so` that is missing various unwinder features (see https://github.com/NixOS/nixpkgs/issues/213453 for the most problematic one). Musl "cuts" link (2), or rather never creates it in the first place. ["Cancellation cleanup handling in musl has no relationship to C++ exceptions and unwinding... glibc implements cancellation as an exception"](https://wiki.musl-libc.org/functional-differences-from-glibc.html#Thread-cancellation). IMHO Musl made the smarter decision here. It is incredibly rare to find a codebase that uses both POSIX thread cancellation *and* C++ exceptions. I have never seen a codebase that uses both *and* expects them to be aware of each other, and I would be astonished if one existed. Glibc paid an immense cost in complexity for something nobody has ever used. ### Changes Made This PR cuts link (3): instead of building libgcc_s.so as part of gcc, we build it separately from gcc. Now there is a strict acyclic graph of `buildInputs`: ``` gccWithoutTargetLibc | +--->glibc-nolibgcc | | | v +--->libgcc | | | v +--->glibc | | | v +--->gcc ``` In other words, there's a simple linear `buildInputs` chain `glibc-nolibgcc` `->` `libgcc` `->` `glibc` `->` `gcc` where all four packages are compiled by (and therefore have as a `(native)BuildInput`) `gccWithoutTargetLibc`. `gccWithoutTargetLibc` and `glibc-nolibgcc` are strictly bootstrapping artifacts; nothing else has them as a `buildInput` and they shouldn't appear in the closure of any final deployment packages. `glibc-nolibgcc` lacks `libgcc_s.so`, so it will segfault if you try to use it with POSIX thread cancellation. Fortunately all we need from it is (a) its headers (`lib.getDev`) and (b) to use it in the `./configure` script for `libgcc`. When translated over to the native bootstrap, `xgcc` takes the place of `gccWithoutTargetLibc`, and the "first `glibc`" (we build two of them) takes the place of `glibc-nolibgcc`. At that point our native and cross bootstrap have the same overall architecture, and it becomes possible to merge them (at last!) [213453]: https://github.com/NixOS/nixpkgs/issues/213453 [238154]: https://github.com/NixOS/nixpkgs/pull/238154 [hardwired]: https://github.com/NixOS/nixpkgs/blob/7553d0fe29801938bcb280bb324b579ef9016aea/pkgs/development/libraries/glibc/default.nix#L69-L88 --- pkgs/development/libraries/glibc/default.nix | 11 ++++++----- pkgs/top-level/all-packages.nix | 5 +++++ 2 files changed, 11 insertions(+), 5 deletions(-) diff --git a/pkgs/development/libraries/glibc/default.nix b/pkgs/development/libraries/glibc/default.nix index 0f6cad157bb7..1c822bf1ed01 100644 --- a/pkgs/development/libraries/glibc/default.nix +++ b/pkgs/development/libraries/glibc/default.nix @@ -4,6 +4,7 @@ , withGd ? false , withLibcrypt? false , buildPackages +, libgcc }: let @@ -16,7 +17,7 @@ in (callPackage ./common.nix { inherit stdenv; } { inherit withLinuxHeaders withGd profilingLibraries withLibcrypt; - pname = "glibc" + lib.optionalString withGd "-gd"; + pname = "glibc" + lib.optionalString withGd "-gd" + lib.optionalString (stdenv.cc.isGNU && libgcc==null) "-nolibgcc"; }).overrideAttrs(previousAttrs: { # Note: @@ -90,8 +91,8 @@ in # makeFlags = (previousAttrs.makeFlags or []) - ++ lib.optionals (stdenv.cc.cc?libgcc) [ - "user-defined-trusted-dirs=${stdenv.cc.cc.libgcc}/lib" + ++ lib.optionals (libgcc != null) [ + "user-defined-trusted-dirs=${libgcc}/lib" ]; postInstall = previousAttrs.postInstall + (if stdenv.hostPlatform == stdenv.buildPlatform then '' @@ -166,8 +167,8 @@ in passthru = (previousAttrs.passthru or {}) - // lib.optionalAttrs (stdenv.cc.cc?libgcc) { - inherit (stdenv.cc.cc) libgcc; + // lib.optionalAttrs (libgcc != null) { + inherit libgcc; }; meta = (previousAttrs.meta or {}) // { description = "The GNU C Library"; }; diff --git a/pkgs/top-level/all-packages.nix b/pkgs/top-level/all-packages.nix index 7314a8c9f89a..44d90dd9c575 100644 --- a/pkgs/top-level/all-packages.nix +++ b/pkgs/top-level/all-packages.nix @@ -21439,6 +21439,11 @@ with pkgs; # Being redundant to avoid cycles on boot. TODO: find a better way glibcCross = callPackage ../development/libraries/glibc { stdenv = gccCrossLibcStdenv; # doesn't compile without gcc + libgcc = callPackage ../development/libraries/gcc/libgcc { + gcc = gccCrossLibcStdenv.cc; + glibc = glibcCross.override { libgcc = null; }; + stdenvNoLibs = gccCrossLibcStdenv; + }; }; muslCross = musl.override { From 1912681314d415cc28e25b7932d9e88dfec75cd3 Mon Sep 17 00:00:00 2001 From: Adam Joseph Date: Tue, 8 Aug 2023 02:06:04 -0700 Subject: [PATCH 15/15] tests.cross.sanity: enable mbuffer test This test passes now. Also fixes a minor oversight in the bug -- the test case needs to `touch $out` on success. --- pkgs/test/cross/default.nix | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/pkgs/test/cross/default.nix b/pkgs/test/cross/default.nix index 0b037b6057ec..d6fd8d3b1f80 100644 --- a/pkgs/test/cross/default.nix +++ b/pkgs/test/cross/default.nix @@ -115,6 +115,7 @@ let in pkgs.runCommand "test-mbuffer" {} '' echo hello | ${emulator} ${mbuffer}/bin/mbuffer + touch $out ''; # This is meant to be a carefully curated list of builds/packages @@ -127,7 +128,7 @@ let # of things that often break. So, no buckshot `mapTestOnCross` # calls here. sanity = [ - #pkgs.mbuffer # https://github.com/NixOS/nixpkgs/issues/213453 + mbuffer #pkgs.pkgsCross.gnu64.bash # https://github.com/NixOS/nixpkgs/issues/243164 pkgs.gcc_multi.cc pkgs.pkgsMusl.stdenv