Two halves of how the compiler finds libstdc++.
The library was not on the link path. `wrapCCWith` was given
`libcxx = libstdcxx`, which tells cc-wrapper where the C++ headers live
but does not put the library where a GNU compiler looks, so every C++
link failed with `cannot find -lstdc++`. Add `-B${libstdcxx}/lib`, as
libgcc, libssp, libatomic and libgomp already are.
The headers had the opposite problem: found too eagerly, by the wrong
language. libstdc++ deliberately ships headers named after C headers --
`math.h`, `stdlib.h`, `complex.h`, `stdckdint.h`, `stdbit.h`,
`stdatomic.h`, `tgmath.h`, `fenv.h` -- whose purpose is to shadow the C
ones when compiling C++. Installed into `$dev/include` they shadowed
unconditionally, since `libcxx` is a propagated target-target dep of
cc-wrapper and the setup hook puts that directory on the **C** include
path of everything built with the compiler. Under C, libstdc++'s
`<stdckdint.h>` is an empty shell, so its functions vanish:
bash: braces.c: implicit declaration of function 'ckd_sub'
coreutils: randperm.c: implicit declaration of function 'stdc_bit_width'
Both build fine with monolithic GCC, whose libstdc++ headers live in
`include/c++/$ver` and are added by the g++ driver alone. Install them
into a sibling `include-cxx`, which keeps them off C's include path while
staying findable for C++; no version or target subdirectory is needed,
since the store path already separates one libstdc++ from another.
Assisted-by: Claude Code (Claude Opus 5)
Operations like `nix eval --file '<nixpkgs>' hello.name` are supposed
to be lazy in the sense that they shouldn't cause any derivations to
be instantiated. However, this was not the case anymore, e.g.
$ time nix eval --file '<nixpkgs>' hello.name -vvvvvvv 2>&1 | grep -c 'copying.*to the store\|^instantiated'
1145
real 0m0.359s
In fact, even evaluating `lib.version` triggers 1145 paths to be
copied to the store. (Why `lib` causes a bunch of derivations to be
evaluated is another issue...)
The reason for this is that cc-wrapper has assertions like
assert libc_bin == bintools.libc_bin
which which Nix implements by comparing their outPaths. Computing an
outPath calls derivationStrict, causing the .drv closure of the
bootstrap libc to be written to the store. Since these asserts ran
whenever a cc-wrapper derivation was forced to WHNF (which the stdenv
bootstrap stage assertions do on every evaluation of the Nixpkgs top
level), merely evaluating e.g. 'hello.name' wrote over a thousand .drv
files.
Now the asserts are (arbitrarily) moved under `unpackPhase`, which is
only forced when the derivation is actually instantiated, so
evaluating metadata attributes stays free of store writes:
$ time nix eval --file '<nixpkgs>' hello.name -vvvvvvv 2>&1 | grep -c 'copying.*to the store\|^instantiated'
0
real 0m0.113s
Assisted-by: Claude Fable 5 <noreply@anthropic.com>
TLSDESC is a more performant way of doing TLS, since it has a custom
calling convention that does not require the caller (of what's usually
__tls_get_addr) to spill clobbered registers and assumes that the callee
preserves all registers.
This adds corresponding plumbing in the machineFlags in the cc-wrapper
that includes version gates for compilers. TLSDESC needs to be supported
by the bintools and libc, so I've only enabled it for architectures that
our packaged glibc, musl, GNU binutils support (x86, x86_64).
We package a lot of LLVM versions and support for -mtls-dialect in the
Clang driver has only landed in LLVM 19, so a version check is added
there too.
Ideally we'd set the default at GCC build-time, but LLVM lacks such an
option, so we'd have to keep it in the compiler wrapper for now.
Gentoo is already building with it by default [1], as is Fedora [2].
In glibc < 2.40 [3] there existed a bug with not all registers being
preserved, but it has since been resolved. x86 support has existed
since basically forever with LLVM adding support in LLVM >= 19.1.
LoongArch support has been added recently too, but it's only available
since musl 1.2.6 while we are stuck at 1.2.5 for now, so I haven't dug
deeper. Aarch64 uses TLSDESC by default already.
The support status on non-Linux is a bit unclear, so these defaults are
scoped only to linux targets.
Sadly RISC-V support is still cooking apparently [4].
See: https://maskray.me/blog/2021-02-14-all-about-thread-local-storage
See: https://groups.google.com/g/x86-64-abi/c/0tjmaQx6nZ0
[1]: 46191b478e
[2]: 8f8d2ea9c3
[3]: https://sourceware.org/bugzilla/show_bug.cgi?id=31372
[4]: https://github.com/riscv-non-isa/riscv-elf-psabi-doc/issues/494
Inline optionalAttrs for Go passthru attrs and fallback_sdk.
Replace mapAttrs+optionalString for Darwin env vars with direct
optionalString calls, eliminating intermediate attrset and // merge.
Build on the initial LLVM Flang wrapper work by exposing the needed clang passthru and teaching cc-wrapper about flang-specific flag handling.
Co-authored-by: stove <stove@rivosinc.com>
Co-authored-by: acture <acture@gmail.com>
Co-authored-by: Emily <hello@emily.moe>
Co-authored-by: Philip Taron <philip.taron@gmail.com>
go1: warning: command-line option '-Wformat=1' is valid for C/C++/ObjC/ObjC++ but not for Go
go1: warning: command-line option '-Wformat-security' is valid for C/C++/ObjC/ObjC++ but not for Go
go1: warning: '-Werror=' argument '-Werror=format-security' is not valid for Go
GDC 11 was the last version that could bootstrap without a D compiler,
and GDC don’t offer their own binaries any more. GCC 11 is now
end‐of‐life and being removed (as is GCC 12, even).
It’s possible that we could use another distribution’s binary
packages to bootstrap this, or go via our DMD package (it’s
apparently not possible to bootstrap GDC with LDC, but I’m not sure
about DMD), but as nobody has worked on it in the three years since
GCC 12 came out, it seems like interest is limited, and it’s more
of a yak shave than I’m up for right now.
A full from‐source bootstrap chain would of course be nice, but is
more the realm of the minimal bootstrap work than something we’d
want to keep GCC 11 around in the main package set indefinitely for.
Without the change both `s390` and `s390x` `glibc` builds fail as
https://hydra.nixos.org/build/303208799:
In file included from ../sysdeps/s390/utf16-utf32-z9.c:501,
from ../sysdeps/s390/multiarch/utf16-utf32-z9.c:20:
../iconv/loop.c: In function '__from_utf16_loop_vx_cu':
../iconv/loop.c:274:1: error: %r11 cannot be used in 'asm' here
274 | }
| ^
Disable the `-fno-omit-frame-pointer` for now.
Because we're building things separately, we don't need the fancy
lib/... namespacing tricks that GCC normally does to squeeze itself in
the FHS. We can just use the normal autotools libdir and include dir,
and the nixpkgs infra will sort everything out.
Where possible I submitted patches to the mailing list, and fetched
those. The ones I am vendoring are the residuals which I don't think are
ready for upstreaming yet. (I can imagine a further reworking upstream
such that we wouldn't need our own patches of that sort, but it would be
good to get the first crop merged first before discussing that.)
Clang cannot handle the gnuabielfv{1,2} ABI specification in the triplet properly. It used to parse it as just "gnu", disregarding the ABI version in it and defaulting to ELFv1. Now, it completely fails to parse such target triplet:
> clang: error: version 'abielfv1' in target triple 'powerpc64-unknown-linux-gnuabielfv1' is invalid
So when it comes time to passing the target triplet to Clang, handle this support deficiency:
1. If the triplet ends in gnuabielfv*, shorten it to just gnu. This makes it get parsed properly.
2. After the above, re-add the ABI via the separate -mabi option. This makes it use the correct ABI for the platform.
Allow easy system-level profiling with e.g. Linux perf or bpf(trace).
Profiling applications in NixOS is quite expensive due to the size of
closures of basic but widely-used libraries. Full-system profiling is
even harder as it effectively requires re-compiling the world with ~0
caching.
By enabling it by default, we make this trivially possible (except for
the packages that explicitly specify -fomit-frame-pointers, of course)
Make an exception for 32bit x86 since it only has 8 general purpose
registers.
Frame pointers are enabled by default in Fedora, Ubuntu, and Arch Linux.
During the Apple SDK revamp of #346043, cc-wrapper and bintools-wrapper
were modified to automatically add a fallback SDK if $DEVELOPER_DIR is
not set [^1]. However, because of the order of the && operands,
apple-sdk is always evaluated even when it's not needed.
Flip the && operands so we only trigger the evaluation when targeting
Darwin.
[^1]: 51755b0c00