fix(sysroot): compile against the sysroot's libc++ headers

clang's driver ranks the host toolchain's own libc++ headers
(<install>/../include/c++/v1) above --sysroot. BuildStdPcm has forced
the sysroot's copy for the std module for that reason, but ordinary
compiles did not. A unit that only does `import std;` never noticed. A
unit that includes a standard header textually got the host's libc++,
configured for the host's libc: cross-building Crafter.Graphics for
aarch64 musl, Crafter.Asset's vendored gdeflate died on <chrono> with
"unknown rune table for this platform". Against a glibc sysroot the
same unit would compile against the wrong libc++ release and say
nothing.

Every non-wasm, non-mingw compile with a sysroot now gets
`-nostdinc++ -isystem <sysroot>/usr/include/c++/v1`. wasm has its own
sysroot handling and mingw is a libstdc++ target.

-nostdinc++ leaves -stdlib=libc++ unused on each compile, which clang
reports once per unit, so the command also carries
-Wno-unused-command-line-argument. The cost is that the driver's
unused-argument diagnostics are silent on sysroot builds, including for
a user's own misplaced flag (a -l or -Wl, option in compileFlags).

Not addressed: external cmake dependencies are still configured
without the target or the sysroot, and objects already built in an
existing sysroot build directory are not invalidated by the new flags.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
Jorijn van der Graaf 2026-10-06 16:50:41 +02:00
commit 3c96d78a7d
Signed by: jorijnvdgraaf
GPG key ID: 2937E59CDCC1BCFB

View file

@ -296,6 +296,21 @@ CompileCommand Crafter::GetCompileCommand(const Configuration& config) {
if (!config.sysroot.empty()) {
out.command += std::format(" --sysroot={}", config.sysroot);
// Same reason as in BuildStdPcm: the driver ranks the host
// toolchain's own libc++ headers (<install>/../include/c++/v1) above
// --sysroot. A unit that only does `import std;` never notices, but
// one that includes a standard header textually (vendored C++ such as
// Crafter.Asset's gdeflate) would get host libc++ configured for the
// host libc, which fails on a musl sysroot with "unknown rune table
// for this platform". Force the sysroot's copy. -nostdinc++ leaves
// -stdlib=libc++ unused on every compile ("argument unused during
// compilation"), hence the silencer; the price is that it also hides
// that diagnostic for a user's own misplaced flag (a -l or -Wl,
// option in compileFlags) on sysroot builds. Not for mingw, which
// uses libstdc++ and has no libc++ in its sysroot.
if (!isWasm && config.target != "x86_64-w64-mingw32") {
out.command += std::format(" -nostdinc++ -isystem {}/usr/include/c++/v1 -Wno-unused-command-line-argument", config.sysroot);
}
}
if (isWasm) {
// -mllvm is consumed by codegen but not the link driver, which is the