Unverified Commit 0dfed0d7 authored by Adam Joseph's avatar Adam Joseph Committed by GitHub
Browse files

Merge pull request #247900 from amjoseph-nixpkgs/pr/stdenv/libgcc-no-more-cycles

glibcCross: use a libgcc built separately from gcc
parents ea95c091 19126813
Loading
Loading
Loading
Loading
+6 −0
Original line number Diff line number Diff line
@@ -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
+37 −0
Original line number Diff line number Diff line
{ 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
  ''
+1 −35
Original line number Diff line number Diff line
@@ -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; })
+140 −0
Original line number Diff line number Diff line
{ lib, stdenvNoLibs, buildPackages
, gcc, glibc
, libiberty
}:

let
  stdenv = stdenvNoLibs;
  gccConfigureFlags = gcc.cc.configureFlags ++ [
    "--disable-fixincludes"
    "--disable-intl"
    "--enable-threads=posix"
    "--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 stdenv.mkDerivation (finalAttrs: {
  pname = "libgcc";
  inherit (gcc.cc) src version;

  outputs = [ "out" "dev" ];

  strictDeps = true;
  depsBuildBuild = [ buildPackages.stdenv.cc ];
  nativeBuildInputs = [ libiberty ];
  buildInputs = [ glibc ];

  postUnpack = ''
    mkdir -p ./build
    buildRoot=$(readlink -e "./build")
  '';

  postPatch =
    gcc.cc.passthru.forceLibgccToBuildCrtStuff
    + ''
      sourceRoot=$(readlink -e "./libgcc")
    '';

  hardeningDisable = [ "pie" ];

  preConfigure =
  ''
    # Drop in libiberty, as external builds are not expected
    cd "$buildRoot"
    (
      mkdir -p build-${stdenv.buildPlatform.config}/libiberty/
      cd build-${stdenv.buildPlatform.config}/libiberty/
      ln -s ${buildPackages.libiberty}/lib/libiberty.a ./
    )
    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
      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=${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'

      "$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

      make \
        config.h \
        libgcc.mvars \
        tconfig.h \
        tm.h \
        options.h \
        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
    )
    mkdir -p "$buildRoot/gcc/include"

    # Preparing to configure + build libgcc itself
    mkdir -p "$buildRoot/gcc/${stdenv.hostPlatform.config}/libgcc"
    cd "$buildRoot/gcc/${stdenv.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=${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=${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" ];
  configureFlags = [
    "cross_compiling=true"
    "--disable-gcov"
    "--with-glibc-version=${glibc.version}"
  ];

  makeFlags = [ "MULTIBUILDTOP:=../" ];

  postInstall = ''
    moveToOutput "lib/gcc/${stdenv.hostPlatform.config}/${finalAttrs.version}/include" "$dev"
    mkdir -p "$out/lib" "$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/"
  '';
})
+6 −5
Original line number Diff line number Diff line
@@ -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"; };
Loading