refactor: drop Windows host support
crafter-build is moving to a single Flatpak distribution, and there is no Windows host in that picture: no build.cmd, no MSVC or mingw host build, no DLL plus launcher. Delete every host-Windows path instead of leaving it to rot unverified: the cmd.exe command runner and quoting, the LOCALAPPDATA cache, the MSVC and mingw-host LoadProject variants with their LIBCXX_DIR and CRAFTER_MINGW_DIR plumbing, the winsock port probe, the LoadLibrary libclang loader, the console-width and isatty shims, and the preprocessor guards around the Linux bodies. The x86_64-w64-mingw32 cross-compile target stays. It is target logic (output names, -femulated-tls, the libstdc++ link extras, copying a dependency DLL next to a mingw exe, wine as the runner) and did not depend on any of the removed code. The msvc target goes with the host that was the only thing able to use it. Three target-path warts fixed on the way: ExpectedOutput named a mingw static library <name>.lib while the archive step wrote lib<name>.a, so those libraries relinked on every run; the import lib is no longer copied next to a mingw exe, since the dependency's own bin dir is already on the link line; and llvm-ar now writes every archive, not only the LTO ones, so Debug and Release archives are made the same way. CRAFTER_API and Crafter.Build-Api.h existed only for the DLL boundary. Nothing downstream used them, so they are removed rather than kept as an empty macro nobody can verify. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
parent
f60ba809b5
commit
46082a3117
24 changed files with 138 additions and 1053 deletions
|
|
@ -1,8 +1,6 @@
|
|||
// SPDX-License-Identifier: LGPL-3.0-only
|
||||
// SPDX-FileCopyrightText: Copyright (C) 2026 Catcrafts®
|
||||
|
||||
module;
|
||||
#include "Crafter.Build-Api.h"
|
||||
export module Crafter.Build:Clang;
|
||||
import std;
|
||||
import :Shader;
|
||||
|
|
@ -65,30 +63,28 @@ export namespace Crafter {
|
|||
|
||||
bool IsLocal() const { return exec.empty(); }
|
||||
|
||||
static CRAFTER_API TestRunner Local();
|
||||
static TestRunner Local();
|
||||
// Prefix runner: wraps the local binary in `<command> {bin} {args}`.
|
||||
// Used for qemu-user, wasmtime, and similar single-binary wrappers.
|
||||
static CRAFTER_API TestRunner Cmd(std::string command);
|
||||
// Run a Windows .exe through Wine. Probes `wine` on PATH; on a Windows
|
||||
// host the wine wrapper is pointless, so callers should route to Local
|
||||
// before reaching here.
|
||||
static CRAFTER_API TestRunner Wine();
|
||||
static TestRunner Cmd(std::string command);
|
||||
// Run a Windows .exe through Wine. Probes `wine` on PATH.
|
||||
static TestRunner Wine();
|
||||
// Parse a `<kind>[:<arg>]` spec used by CRAFTER_BUILD_RUNNER_<target>
|
||||
// and --runner=. Supported: "local", "cmd:<binary>". Returns nullopt
|
||||
// for an empty string; throws on a non-empty unrecognized spec.
|
||||
static CRAFTER_API std::optional<TestRunner> FromSpec(std::string_view spec);
|
||||
static std::optional<TestRunner> FromSpec(std::string_view spec);
|
||||
// Honor CRAFTER_BUILD_RUNNER_<target> (power-user override). Triple
|
||||
// dashes/dots become underscores so they're valid in env-var names.
|
||||
// Returns `fallback` when the env var is unset.
|
||||
static CRAFTER_API TestRunner FromEnv(std::string_view target, TestRunner fallback = Local());
|
||||
static TestRunner FromEnv(std::string_view target, TestRunner fallback = Local());
|
||||
// Derive a runner from a Configuration's target triple + sysroot.
|
||||
// Returns Local() when target equals the host, Wine() for Windows
|
||||
// targets on a non-Windows host, `qemu-<arch>` (with QEMU_LD_PREFIX
|
||||
// targets, `qemu-<arch>` (with QEMU_LD_PREFIX
|
||||
// set when cfg.sysroot is non-empty) for non-host -linux- triples,
|
||||
// `wasmtime` for wasm32-wasi/wasm64-wasi, and Local() as a last
|
||||
// resort. CRAFTER_BUILD_RUNNER_<target> still wins as an override
|
||||
// upstream of this — see FromEnv.
|
||||
static CRAFTER_API TestRunner ForTarget(const struct Configuration& cfg);
|
||||
static TestRunner ForTarget(const struct Configuration& cfg);
|
||||
};
|
||||
|
||||
enum class TestOutcome { Pass, Fail, Crash, Timeout, Skipped };
|
||||
|
|
@ -233,17 +229,18 @@ export namespace Crafter {
|
|||
};
|
||||
|
||||
// Per-file view handed to each LintRule's check callback. Every member
|
||||
// function is out-of-line and CRAFTER_API (defined in Crafter.Build:Lint's
|
||||
// implementation unit) because rule lambdas execute from the user's
|
||||
// project DLL on Windows — clang does not emit module-attached in-class
|
||||
// inline bodies into consumers (see ArgQuery below).
|
||||
// function is out-of-line (defined in Crafter.Build:Lint's implementation
|
||||
// unit) because rule lambdas execute from the user's project.so and
|
||||
// resolve against the running executable: clang does not emit
|
||||
// module-attached in-class inline bodies into consumers (see ArgQuery
|
||||
// below).
|
||||
struct LintContext {
|
||||
fs::path file; // absolute path of the file under lint
|
||||
std::string content; // whole file as read from disk
|
||||
std::vector<std::string_view> lines; // views into `content`, one per line, no '\n'
|
||||
|
||||
CRAFTER_API std::string Extension() const; // ".cppm", ".cpp", ".h", ...
|
||||
CRAFTER_API std::string_view Line(std::size_t n) const; // 1-based; empty if out of range
|
||||
std::string Extension() const; // ".cppm", ".cpp", ".h", ...
|
||||
std::string_view Line(std::size_t n) const; // 1-based; empty if out of range
|
||||
// `content` with comments and string/char literal bodies blanked to
|
||||
// spaces, newlines preserved — offsets and line numbers stay valid.
|
||||
// Built from Tokens() on first call, cached per file, so raw strings,
|
||||
|
|
@ -254,9 +251,9 @@ export namespace Crafter {
|
|||
// Convenient for a quick scan, but Tokens() is the better tool for
|
||||
// anything structural: this view cannot tell an identifier from a
|
||||
// keyword, and it has already thrown away where the literals were.
|
||||
CRAFTER_API const std::string& CommentStripped();
|
||||
const std::string& CommentStripped();
|
||||
// Record a finding at `line` (1-based; pass 0 for a whole-file finding).
|
||||
CRAFTER_API void Report(std::size_t line, std::string message);
|
||||
void Report(std::size_t line, std::string message);
|
||||
// Replace the file's content. Makes this rule a *transform*:
|
||||
// `crafter-build format` writes the result back to disk; `lint`
|
||||
// derives would-reformat findings from it (dry — never writes).
|
||||
|
|
@ -265,7 +262,7 @@ export namespace Crafter {
|
|||
// pattern: build the new string, call SetContent once at the end. Do
|
||||
// not assign `content` directly — that bypasses the re-split. May be
|
||||
// combined with Report() in the same rule.
|
||||
CRAFTER_API void SetContent(std::string newContent);
|
||||
void SetContent(std::string newContent);
|
||||
// True when `rule` is suppressed at `line` (1-based; 0 = whole-file,
|
||||
// which only file-level directives cover) by a suppression comment:
|
||||
// // lint-disable-next-line [rules...] applies to the following line
|
||||
|
|
@ -277,7 +274,7 @@ export namespace Crafter {
|
|||
// itself for every line its edit touches (the driver cannot map lines
|
||||
// across a count-changing rewrite). Parsed lazily from the raw lines;
|
||||
// re-parsed after SetContent.
|
||||
CRAFTER_API bool Suppressed(std::string_view rule, std::size_t line);
|
||||
bool Suppressed(std::string_view rule, std::size_t line);
|
||||
|
||||
// The file lexed by clang, in source order. Built on first call, cached
|
||||
// per file, re-lexed after SetContent. Empty for extensions that are
|
||||
|
|
@ -287,16 +284,16 @@ export namespace Crafter {
|
|||
// raw strings, line splices, digraphs and nested quoting right, and
|
||||
// offsets index straight into `content`, so a transform can find in
|
||||
// the token stream and edit in place.
|
||||
CRAFTER_API std::span<const LintToken> Tokens();
|
||||
std::span<const LintToken> Tokens();
|
||||
// The token's own bytes: content.substr(tok.offset, tok.length).
|
||||
CRAFTER_API std::string_view TokenText(const LintToken& token) const;
|
||||
std::string_view TokenText(const LintToken& token) const;
|
||||
// Tokens whose FIRST byte is on `line` (1-based). A token that starts
|
||||
// earlier and spans into `line` — a raw string, a block comment — is
|
||||
// not included; ask Tokens() directly when that matters.
|
||||
CRAFTER_API std::span<const LintToken> TokensOnLine(std::size_t line);
|
||||
std::span<const LintToken> TokensOnLine(std::size_t line);
|
||||
// True when a comment token starts on `line`. Replaces `Line(n).contains("//")`,
|
||||
// which false-positives on a `//` inside a string literal.
|
||||
CRAFTER_API bool LineHasComment(std::size_t line);
|
||||
bool LineHasComment(std::size_t line);
|
||||
// True when `line` (1-based) is touched by a token that spans more
|
||||
// than one line — a raw string or a block comment. A transform that
|
||||
// joins, splits or rewrites such a line changes what is inside that
|
||||
|
|
@ -304,7 +301,7 @@ export namespace Crafter {
|
|||
// Replaces `Line(n).contains("R\"")`, which both misses raw strings
|
||||
// opened on an earlier line and fires on the characters R" appearing
|
||||
// inside an ordinary literal.
|
||||
CRAFTER_API bool LineHasMultiLineToken(std::size_t line);
|
||||
bool LineHasMultiLineToken(std::size_t line);
|
||||
|
||||
// Declarations written in this file, flattened depth-first with
|
||||
// parents before children (see LintDecl). Empty when the AST is not
|
||||
|
|
@ -321,11 +318,11 @@ export namespace Crafter {
|
|||
// slice. Declarations inside a preprocessor branch that is inactive
|
||||
// for the host are absent here, though Tokens() still sees them. Rules
|
||||
// that must cover every platform belong on tokens.
|
||||
CRAFTER_API std::span<const LintDecl> Decls();
|
||||
CRAFTER_API bool AstAvailable();
|
||||
std::span<const LintDecl> Decls();
|
||||
bool AstAvailable();
|
||||
// Why AstAvailable() is false — a missing PCM, a parse error, a file
|
||||
// that is not a translation unit. Empty when the AST is available.
|
||||
CRAFTER_API std::string_view AstUnavailableReason();
|
||||
std::string_view AstUnavailableReason();
|
||||
|
||||
// Driver wiring — set by RunLint before each check call. Not for rules.
|
||||
std::string activeRule;
|
||||
|
|
@ -363,7 +360,7 @@ export namespace Crafter {
|
|||
// Configuration::target so projects don't have to hardcode it for the
|
||||
// no-cross-compile case. Returns "" if clang isn't on PATH or doesn't
|
||||
// print a triple — those projects still need an explicit cfg.target.
|
||||
CRAFTER_API std::string HostTarget();
|
||||
std::string HostTarget();
|
||||
|
||||
struct Configuration {
|
||||
fs::path path;
|
||||
|
|
@ -439,7 +436,7 @@ export namespace Crafter {
|
|||
std::vector<Test> tests;
|
||||
// Lint rules for `crafter-build lint`. Populate via AddLintRule.
|
||||
std::vector<LintRule> lintRules;
|
||||
CRAFTER_API void GetInterfacesAndImplementations(std::span<fs::path> interfaces, std::span<fs::path> implementations);
|
||||
void GetInterfacesAndImplementations(std::span<fs::path> interfaces, std::span<fs::path> implementations);
|
||||
// Retry the `import X;` names GetInterfacesAndImplementations could not
|
||||
// place, against the dependency DAG as it stands now. Sources are
|
||||
// scanned when they're declared, but `dependencies` is often assigned
|
||||
|
|
@ -448,30 +445,30 @@ export namespace Crafter {
|
|||
// change and this Configuration's objects would be silently reused
|
||||
// against the new layout. Build() calls this before checking mtimes;
|
||||
// calling it again is harmless.
|
||||
CRAFTER_API void ResolvePendingImports();
|
||||
void ResolvePendingImports();
|
||||
// Declare a test. Sources default to `tests/<name>/main.cpp` resolved
|
||||
// against this Configuration's path; target/march/mtune/sysroot/debug
|
||||
// are inherited from this Configuration so cross-arch projects don't
|
||||
// have to re-specify. Returns a builder for chaining defines, deps,
|
||||
// etc. Defined in Crafter.Build:Test.
|
||||
CRAFTER_API struct TestBuilder AddTest(std::string_view name);
|
||||
struct TestBuilder AddTest(std::string_view name);
|
||||
// Same as AddTest, but compiles the parent's `interfaces` directly
|
||||
// into this test's Configuration (rather than going through a dep).
|
||||
// Use when the test must rebuild those interfaces with its own
|
||||
// compile flags — typically per-march SIMD codegen.
|
||||
CRAFTER_API struct TestBuilder AddTest(std::string_view name, std::span<fs::path> interfaces);
|
||||
struct TestBuilder AddTest(std::string_view name, std::span<fs::path> interfaces);
|
||||
// Math-style fan-out: one Test per MarchTier, all sharing the same
|
||||
// `tests/<name>/main.cpp` source and the same interface set, each
|
||||
// compiled with the tier's `-march`/`-mtune`. Test names are
|
||||
// `<name>-<march>`.
|
||||
CRAFTER_API void AddMarchVariants(std::string_view name, std::span<fs::path> interfaces, std::span<const struct MarchTier> tiers);
|
||||
void AddMarchVariants(std::string_view name, std::span<fs::path> interfaces, std::span<const struct MarchTier> tiers);
|
||||
// Register a lint rule for `crafter-build lint` / `format`. Rules
|
||||
// registered on any Configuration whose path lies inside the project
|
||||
// root are collected (deduplicated by name, root-first) — attach them
|
||||
// to the lib or the exe config, either works. Rules that call
|
||||
// ctx.SetContent are transforms (see LintContext::SetContent).
|
||||
// Defined in Crafter.Build:Lint.
|
||||
CRAFTER_API void AddLintRule(std::string name, std::function<void(LintContext&)> check);
|
||||
void AddLintRule(std::string name, std::function<void(LintContext&)> check);
|
||||
// Same, for a rule that reads LintContext::Decls(). Declared
|
||||
// separately rather than as a flag on AddLintRule so existing
|
||||
// registrations keep compiling. Such a rule makes the run build the
|
||||
|
|
@ -479,7 +476,7 @@ export namespace Crafter {
|
|||
// produced becomes an error instead of a silent pass. Prefer
|
||||
// report-only: a transform running after the first one forces a
|
||||
// re-parse of everything it changed.
|
||||
CRAFTER_API void AddAstLintRule(std::string name, std::function<void(LintContext&)> check);
|
||||
void AddAstLintRule(std::string name, std::function<void(LintContext&)> check);
|
||||
// Suffix that uniquely identifies this Configuration's compile state.
|
||||
// target+march+mtune are spelled out for readability; the rest
|
||||
// (type, debug, sysroot, defines, compileFlags) collapse into a short
|
||||
|
|
@ -544,14 +541,14 @@ export namespace Crafter {
|
|||
// Directory holding the std module PCM for this Configuration. Keyed on
|
||||
// target+march because a BMI is only loadable by a TU with matching target
|
||||
// features, and suffixed with the wasm variant flags for the same reason.
|
||||
CRAFTER_API fs::path StdPcmDir(const Configuration& config);
|
||||
fs::path StdPcmDir(const Configuration& config);
|
||||
|
||||
// Where Build leaves this Configuration's linked artifact: the executable
|
||||
// (with the target's suffix), `lib<name>.a` / `<name>.lib`, or the shared
|
||||
// library / DLL. The one rule every "is the consumer older than its
|
||||
// dependency" check reads, so a staleness test and the link step can't
|
||||
// disagree about the file name.
|
||||
CRAFTER_API fs::path ExpectedOutput(const Configuration& config);
|
||||
fs::path ExpectedOutput(const Configuration& config);
|
||||
|
||||
// The clang invocation every C++ translation unit in this Configuration is
|
||||
// compiled with, before anything that depends on work having happened
|
||||
|
|
@ -586,14 +583,14 @@ export namespace Crafter {
|
|||
fs::path stdPcmDir;
|
||||
fs::path pcmDir;
|
||||
};
|
||||
CRAFTER_API CompileCommand GetCompileCommand(const Configuration& config);
|
||||
CompileCommand GetCompileCommand(const Configuration& config);
|
||||
|
||||
CRAFTER_API BuildResult Build(Configuration& config, std::unordered_map<fs::path, std::shared_future<BuildResult>>& depResults, std::mutex& depMutex);
|
||||
BuildResult Build(Configuration& config, std::unordered_map<fs::path, std::shared_future<BuildResult>>& depResults, std::mutex& depMutex);
|
||||
|
||||
// Takes main's argv verbatim so the CLI entry point is a one-liner;
|
||||
// the shape is inherited from the language, not chosen here.
|
||||
// lint-disable-next-line no-char-pointer
|
||||
CRAFTER_API std::int32_t Run(std::int32_t argc, char** argv);
|
||||
std::int32_t Run(std::int32_t argc, char** argv);
|
||||
|
||||
// Delete the bin/ and build/ trees beside `projectFile`, returning the paths
|
||||
// that existed and were removed. Backs `crafter-build clean`.
|
||||
|
|
@ -603,7 +600,7 @@ export namespace Crafter {
|
|||
// to compile (and its git dependencies to be present) is useless exactly
|
||||
// then. That means variant directories are not enumerated — the whole tree
|
||||
// goes, which is what the by-hand `rm -rf bin build` did anyway.
|
||||
CRAFTER_API std::vector<fs::path> CleanProject(const fs::path& projectFile);
|
||||
std::vector<fs::path> CleanProject(const fs::path& projectFile);
|
||||
|
||||
// Add a small index.html + runtime.js pair next to the .wasm output so the
|
||||
// build can be loaded directly in a browser (just `serve` the bin dir and
|
||||
|
|
@ -611,7 +608,7 @@ export namespace Crafter {
|
|||
// this and shouldn't carry the extra files. Call from project.cpp after
|
||||
// outputName is set; index.html is generated against the current
|
||||
// outputName so renaming the binary later requires another call.
|
||||
CRAFTER_API void EnableWasiBrowserRuntime(Configuration& cfg);
|
||||
void EnableWasiBrowserRuntime(Configuration& cfg);
|
||||
|
||||
// Register the relaxed-SIMD codegen variant on cfg. Builds an additional
|
||||
// outputName.relaxed-simd.wasm compiled with -mrelaxed-simd (FMA,
|
||||
|
|
@ -622,17 +619,17 @@ export namespace Crafter {
|
|||
// 2026). Idempotent. Call before EnableWasiBrowserRuntime so the emitted
|
||||
// variants.json manifest includes it. A no-op for non-wasm targets at build
|
||||
// time (no wasm is produced), but harmless to declare unconditionally.
|
||||
CRAFTER_API void EnableWasiRelaxedSimdVariant(Configuration& cfg);
|
||||
void EnableWasiRelaxedSimdVariant(Configuration& cfg);
|
||||
|
||||
// View over the project's args with simple query helpers. Has(flag) for
|
||||
// boolean switches; Get(prefix) for valued options (e.g. Get("--prefix=")
|
||||
// returns the substring after the equals). Definitions are out-of-line
|
||||
// and CRAFTER_API so they cross the Windows DLL boundary cleanly — clang
|
||||
// does not emit module-attached in-class inline bodies into consumers.
|
||||
// returns the substring after the equals). Definitions are out-of-line so
|
||||
// project.so resolves them from the executable: clang does not emit
|
||||
// module-attached in-class inline bodies into consumers.
|
||||
struct ArgQuery {
|
||||
std::span<const std::string_view> args;
|
||||
CRAFTER_API bool Has(std::string_view flag) const;
|
||||
CRAFTER_API std::optional<std::string> Get(std::string_view prefix) const;
|
||||
bool Has(std::string_view flag) const;
|
||||
std::optional<std::string> Get(std::string_view prefix) const;
|
||||
};
|
||||
|
||||
// Apply the framework's standard CLI args + env vars onto cfg:
|
||||
|
|
@ -651,5 +648,5 @@ export namespace Crafter {
|
|||
// pre-set defaults. Returns an ArgQuery over the same span so projects
|
||||
// can query their own flags (`--timing`, ...) without re-rolling the
|
||||
// for-arg-in-args loop.
|
||||
CRAFTER_API ArgQuery ApplyStandardArgs(Configuration& cfg, std::span<const std::string_view> args);
|
||||
ArgQuery ApplyStandardArgs(Configuration& cfg, std::span<const std::string_view> args);
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue