Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

glibcCross: use a libgcc built separately from gcc #247900

Merged
15 commits merged into from Aug 15, 2023
Merged
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 @@ -18911,6 +18911,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 @@ -21437,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 {
Expand Down