// SPDX-License-Identifier: LGPL-3.0-only // SPDX-FileCopyrightText: Copyright (C) 2026 Catcrafts® module; #include "Crafter.Build-Api.h" export module Crafter.Build:Platform; import std; namespace fs = std::filesystem; namespace Crafter { struct Configuration; struct CommandResult { std::int32_t exitCode = 0; std::string output; bool crashed = false; bool timedOut = false; std::int32_t signal = 0; }; std::string BuildStdPcm(const Configuration& config, fs::path stdPcm); fs::path GetCacheDir(); CommandResult RunCommandChecked(std::string_view command); // A compile / link / archive step. Success is the command's exit status, // never whether it printed anything: a warning does not stop the compiler // from writing a valid object, and warnings are only emitted when a // translation unit is actually recompiled — so keying failure off the // output made the same unchanged source pass or fail depending on whether // its object happened to be up to date. // // Returns an empty string on success (any warnings go to the user via // Progress::Diagnostic), otherwise the compiler's diagnostics. Callers // therefore keep the `if (!result.empty())` shape they already had. std::string RunBuildCommand(std::string_view command); export CRAFTER_API CommandResult RunCommandWithTimeout(std::string_view command, std::chrono::seconds timeout); std::string GetBaseCommand(const Configuration& config); export CRAFTER_API Configuration LoadProject(const fs::path& projectFile, std::span args); // A dependency the project file currently running its CrafterBuildProject // declared with `#pragma crafter dependency`, so it can also be wired // into the build graph (a test that links the same module, say) without // spelling the source twice. `name` is the dependency's Configuration // name or any module it exports — whatever the project file `import`s. // Throws when no such dependency was declared, or when called from // anywhere other than inside LoadProject. export CRAFTER_API Configuration* ProjectDependency(std::string_view name); // True while the project file crafter-build was pointed at runs its // CrafterBuildProject, and when no project file is running at all; false // inside a dependency's project file (a `#pragma crafter dependency`, // GitProject or LocalProject target). Wire anything only the project's // own build or test run needs behind it. The case that forced it: a // library's test links crafter-build itself, so when crafter-build loads // that library as a dependency, the test's GitProject loads crafter-build's // project file in turn and the two recurse until the cycle guard throws. export CRAFTER_API bool IsTopLevelProject(); // Resolves the directory holding distributed runtime assets (Crafter.Build // module sources, wasi-runtime/, etc). Honors CRAFTER_BUILD_HOME; otherwise // derives /share/crafter-build from the running executable's path. export CRAFTER_API fs::path GetCrafterBuildHome(); // Newest mtime among the prerequisites a compiler recorded in `depFile` // (clang's `-MD -MF .d`). This is how a build step learns which // headers its source pulled in: the module scanner only reads `import` // lines, so an `#include`d file is invisible to it until the compiler // reports what it actually opened. // // Returns file_time_type::max() when freshness cannot be proven — no // depfile (nothing has compiled this artifact since depfiles were emitted, // including every object left over from an older crafter-build) or a // prerequisite that no longer exists. Callers compare the result against // their artifact's mtime, so max() reads as "rebuild". fs::file_time_type NewestPrerequisite(const fs::path& depFile); // Wildcard name matching ('*', '?') shared by the test and lint verbs. bool MatchGlob(std::string_view glob, std::string_view name); // Empty `globs` matches everything. bool MatchAny(std::span globs, std::string_view name); }