The example was a placeholder that printed which build it was. It is now a headless simulation of five balls dropped onto a 10 cm floor slab at 60 ticks a second, with a bug planted the way such bugs are written: collision is checked only where each step lands, so the ball dropped from 60 m, at 34 m/s, steps over the slab and falls forever. It shows the consumer side end to end: - Basic.DebugShim forwards Pump, Advance, QuitRequested, Log, Check, Emit and Sample to Crafter.Debug in debug builds and does nothing in plain ones, so the simulation and main have no #ifdef but the session's. - Basic.DebugCommands, compiled only when Debug::Use returns true, registers World_Spawn, World_Reset, World_Clear and Ball_Get, and watches for the physics, the floor and the balls. - The simulation checks each ball stays above the floor, emits Bounce and samples the fastest ball, so `pause --on-check`, `wait --event` and `trace --history` have something to show. Driven over the real transport, it shows the whole loop: `log --level warn` names the ball, `pause --on-check` stops the frame it fails, `set physics.substeps 4` and `call World_Reset` show the fix holds before any code changes. The plain build simulates ten seconds and prints that one ball fell through. Its agent notes describe the app without the bug. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
38 lines
1.7 KiB
C++
38 lines
1.7 KiB
C++
// SPDX-License-Identifier: MIT
|
|
// SPDX-FileCopyrightText: Copyright (C) 2026 Catcrafts®
|
|
|
|
import std;
|
|
import Crafter.Build;
|
|
// This checkout's own build helper. A consumer elsewhere names the repository:
|
|
// #pragma crafter dependency "https://forgejo.catcrafts.net/Catcrafts/Crafter.Debug.git" project "tooling/project.cpp"
|
|
#pragma crafter dependency "../.." project "tooling/project.cpp"
|
|
import Crafter.Debug.Build;
|
|
namespace fs = std::filesystem;
|
|
using namespace Crafter;
|
|
|
|
extern "C" Configuration CrafterBuildProject(std::span<const std::string_view> args) {
|
|
Configuration cfg;
|
|
cfg.path = "./";
|
|
cfg.name = "Basic";
|
|
cfg.outputName = "basic";
|
|
cfg.type = ConfigurationType::Executable;
|
|
const ArgQuery opts = ApplyStandardArgs(cfg, args);
|
|
|
|
// What every dependency gets: this project's args minus the flags only it
|
|
// reads. A dependency that two paths share must get one list on both.
|
|
std::vector<std::string> depArgs;
|
|
for (const std::string_view arg : args) {
|
|
if (arg != "--debug-api") depArgs.emplace_back(arg);
|
|
}
|
|
const bool debugApi = Debug::Use(cfg, { .enabled = opts.Has("--debug-api"), .flag = "--debug-api", .define = "BASIC_DEBUG_API", .args = depArgs });
|
|
|
|
std::vector<fs::path> interfaces = { "interfaces/Basic.DebugShim", "interfaces/Basic.World" };
|
|
std::vector<fs::path> implementations = { "implementations/Basic.World", "implementations/main" };
|
|
// The agent's commands and watches, in debug builds only.
|
|
if (debugApi) {
|
|
interfaces.emplace_back("interfaces/Basic.DebugCommands");
|
|
implementations.emplace_back("implementations/Basic.DebugCommands");
|
|
}
|
|
cfg.GetInterfacesAndImplementations(interfaces, implementations);
|
|
return cfg;
|
|
}
|