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
38
project.cpp
38
project.cpp
|
|
@ -30,21 +30,30 @@ extern "C" Configuration CrafterBuildProject(std::span<const std::string_view> a
|
|||
|
||||
CrafterBuildLib->dependencies = { math, asset };
|
||||
CrafterBuildLib->defines.push_back({"CRAFTER_BUILD_HAS_ASSET", ""});
|
||||
// Crafter.Build-Lint includes libclang's clang-c/Index.h. glibc distros
|
||||
// keep it in /usr/include; Alpine keeps LLVM under /usr/lib/llvmNN, so ask
|
||||
// llvm-config and add the dir when it is not already on the default path
|
||||
// (never /usr/include itself: that breaks libc++'s #include_next).
|
||||
if (CrafterBuildLib->target.ends_with("-linux-gnu") || CrafterBuildLib->target.ends_with("-linux-musl")) {
|
||||
auto llvmInc = RunCommandWithTimeout("llvm-config --includedir 2>/dev/null", std::chrono::seconds(10));
|
||||
std::string incDir = llvmInc.output;
|
||||
while (!incDir.empty() && (incDir.back() == '\n' || incDir.back() == '\r')) incDir.pop_back();
|
||||
if (llvmInc.exitCode == 0 && !incDir.empty() && incDir != "/usr/include") {
|
||||
CrafterBuildLib->compileFlags.push_back(std::format("-I{}", incDir));
|
||||
}
|
||||
// Crafter.Build-Lint includes libclang's clang-c/Index.h, which is only
|
||||
// on the default include path for a toolchain installed in /usr.
|
||||
if (const fs::path& llvmInclude = GetToolchain().llvmIncludeDir; !llvmInclude.empty()) {
|
||||
CrafterBuildLib->compileFlags.push_back(std::format("-I{}", llvmInclude.string()));
|
||||
}
|
||||
// The version the binary reports: CI sets it from the tag, a checkout
|
||||
// describes itself, anything else is a development build. A define on
|
||||
// the library, so each version is its own library variant.
|
||||
std::string version;
|
||||
if (const char* env = std::getenv("CRAFTER_BUILD_VERSION"); env && *env) {
|
||||
version = env;
|
||||
} else {
|
||||
auto described = RunCommandWithTimeout("git describe --tags --always --dirty --exclude=latest 2>/dev/null", std::chrono::seconds(10));
|
||||
version = described.output;
|
||||
while (!version.empty() && (version.back() == '\n' || version.back() == '\r')) version.pop_back();
|
||||
if (described.exitCode != 0 || version.empty()) version = "0.0.0-dev";
|
||||
}
|
||||
// Backslash-escaped quotes: the define travels through the shell before
|
||||
// it reaches clang, which must still see a string literal.
|
||||
CrafterBuildLib->defines.push_back({"CRAFTER_BUILD_VERSION", std::format("\\\"{}\\\"", version)});
|
||||
{
|
||||
std::array<fs::path, 11> interfaces = {
|
||||
std::array<fs::path, 12> interfaces = {
|
||||
"interfaces/Crafter.Build",
|
||||
"interfaces/Crafter.Build-Toolchain",
|
||||
"interfaces/Crafter.Build-Shader",
|
||||
"interfaces/Crafter.Build-Platform",
|
||||
"interfaces/Crafter.Build-Interface",
|
||||
|
|
@ -56,7 +65,8 @@ extern "C" Configuration CrafterBuildProject(std::span<const std::string_view> a
|
|||
"interfaces/Crafter.Build-Progress",
|
||||
"interfaces/Crafter.Build-Asset",
|
||||
};
|
||||
std::array<fs::path, 10> implementations = {
|
||||
std::array<fs::path, 11> implementations = {
|
||||
"implementations/Crafter.Build-Toolchain",
|
||||
"implementations/Crafter.Build-Shader",
|
||||
"implementations/Crafter.Build-Platform",
|
||||
"implementations/Crafter.Build-Interface",
|
||||
|
|
@ -118,6 +128,8 @@ extern "C" Configuration CrafterBuildProject(std::span<const std::string_view> a
|
|||
cfg.AddTest("StandardArgs").Dependencies({ CrafterBuildLib.get() });
|
||||
cfg.AddTest("TestRunnerSpec").Dependencies({ CrafterBuildLib.get() });
|
||||
cfg.AddTest("VariantId").Dependencies({ CrafterBuildLib.get() });
|
||||
cfg.AddTest("ToolchainResolve").Dependencies({ CrafterBuildLib.get() });
|
||||
cfg.AddTest("VersionFlag").Dependencies({ CrafterBuildLib.get() });
|
||||
cfg.AddTest("WasiBrowserRuntime").Dependencies({ CrafterBuildLib.get() });
|
||||
cfg.AddTest("WasmVariants").Dependencies({ CrafterBuildLib.get() });
|
||||
cfg.AddTest("RunSingleTestExit").Dependencies({ CrafterBuildLib.get() });
|
||||
|
|
|
|||
Loading…
Reference in a new issue