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

WIP: GCC with separated runtime libraries #132343

Draft
wants to merge 19 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
111 changes: 91 additions & 20 deletions pkgs/development/compilers/gcc-ng/11/default.nix
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
{ lowPrio, newScope, pkgs, lib, stdenv, cmake
, fetchurl
, wrapCCWith
, overrideCC
{ lowPrio, newScope, pkgs, lib, stdenv
, fetchzip, wrapCCWith, overrideCC
, preLibcCrossHeaders
, buildGccTools # tools, but from the previous stage, for cross
, targetGccLibraries # libraries, but from the next stage, for cross
Expand All @@ -14,14 +12,25 @@
}:

let
version = "11.1.0";
version = "11.2.0";

src = fetchurl {
# fetchzip to unpack makes debug cycle much better
gcc_src = fetchzip {
url = "mirror://gcc/releases/gcc-${version}/gcc-${version}.tar.xz";
sha256 = "1pwxrjhsymv90xzh0x42cxfnmhjinf2lnrrf3hj5jq1rm2w6yjjc";
sha256 = "0aj1l0wkdbd5l2h5qybw0i5nwqbhqx89klnp7m5mwr63gmjfxwmi";
};

gcc_meta = {
description = "GNU Compiler Collection";
longDescription = ''
The GNU Compiler Collection includes compiler front ends for C, C++,
Objective-C, Fortran, OpenMP for C/C++/Fortran, and Ada, as well as
libraries for these languages (libstdc++, libgomp,...).

GCC development is a part of the GNU Project, aiming to improve the
compiler used in the GNU system including the GNU/Linux variant.
'';
homepage = "https://gcc.gnu.org/";
maintainers = with lib.maintainers; [ ericson231 sternenseemann ];
};
gcc_libs_meta = gcc_meta // {
Expand All @@ -34,58 +43,120 @@ let
};

tools = lib.makeExtensible (tools: let
callPackage = newScope (tools // {
inherit stdenv version src buildGccTools gcc_tools_meta;
});
callPackage = newScope (tools // { inherit version gcc_tools_meta gcc_src buildGccTools; });

mkExtraBuildCommands0 = _: "";

mkExtraBuildCommands = _: "";

in {

gcc-unwrapped = callPackage ./gcc { };

# TODO: support libcxx? is there even an usecase for that?
gcc = tools.libstdcxxGcc;
gcc = if stdenv.cc.isClang then tools.libcxxGcc else tools.libstdcxxGcc;

libcxxGcc = wrapCCWith rec {
cc = tools.gcc-unwrapped;
extraPackages = [
targetGccLibraries.libgcc
];
extraBuildCommands = mkExtraBuildCommands cc;
};

libstdcxxGcc = wrapCCWith rec {
cc = tools.gcc-unwrapped;
libcxx = targetGccLibraries.libstdcxx;
extraPackages = [
targetGccLibraries.libgcc
];
extraBuildCommands = mkExtraBuildCommands cc;
};

# Below, is the GCC Next Gen bootstrapping logic. It handles building a
# fully GCC toolchain from scratch via Nix. No LLVM toolchain should be
# pulled in. We should deduplicate this bootstrapping with its LLVM
# equivalence one GCC "old gen" is gone.

gccUseGccNg = wrapCCWith rec {
cc = tools.gcc-unwrapped;
libcxx = targetGccLibraries.libstdcxx;
extraPackages = [
targetGccLibraries.libgcc
] ++ lib.optionals (!stdenv.targetPlatform.isWasm) [
targetGccLibraries.libunwind
];
extraBuildCommands = ''
echo "-rtlib=libgcc -Wno-unused-command-line-argument" >> $out/nix-support/cc-cflags
echo "-B${targetGccLibraries.libgcc}/lib" >> $out/nix-support/cc-cflags
'' + lib.optionalString (!stdenv.targetPlatform.isWasm) ''
echo "--unwindlib=libunwind" >> $out/nix-support/cc-cflags
'' + lib.optionalString (!stdenv.targetPlatform.isWasm && stdenv.targetPlatform.useLLVM or false) ''
echo "-lunwind" >> $out/nix-support/cc-ldflags
'' + lib.optionalString stdenv.targetPlatform.isWasm ''
echo "-fno-exceptions" >> $out/nix-support/cc-cflags
'' + mkExtraBuildCommands cc;
};

gccNoLibstdcxx = wrapCCWith rec {
cc = tools.gcc-unwrapped;
libcxx = null;
bintools = bintools;
extraPackages = [
targetGccLibraries.libgcc
];
extraBuildCommands = ''
echo "-rtlib=libgcc" >> $out/nix-support/cc-cflags
echo "-B${targetGccLibraries.libgcc}/lib" >> $out/nix-support/cc-cflags
echo "-nostdlib++" >> $out/nix-support/cc-cflags
'' + mkExtraBuildCommands cc;
};

gccNoLibc = wrapCCWith rec {
cc = tools.gcc-unwrapped;
libcxx = null;
bintools = bintoolsNoLibc;
extraPackages = [
targetGccLibraries.libgcc
];
extraBuildCommands = ''
echo "-rtlib=libgcc" >> $out/nix-support/cc-cflags
echo "-B${targetGccLibraries.libgcc}/lib" >> $out/nix-support/cc-cflags
'' + mkExtraBuildCommands cc;
};

# TODO: gccNoLibgcc, gccNoLibgccWithLibc (if possible?)
gccNoLibgcc = wrapCCWith rec {
cc = tools.gcc-unwrapped;
libcxx = null;
bintools = bintoolsNoLibc;
extraPackages = [ ];
extraBuildCommands = ''
echo "-nostartfiles" >> $out/nix-support/cc-cflags
'' + mkExtraBuildCommands0 cc;
};

});

libraries = lib.makeExtensible (libraries: let
callPackage = newScope (libraries // buildGccTools // {
inherit stdenv version src gcc_libs_meta;
});
callPackage = newScope (libraries // buildGccTools // { inherit version gcc_libs_meta gcc_src; });
in {

libgcc = callPackage ./libgcc {
stdenv = overrideCC stdenv buildGccTools.gccNoLibgcc;
};

stdenv = overrideCC stdenv buildGccTools.gcc;

libstdcxxStdenv = overrideCC stdenv buildGccTools.libstdcxxGcc;

libgcc = callPackage ./libgcc { };

libada = callPackage ./libada { };

libgfortran = callPackage ./libgfortran { };

libstdcxx = callPackage ./libstdc++ { };
libstdcxx = callPackage ./libstdcxx {
stdenv = overrideCC stdenv buildGccTools.gccNoLibstdcxx;
};

# TODO add (gnu) libunwind here? can already be built separately aiui

});

in { inherit tools libraries; } // libraries // tools
207 changes: 207 additions & 0 deletions pkgs/development/compilers/gcc-ng/11/gcc/default.nix
Original file line number Diff line number Diff line change
@@ -0,0 +1,207 @@
{ lib, stdenv, targetPackages, fetchurl, fetchpatch
, gcc_tools_meta, gcc_src, version

, langAda ? false
, langC ? true
, langCC ? true
, langD ? false
, langFortran ? false
, langGo ? false
, langJava ? false
, langObjC ? stdenv.targetPlatform.isDarwin
, langObjCpp ? stdenv.targetPlatform.isDarwin

, reproducibleBuild ? true
, profiledCompiler ? false
, langJit ? false
, texinfo ? null
, perl ? null # lib.optional, for texi2pod (then pod2man)
, gmp, mpfr, libmpc, gettext, which, patchelf
, libelf # lib.optional, for link-time optimizations (LTO)
, isl ? null
, zlib ? null
, name ? "gcc"
, gnused ? null
, nonRelease ? false, flex ? null, bison ? null # Convenience for working on GCC
SuperSandro2000 marked this conversation as resolved.
Show resolved Hide resolved
, buildPackages
}:

# LTO needs libelf and zlib.
assert libelf != null -> zlib != null;

# Make sure we get GNU sed.
assert stdenv.hostPlatform.isDarwin -> gnused != null;

# The go frontend is written in c++
assert langGo -> langCC;

# The source tree has less pregenerated code
assert nonRelease -> flex != null && bison != null;

# profiledCompiler builds inject non-determinism in one of the compilation stages.
# If turned on, we can't provide reproducible builds anymore
assert reproducibleBuild -> profiledCompiler == false;

let
inherit (stdenv) buildPlatform hostPlatform targetPlatform;

targetPrefix = lib.optionalString (targetPlatform != hostPlatform) "${targetPlatform.config}-";
in

stdenv.mkDerivation ({
pname = targetPrefix + name;
inherit version;

src = gcc_src;

patches = [
../../../gcc/no-sys-dirs.patch
./find-prefixed-progs.patch
] ++ lib.optional langFortran ../../gcc/gfortran-driving.patch
++ lib.optional (stdenv.isDarwin && stdenv.isAarch64) (fetchpatch {
url = "https://github.com/fxcoudert/gcc/compare/releases/gcc-11.1.0...gcc-11.1.0-arm-20210504.diff";
sha256 = "sha256-JqCGJAfbOxSmkNyq49aFHteK/RFsCSLQrL9mzUCnaD0=";
})

# Obtain latest patch with ../../gcc/update-mcfgthread-patches.sh
++ lib.optional targetPlatform.isMinGW ../../gcc/11/Added-mcf-thread-model-support-from-mcfgthread.patch;

# TODO someday avoid target-specific subdirs all over the place and split libs from binaries
outputs = [ "out" "dev" "man" "info" ];

strictDeps = true;

depsBuildBuild = [ buildPackages.stdenv.cc ];
nativeBuildInputs = [ texinfo which gettext ]
++ lib.optional (perl != null) perl
++ lib.optionals nonRelease [ flex bison ]
;

buildInputs = [
gmp mpfr libmpc libelf
#libiberty # TODO use prebuilt
] ++ lib.optional (isl != null) isl
++ lib.optional (zlib != null) zlib
# The builder relies on GNU sed (for instance, Darwin's `sed' fails with
# "-i may not be used with stdin"), and `stdenvNative' doesn't provide it.
++ lib.optional hostPlatform.isDarwin gnused
;

enableParallelBuilding = true;

hardeningDisable = [
"format" # Some macro-indirect formatting in e.g. libcpp
];

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

postPatch = ''
configureScripts=$(find . -name configure)
for configureScript in $configureScripts; do
patchShebangs $configureScript
done
''
# This should kill all the stdinc frameworks that gcc and friends like to
# insert into default search paths.
+ lib.optionalString hostPlatform.isDarwin ''
substituteInPlace gcc/config/darwin-c.c \
--replace 'if (stdinc)' 'if (0)'
'';

preConfigure =
# Don't built target libraries, because we want to build separately
''
substituteInPlace configure \
--replace 'noconfigdirs=""' 'noconfigdirs="$noconfigdirs $target_libraries"'
''
# HACK: if host and target config are the same, but the platforms are
# actually different we need to convince the configure script that it
# is in fact building a cross compiler although it doesn't believe it.
+ lib.optionalString (targetPlatform.config == hostPlatform.config && targetPlatform != hostPlatform) ''
substituteInPlace configure --replace is_cross_compiler=no is_cross_compiler=yes
''
# Cannot configure from src dir
+ ''
cd $buildRoot
configureScript=../$sourceRoot/configure
'';

# Don't store the configure flags in the resulting executables.
postConfigure = ''
sed -e '/TOPLEVEL_CONFIGURE_ARGUMENTS=/d' -i Makefile
'';

# These flags confusingly control the runtime with GCC.
dontDisableStatic = true;

configurePlatforms = [ "build" "host" "target" ];

configureFlags = [
# Force target prefix. The behavior if `--target` and `--host` are
# specified is inconsistent: Sometimes specifying `--target` always causes
# a prefix to be generated, sometimes it's only added if the `--host` and
# `--target` differ. This means that sometimes there may be a prefix even
# though nixpkgs doesn't expect one and sometimes there may be none even
# though nixpkgs expects one (since not all information is serialized into
# the config attribute). The easiest way out of these problems is to always
# set the program prefix, so gcc will conform to our expectations.
"--program-prefix=${targetPrefix}"

"--disable-dependency-tracking"
"--enable-fast-install"
"--disable-serial-configure"
"--disable-bootstrap"
"--disable-decimal-float"
"--disable-install-libiberty"
"--disable-multilib"
"--disable-nls"
"--disable-shared"
"--enable-plugin"
"--enable-plugins"
"--enable-languages=${
lib.concatStrings (lib.intersperse ","
( lib.optional langC "c"
++ lib.optional langCC "c++"
++ lib.optional langD "d"
++ lib.optional langFortran "fortran"
++ lib.optional langJava "java"
++ lib.optional langAda "ada"
++ lib.optional langGo "go"
++ lib.optional langObjC "objc"
++ lib.optional langObjCpp "obj-c++"
++ lib.optional langJit "jit"
)
)
}"
(lib.withFeature (isl != null) "isl")
"--without-headers"
"--with-gnu-as"
"--with-gnu-ld"
"--with-system-zlib"
"--without-included-gettext"
"--enable-linker-build-id"
"--with-multilib-list="
];

postInstall = ''
moveToOutput "lib/gcc/${targetPlatform.config}/${version}/plugin/include" "$dev"
'';

passthru = {
inherit langC langCC langObjC langObjCpp langAda langFortran langGo version;
isGNU = true;
};

meta = gcc_tools_meta // {
description = gcc_tools_meta.description + " - compiler proper";
};
}

# // lib.optionalAttrs (targetPlatform != hostPlatform && targetPlatform.libc == "msvcrt" && crossStageStatic) {
# makeFlags = [ "all-gcc" "all-target-libgcc" ];
# installTargets = "install-gcc install-target-libgcc";
# }
)
Loading