mirror of
https://github.com/NixOS/nixpkgs.git
synced 2026-09-13 02:39:58 +00:00
- `gccNGPackages.libbacktrace`: Remove, in favor of the `libbacktrace` package in `pkgs/by-name` - `stdenvNoCxx`: New, a compiler with a libc but no C++ standard library - `libbacktrace`: Build with `stdenvNoCxx`, so `libstdc++` can link it without a cycle - `gccNGPackages.gcc`, `gccNGPackages.libgfortran`, `gccNGPackages.libstdcxx`: Take `libbacktrace` as a build input and pass `--with-system-libbacktrace` That option is not upstream; it comes from a patch posted to gcc-patches[^1], which we fetch from the archive rather than vendor. One posting covers every component that links libbacktrace, so each package filters it down to the files its own `src` carries, and leaves out the generated files because we regenerate those locally anyway. `gcc` and `libgfortran` were already using this `libbacktrace`, but by faking up the sibling directory an in-tree build would have had -- archive, libtool archive and headers -- for the relative paths to resolve against. Passing the flag lets that go. Note that this means our libstdc++ is getting `std::stacktrace` support for the first time; we were unwittingly excluding the vendored support. Nothing failed, which is why it went unnoticed: `--enable-libstdcxx-backtrace` defaults to `auto`, and `auto` means yes wherever the library is hosted, so the feature was asked for. But the probe that picks the object format runs `libbacktrace/filetype.awk`, which was not among the files we copied, so it got nothing back, warned "could not determine output file type", and quietly settled on `enable_libstdcxx_backtrace=no`. Note also that with this approach, a downstream `libbacktrace` *cannot* be built by the regular `stdenv` with `useGccNG = true`, because its symbols would conflict. We'll see whether that is acceptable or not. If it isn't, we can still avoid vendoring, but we will need to replicate the symbol renaming that GCC would have done externally. [^1]: https://inbox.sourceware.org/gcc-patches/20260814013206.3818461-1-git@JohnEricson.me/ Assisted-by: Claude Code (Claude Opus 5)
227 lines
7.1 KiB
Nix
227 lines
7.1 KiB
Nix
{
|
|
lib,
|
|
stdenv,
|
|
gcc_meta,
|
|
release_version,
|
|
version,
|
|
getVersionFile,
|
|
monorepoSrc ? null,
|
|
fetchpatch,
|
|
autoreconfHook269,
|
|
runCommand,
|
|
gettext,
|
|
libgcc,
|
|
libbacktrace,
|
|
}:
|
|
stdenv.mkDerivation (finalAttrs: {
|
|
pname = "libstdcxx";
|
|
inherit version;
|
|
|
|
src = runCommand "libstdcxx-src-${version}" { src = monorepoSrc; } (
|
|
''
|
|
runPhase unpackPhase
|
|
|
|
mkdir -p "$out/gcc"
|
|
cp gcc/BASE-VER "$out/gcc"
|
|
cp gcc/DATESTAMP "$out/gcc"
|
|
|
|
mkdir -p "$out/libgcc"
|
|
cp libgcc/gthr*.h "$out/libgcc"
|
|
cp libgcc/unwind-pe.h "$out/libgcc"
|
|
|
|
cp -r libstdc++-v3 "$out"
|
|
|
|
cp -r libiberty "$out"
|
|
cp -r include "$out"
|
|
cp -r contrib "$out"
|
|
|
|
cp -r config "$out"
|
|
cp -r multilib.am "$out"
|
|
|
|
cp config.guess "$out"
|
|
cp config.rpath "$out"
|
|
cp config.sub "$out"
|
|
cp config-ml.in "$out"
|
|
cp ltmain.sh "$out"
|
|
cp install-sh "$out"
|
|
cp mkinstalldirs "$out"
|
|
|
|
''
|
|
# `src/Makefile` runs this to compute `LTLDFLAGS`, reaching out of the
|
|
# subdirectory for it as `$(top_srcdir)/../libtool-ldflags`. Missing, the
|
|
# shell says "No such file or directory" and `LTLDFLAGS` silently comes out
|
|
# empty, dropping our `LDFLAGS` from every library link.
|
|
+ ''
|
|
cp libtool-ldflags "$out"
|
|
|
|
''
|
|
# `MD5SUMS` exists only in release tarballs, not in a VCS checkout.
|
|
+ ''
|
|
if [[ -f MD5SUMS ]]; then cp MD5SUMS "$out"; fi
|
|
''
|
|
);
|
|
|
|
outputs = [
|
|
"out"
|
|
"dev"
|
|
];
|
|
|
|
patches = [
|
|
(fetchpatch {
|
|
name = "custom-threading-model.patch";
|
|
url = "https://github.com/gcc-mirror/gcc/commit/e5d853bbe9b05d6a00d98ad236f01937303e40c4.diff";
|
|
hash = "sha256-f0XAim3uzHnUx5lm/xO00IqBHu4YUEHF2WY+c0yCF6Y=";
|
|
includes = [
|
|
"config/*"
|
|
"libstdc++-v3/acinclude.m4"
|
|
];
|
|
})
|
|
(getVersionFile "libstdcxx/force-regular-dirs.patch")
|
|
|
|
# From the posting to gcc-patches, which covers every component that links
|
|
# libbacktrace. Take only this component's non-generated files: the
|
|
# generated ones are rebuilt by `autoreconfHook269` below, against a GCC
|
|
# slightly different from the one the patch was made against.
|
|
(fetchpatch {
|
|
name = "system-libbacktrace.patch";
|
|
url = "https://inbox.sourceware.org/gcc-patches/20260814013206.3818461-1-git@JohnEricson.me/raw";
|
|
includes = [
|
|
"config/libbacktrace.m4"
|
|
"libstdc++-v3/acinclude.m4"
|
|
"libstdc++-v3/src/Makefile.am"
|
|
"libstdc++-v3/src/c++23/Makefile.am"
|
|
"libstdc++-v3/src/c++23/stacktrace.cc"
|
|
"libstdc++-v3/src/experimental/Makefile.am"
|
|
];
|
|
hash = "sha256-qcs5N+KgBs2FScqGUZRYbAKkI2oDnm+G/ZN9RCAgZpw=";
|
|
})
|
|
];
|
|
|
|
postUnpack = ''
|
|
mkdir -p ./build
|
|
buildRoot=$(readlink -e "./build")
|
|
'';
|
|
|
|
preAutoreconf = ''
|
|
sourceRoot=$(readlink -e "./libstdc++-v3")
|
|
cd $sourceRoot
|
|
'';
|
|
|
|
enableParallelBuilding = true;
|
|
|
|
buildInputs = [ libbacktrace ];
|
|
|
|
nativeBuildInputs = [
|
|
autoreconfHook269
|
|
gettext
|
|
];
|
|
|
|
preConfigure = ''
|
|
cd "$buildRoot"
|
|
configureScript=$sourceRoot/configure
|
|
chmod +x "$configureScript"
|
|
|
|
''
|
|
# Build libstdc++ with the *C* driver, not `g++`. `g++` implies `-lstdc++`,
|
|
# which cannot be satisfied while building the very library that provides
|
|
# it, and the link fails with `cannot find -lstdc++`.
|
|
#
|
|
# This is not our invention; it is what a monolithic build does, and
|
|
# `libstdc++-v3/src/Makefile.am` says so where it defines `CXXLINK`:
|
|
#
|
|
# We cannot allow g++ to be used since this would add -lstdc++ to the
|
|
# link line which of course is problematic at this point. So, we get
|
|
# the top-level directory to configure libstdc++-v3 to use gcc as the
|
|
# C++ compilation driver.
|
|
#
|
|
# The top level does that through `RAW_CXX_FOR_TARGET`, which is `xgcc`
|
|
# -- not `xg++` -- plus `-shared-libgcc` and `-nostdinc++`. Building
|
|
# standalone there is no top level to arrange it, so arrange it here. The
|
|
# C driver still compiles `.cc` as C++ by extension; what it drops is the
|
|
# implicit `-lstdc++`. `-shared-libgcc` puts back the linkage `g++` would
|
|
# have chosen, which the C driver does not default to, and `-nostdinc++`
|
|
# keeps any already-installed C++ headers out of a build whose whole
|
|
# purpose is to produce them.
|
|
+ ''
|
|
cxxForLibstdcxx="$CC -shared-libgcc -nostdinc++"
|
|
|
|
''
|
|
# Put libgcc's `gthr-default.h` where libstdc++ expects to find it.
|
|
#
|
|
# It is not a source file. In a monolithic build libgcc's Makefile creates
|
|
# it by copying whichever `gthr-<model>.h` matches the target's thread
|
|
# model, and libstdc++ -- configured inside that same build tree -- picks
|
|
# it up. Standalone there is no such tree, so take the one `libgcc`
|
|
# installed. The two implement a single threading model between them, and
|
|
# copying libgcc's own answer is what makes them agree by construction
|
|
# rather than by two independent guesses that can drift apart. `libgcc`
|
|
# decided it from the libc; `gcc_cv_target_thread_file` below repeats the
|
|
# same value.
|
|
#
|
|
# The consequence of getting this wrong is worth spelling out, because the
|
|
# installed headers do not show it. `GLIBCXX_CHECK_GTHREADS` compiles
|
|
# `#include "gthr.h"` and requires `__GTHREADS_CXX0X`, which
|
|
# `gthr-posix.h` defines unconditionally. With no posix `gthr-default.h`
|
|
# on the include path that test fails, configure concludes there are no
|
|
# gthreads, and `_GLIBCXX_HAS_GTHREADS` is left undefined in
|
|
# `c++config.h` -- so `<mutex>` compiles away and `std::mutex` does not
|
|
# exist. Stating the intent with `--enable-threads=posix` does not help:
|
|
# the probe overrides intent with an empirical answer, so the header has
|
|
# to actually be there.
|
|
+ ''
|
|
cp ${lib.getDev libgcc}/include/gthr-default.h "$sourceRoot/../libgcc/gthr-default.h"
|
|
|
|
export CXX="$cxxForLibstdcxx"
|
|
echo "libstdcxx: building with CXX=$CXX"
|
|
'';
|
|
|
|
configurePlatforms = [
|
|
"build"
|
|
"host"
|
|
];
|
|
|
|
configureFlags = [
|
|
"--disable-dependency-tracking"
|
|
# The same answer `libgcc` used, and the model of the `gthr-default.h`
|
|
# copied in above. A mismatch here is silent: the unwinder's locks vanish
|
|
# while `libstdc++` still hands out `std::thread`.
|
|
"gcc_cv_target_thread_file=${libgcc.threadModel}"
|
|
"cross_compiling=true"
|
|
"--disable-multilib"
|
|
|
|
"--with-system-libbacktrace"
|
|
|
|
# `gnu` is the glibc locale model: `config/locale/gnu/ctype_members.cc`
|
|
# reads `__ctype_b`, which only glibc has. Forcing it everywhere breaks any
|
|
# other libc -- on musl the build fails converting `const unsigned short *`
|
|
# to `const ctype_base::mask *`. Configure picks the right model from the
|
|
# host triple on its own, as it does for the monolithic build, which passes
|
|
# no `--enable-clocale` at all.
|
|
|
|
"--disable-libstdcxx-pch"
|
|
"--disable-vtable-verify"
|
|
"--enable-libstdcxx-visibility"
|
|
"--with-default-libstdcxx-abi=new"
|
|
];
|
|
|
|
hardeningDisable = [
|
|
# PATH_MAX
|
|
"fortify"
|
|
];
|
|
|
|
postInstall = ''
|
|
moveToOutput lib/libstdc++.modules.json "$dev"
|
|
'';
|
|
|
|
doCheck = true;
|
|
|
|
passthru = {
|
|
isGNU = true;
|
|
};
|
|
|
|
meta = gcc_meta // {
|
|
homepage = "https://gcc.gnu.org/onlinedocs/libstdc++";
|
|
description = "GNU C++ Library";
|
|
};
|
|
})
|