diff --git a/README.md b/README.md index 604cc32..817e5b5 100644 --- a/README.md +++ b/README.md @@ -56,15 +56,17 @@ extern "C" Configuration CrafterBuildProject(std::span a if (arg != "--debug-api") depArgs.emplace_back(arg); } // ...give depArgs to every other dependency too... - 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 }); + // ...your sources, plus the debug-only ones when debugApi... } ``` **What `Use` does with the flag:** -- **Flag on, native Linux target:** it adds the define and the library, from the checkout the pragma names, and writes `build/crafter-debug`. -- **Otherwise:** it adds nothing, and release builds never link Crafter.Debug. Until a debug build has run, `build/crafter-debug` is a stub that says to build one. +- **Flag on, native Linux target:** it adds the define and the library, from the checkout the pragma names, writes `build/crafter-debug`, and returns true. +- **Otherwise:** it adds nothing and returns false, and release builds never link Crafter.Debug. Until a debug build has run, `build/crafter-debug` is a stub that says to build one. + +Add your debug-only sources when `Use` returns true, not when the flag is on: a non-Linux target with the flag gets neither the library nor the define. A dependency that two paths in the build graph share must get the **same arg list on both**. Otherwise crafter-build refuses the graph with "module … built twice". Build one `depArgs` and give it to every dependency, as above. diff --git a/tooling/interfaces/Crafter.Debug.Build.cppm b/tooling/interfaces/Crafter.Debug.Build.cppm index d2c773b..0c2aee6 100644 --- a/tooling/interfaces/Crafter.Debug.Build.cppm +++ b/tooling/interfaces/Crafter.Debug.Build.cppm @@ -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; } }