feat(tooling): Debug::Use says whether it added the library

A consumer adds its debug-only sources, the ones that import
Crafter.Debug, under the same condition Use adds the library. Testing
its own flag is not that condition: a build with the flag for a target
other than native Linux gets neither the library nor the define, and
its debug-only sources would then fail to import Crafter.Debug. Use
now returns whether it added them, and the README shows the pattern.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Jorijn van der Graaf 2026-11-01 03:21:41 +01:00
commit 6da3b274a6
Signed by: jorijnvdgraaf
GPG key ID: 2937E59CDCC1BCFB
2 changed files with 19 additions and 12 deletions

View file

@ -6,8 +6,9 @@
// #pragma crafter dependency "https://forgejo.catcrafts.net/Catcrafts/Crafter.Debug.git" project "tooling/project.cpp"
// import Crafter.Debug.Build;
// ...
// Debug::Use(cfg, { .enabled = opts.Has("--debug-api"), .flag = "--debug-api",
// .define = "MYAPP_DEBUG_API", .args = depArgs });
// const bool debugApi = Debug::Use(cfg, { .enabled = opts.Has("--debug-api"), .flag = "--debug-api",
// .define = "MYAPP_DEBUG_API", .args = depArgs });
// if (debugApi) { /* add the debug-only sources */ }
//
// crafter-build builds this module for the host and links it into the
// consumer's project.so, the way Crafter.LintRules gets in, so Use runs each
@ -164,9 +165,12 @@ export namespace Crafter::Debug {
};
// Adds Crafter.Debug to `cfg` when options.enabled, and writes the
// launcher; see the comment at the top. `at` defaults to the call site,
// which is how Use finds the consumer's directory.
void Use(Configuration& cfg, const UseOptions& options, std::source_location at = std::source_location::current()) {
// launcher; see the comment at the top. Returns whether it added the
// library and the define, which is when the consumer adds its debug-only
// sources: not for every build with the flag, since a target other than
// native Linux gets neither. `at` defaults to the call site, which is how
// Use finds the consumer's directory.
bool Use(Configuration& cfg, const UseOptions& options, std::source_location at = std::source_location::current()) {
const fs::path launcher = fs::path(at.file_name()).parent_path() / "build" / "crafter-debug";
// Only for the project crafter-build was pointed at: a consumer loaded
// as someone else's dependency has no agent driving it from its own
@ -174,17 +178,18 @@ export namespace Crafter::Debug {
const bool topLevel = IsTopLevelProject();
if (!options.enabled || !NativeLinux(cfg.target)) {
if (topLevel && !fs::exists(launcher)) WriteIfChanged(launcher, StubText(options.flag));
return;
return false;
}
Configuration* library = LocalProject({ .projectFile = Checkout() / "project.cpp", .args = options.args });
cfg.dependencies.push_back(library);
if (!options.define.empty()) cfg.defines.push_back({ options.define, "" });
if (!topLevel) return;
if (!topLevel) return true;
const auto client = std::ranges::find(library->dependencies, std::string_view("crafter.debug-cli"),
[](const Configuration* dependency) { return std::string_view(dependency->name); });
if (client == library->dependencies.end()) {
throw std::runtime_error(std::format("Crafter.Debug: {} declares no crafter.debug-cli client", (Checkout() / "project.cpp").string()));
}
WriteIfChanged(launcher, LauncherText((*client)->BinDir() / (*client)->outputName, CurrentSandbox(), options.flag));
return true;
}
}