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
|
|
@ -9,6 +9,7 @@ import std;
|
|||
import :Lint;
|
||||
import :Clang;
|
||||
import :Platform;
|
||||
import :Toolchain;
|
||||
import :Progress;
|
||||
namespace fs = std::filesystem;
|
||||
using namespace Crafter;
|
||||
|
|
@ -92,14 +93,14 @@ namespace {
|
|||
LibClang LoadLibClang() {
|
||||
LibClang lib;
|
||||
std::vector<std::string> tried;
|
||||
// CRAFTER_BUILD_LIBCLANG pins an exact path, mirroring the
|
||||
// CRAFTER_MINGW_DIR override used elsewhere. It is exclusive: pointing
|
||||
// it at a broken path must fail loudly rather than quietly succeed with
|
||||
// some other libclang, or the override is useless for diagnosing which
|
||||
// library is actually in play.
|
||||
// The toolchain pins libclang when it knows where it is: the
|
||||
// CRAFTER_BUILD_LIBCLANG override, or the libclang.so beside the
|
||||
// compiler. A pin is exclusive: pointing the override at a broken
|
||||
// path must fail loudly rather than quietly succeed with some other
|
||||
// libclang, or it is useless for diagnosing which library is in play.
|
||||
std::vector<std::string> candidates;
|
||||
if (const char* pinned = std::getenv("CRAFTER_BUILD_LIBCLANG"); pinned && *pinned) {
|
||||
candidates.emplace_back(pinned);
|
||||
if (const std::optional<fs::path>& pinned = GetToolchain().libclang) {
|
||||
candidates.emplace_back(pinned->string());
|
||||
} else {
|
||||
for (std::string_view name : LibClangNames) candidates.emplace_back(name);
|
||||
}
|
||||
|
|
@ -119,7 +120,7 @@ namespace {
|
|||
tried.push_back(name);
|
||||
}
|
||||
if (!lib.handle) {
|
||||
lib.error = std::format("could not load libclang (tried {}); install clang, or point CRAFTER_BUILD_LIBCLANG at it", join(tried));
|
||||
lib.error = std::format("could not load libclang (tried {}); install clang, set CRAFTER_BUILD_LLVM_DIR, or point CRAFTER_BUILD_LIBCLANG at it", join(tried));
|
||||
return lib;
|
||||
}
|
||||
|
||||
|
|
@ -710,7 +711,7 @@ namespace {
|
|||
// explicitly. Cached like HostTarget, and for the same reason.
|
||||
const std::string& ClangResourceDir() {
|
||||
static const std::string Cached = []() -> std::string {
|
||||
CommandResult r = RunCommandChecked("clang++ -print-resource-dir");
|
||||
CommandResult r = RunCommandChecked(std::format("{} -print-resource-dir", GetToolchain().clangxx.string()));
|
||||
if (r.exitCode != 0) return {};
|
||||
std::string out = std::move(r.output);
|
||||
while (!out.empty() && (out.back() == '\n' || out.back() == '\r')) out.pop_back();
|
||||
|
|
|
|||
Loading…
Reference in a new issue