feat(toolchain): resolve the compiler in one place
Every clang++, clang and llvm-ar the tool spawned was a bare name on PATH, the std module source was /usr/share/libc++/v1/std.cppm, the WASI sysroot /usr/share/wasi-sysroot and the mingw headers /usr/x86_64-w64-mingw32, spelled out at eighteen call sites. A toolchain installed anywhere else, which is what the Flatpak ships under /app, had no way in. Crafter.Build:Toolchain resolves all of it once per process: CRAFTER_BUILD_LLVM_DIR, else a clang++ installed beside crafter-build (<prefix>/bin, found through the same walk GetCrafterBuildHome does), else PATH. What sits beside the compiler is used when present: its libclang.so, its clang-c headers, its std module source, its WASI sysroot. An explicit prefix without a clang++ is an error rather than a fallback, for the same reason CRAFTER_BUILD_LIBCLANG was already exclusive. CRAFTER_BUILD_LIBCXX_DIR points at a libc++ install other than the compiler's own, and CRAFTER_MINGW_DIR now does what its help line always claimed: it is passed as --sysroot for the mingw target. Binaries linked by a toolchain outside /usr get an rpath to its lib dir, since its libc++.so.1 is not on the loader's default path. HostTarget() is the resolved clang's -print-target-triple. A clang built without a vendor reports x86_64-unknown-linux-gnu where Arch's reports x86_64-pc-linux-gnu, so target equality that decides whether a test runs locally and which targets a bare `test` sweeps goes through SameTarget, which ignores the vendor field. The strings themselves are never rewritten: clang rejects a PCM whose triple differs from the importing unit's. The examples and README stop hardcoding the host triple; the default is already the host. `crafter-build --version` prints the version baked in at build time (CRAFTER_BUILD_VERSION, else `git describe`, else 0.0.0-dev), the compiler and the host triple, and is answered before any argument is forwarded to project.cpp. The version is a define on the library, so each version is its own library variant and relinks the executable and tests once per commit. build.sh gains a shebang and `set -eu`, honours CRAFTER_BUILD_LLVM_DIR and CRAFTER_BUILD_VERSION, skips the glslang clone when it is already there, and writes a fresh archive instead of appending to one that may hold members from an older layout. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
parent
68e9b6bfa5
commit
046609ff6f
18 changed files with 767 additions and 190 deletions
|
|
@ -4,6 +4,7 @@
|
|||
module Crafter.Build:External_impl;
|
||||
import std;
|
||||
import :External;
|
||||
import :Toolchain;
|
||||
import :Platform;
|
||||
import :Progress;
|
||||
import :Clang;
|
||||
|
|
@ -118,15 +119,16 @@ std::string BuildInjectedCMakeFlags(const fs::path& cmakeBuildDir, std::string_v
|
|||
// suffix to library names assuming a debug build, breaking -l<name>
|
||||
// linking. Pin to Release.
|
||||
out += " -DCMAKE_BUILD_TYPE=Release";
|
||||
out += " -DCMAKE_C_COMPILER=clang";
|
||||
out += " -DCMAKE_CXX_COMPILER=clang++";
|
||||
const Toolchain& tc = GetToolchain();
|
||||
out += std::format(" -DCMAKE_C_COMPILER={}", ShellQuote(tc.clang.string()));
|
||||
out += std::format(" -DCMAKE_CXX_COMPILER={}", ShellQuote(tc.clangxx.string()));
|
||||
// Stdlib choice: libc++ for Linux targets (matches how crafter-build
|
||||
// itself is built with -stdlib=libc++); the mingw cross-compile uses the
|
||||
// libstdc++ shipped by the mingw-w64 toolchain, so it keeps the default.
|
||||
if (target.ends_with("-linux-gnu") || target.ends_with("-linux-musl")) {
|
||||
out += " -DCMAKE_CXX_FLAGS=-stdlib=libc++";
|
||||
out += " -DCMAKE_EXE_LINKER_FLAGS=-stdlib=libc++";
|
||||
out += " -DCMAKE_SHARED_LINKER_FLAGS=-stdlib=libc++";
|
||||
out += std::format(" -DCMAKE_CXX_FLAGS={}", ShellQuote(std::format("-stdlib=libc++{}", tc.LibcxxCompileFlags())));
|
||||
out += std::format(" -DCMAKE_EXE_LINKER_FLAGS={}", ShellQuote(std::format("-stdlib=libc++{}", tc.LibcxxLinkFlags())));
|
||||
out += std::format(" -DCMAKE_SHARED_LINKER_FLAGS={}", ShellQuote(std::format("-stdlib=libc++{}", tc.LibcxxLinkFlags())));
|
||||
}
|
||||
if (target == "x86_64-w64-mingw32") {
|
||||
out += " -DCMAKE_SYSTEM_NAME=Windows";
|
||||
|
|
@ -142,6 +144,10 @@ std::string BuildInjectedCMakeFlags(const fs::path& cmakeBuildDir, std::string_v
|
|||
std::string ConfigureCMake(const fs::path& cloneDir, const fs::path& cmakeBuildDir, std::span<const std::string> options, std::string_view target) {
|
||||
fs::path optionsFile = cmakeBuildDir / ".crafter-options";
|
||||
std::string optionsKey = JoinOptions(options);
|
||||
// The injected flags are inputs too: a different compiler or libc++
|
||||
// must reconfigure rather than reuse a CMakeCache made with the old one.
|
||||
const std::string injected = BuildInjectedCMakeFlags(cmakeBuildDir, target);
|
||||
const std::string configureKey = injected + '\n' + optionsKey;
|
||||
|
||||
bool needsConfigure = !fs::exists(cmakeBuildDir / "CMakeCache.txt");
|
||||
if (!needsConfigure) {
|
||||
|
|
@ -151,7 +157,7 @@ std::string ConfigureCMake(const fs::path& cloneDir, const fs::path& cmakeBuildD
|
|||
} else {
|
||||
std::stringstream buf;
|
||||
buf << existing.rdbuf();
|
||||
if (buf.str() != optionsKey) needsConfigure = true;
|
||||
if (buf.str() != configureKey) needsConfigure = true;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -159,7 +165,7 @@ std::string ConfigureCMake(const fs::path& cloneDir, const fs::path& cmakeBuildD
|
|||
|
||||
if (!fs::exists(cmakeBuildDir)) fs::create_directories(cmakeBuildDir);
|
||||
|
||||
std::string cmd = std::format("cmake -S {} -B {}{}", ShellQuote(fs::absolute(cloneDir).string()), ShellQuote(fs::absolute(cmakeBuildDir).string()), BuildInjectedCMakeFlags(cmakeBuildDir, target));
|
||||
std::string cmd = std::format("cmake -S {} -B {}{}", ShellQuote(fs::absolute(cloneDir).string()), ShellQuote(fs::absolute(cmakeBuildDir).string()), injected);
|
||||
if (!options.empty()) {
|
||||
cmd += " ";
|
||||
cmd += optionsKey;
|
||||
|
|
@ -170,7 +176,7 @@ std::string ConfigureCMake(const fs::path& cloneDir, const fs::path& cmakeBuildD
|
|||
return std::format("cmake configure failed (exit {}): {}", r.exitCode, r.output);
|
||||
}
|
||||
|
||||
std::ofstream(optionsFile) << optionsKey;
|
||||
std::ofstream(optionsFile) << configureKey;
|
||||
return "";
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue