2026-10-06 16:50:41 +02:00
|
|
|
// SPDX-License-Identifier: LGPL-3.0-only
|
|
|
|
|
// SPDX-FileCopyrightText: Copyright (C) 2026 Catcrafts®
|
|
|
|
|
|
|
|
|
|
import std;
|
|
|
|
|
import Crafter.Build;
|
|
|
|
|
namespace fs = std::filesystem;
|
|
|
|
|
using namespace Crafter;
|
|
|
|
|
|
|
|
|
|
// clang's driver ranks the host toolchain's own libc++ headers
|
|
|
|
|
// (<install>/../include/c++/v1) above --sysroot. A unit that only does
|
|
|
|
|
// `import std;` never notices, because the std module is precompiled with the
|
|
|
|
|
// sysroot's headers forced. A unit that includes a standard header textually
|
|
|
|
|
// (vendored C++ in a dependency, say) got the host's libc++ configured for the
|
|
|
|
|
// host's libc: against a musl sysroot every such unit died with "unknown rune
|
|
|
|
|
// table for this platform", and against a glibc sysroot it compiled against
|
|
|
|
|
// the wrong release without a word.
|
|
|
|
|
//
|
|
|
|
|
// GetCompileCommand therefore has to point every sysroot compile at the
|
|
|
|
|
// sysroot's copy. It must not do so where there is no sysroot, for wasm (which
|
|
|
|
|
// has its own sysroot handling) or for mingw (libstdc++, no libc++ at all).
|
|
|
|
|
// The command is checked as text: no compiler runs.
|
fix(mingw): view only a prefix that holds a Linux system
The first fix showed clang every mingw prefix through a view of its
mingw-w64 parts. That broke a prefix that holds mingw-w64 alone, where
Windows libraries installed with --prefix land in include/ and lib/:
with CRAFTER_MINGW_DIR=/opt/mingw, <SDL2/SDL.h> and -lSDL2 were no
longer found. Such a prefix is clang's sysroot whole again. Only a
prefix that also holds a Linux system gets the view
(Toolchain::mingwPrefixIsSystem): the host's /usr inside the Flatpak,
whatever its include/ holds, and a prefix whose include/ has a C
library's features.h, which every glibc and musl header includes and
mingw-w64 has no use for, as CRAFTER_MINGW_DIR=/usr has.
MakeMingwSysroot makes the view in the cache, or in
$XDG_RUNTIME_DIR/crafter.build when the cache's filesystem takes no
symbolic links (vfat, exFAT, CIFS without unix extensions): the XDG
spec promises them there, and nothing else in the cache needs them.
Its path is absolute, because CMake runs the compiler from directories
of its own and a relative cache did not resolve from there. The prefix
is resolved once, absolute and lexically normal, so /opt/mingw/ and
/opt/mingw are one prefix and not two builds.
clang names a header by the path it found it at, so every diagnostic
from a viewed mingw-w64 header named a hashed cache directory.
RunBuildCommand now writes paths into the view as paths into the
prefix, as BuildStdPcm did for its manifest messages already.
Also from the review of PR #44: SysrootCompileFlags builds a mingw
command, which can make a view, so it redirects the cache like the
other tests; the manifest filter's comment names what it still keeps
out; the C path asks MingwSysroot() once.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-31 22:58:30 +01:00
|
|
|
|
|
|
|
|
extern "C" int setenv(const char* name, const char* value, int overwrite);
|
|
|
|
|
|
2026-10-06 16:50:41 +02:00
|
|
|
namespace {
|
|
|
|
|
std::int32_t Failures = 0;
|
|
|
|
|
|
|
|
|
|
void Check(bool cond, std::string_view msg) {
|
|
|
|
|
if (!cond) {
|
|
|
|
|
std::println(std::cerr, "FAIL: {}", msg);
|
|
|
|
|
++Failures;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
std::string CommandFor(std::string_view target, std::string_view sysroot) {
|
|
|
|
|
Configuration cfg;
|
|
|
|
|
cfg.path = "/tmp/crafter-build-sysroot-compile-flags";
|
|
|
|
|
cfg.name = "flags";
|
|
|
|
|
cfg.outputName = "flags";
|
|
|
|
|
cfg.target = std::string(target);
|
|
|
|
|
cfg.march = "generic";
|
|
|
|
|
cfg.mtune = "generic";
|
|
|
|
|
cfg.type = ConfigurationType::Executable;
|
|
|
|
|
cfg.sysroot = std::string(sysroot);
|
|
|
|
|
return GetCompileCommand(cfg).command;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int main() {
|
fix(mingw): view only a prefix that holds a Linux system
The first fix showed clang every mingw prefix through a view of its
mingw-w64 parts. That broke a prefix that holds mingw-w64 alone, where
Windows libraries installed with --prefix land in include/ and lib/:
with CRAFTER_MINGW_DIR=/opt/mingw, <SDL2/SDL.h> and -lSDL2 were no
longer found. Such a prefix is clang's sysroot whole again. Only a
prefix that also holds a Linux system gets the view
(Toolchain::mingwPrefixIsSystem): the host's /usr inside the Flatpak,
whatever its include/ holds, and a prefix whose include/ has a C
library's features.h, which every glibc and musl header includes and
mingw-w64 has no use for, as CRAFTER_MINGW_DIR=/usr has.
MakeMingwSysroot makes the view in the cache, or in
$XDG_RUNTIME_DIR/crafter.build when the cache's filesystem takes no
symbolic links (vfat, exFAT, CIFS without unix extensions): the XDG
spec promises them there, and nothing else in the cache needs them.
Its path is absolute, because CMake runs the compiler from directories
of its own and a relative cache did not resolve from there. The prefix
is resolved once, absolute and lexically normal, so /opt/mingw/ and
/opt/mingw are one prefix and not two builds.
clang names a header by the path it found it at, so every diagnostic
from a viewed mingw-w64 header named a hashed cache directory.
RunBuildCommand now writes paths into the view as paths into the
prefix, as BuildStdPcm did for its manifest messages already.
Also from the review of PR #44: SysrootCompileFlags builds a mingw
command, which can make a view, so it redirects the cache like the
other tests; the manifest filter's comment names what it still keeps
out; the C path asks MingwSysroot() once.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-31 22:58:30 +01:00
|
|
|
// A compile command names the std module's directory in the cache, and
|
|
|
|
|
// the mingw one can make the view of a system mingw prefix there
|
|
|
|
|
// (MingwSysroot), as with CRAFTER_MINGW_DIR=/usr or inside the Flatpak
|
|
|
|
|
// on a host with mingw-w64. Set before anything resolves the toolchain.
|
|
|
|
|
const fs::path scratch = fs::temp_directory_path() / "crafter-build-sysroot-compile-flags-cache";
|
|
|
|
|
std::error_code ec;
|
|
|
|
|
fs::remove_all(scratch, ec);
|
|
|
|
|
setenv("XDG_CACHE_HOME", scratch.c_str(), 1);
|
|
|
|
|
|
2026-10-06 16:50:41 +02:00
|
|
|
const std::string sysroot = "/opt/crafter-build-test-sysroot";
|
|
|
|
|
const std::string forced = std::format("-nostdinc++ -isystem {}/usr/include/c++/v1", sysroot);
|
|
|
|
|
|
|
|
|
|
for (std::string_view target : {"aarch64-alpine-linux-musl", "aarch64-unknown-linux-gnu", "x86_64-pc-linux-gnu"}) {
|
|
|
|
|
const std::string command = CommandFor(target, sysroot);
|
|
|
|
|
Check(command.contains(std::format("--sysroot={}", sysroot)), std::format("{}: the sysroot is passed", target));
|
|
|
|
|
Check(command.contains(forced), std::format("{}: the sysroot's libc++ headers are forced", target));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Check(!CommandFor("x86_64-pc-linux-gnu", "").contains("/usr/include/c++/v1 -Wno-unused-command-line-argument"), "no sysroot: nothing is forced");
|
|
|
|
|
Check(!CommandFor("wasm32-wasip1", sysroot).contains(forced), "wasm: left to its own sysroot handling");
|
|
|
|
|
Check(!CommandFor("x86_64-w64-mingw32", sysroot).contains(forced), "mingw: libstdc++ target, libc++ headers are not forced");
|
|
|
|
|
|
fix(mingw): view only a prefix that holds a Linux system
The first fix showed clang every mingw prefix through a view of its
mingw-w64 parts. That broke a prefix that holds mingw-w64 alone, where
Windows libraries installed with --prefix land in include/ and lib/:
with CRAFTER_MINGW_DIR=/opt/mingw, <SDL2/SDL.h> and -lSDL2 were no
longer found. Such a prefix is clang's sysroot whole again. Only a
prefix that also holds a Linux system gets the view
(Toolchain::mingwPrefixIsSystem): the host's /usr inside the Flatpak,
whatever its include/ holds, and a prefix whose include/ has a C
library's features.h, which every glibc and musl header includes and
mingw-w64 has no use for, as CRAFTER_MINGW_DIR=/usr has.
MakeMingwSysroot makes the view in the cache, or in
$XDG_RUNTIME_DIR/crafter.build when the cache's filesystem takes no
symbolic links (vfat, exFAT, CIFS without unix extensions): the XDG
spec promises them there, and nothing else in the cache needs them.
Its path is absolute, because CMake runs the compiler from directories
of its own and a relative cache did not resolve from there. The prefix
is resolved once, absolute and lexically normal, so /opt/mingw/ and
/opt/mingw are one prefix and not two builds.
clang names a header by the path it found it at, so every diagnostic
from a viewed mingw-w64 header named a hashed cache directory.
RunBuildCommand now writes paths into the view as paths into the
prefix, as BuildStdPcm did for its manifest messages already.
Also from the review of PR #44: SysrootCompileFlags builds a mingw
command, which can make a view, so it redirects the cache like the
other tests; the manifest filter's comment names what it still keeps
out; the C path asks MingwSysroot() once.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-31 22:58:30 +01:00
|
|
|
fs::remove_all(scratch, ec);
|
2026-10-06 16:50:41 +02:00
|
|
|
if (Failures > 0) {
|
|
|
|
|
std::println(std::cerr, "{} assertions failed", Failures);
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
return 0;
|
|
|
|
|
}
|