// SPDX-License-Identifier: LGPL-3.0-only // SPDX-FileCopyrightText: Copyright (C) 2026 Catcrafts® // Three configurations: // Crafter.Debug.Core what the app and the client share (values, codecs) // crafter.debug-cli the client, crafter-debug // Crafter.Debug what an app links (returned), depending on both // The client is one of the library's dependencies only so that a consumer's // debug build compiles it in the same pass as the app; an executable adds no // link flags to what depends on it. Consumers load this file through // Debug::Use (tooling/), which also writes their launcher. import std; import Crafter.Build; namespace fs = std::filesystem; using namespace Crafter; namespace { // The configurations this file makes besides the one it returns, at // stable addresses for the pointers in `dependencies`. One set per load, // not statics: a static would keep the first load's args for every load. std::deque owned; // This file's directory. A configuration a project file makes for itself // keeps the path it is given, and "./" would later resolve against the // consumer's directory instead of this one. fs::path Root() { return fs::path(std::source_location::current().file_name()).parent_path(); } // Tests of the core, linked against it alone. constexpr std::array coreTests = { "ShouldRoundTripJson", "ShouldRoundTripAggregates", "ShouldReportDecodeErrorsWithPaths", "ShouldDescribeDefaultsAndRequired", }; // Tests of the app library. constexpr std::array libraryTests = { "ShouldInvokeCommands", "ShouldResolveWatchPaths", "ShouldRecordTimeline", "ShouldEvaluateConditions", }; } extern "C" Configuration CrafterBuildProject(std::span args) { Configuration cfg; cfg.path = "./"; cfg.name = "Crafter.Debug"; cfg.outputName = "Crafter.Debug"; cfg.type = ConfigurationType::LibraryStatic; ApplyStandardArgs(cfg, args); Configuration& core = owned.emplace_back(); core.path = Root(); core.name = "Crafter.Debug.Core"; core.outputName = "Crafter.Debug.Core"; core.type = ConfigurationType::LibraryStatic; ApplyStandardArgs(core, args); { std::array interfaces = { "interfaces/Crafter.Debug.Core-Value", "interfaces/Crafter.Debug.Core-Reflect", "interfaces/Crafter.Debug.Core-Codec", "interfaces/Crafter.Debug.Core-Result", "interfaces/Crafter.Debug.Core", }; std::array implementations = { "implementations/Crafter.Debug.Core-Value", "implementations/Crafter.Debug.Core-Codec", }; core.GetInterfacesAndImplementations(interfaces, implementations); } // The client, built for the library's target. Not through // ApplyStandardArgs: a consumer's --lib would make it a library. Configuration& client = owned.emplace_back(); client.path = Root(); client.name = "crafter.debug-cli"; client.outputName = "crafter-debug"; client.type = ConfigurationType::Executable; client.target = cfg.target; client.march = cfg.march; client.mtune = cfg.mtune; client.sysroot = cfg.sysroot; client.debug = cfg.debug; client.dependencies = { &core }; { std::array interfaces = {}; std::array implementations = { "implementations/main" }; client.GetInterfacesAndImplementations(interfaces, implementations); } cfg.dependencies = { &core, &client }; { std::array interfaces = { "interfaces/Crafter.Debug-Registry", "interfaces/Crafter.Debug-Timeline", "interfaces/Crafter.Debug-Condition", "interfaces/Crafter.Debug", }; std::array implementations = { "implementations/Crafter.Debug-Registry", "implementations/Crafter.Debug-Timeline", "implementations/Crafter.Debug-Condition", }; cfg.GetInterfacesAndImplementations(interfaces, implementations); } // Tests only when this is the project being built: a consumer's load of // this file has no use for them. if (IsTopLevelProject()) { for (const std::string_view test : coreTests) cfg.AddTest(test).Dependencies({ &core }); for (const std::string_view test : libraryTests) cfg.AddTest(test).Dependencies({ &cfg }); } return cfg; }