summary refs log tree commit diff
path: root/pkgs/development
diff options
context:
space:
mode:
Diffstat (limited to 'pkgs/development')
-rw-r--r--pkgs/development/compilers/gcc/11/default.nix8
-rw-r--r--pkgs/development/compilers/gcc/12/default.nix3
-rw-r--r--pkgs/development/compilers/gcc/common/libgcc.nix96
-rw-r--r--pkgs/development/libraries/glibc/default.nix53
4 files changed, 128 insertions, 32 deletions
diff --git a/pkgs/development/compilers/gcc/11/default.nix b/pkgs/development/compilers/gcc/11/default.nix
index 6ad7ce27f25..b003a1c30fd 100644
--- a/pkgs/development/compilers/gcc/11/default.nix
+++ b/pkgs/development/compilers/gcc/11/default.nix
@@ -49,7 +49,7 @@ with builtins;
 
 let majorVersion = "11";
     version = "${majorVersion}.3.0";
-    disableBootstrap = !(with stdenv; targetPlatform == hostPlatform && hostPlatform == buildPlatform);
+    disableBootstrap = true;
 
     inherit (stdenv) buildPlatform hostPlatform targetPlatform;
 
@@ -250,9 +250,8 @@ lib.pipe (stdenv.mkDerivation ({
   targetConfig = if targetPlatform != hostPlatform then targetPlatform.config else null;
 
   buildFlags =
-    let target =
-          lib.optionalString (profiledCompiler) "profiled" +
-          lib.optionalString (targetPlatform == hostPlatform && hostPlatform == buildPlatform && !disableBootstrap) "bootstrap";
+    let target = lib.optionalString (profiledCompiler) "profiled"
+      + lib.optionalString (targetPlatform == hostPlatform && hostPlatform == buildPlatform && !disableBootstrap) "bootstrap";
     in lib.optional (target != "") target;
 
   inherit (callFile ../common/strip-attributes.nix { })
@@ -312,4 +311,5 @@ lib.pipe (stdenv.mkDerivation ({
 // optionalAttrs (enableMultilib) { dontMoveLib64 = true; }
 ))
 [
+  (callPackage ../common/libgcc.nix   { inherit langC langCC langJit; })
 ]
diff --git a/pkgs/development/compilers/gcc/12/default.nix b/pkgs/development/compilers/gcc/12/default.nix
index b0c7b431031..5c622593c24 100644
--- a/pkgs/development/compilers/gcc/12/default.nix
+++ b/pkgs/development/compilers/gcc/12/default.nix
@@ -54,7 +54,7 @@ with builtins;
 
 let majorVersion = "12";
     version = "${majorVersion}.2.0";
-    disableBootstrap = !(with stdenv; targetPlatform == hostPlatform && hostPlatform == buildPlatform);
+    disableBootstrap = true;
 
     inherit (stdenv) buildPlatform hostPlatform targetPlatform;
 
@@ -346,5 +346,6 @@ lib.pipe (stdenv.mkDerivation ({
 // optionalAttrs (enableMultilib) { dontMoveLib64 = true; }
 ))
 [
+  (callPackage ../common/libgcc.nix   { inherit langC langCC langJit; })
 ]
 
diff --git a/pkgs/development/compilers/gcc/common/libgcc.nix b/pkgs/development/compilers/gcc/common/libgcc.nix
new file mode 100644
index 00000000000..e3523936019
--- /dev/null
+++ b/pkgs/development/compilers/gcc/common/libgcc.nix
@@ -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
+    '');
+}))
diff --git a/pkgs/development/libraries/glibc/default.nix b/pkgs/development/libraries/glibc/default.nix
index e1a427e35b6..8ad9c90ff7a 100644
--- a/pkgs/development/libraries/glibc/default.nix
+++ b/pkgs/development/libraries/glibc/default.nix
@@ -66,33 +66,26 @@ in
         ]);
     };
 
-    # When building glibc from bootstrap-tools, we need libgcc_s at RPATH for
-    # any program we run, because the gcc will have been placed at a new
-    # store path than that determined when built (as a source for the
-    # bootstrap-tools tarball)
-    # 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
-    # any special hack.
-    # TODO: remove this hack. Things that rely on this hack today:
-    # - dejagnu: during linux bootstrap tcl SIGSEGVs
-    # - clang-wrapper in cross-compilation
-    # Last attempt: https://github.com/NixOS/nixpkgs/pull/36948
-    preInstall = lib.optionalString (stdenv.hostPlatform == stdenv.buildPlatform) ''
-      if [ -f ${lib.getLib stdenv.cc.cc}/lib/libgcc_s.so.1 ]; then
-          mkdir -p $out/lib
-          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
-          cp -a ${lib.getLib stdenv.cc.cc}/lib/libgcc_s.so $out/lib/libgcc_s.so
-          # wipe out reference to previous libc it was built against
-          chmod +w $out/lib/libgcc_s.so.1
-          # 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
-    '';
+    # glibc needs to `dlopen()` `libgcc_s.so` but does not link
+    # against it.  Furthermore, glibc doesn't use the ordinary
+    # `dlopen()` call to do this; instead it uses one which ignores
+    # most paths:
+    #
+    #   https://sourceware.org/legacy-ml/libc-help/2013-11/msg00026.html
+    #
+    # In order to get it to not ignore `libgcc_s.so`, we have to add its path to
+    # `user-defined-trusted-dirs`:
+    #
+    #   https://sourceware.org/git/?p=glibc.git;a=blob;f=elf/Makefile;h=b509b3eada1fb77bf81e2a0ca5740b94ad185764#l1355
+    #
+    # Conveniently, this will also inform Nix of the fact that glibc depends on
+    # gcc.libgcc, since the path will be embedded in the resulting binary.
+    #
+    makeFlags =
+      (previousAttrs.makeFlags or [])
+      ++ lib.optionals (stdenv.cc.cc?libgcc) [
+        "user-defined-trusted-dirs=${stdenv.cc.cc.libgcc}/lib"
+      ];
 
     postInstall = (if stdenv.hostPlatform == stdenv.buildPlatform then ''
       echo SUPPORTED-LOCALES=C.UTF-8/UTF-8 > ../glibc-2*/localedata/SUPPORTED
@@ -164,6 +157,12 @@ in
 
     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"; };
 })