Skip to content

Commit

Permalink
Merge pull request #247900 from amjoseph-nixpkgs/pr/stdenv/libgcc-no-…
Browse files Browse the repository at this point in the history
…more-cycles

glibcCross: use a libgcc built separately from gcc
  • Loading branch information
Adam Joseph authored Aug 15, 2023
2 parents ea95c09 + 1912681 commit 0dfed0d
Show file tree
Hide file tree
Showing 9 changed files with 207 additions and 49 deletions.
6 changes: 6 additions & 0 deletions pkgs/development/compilers/gcc/common/builder.nix
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
37 changes: 37 additions & 0 deletions pkgs/development/compilers/gcc/common/libgcc-buildstuff.nix
Original file line number Diff line number Diff line change
@@ -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
''
14 changes: 7 additions & 7 deletions pkgs/development/compilers/gcc/common/libgcc.nix
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down
36 changes: 1 addition & 35 deletions pkgs/development/compilers/gcc/common/pre-configure.nix
Original file line number Diff line number Diff line change
Expand Up @@ -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 changes: 140 additions & 0 deletions pkgs/development/libraries/gcc/libgcc/default.nix
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
{ 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/"
'';
})
11 changes: 6 additions & 5 deletions pkgs/development/libraries/glibc/default.nix
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
, withGd ? false
, withLibcrypt? false
, buildPackages
, libgcc
}:

let
Expand All @@ -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:
Expand Down Expand Up @@ -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 ''
Expand Down Expand Up @@ -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"; };
Expand Down
4 changes: 3 additions & 1 deletion pkgs/test/cross/default.nix
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -127,13 +128,14 @@ 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
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
Expand Down
1 change: 0 additions & 1 deletion pkgs/top-level/aliases.nix
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
7 changes: 7 additions & 0 deletions pkgs/top-level/all-packages.nix
Original file line number Diff line number Diff line change
Expand Up @@ -18918,6 +18918,8 @@ with pkgs;

librarian-puppet-go = callPackage ../development/tools/librarian-puppet-go { };

libgcc = stdenv.cc.cc.libgcc or null;

# This is for e.g. LLVM libraries on linux.
gccForLibs =
if stdenv.targetPlatform == stdenv.hostPlatform && targetPackages.stdenv.cc.isGNU
Expand Down Expand Up @@ -21444,6 +21446,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 {
Expand Down

0 comments on commit 0dfed0d

Please sign in to comment.