diff --git a/AGENTS.template.md b/AGENTS.template.md index b60a81a..cb23933 100644 --- a/AGENTS.template.md +++ b/AGENTS.template.md @@ -22,7 +22,7 @@ crafter-build is a C++26 modules build system. A project is described by a `proj Partitions and what they own: -- `:Toolchain` resolves the compiler once per process (`GetToolchain`): clang++, clang, llvm-ar, libclang, libc++'s std module source and the default sysroots, from `CRAFTER_BUILD_LLVM_DIR`, else a toolchain installed beside crafter-build, else PATH. It also holds the version baked in at build time. `SysrootStdModule` picks the std module source for a sysroot build by the sysroot's libc++ release. `MingwSysroot` makes the mingw target's `--sysroot`, a view in the cache of the mingw-w64 prefix's own directories: the prefix itself is never a sysroot, since clang would search its `include/` and `lib/`, and for `/usr` those are the Linux system's (issue #43). +- `:Toolchain` resolves the compiler once per process (`GetToolchain`): clang++, clang, llvm-ar, libclang, libc++'s std module source and the default sysroots, from `CRAFTER_BUILD_LLVM_DIR`, else a toolchain installed beside crafter-build, else PATH. It also holds the version baked in at build time. `SysrootStdModule` picks the std module source for a sysroot build by the sysroot's libc++ release. - `:Clang` holds `Configuration`, `Build()`, `VariantId()`, `ApplyStandardArgs`, `HostTarget`, the CLI entry point `Crafter::Run`, and the lint, test and script data types. - `:Platform` runs commands, implements `LoadProject` (compile and load `project.cpp`), the host PCM cache, `#pragma crafter dependency`, and all OS-specific code. - `:Interface` and `:Implementation` model module units, their staleness checks and their compiles. @@ -118,14 +118,14 @@ Beyond the rules: - There is no host-platform preprocessor split: the host is Linux. Target differences (mingw, wasm) branch on `cfg.target` strings at runtime, in the library as well as in `project.cpp` and tests. - A build step fails when its command exits nonzero, never because it printed. Use `RunBuildCommand` or `RunCommandChecked`; warnings go to `Progress::Diagnostic`. - Every output path goes through `Configuration::BinDir()`, `BuildDir()` and `PcmDir()`. Hand-rolled `path / "bin" / ...` clobbered variants before; do not add new ones. -- Anything that changes what gets compiled or bundled belongs in `VariantId()`. It already hashes type, debug, sysroot, defines, compile flags, the wasm baseline and variant flags, the mingw-w64 prefix for the mingw target, uninterpreted project args and the toolchain (`Toolchain::Key()`). +- Anything that changes what gets compiled or bundled belongs in `VariantId()`. It already hashes type, debug, sysroot, defines, compile flags, the wasm baseline and variant flags, uninterpreted project args and the toolchain (`Toolchain::Key()`). ## Design rules These were decided deliberately. Do not undo them without the maintainer's say-so. 1. **Configuration is C++.** No JSON, YAML, TOML or DSL for project, runner or lint configuration. Lint rules are C++ callbacks; there is no clang-format or clang-tidy integration and no separate "format rule" type. A rule that calls `ctx.SetContent` is a transform, and that is the whole mechanism. -2. **Per-project artifacts go in `/build` and `/bin`. Only cross-project things go in `~/.cache/crafter.build/`:** the std PCM and Crafter.Build PCMs per target and march, external clones keyed by their spec hash, and the mingw sysroot views keyed by prefix. +2. **Per-project artifacts go in `/build` and `/bin`. Only cross-project things go in `~/.cache/crafter.build/`:** the std PCM and Crafter.Build PCMs per target and march, and external clones keyed by their spec hash. 3. **Sources ship, PCMs build locally.** The Flatpak installs `*.cppm` under `/app/share/crafter-build/`. Nothing target-baked ships except the executable and the toolchain beside it, and the executable is built for a portable `-march`. 4. **crafter-build is a monolithic executable with `--export-dynamic`.** `project.so` resolves `Crafter::` symbols from the running binary at dlopen time. There is no Windows host; `x86_64-w64-mingw32` is a cross-compile target for user projects only. 5. **Convention over configuration.** Lead with the zero-config path. Env var, then CLI flag, then full `project.cpp` are the escalation, not the entry point. diff --git a/README.md b/README.md index 11248aa..c57beb6 100644 --- a/README.md +++ b/README.md @@ -201,7 +201,7 @@ For elaborate setups (rsync, ssh ControlMaster, env vars on the spawn, `QEMU_LD_ For cross-arch builds, set `cfg.sysroot` on the `Configuration` to point at a sysroot for the target. `BuildStdPcm` and the compile/link commands both consume it: `--sysroot=` is passed to clang, and the std module is precompiled against the sysroot's libc++ headers. Ordinary compiles are pointed at the same headers (`-nostdinc++ -isystem /usr/include/c++/v1`), so a unit that `#include`s a standard header gets the sysroot's libc++ and not the host toolchain's. The module source has to come from the same libc++ release as those headers, so it is taken from `/usr/share/libc++/v1/std.cppm` when the sysroot ships it, else from the toolchain when both are the same major release, else from the sources crafter-build carries for other releases (`share/crafter-build/libc++-modules//`, `crafter-build --version` lists them). Alpine is the common case for the last two: its `libc++-dev` has the headers and no module source. When nothing matches, the build stops with one line naming both releases, installing that release's `share/libc++/v1` directory into the sysroot resolves it. The cheapest aarch64 sysroot is an extracted [Arch Linux ARM rootfs](http://os.archlinuxarm.org/) plus `libc++` + `libc++abi` + `gcc` installed into it via `pacman --root --config --dbpath /var/lib/pacman -Sy …` (point pacman at ALARM's mirrors via explicit config to avoid pulling host-arch packages). -For `--target=x86_64-w64-mingw32` (Windows from Linux), the pipeline cross-compiles as long as `mingw-w64` is installed, with libstdc++ 15 or newer for its std module. clang finds it by the `x86_64-w64-mingw32-gcc` on `PATH`; `CRAFTER_MINGW_DIR` names another prefix (the directory holding `x86_64-w64-mingw32/` and `lib/gcc/`), and inside the Flatpak the host's `/usr` is used when it has mingw-w64. Without one the build stops with a message saying where it looked. clang is shown only the prefix's `x86_64-w64-mingw32/` and `lib/gcc/`, as links in `~/.cache/crafter.build/mingw-sysroot/`: it searches the `include/` and `lib/` of whatever it gets as the sysroot, and those of a prefix like `/usr` are the Linux system's own, glibc's headers among them. Pair it with `--runner=cmd:wine` to run the result. Only the MinGW ABI is supported, there is no MSVC target and no Windows host. `-fuse-ld=lld` is auto-injected on every link, and `-lstdc++exp` is auto-linked for the mingw target so user projects don't need to declare those flags. +For `--target=x86_64-w64-mingw32` (Windows from Linux), the pipeline cross-compiles as long as `mingw-w64` is installed, with libstdc++ 15 or newer for its std module. clang finds it by the `x86_64-w64-mingw32-gcc` on `PATH`; `CRAFTER_MINGW_DIR` names another prefix (the directory holding `x86_64-w64-mingw32/` and `lib/gcc/`), and inside the Flatpak the host's `/usr` is used when it has mingw-w64. Without one the build stops with a message saying where it looked. Pair it with `--runner=cmd:wine` to run the result. Only the MinGW ABI is supported, there is no MSVC target and no Windows host. `-fuse-ld=lld` is auto-injected on every link, and `-lstdc++exp` is auto-linked for the mingw target so user projects don't need to declare those flags. For `--target=wasm32-wasip1`, the WASI sysroot is the one beside the toolchain (the Flatpak bundles one) unless `CRAFTER_BUILD_WASI_SYSROOT` names another, and tests run under `wasmtime`. C++ exceptions work as on the other targets: every unit and the std module are compiled with `-fwasm-exceptions` in the standardized form of WebAssembly exception handling (exnref), against the exception-enabled libc++ in the sysroot's `lib//eh/`, and `-lunwind` is linked automatically. A sysroot without that libc++ (wasi-sdk before 33) stops the build with one line saying so. The result runs on engines with that proposal: Chrome 137, Firefox 131 and Safari 18.4 or newer, and the wasmtime the Flatpak bundles. A page from `EnableWasiBrowserRuntime` checks first and names what an older browser lacks in the console, instead of failing to compile the module. An exception that escapes `main` leaves the program as an uncaught WebAssembly exception (wasmtime reports `thrown Wasm exception` and exits 1, a page gets a `WebAssembly.Exception`) without calling `std::terminate`, so a `std::set_terminate` handler does not run and nothing prints the exception's type or `what()`: wasm exception handling unwinds in a single phase, and nothing finds out that no handler is left until the stack is gone. Catch it in `main` to report it. diff --git a/implementations/Crafter.Build-Clang.cpp b/implementations/Crafter.Build-Clang.cpp index f5943ca..c37c362 100644 --- a/implementations/Crafter.Build-Clang.cpp +++ b/implementations/Crafter.Build-Clang.cpp @@ -265,13 +265,6 @@ fs::path Crafter::StdPcmDir(const Configuration& config) { if (config.target.starts_with("wasm32")) { stdPcmKey += std::format("-{:08x}", static_cast(std::hash{}(WasmBaselineFlags))); } - // The same goes for the mingw-w64 prefix the mingw std module is - // compiled against: releases up to the fix for issue #43 gave clang the - // prefix itself as the sysroot and the ones after give it a view of it, - // and two prefixes are two sets of headers. - if (config.target == "x86_64-w64-mingw32" && !GetToolchain().mingwPrefix.empty()) { - stdPcmKey += std::format("-{:08x}", static_cast(std::hash{}(GetToolchain().mingwPrefix.string()))); - } for (const std::string& f : config.wasmVariantFlags) { stdPcmKey += "+"; for (char c : f) stdPcmKey += (c == '/' || c == '\\') ? '_' : c; @@ -935,9 +928,9 @@ BuildResult Crafter::Build(Configuration& config, std::unordered_map source = StdModuleSourcePath(FileBytes(manifestPath)); if (!source) return std::format("{} names no std module", manifestPath.string()); const fs::path stdCc = (manifestPath.parent_path() / *source).lexically_normal(); @@ -869,9 +862,9 @@ std::string Crafter::GetBaseCommand(const Configuration& config) { if (config.target == "x86_64-w64-mingw32") { // libstdc++ from the mingw toolchain, said outright: a clang built to // default to libc++ (the Flatpak's) would otherwise reach for that. - // Found by clang's own mingw discovery unless there is a prefix. + // Found by clang's own mingw discovery unless there is a sysroot. command += " -stdlib=libstdc++"; - if (const fs::path& sysroot = MingwSysroot(); !sysroot.empty()) command += std::format(" --sysroot={}", sysroot.string()); + if (!tc.mingwSysroot.empty()) command += std::format(" --sysroot={}", tc.mingwSysroot.string()); return command; } command += " -stdlib=libc++"; diff --git a/implementations/Crafter.Build-Toolchain.cpp b/implementations/Crafter.Build-Toolchain.cpp index c75f627..68d9f8f 100644 --- a/implementations/Crafter.Build-Toolchain.cpp +++ b/implementations/Crafter.Build-Toolchain.cpp @@ -43,20 +43,6 @@ namespace { while (!s.empty() && (s.back() == '\n' || s.back() == '\r' || s.back() == ' ')) s.pop_back(); return s; } - - // `link` made a symbolic link to `target`, or found one already. Another - // crafter-build may make the same link at the same moment, which is as - // good as making it; a link to anything else is an error. - void EnsureSymlink(const fs::path& target, const fs::path& link) { - std::error_code ec; - if (fs::read_symlink(link, ec) == target) return; - fs::create_directories(link.parent_path()); - fs::create_directory_symlink(target, link, ec); - std::error_code ignored; - if (ec && fs::read_symlink(link, ignored) != target) { - throw fs::filesystem_error("cannot make the mingw-w64 sysroot view", target, link, ec); - } - } } std::string Toolchain::LibcxxCompileFlags() const { @@ -150,14 +136,11 @@ Toolchain Crafter::ResolveToolchain(const ToolchainInputs& in) { tc.wasiSysroot = "/usr/share/wasi-sysroot"; } if (std::string_view dir = Env(in, "CRAFTER_MINGW_DIR"); !dir.empty()) { - // Made absolute here, once: the prefix becomes the target of links - // in the cache and part of directory names, and a relative path read - // later from another working directory would name something else. - tc.mingwPrefix = fs::absolute(fs::path(dir)); + tc.mingwSysroot = fs::path(dir); } else if (!in.hostRoot.empty() && fs::exists(in.hostRoot / "usr" / "x86_64-w64-mingw32")) { // The sandbox has no mingw-w64 of its own, and no mingw gcc on PATH // for clang to find one by. - tc.mingwPrefix = in.hostRoot / "usr"; + tc.mingwSysroot = in.hostRoot / "usr"; } return tc; } @@ -203,31 +186,6 @@ const Toolchain& Crafter::RequireToolchain() { return tc; } -const fs::path& Crafter::MingwSysroot() { - // Made on first use rather than by GetToolchain(), so only a mingw build - // writes to the cache for it, and a failure surfaces as that build's - // error instead of on every command. - static const fs::path Sysroot = []() -> fs::path { - const fs::path& prefix = GetToolchain().mingwPrefix; - if (prefix.empty()) return {}; - // A view per prefix keeps two shells with different - // CRAFTER_MINGW_DIRs, which share one cache, from rewriting each - // other's. - const fs::path sysroot = GetCacheDir() / "mingw-sysroot" / std::format("{:016x}", std::hash{}(prefix.string())); - // All clang's mingw driver takes from a sysroot other than its - // include/ and the rest of its lib/: the mingw-w64 tree (headers, - // libraries, and libstdc++ where a distro's cross gcc installs it) - // and gcc's per-target directory (crtbegin.o, libgcc, and the version - // that names libstdc++'s header directory), which openSUSE keeps - // under lib64. A link to nothing is skipped like a missing directory. - for (std::string_view entry : {"x86_64-w64-mingw32", "lib/gcc", "lib64/gcc"}) { - EnsureSymlink(prefix / entry, sysroot / entry); - } - return sysroot; - }(); - return Sysroot; -} - std::int32_t Crafter::LibcxxVersion(const fs::path& includeDir) { // "# define _LIBCPP_VERSION 230102", the one place libc++ states its // release in a form the preprocessor does not have to be run for. diff --git a/interfaces/Crafter.Build-Clang.cppm b/interfaces/Crafter.Build-Clang.cppm index 89583cc..b4bbc68 100644 --- a/interfaces/Crafter.Build-Clang.cppm +++ b/interfaces/Crafter.Build-Clang.cppm @@ -628,17 +628,6 @@ export namespace Crafter { compileKey += "|B:"; compileKey += WasmBaselineFlags; } - // The mingw-w64 prefix decides what the mingw target compiles - // against, and until issue #43 clang got it as the sysroot - // itself, which put the host's own headers on the include path. - // Unkeyed, the release that fixed it kept the objects compiled - // against glibc's headers: the build after the update only - // relinked them, and failed to link as before. No prefix keeps - // the id as it was, since clang's own discovery has not changed. - if (target == "x86_64-w64-mingw32" && !toolchain.mingwPrefix.empty()) { - compileKey += "|M:"; - compileKey += toolchain.mingwPrefix.string(); - } // Sorted by ApplyStandardArgs, so flag order on the command line // doesn't split the cache. for (const std::string& a : projectArgs) { diff --git a/interfaces/Crafter.Build-Toolchain.cppm b/interfaces/Crafter.Build-Toolchain.cppm index d6b360a..797fd94 100644 --- a/interfaces/Crafter.Build-Toolchain.cppm +++ b/interfaces/Crafter.Build-Toolchain.cppm @@ -39,14 +39,11 @@ export namespace Crafter { fs::path wasiSysroot; // The mingw-w64 install prefix, the directory that holds // x86_64-w64-mingw32/ and lib/gcc/x86_64-w64-mingw32/ (/usr for a - // distro package), as an absolute path. Empty means clang's own - // discovery, which follows the mingw gcc on PATH. Set by - // CRAFTER_MINGW_DIR, else the host's /usr when running sandboxed and - // it has mingw-w64 (the sandbox's own /usr never does). clang never - // gets the prefix itself: the mingw target's --sysroot is - // MingwSysroot(), a view of it. Keyed into the mingw target's - // VariantId and std PCM directory. - fs::path mingwPrefix; + // distro package), passed to clang as --sysroot for the mingw target. + // Empty means clang's own discovery, which follows the mingw gcc on + // PATH. Set by CRAFTER_MINGW_DIR, else the host's /usr when running + // sandboxed and it has mingw-w64 (the sandbox's own /usr never does). + fs::path mingwSysroot; // `clang++ -print-target-triple` and the first line of // `clang++ --version`; both empty when clang++ could not be run. std::string hostTriple; @@ -89,18 +86,6 @@ export namespace Crafter { const Toolchain& GetToolchain(); // GetToolchain(), or a std::runtime_error carrying its error. const Toolchain& RequireToolchain(); - // The --sysroot of every compile, link and CMake configure for the mingw - // target: a directory in crafter-build's cache holding only links to the - // x86_64-w64-mingw32/, lib/gcc/ and lib64/gcc/ of GetToolchain()'s - // mingwPrefix, made on the first call of a process. Empty without a - // prefix. The prefix cannot be the sysroot: clang takes a mingw sysroot - // for a tree that holds mingw-w64 alone and searches its include/ and - // lib/ as well, which for /usr (the host's, in the Flatpak) are the - // Linux system's own. A Windows build then saw glibc's headers, and - // libstdc++, finding , had shared_ptr read - // __libc_single_threaded, which nothing on Windows defines (issue #43). - // Throws when the view cannot be made. - const fs::path& MingwSysroot(); // _LIBCPP_VERSION as the <__config> in `includeDir` (an include/c++/v1) // defines it, XXYYZZ; 0 when the file is missing or has no such line. std::int32_t LibcxxVersion(const fs::path& includeDir); diff --git a/project.cpp b/project.cpp index adedaef..83f70d6 100644 --- a/project.cpp +++ b/project.cpp @@ -253,7 +253,6 @@ extern "C" Configuration CrafterBuildProject(std::span a cfg.AddTest("ShaderVariantBuild").Dependencies({ CrafterBuildLib.get() }); cfg.AddTest("ShaderIncludeChange").Dependencies({ CrafterBuildLib.get() }); cfg.AddTest("MingwMissing").Dependencies({ CrafterBuildLib.get() }); - cfg.AddTest("MingwSysroot").Dependencies({ CrafterBuildLib.get() }); cfg.AddTest("GitSubmodules").Dependencies({ CrafterBuildLib.get() }); cfg.AddTest("LinkFlagsChange").Dependencies({ CrafterBuildLib.get() }); cfg.AddTest("ExternalArtifactTime").Dependencies({ CrafterBuildLib.get() }); diff --git a/tests/MingwSysroot/fixture/cprobe.c b/tests/MingwSysroot/fixture/cprobe.c deleted file mode 100644 index 3cd5215..0000000 --- a/tests/MingwSysroot/fixture/cprobe.c +++ /dev/null @@ -1,13 +0,0 @@ -// SPDX-License-Identifier: LGPL-3.0-only -// SPDX-FileCopyrightText: Copyright (C) 2026 Catcrafts® - -// probe.cpp's checks for the C sources, which are compiled by a command of -// their own. -#if __has_include() -#error the include/ of the prefix is on the C include path: a Windows build sees the headers of the Linux system -#endif -#if !__has_include(<_mingw.h>) -#error the mingw-w64 headers are not on the C include path -#endif - -void CProbe(void) {} diff --git a/tests/MingwSysroot/fixture/probe.cpp b/tests/MingwSysroot/fixture/probe.cpp deleted file mode 100644 index 704d42b..0000000 --- a/tests/MingwSysroot/fixture/probe.cpp +++ /dev/null @@ -1,16 +0,0 @@ -// SPDX-License-Identifier: LGPL-3.0-only -// SPDX-FileCopyrightText: Copyright (C) 2026 Catcrafts® - -// Built for x86_64-w64-mingw32 against the prefix tests/MingwSysroot stages: -// a Linux system's /usr with a mingw-w64 cross toolchain in it. -#if __has_include() -#error the include/ of the prefix is on the include path: a Windows build sees the headers of the Linux system -#endif -#if !__has_include(<_mingw.h>) -#error the mingw-w64 headers are not on the include path -#endif -#if !__has_include() -#error the libstdc++ headers are not on the include path: clang found no gcc version under lib/gcc of the prefix -#endif - -void Probe() {} diff --git a/tests/MingwSysroot/main.cpp b/tests/MingwSysroot/main.cpp deleted file mode 100644 index 2388acf..0000000 --- a/tests/MingwSysroot/main.cpp +++ /dev/null @@ -1,97 +0,0 @@ -// 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; - -// A mingw-w64 prefix that is a whole Linux system's /usr must not hand that -// system's headers to a Windows build. Inside the Flatpak the prefix is the -// host's /usr, and clang got it as the --sysroot. clang's mingw driver takes -// a sysroot for a tree that holds mingw-w64 alone and searches its include/ -// after mingw-w64's own headers, so every header mingw-w64 lacks came from -// glibc: libstdc++ found and had shared_ptr read -// __libc_single_threaded, which nothing on Windows defines, and every -// program that used one failed to link (issue #43). CRAFTER_MINGW_DIR=/usr -// did the same outside the Flatpak. -// -// The prefix staged here has the shape of such a /usr and needs no real -// mingw-w64: glibc's in include/, gcc's per-target -// directory, which clang derives libstdc++'s header directory from, and a -// stand-in mingw-w64 tree whose libstdc++ has a std module with nothing in -// it. The fixture is a static library, so nothing is linked, and its C++ and -// C sources stop the compile when they see the prefix's include/ or miss -// mingw-w64's or libstdc++'s headers. -// -// The std module such a build compiles is not the one releases before the -// fix compiled against the prefix itself, so it has to live in a directory -// of its own: the Flatpak's branches share one cache, and two releases -// taking turns rebuilding one PCM do it under the PCMs built against it. - -extern "C" int setenv(const char* name, const char* value, int overwrite); - -namespace { - std::int32_t failures = 0; - - void Check(bool cond, std::string_view msg) { - if (!cond) { - std::println(std::cerr, "FAIL: {}", msg); - ++failures; - } - } - - void Write(const fs::path& file, std::string_view text) { - fs::create_directories(file.parent_path()); - std::ofstream(file, std::ios::binary | std::ios::trunc) << text; - } -} - -int main() { - const fs::path scratch = fs::temp_directory_path() / "crafter-build-mingw-sysroot"; - std::error_code ec; - fs::remove_all(scratch, ec); - fs::create_directories(scratch); - const fs::path project = scratch / "project"; - fs::copy(fs::current_path() / "tests" / "MingwSysroot" / "fixture", project, fs::copy_options::recursive); - - const fs::path prefix = scratch / "usr"; - Write(prefix / "include" / "sys" / "single_threaded.h", "extern char __libc_single_threaded;\n"); - fs::create_directories(prefix / "lib" / "gcc" / "x86_64-w64-mingw32" / "15.1.0"); - const fs::path mingw = prefix / "x86_64-w64-mingw32"; - Write(mingw / "include" / "_mingw.h", ""); - Write(mingw / "include" / "c++" / "15.1.0" / "memory", ""); - // Through std::format because the build's import scanner reads string - // literals as code: one holding "module std;" made this file a unit of a - // module std, and the test did not build. - Write(mingw / "include" / "c++" / "15.1.0" / "bits" / "std.cc", std::format("export module {};\n", "std")); - Write(mingw / "lib" / "libstdc++.modules.json", R"({"version": 1, "modules": [{"logical-name": "std", "source-path": "../include/c++/15.1.0/bits/std.cc", "is-std-library": true}]})"); - // Before anything resolves the toolchain, which reads both once. The - // std module cache goes to the scratch directory too. - setenv("CRAFTER_MINGW_DIR", prefix.c_str(), 1); - setenv("XDG_CACHE_HOME", (scratch / "cache").c_str(), 1); - - Configuration lib; - lib.path = project; - lib.name = "probe"; - lib.outputName = "probe"; - lib.target = "x86_64-w64-mingw32"; - lib.type = ConfigurationType::LibraryStatic; - std::array ifaces = {}; - std::array impls = { "probe" }; - lib.GetInterfacesAndImplementations(ifaces, impls); - lib.cFiles = { project / "cprobe" }; - std::unordered_map> depResults; - std::mutex depMutex; - const BuildResult built = Build(lib, depResults, depMutex); - Check(built.result.empty(), std::format("a Windows build sees mingw-w64's and libstdc++'s headers and not the prefix's own: {}", built.result)); - const std::string unkeyed = std::format("{}-{}-{}", lib.target, lib.march, GetToolchain().Key()); - Check(StdPcmDir(lib).filename() != unkeyed, std::format("the std module of a mingw build with a prefix is not cached where older releases built it against the prefix itself: {}", StdPcmDir(lib).string())); - - fs::remove_all(scratch, ec); - if (failures > 0) { - std::println(std::cerr, "{} assertions failed", failures); - return 1; - } - return 0; -} diff --git a/tests/ToolchainResolve/main.cpp b/tests/ToolchainResolve/main.cpp index 1912418..81969eb 100644 --- a/tests/ToolchainResolve/main.cpp +++ b/tests/ToolchainResolve/main.cpp @@ -61,7 +61,7 @@ int main() { Check(tc.libcxxVersion == LibcxxVersion("/usr/include/c++/v1"), "the system libc++ headers state the release of the system module source"); Check(tc.stdModulesDir.empty(), "no crafter-build prefix, no shipped module sources"); Check(tc.wasiSysroot == "/usr/share/wasi-sysroot", "the system wasi sysroot is the default"); - Check(tc.mingwPrefix.empty(), "outside a sandbox, clang finds mingw-w64 itself: no prefix"); + Check(tc.mingwSysroot.empty(), "outside a sandbox, clang finds mingw-w64 itself: no --sysroot"); Check(tc.LibcxxCompileFlags().empty() && tc.LibcxxLinkFlags().empty(), "the PATH fallback adds no libc++ flags"); } { @@ -144,9 +144,7 @@ int main() { in.env["CRAFTER_MINGW_DIR"] = "/opt/mingw"; Toolchain tc = ResolveToolchain(in); Check(tc.wasiSysroot == "/opt/wasi", "CRAFTER_BUILD_WASI_SYSROOT overrides the wasi sysroot"); - Check(tc.mingwPrefix == "/opt/mingw", "CRAFTER_MINGW_DIR names the mingw prefix"); - in.env["CRAFTER_MINGW_DIR"] = "mingw"; - Check(ResolveToolchain(in).mingwPrefix == fs::absolute("mingw"), "a relative CRAFTER_MINGW_DIR is resolved against the working directory once, when the toolchain is"); + Check(tc.mingwSysroot == "/opt/mingw", "CRAFTER_MINGW_DIR names the mingw prefix passed as --sysroot"); } { // Sandboxed, the host's /usr stands in for the missing mingw-w64, @@ -155,11 +153,11 @@ int main() { fs::remove_all(host); ToolchainInputs in; in.hostRoot = host; - Check(ResolveToolchain(in).mingwPrefix.empty(), "a host without mingw-w64 gives no mingw prefix"); + Check(ResolveToolchain(in).mingwSysroot.empty(), "a host without mingw-w64 gives no --sysroot"); fs::create_directories(host / "usr" / "x86_64-w64-mingw32"); - Check(ResolveToolchain(in).mingwPrefix == host / "usr", "a host with mingw-w64 gives its /usr as the mingw prefix"); + Check(ResolveToolchain(in).mingwSysroot == host / "usr", "a host with mingw-w64 gives its /usr as the mingw prefix"); in.env["CRAFTER_MINGW_DIR"] = "/opt/mingw"; - Check(ResolveToolchain(in).mingwPrefix == "/opt/mingw", "CRAFTER_MINGW_DIR wins over the host's"); + Check(ResolveToolchain(in).mingwSysroot == "/opt/mingw", "CRAFTER_MINGW_DIR wins over the host's"); fs::remove_all(host); } { diff --git a/tests/VariantId/main.cpp b/tests/VariantId/main.cpp index e658b3e..e4d2a36 100644 --- a/tests/VariantId/main.cpp +++ b/tests/VariantId/main.cpp @@ -160,25 +160,6 @@ int main() { Check(cfg.VariantId() == cfg.VariantId(GetToolchain()), "VariantId() is the variant under the running toolchain"); Check(cfg.BuildDir().filename() == cfg.VariantId(GetToolchain()), "BuildDir is named for the running toolchain's variant"); } - { - // The mingw-w64 prefix decides what a mingw build compiles against. - // Before issue #43 it was clang's sysroot as is, which put the host's - // headers on the include path, and with the prefix left out of the - // id, the release that fixed that reused the objects built against - // them: the next build only relinked, and failed to link as before. - Configuration mingw = MakeBase(); - mingw.target = "x86_64-w64-mingw32"; - Toolchain discovered; - discovered.clangxx = "/app/bin/clang++"; - Toolchain hostUsr = discovered; - hostUsr.mingwPrefix = "/run/host/usr"; - Toolchain optMingw = discovered; - optMingw.mingwPrefix = "/opt/mingw"; - Check(mingw.VariantId(discovered) != mingw.VariantId(hostUsr), "a mingw prefix perturbs a mingw configuration's VariantId"); - Check(mingw.VariantId(hostUsr) != mingw.VariantId(optMingw), "two mingw prefixes are two variants"); - Configuration host = MakeBase(); - Check(host.VariantId(discovered) == host.VariantId(hostUsr), "the mingw prefix leaves other targets' variants alone"); - } if (Failures > 0) { std::println(std::cerr, "{} assertions failed", Failures);