diff --git a/_docs/46-cpp-toolbox.md b/_docs/46-cpp-toolbox.md new file mode 100644 index 0000000..ec453ba --- /dev/null +++ b/_docs/46-cpp-toolbox.md @@ -0,0 +1,815 @@ +--- +title: "The C++ toolbox: CMake presets, Conan lockfiles, and GCC-vs-clang parity" +order: 46 +part: "Appendices: Tooling" +description: "cpp-toolbox is one C++23 binary and the full toolchain wrapped around it -- seven CMakePresets.json configurations sharing one _base, a committed Conan 2 lockfile for an isolated fmt sub-target, and a GCC-vs-clang parity gate on toolbox report -- read by clang-tidy, clang-format, and a custom gdb Python pretty-printer, with ccache and mold demonstrated but absent on the reference host. Verified on the Fedora 44 host: verify.lua PASS 20/FAIL 0, GCC and clang release builds byte-identical (digest=0x481984990deee5ff, diff empty), UBSan catching a seeded signed-integer overflow at toolbox.cpp:43, and gdb rendering Digest(0x481984990deee5ff) through toolbox-printers.py." +duration: "50 minutes" +--- + +Chapter 45 opened this part with three suites that watch a whole fleet from +outside — Cockpit's console, SystemTap's kernel modules, PCP's pull-based +metrics — and none of them cared what language produced the process they +were watching. This chapter turns all the way around: one language, one +small program, and every tool that touches it before it ever runs. Chapter +31 already gave C++ one paragraph of toolbelt each — `perf`, `clang-tidy`, +GCC's `-fanalyzer` — on the way to covering Go and Rust too. This chapter +reopens exactly that toolchain and does not move on. `toolbox` is a single +C++23 binary, engineered so that every tool pointed at it — two compilers, +a build-system generator, a package manager, a static analyzer, a +formatter, a debugger that needs help understanding a custom type — has +something concrete to catch or confirm, not just a clean exit. + +The shape of the problem is specific to C++. Go ships one command +(`go build`) and Rust ships one command (`cargo build`); C++ ships a +language standard and leaves the rest — which compiler, which generator, +which package manager, whether the debugger understands your types out of +the box — as choices a project has to make explicit. `toolbox` makes seven +of those choices as seven named `CMakePresets.json` configurations, pins a +Conan 2 dependency to an exact, committed lockfile, and prints one +deterministic digest so that GCC and clang can be asked, byte for byte, +whether they agree. + +{% include excalidraw.html + file="46-cmake-preset-graph" + alt="A tree diagram. At the top, a hidden _base configure preset (generator Ninja, binaryDir sourceDir/build/presetName) fans out to six visible presets: release (RelWithDebInfo, GCC), debug (Debug, GCC), asan (Debug + -fsanitize=address,undefined), and ubsan (Debug + -fsanitize=undefined -fno-sanitize-recover=undefined) sit in one column; release-clang and debug-clang sit beside them, each drawn inheriting from release/debug respectively with an arrow labeled inherits plus a CMAKE_CXX_COMPILER=clang++ override. Each of the six feeds its own build/ directory box below it. A seventh preset, conan, also inherits _base but is drawn held apart in a dashed box labeled isolated -- only reachable when TOOLBOX_ENABLE_CONAN=ON, needed by no other preset, so the default build never touches Conan. A caption note names which preset the parity gate uses (release vs release-clang), which the UBSan gate uses (ubsan), and which gdb uses (debug)." + caption="Figure 46.1 — the CMakePresets inheritance graph: one _base config fanning out to release/debug/asan/ubsan and their clang twins, each into build/${presetName}, with the Conan sub-target preset held apart so the default build needs no Conan" %} + +> **Tools used** — `cmake` and `ninja` (host; both are hard requirements in +> `scripts/check-host.sh`), `g++` and `clang++` (host; both are hard +> requirements in `scripts/check-host.sh`), `clang-tidy` and `clang-format` +> (host; ship from the same LLVM toolchain `check-host.sh` verifies via +> `clang`, but are not separately gated by it), `gdb` plus its Python +> pretty-printer extension (host; `gdb` is a hard requirement in +> `scripts/check-host.sh`), `conan` (host; a soft/warn entry in +> `scripts/check-host.sh` — a missing Conan degrades that section's gate to +> an informational `SKIP:`, it never fails the example), and `ccache`/`mold` +> (host; demonstrated in this chapter's recipes but absent on the reference +> host, so those two sections are marked unverified below). No VM, no root, +> no LGTM stack — `examples/46-cpp-toolbox` is `mode: local` in +> `examples/manifest.yaml`. + +Because the C++ toolchain is itself the subject, `examples/46-cpp-toolbox/` +ships `langs: [cpp]` only — a Go or Rust build would have nothing new to +say about a `CMakePresets.json` file or a `.clang-tidy` config. Every code +block below is a plain fenced `cpp`/`console`/`json` block, the way Chapter +44's Go runtime chapter presented Go alone; there is no language-tab +include to reach for when there is only one language in the room. + +## CMake presets in depth + +`cpp/CMakePresets.json` declares schema `"version": 6` and one hidden base +every other preset inherits from: + +```json +{ + "version": 6, + "cmakeMinimumRequired": { "major": 3, "minor": 25, "patch": 0 }, + "configurePresets": [ + { + "name": "_base", + "hidden": true, + "generator": "Ninja", + "binaryDir": "${sourceDir}/build/${presetName}", + "cacheVariables": { + "CMAKE_EXPORT_COMPILE_COMMANDS": "ON" + } + }, +``` + +`hidden: true` keeps `_base` out of every preset-selection UI and off +`cmake --list-presets` — it exists only to be inherited from, never chosen +directly. The one line worth reading twice is `binaryDir`: +{% raw %}`"${sourceDir}/build/${presetName}"`{% endraw %} means every preset +that inherits `_base` gets its own build directory for free, named after +itself — `build/release`, `build/debug`, `build/asan`, and so on — with no +preset having to repeat the path. `{% raw %}${presetName}{% endraw %}` is +CMake Presets' own variable, resolved at configure time to whichever +preset's name you passed to `--preset`; it is not something this chapter's +own tooling or Jekyll ever expands. + +Six more presets inherit `_base` (a seventh, `conan`, is covered on its +own below): + +| Preset | Inherits | Compiler | Build type / flags | +|---|---|---|---| +| `release` | `_base` | GCC (default) | `RelWithDebInfo` (`-O2 -g`) | +| `debug` | `_base` | GCC (default) | `Debug` | +| `asan` | `_base` | GCC (default) | `Debug`, `-fsanitize=address,undefined` | +| `ubsan` | `_base` | GCC (default) | `Debug`, `-fsanitize=undefined -fno-sanitize-recover=undefined` | +| `release-clang` | `release` | clang | same as `release`, compiler overridden | +| `debug-clang` | `debug` | clang | same as `debug`, compiler overridden | + +`release-clang` and `debug-clang` show the other half of `inherits`: they +inherit from `release`/`debug` — not from `_base` — and add exactly two +cache variables on top: + +```json + { + "name": "release-clang", + "inherits": "release", + "displayName": "Release (clang)", + "cacheVariables": { + "CMAKE_C_COMPILER": "clang", + "CMAKE_CXX_COMPILER": "clang++" + } + }, +``` + +Everything else — the `RelWithDebInfo` build type, `binaryDir`, compile +commands export — comes along from `release` unchanged; only the compiler +differs. That is the whole mechanism the parity gate below leans on: two +presets that are identical except for which compiler builds them. `asan` +and `ubsan` look similar to each other but serve different jobs on +purpose: `asan` combines `-fsanitize=address,undefined` with no +`-fno-sanitize-recover` — a general bug-hunting build that keeps running +and reports every violation it finds — while `ubsan` adds +`-fno-sanitize-recover=undefined`, so the *first* undefined-behavior +violation aborts the process immediately with a nonzero exit. That +determinism is exactly what a gate that has to produce a fixed exit code +needs, which is why "UBSan recipe" below reaches for `ubsan`, not `asan`. + +`buildPresets` is a flat, 1:1 mirror of the seven configure presets — each +build preset just names the configure preset it drives: + +```json + "buildPresets": [ + { "name": "release", "configurePreset": "release" }, + { "name": "debug", "configurePreset": "debug" }, + { "name": "asan", "configurePreset": "asan" }, + { "name": "ubsan", "configurePreset": "ubsan" }, + { "name": "release-clang", "configurePreset": "release-clang" }, + { "name": "debug-clang", "configurePreset": "debug-clang" }, + { "name": "conan", "configurePreset": "conan" } + ] +``` + +Once a configure preset exists, its build preset is `cmake --build +--preset ` and nothing more — no per-preset generator flags, no +target list, because `binaryDir` and `generator` already came from +`_base`. + +## Conan 2 lockfiles + +The seventh preset, `conan`, is the odd one out on purpose: + +```json + { + "name": "conan", + "inherits": "_base", + "displayName": "Conan 2 sub-target (fmt, isolated)", + "cacheVariables": { + "CMAKE_BUILD_TYPE": "Release", + "CMAKE_TOOLCHAIN_FILE": "${sourceDir}/build/conan/generators/conan_toolchain.cmake", + "TOOLBOX_ENABLE_CONAN": "ON" + } + } +``` + +`TOOLBOX_ENABLE_CONAN` is a CMake `option()` defined in +`cpp/CMakeLists.txt`, off by default: + +``` +option(TOOLBOX_ENABLE_CONAN "Build the Conan-provided fmt sub-target" OFF) +if(TOOLBOX_ENABLE_CONAN) + add_subdirectory(conan) +endif() +``` + +Only the `conan` preset turns it `ON`; every other preset — including +`release`, what `./demo.sh cpp build` and fedora:44's CI build-smoke both +use — never evaluates `cpp/conan/` and never needs Conan installed at all. +That isolation is the whole design decision this section is about: a +tutorial reader without Conan on `PATH` still gets a clean default build, +and CI never has to install a package manager it doesn't otherwise need. + +`cpp/conan/conanfile.py` is a small, self-contained Conan 2 consumer that +pulls exactly one dependency: + +```python +class ToolboxConanDemo(ConanFile): + name = "toolbox-conan-demo" + version = "1.0.0" + settings = "os", "compiler", "build_type", "arch" + + def requirements(self): + self.requires("fmt/11.0.2") + + def layout(self): + # Generated files land in build/conan/generators/ (relative to the + # --output-folder passed on the CLI), matching the "conan" + # CMakePresets.json preset's CMAKE_TOOLCHAIN_FILE path. + self.folders.generators = "generators" + + def generate(self): + CMakeDeps(self).generate() + CMakeToolchain(self).generate() +``` + +`self.folders.generators = "generators"` is the line that ties this file +to the preset above: it makes Conan write `conan_toolchain.cmake` into +`build/conan/generators/`, exactly where the `conan` preset's +`CMAKE_TOOLCHAIN_FILE` looks for it. Get that path wrong in either file and +`cmake --preset conan` fails to configure before a single line of C++ ever +compiles. + +The lockfile is what makes this reproducible rather than "whatever `fmt` +version happens to resolve today": `cpp/conan/conan.lock` is committed and +pins one exact package revision, timestamp included: + +```json +{ + "version": "0.5", + "requires": [ + "fmt/11.0.2#7b5e2770c1ccb3d4af9b4f6762135645%1778145873.016" + ], + "build_requires": [], + "python_requires": [], + "config_requires": [] +} +``` + +`conan install conan --output-folder=build/conan --build=missing +--lockfile=conan/conan.lock` resolves against that exact revision, not +whatever `fmt/11.0.2` happens to mean on the day someone else runs it — the +same discipline `go.sum`/`Cargo.lock` give the other two languages, +expressed in Conan's own lockfile format. On this host, that install, the +`conan` preset's configure and build, and the resulting binary all ran for +real: + +```console +$ conan install conan -of build/conan --build=missing --lockfile=conan/conan.lock # fmt/11.0.2 from lockfile +$ cmake --preset conan && cmake --build --preset conan # builds toolbox-conan-demo +$ ./build/conan/toolbox-conan-demo → toolbox-conan: fmt sub-target ok (exit 0) +``` + +`toolbox-conan-demo`'s own source is three lines that only exist to prove +the link succeeded — it never touches `toolbox`'s digest, so nothing about +Conan can affect the GCC-vs-clang parity story below: + +```cpp +#include + +int main() { + fmt::print("toolbox-conan: fmt sub-target ok\n"); + return 0; +} +``` + +## GCC-vs-clang parity — and where the two compilers disagree + +`toolbox report` exists to make a hard question answerable with a `diff`: +does the *exact same source*, built by two different compilers, produce +the exact same bytes? Making that question answerable at all takes care — +floats round differently, pointer values differ between runs, timestamps +differ by definition, and unordered-container iteration order is +compiler- and library-defined. `toolbox report` avoids every one of those +by construction: it hashes a fixed embedded payload with FNV-1a and prints +only integers and strings. + +```cpp +struct Digest { + std::uint64_t fnv; +}; + +// FNV-1a over a fixed, embedded byte array. Integer/string-only, no floats, +// no addresses, no timing, no unordered-container iteration -- the same +// input bytes must produce the same digest bit-for-bit on every conforming +// C++23 compiler, which is what the GCC-vs-clang parity gate (ch46 Sec. +// "GCC-vs-clang parity") relies on. +Digest fnv1a(const std::uint8_t* data, std::size_t len); +``` + +```cpp +int cmd_report() { + const Digest d = fnv1a(kPayload.data(), kPayload.size()); + const std::string label = decorate_label("report"); + std::printf("toolbox report: label=%s payload_len=%zu digest=0x%016llx\n", label.c_str(), + kPayload.size(), static_cast(d.fnv)); + return 0; +} +``` + +Built once with the `release` preset (GCC) and once with `release-clang`, +`toolbox report`'s output is identical to the byte, and it matches a fixed +literal this chapter pins in `verify.lua`: + +```console +$ ./cpp/build/release/toolbox report +toolbox report: label=[toolbox] report payload_len=16 digest=0x481984990deee5ff +$ ./cpp/build/release-clang/toolbox report +toolbox report: label=[toolbox] report payload_len=16 digest=0x481984990deee5ff +$ diff <(release/toolbox report) <(release-clang/toolbox report) → (empty, exit 0) +``` + +That empty `diff` is the chapter's central claim, made falsifiable: two +independently built binaries, one compiled by GCC 16.1.1, one by clang +22.1.8, from the identical source, land on the identical 64-bit digest, +`0x481984990deee5ff`. + +Byte-identical *output* does not mean byte-identical *diagnostics* — GCC +and clang disagree constantly about how to phrase the same finding, which +is worth seeing directly rather than taking on faith. Two comparisons run +this session, against this exact source, make the point at both ends of +the build: compile time and run time. + +At compile time, a scratch copy of `toolbox.cpp` with one semicolon +deleted from `cmd_report` (`const std::string label = +decorate_label("report")`, no trailing `;`) gets two differently +*located* errors for the identical mistake: + +```console +$ g++ -std=c++23 -c toolbox.cpp -o /dev/null +toolbox.cpp: In function 'int {anonymous}::cmd_report()': +toolbox.cpp:31:5: error: expected ',' or ';' before 'std' + 31 | std::printf("toolbox report: label=%s payload_len=%zu digest=0x%016llx\n", label.c_str(), + | ^~~ +$ clang++ -std=c++23 -c toolbox.cpp -o /dev/null +toolbox.cpp:30:55: error: expected ';' at end of declaration + 30 | const std::string label = decorate_label("report") + | ^ + | ; +1 error generated. +``` + +GCC keeps parsing past the missing `;` and reports the error where it +first becomes unrecoverable — line 31, the *next* statement — with a +message phrased around what it expected there (`','` or `';'` before +`std`). clang stops exactly where the semicolon should have gone — line +30, column 55, the true end of the broken declaration — and even offers a +fix-it caret pointing at the missing character. Same bug, two real and +differently useful answers to "where is it." + +At run time, the seeded overflow this chapter uses for the UBSan gate +(below) shows the same kind of drift. The hard-gated `ubsan` preset builds +with GCC by default; building the identical flags with clang instead (an +ad hoc build, not one of the seven named presets) catches the same defect +one column earlier and adds a line GCC's runtime does not print: + +```console +$ ./cpp/build/ubsan/toolbox defect overflow # ubsan preset, GCC (default compiler) +toolbox defect overflow: max_value=2147483647 +.../cpp/src/toolbox.cpp:43:34: runtime error: signed integer overflow: 2147483647 + 1 cannot be represented in type 'int' +$ clang++ -O1 -g -fsanitize=undefined -fno-sanitize-recover=undefined toolbox.cpp digest.cpp smell.cpp -o /tmp/toolbox-clang-ubsan +$ /tmp/toolbox-clang-ubsan defect overflow # same flags, clang, ad hoc (not a named preset) +toolbox defect overflow: max_value=2147483647 +toolbox.cpp:43:32: runtime error: signed integer overflow: 2147483647 + 1 cannot be represented in type 'int' +SUMMARY: UndefinedBehaviorSanitizer: undefined-behavior toolbox.cpp:43:32 +``` + +Column 34 is the literal `1` in `max_value + 1`; column 32 is the `+` +operator itself — GCC's libubsan blames the operand, clang's blames the +operation, and only clang's runtime appends a `SUMMARY:` line by default. +Neither is wrong. Both are real diagnostics for the identical undefined +behavior, and `verify.lua`'s own assertion (quoted in "Errors, three ways" +below) only matches the fixed substring `runtime error: signed integer +overflow`, precisely because the rest of the line is not something either +compiler owes you stability on across versions. + +## How the code works + +`toolbox`'s whole source is four small translation units. `src/toolbox.cpp` +is the dispatcher: `report` computes the FNV-1a digest and prints it, +`defect overflow` seeds the UBSan trap, anything else prints usage and +exits 2. + +```cpp +int cmd_defect_overflow() { + // `volatile` blocks the compiler from constant-folding the overflow at + // compile time -- the point is a *runtime* UBSan trap, not a compiler + // diagnostic. This one statement is the entire seeded defect. + volatile int max_value = INT_MAX; + std::printf("toolbox defect overflow: max_value=%d\n", max_value); + std::fflush(stdout); // UBSan's trap handler may skip normal atexit flushing. + int overflowed = max_value + 1; // UB: signed integer overflow. + std::printf("unreachable: overflowed=%d\n", overflowed); + return 0; +} +``` + +`volatile` is doing real work in that function, not decoration: without +it, a compiler is entitled to see `INT_MAX + 1` as a compile-time constant +expression and either fold it away or reject the translation unit outright +— neither of which is the point. Marking `max_value` `volatile` forces the +addition to happen at run time, where only a sanitizer or the CPU's own +overflow flag can catch it. + +`src/digest.hpp`/`digest.cpp` hold the `Digest` type and the FNV-1a +implementation quoted above; `src/smell.hpp`/`smell.cpp` hold one +deliberate, behavior-preserving defect for clang-tidy to find (next +section). Nothing in any of the four files depends on which compiler built +it — no `#ifdef __clang__`, no compiler-specific pragma — which is exactly +what makes the parity claim a claim about the *language standard*, not +about code written to please one compiler over another. + +{% include excalidraw.html + file="46-toolbox-pipeline" + alt="One source box, toolbox.cpp plus digest and smell translation units, splits into two build arrows -- one through GCC, one through clang -- each landing in its own build/ binary. Both binaries feed into a report command box, and their outputs converge on an amber diff box marked empty, the byte-identical parity gate, digest=0x481984990deee5ff. Below the source box, a static-analysis arm branches off into clang-tidy (flagging performance-unnecessary-value-param in smell.cpp) and clang-format --dry-run --Werror (clean on tracked sources, nonzero on a misformatted fixture). A separate runtime arm branches into the ubsan build, which traps the seeded signed-integer overflow with an abort icon, and the debug build, which feeds gdb plus a Python pretty-printer producing Digest(0x481984990deee5ff). Two dashed accelerator boxes, ccache and mold, sit off to the side labeled shown, not verified on this host." + caption="Figure 46.2 — the toolbox pipeline: one source built by two compilers into byte-identical output (the parity gate), with static tools (clang-tidy, clang-format) and runtime tools (UBSan, gdb pretty-printers) around it, and ccache/mold as optional accelerators" %} + +## Errors, three ways + +With one language and one binary, "three ways" means three different +*tools* surfacing an error about the same source, not three languages +producing the same message. The compile-time diagnostic above — GCC's +`expected ',' or ';' before 'std'` against clang's `expected ';' at end of +declaration` for an identical missing semicolon — is the first: a mistake +the compiler itself refuses to build past. + +The second is a finding a compiler never flags at all, because nothing +about it is *wrong* — only wasteful. `src/smell.hpp` documents its own +defect: + +```cpp +// Deliberate, behavior-preserving smell for the clang-tidy gate (ch46 Sec. +// "Errors, three ways" -- the tidy finding). `label` is only ever read, so +// taking it by value forces an avoidable copy on every call; clang-tidy's +// performance-unnecessary-value-param flags this parameter, and the fix is +// `const std::string&`. Left as `std::string` on purpose -- do not "fix" +// this without re-pinning the tidy chapter section. +std::string decorate_label(std::string label); +``` + +`src/smell.cpp` is the four-line definition the declaration above +describes, and its line 3 is exactly where the warning below lands: + +```cpp +std::string decorate_label(std::string label) { + return "[toolbox] " + label; +} +``` + +`clang-tidy -p build/release src/smell.cpp` reads the compile-commands +database `CMAKE_EXPORT_COMPILE_COMMANDS: ON` produces for every preset, and +flags exactly the parameter the comment predicts: + +```console +$ clang-tidy -p build/release src/smell.cpp +/…/cpp/src/smell.cpp:3:40: warning: the parameter 'label' of type 'std::string' ... [performance-unnecessary-value-param] +``` + +`.clang-tidy` pins the check name, not the message wording, precisely +because message text drifts across clang-tidy releases the same way the +UBSan line did above: + +```yaml +Checks: > + bugprone-*, + modernize-*, + performance-*, + readability-*, + -modernize-use-trailing-return-type, + -readability-identifier-length +WarningsAsErrors: '' +HeaderFilterRegex: '.*' +FormatStyle: file +``` + +The third is the UBSan runtime abort already introduced above, this time +as the pinned gate `verify.lua` actually runs: + +```lua +local ubsan_run = checks.run("./cpp/build/ubsan/toolbox defect overflow") +checks.expect_exit(ubsan_run, 1, "cpp: ubsan build exits 1 on the seeded overflow") +checks.expect_match(ubsan_run.out, "runtime error: signed integer overflow", + "cpp: UBSan reports 'runtime error: signed integer overflow'") +``` + +Three surfaces, three different moments a defect becomes visible: a +compiler refusing to finish parsing, a static analyzer reading a +compile-commands database with no execution at all, and a sanitizer +watching one specific arithmetic operation at run time — and every one of +them names a different line, or a different column on the same line, for +a reason grounded in how that particular tool works. + +## Concurrency lens: the build graph's own parallelism + +Every earlier concurrency lens in this book — Chapter 25's threads, +Chapter 44's GMP scheduler — asked how a *running program* multiplexes +work. This chapter's build has no threads of its own to watch, but the +tool building it does: Ninja's default job count is bounded by the host's +CPU count, and every one of `toolbox`'s translation units that has no +dependency on another can compile in parallel — `cmake --build --preset +release -- -j$(nproc)` (or simply `-j`, Ninja's own auto-detected default) +hands `digest.cpp`, `smell.cpp`, and `toolbox.cpp` to as many parallel +`g++`/`clang++` invocations as there are idle cores, then serializes only +at the final link, the one step that needs every object file to exist +first. Three translation units is too small a graph to *see* that +parallelism move the needle on this chapter's own build times, but the +dependency shape — many independent compiles fanning in to one serial +link — is the same shape a much larger C++ project's build graph has at +any size, just wider. + +The link step itself is where a second, differently-parallel tool would +matter more directly: `mold`, "a Modern Linker," parallelizes symbol +resolution and section layout internally, the way a traditional +single-threaded linker (`ld.bfd`) never does — this book's own earlier +concurrency lenses (Chapter 44's M:N scheduler, Chapter 25's thread pool) +are about overlapping *independent* units of work, and `mold`'s internal +design is the identical idea applied to the one step Ninja itself cannot +parallelize away, because a link has to see every object file at once. +`mold` is demonstrated, not verified, in "lint, format, sanitize, +ccache, mold" below — it is absent on the reference host, so its +speed-up is a documented recipe here, not a measured number. + +## gdb pretty-printers + +`Digest` is a one-field aggregate, and without help gdb prints exactly +that — a raw struct, no more legible than reading the eight bytes by +hand. `cpp/toolbox-printers.py` teaches gdb what the field means: + +```python +class DigestPrinter: + def __init__(self, val): + self.val = val + + def to_string(self): + fnv = int(self.val["fnv"]) & 0xFFFFFFFFFFFFFFFF + return "Digest(0x{:016x})".format(fnv) + + +def _lookup(val): + t = val.type.unqualified().strip_typedefs() + if t.tag == "Digest": + return DigestPrinter(val) + return None + + +def register_printers(): + gdb.pretty_printers.append(_lookup) +``` + +`_lookup` is gdb's pretty-printer registration contract: given a value, +return a printer object if you know how to render its type, or `None` to +let gdb (or the next registered printer) try something else. Matching on +`t.tag == "Digest"` after `strip_typedefs()` means the printer fires +regardless of `const`/reference qualifiers on the value gdb hands it — +`Digest`, `const Digest&`, and `Digest&` all normalize to the same tag. +`cpp/.gdbinit` is what loads it: + +``` +set debuginfod enabled off +source cpp/toolbox-printers.py +``` + +Run from the example root against the `debug` preset's build, with a +breakpoint on the line that first constructs a `Digest`: + +```console +$ gdb -batch -x cpp/.gdbinit -ex 'b toolbox.cpp:30' -ex run -ex 'p d' --args cpp/build/debug/toolbox report +Breakpoint 1, (anonymous namespace)::cmd_report () at .../toolbox.cpp:30 +30 const std::string label = decorate_label("report"); +$1 = Digest(0x481984990deee5ff) +``` + +`$1 = Digest(0x481984990deee5ff)` — the exact same digest the parity gate +printed above, this time read straight out of the stopped process's stack +by a debugger that would otherwise have shown `{fnv = 5202111637775040511}` +(the same 64-bit value, decimal, with no field name to explain what it +is). The pretty-printer changes nothing about what gdb *has*; it only +changes how much of that the type system throws away by default. + +## Lint, format, sanitize, ccache, mold — the recipes + +**clang-tidy** and **clang-format** were both exercised for real above and +in "Errors, three ways"; the format half of that pair is worth showing on +its own, because — unlike a `warning:` — a clean formatter run is silent, +and its *effect* is only visible in the exit code: + +```console +$ clang-format --dry-run --Werror src/*.cpp src/*.hpp conan/src/*.cpp # tracked sources +$ echo $? +0 +$ clang-format --dry-run --Werror fixtures/misformatted.cpp # deliberately misformatted, NOT built +$ echo $? +1 +``` + +`cpp/fixtures/misformatted.cpp` exists for exactly this: a file +`clang-format --dry-run --Werror` is guaranteed to reject, kept out of +`CMakeLists.txt`'s `add_executable` sources entirely so it never affects a +build, only this one check. `.clang-format` pins the style being checked +against: + +```yaml +BasedOnStyle: LLVM +Language: Cpp +Standard: Latest +IndentWidth: 4 +ColumnLimit: 100 +PointerAlignment: Left +AllowShortFunctionsOnASingleLine: Inline +``` + +**Sanitizing** is the `asan`/`ubsan` presets already covered above — +`cmake --preset ubsan && cmake --build --preset ubsan` is the exact +recipe `verify.lua` runs for the hard-gated overflow catch; `cmake +--preset asan` is the same idea without `-fno-sanitize-recover`, for +exploratory bug-hunting where you want the process to keep running and +report every violation instead of aborting on the first. + +**ccache** and **mold** are the two tools this chapter shows without +being able to verify on the reference host — neither is installed here: + +```console +$ command -v ccache; echo "exit=$?" +exit=1 +$ command -v mold; echo "exit=$?" +exit=1 +``` + +The recipe for each is real, just not run: adding +`"CMAKE_CXX_COMPILER_LAUNCHER": "ccache"` to a preset's `cacheVariables` +makes every compile invocation go through `ccache` first, which hashes the +preprocessed source plus compiler flags and serves a cache hit instead of +re-invoking the compiler on an unchanged translation unit — the second +build of an unchanged tree turning into a cache lookup instead of a +recompile is the effect a real run would show. `mold` swaps in as the +linker with `"CMAKE_EXE_LINKER_FLAGS": "-fuse-ld=mold"`, and a binary it +actually linked would carry its own name in the `.comment` ELF section, +checkable with `readelf -p .comment build/release/toolbox | grep mold` +with no debugger needed at all. Both recipes are shown here exactly as +they would be run; neither produced output on this host, and the status +footer below marks them accordingly. + +## Build, run, observe + +```console +[host]$ cd examples/46-cpp-toolbox && ./demo.sh cpp build +``` + +That builds the `release` preset (GCC). Hand-running the two compilers' +builds side by side is what "GCC-vs-clang parity" above quoted verbatim; +the deliberately seeded defects follow the same shape: + +```console +[host]$ ./cpp/build/release/toolbox report +toolbox report: label=[toolbox] report payload_len=16 digest=0x481984990deee5ff +[host]$ cd cpp && cmake --preset ubsan && cmake --build --preset ubsan && cd .. +[host]$ ./cpp/build/ubsan/toolbox defect overflow +toolbox defect overflow: max_value=2147483647 +.../cpp/src/toolbox.cpp:43:34: runtime error: signed integer overflow: 2147483647 + 1 cannot be represented in type 'int' +``` + +The full gate, exactly as run this session: + +```console +[host]$ LSP_LANG=cpp REPO_ROOT=$(cd ../.. && pwd) lua verify.lua +... +PASS 20 / FAIL 0 +[host]$ python3 scripts/test-all-examples.py --only 46-cpp-toolbox +... +1 passed, 0 failed, 0 skipped +``` + +Twenty real assertions, none of them a bare exit code: the GCC/clang +parity chain (build both, run both, diff both, match the literal digest — +seven assertions on its own), the `ubsan` build and its exact runtime-error +substring, the `debug` build and gdb's pretty-printed `Digest`, the +`clang-tidy` check-name token, `clang-format`'s clean-tracked/dirty-fixture +pair, and the Conan install-configure-build-run chain ending in +`toolbox-conan: fmt sub-target ok`. + +## Cross-check: two compilers, one digest + +The claim this chapter is built around is falsifiable in the strictest +sense — either two independently-built binaries print the same 64-bit +number or they don't — and it was actually checked, not assumed. GCC +16.1.1 and clang 22.1.8 are different compiler front-ends, different +optimizers, and different code generators, sharing nothing but the C++23 +standard and the source text `toolbox.cpp`/`digest.hpp`/`digest.cpp` +compile from. `diff <(release/toolbox report) <(release-clang/toolbox +report)` — empty, exit 0 — is the cross-check the parity section already +walked through in detail: it is not "the same shape of output," it is the +identical byte sequence, `digest=0x481984990deee5ff`, arrived at by two +compilers that disagree, demonstrably, about how to phrase both a +compile-time syntax error and a runtime UBSan trap for the same source. +That disagreement on *diagnostics* against agreement on *output* is the +whole point: the C++23 standard constrains what a program must compute, +not what a compiler must say while compiling or running it, and +`toolbox report` was written specifically to only ever exercise the part +both compilers are required to agree on. + +`verify.lua`'s own parity assertions are the automated version of the same +check: + +```lua +local gcc_report = checks.run("./cpp/build/release/toolbox report") +checks.expect_exit(gcc_report, 0, "cpp: GCC-built toolbox report runs") +checks.expect_match(gcc_report.out, lit(EXPECTED_REPORT), + "cpp: GCC-built report equals the expected literal") + +local clang_report = checks.run("./cpp/build/release-clang/toolbox report") +checks.expect_exit(clang_report, 0, "cpp: clang-built toolbox report runs") +checks.expect_match(clang_report.out, lit(EXPECTED_REPORT), + "cpp: clang-built report equals the expected literal") + +local parity = checks.run( + "bash -c 'diff <(./cpp/build/release/toolbox report) <(./cpp/build/release-clang/toolbox report)'") +checks.expect_exit(parity, 0, + "cpp: GCC vs clang report output is byte-identical (empty diff)") +``` + +Three assertions, not one: both binaries individually match a fixed +literal (so neither compiler quietly drifted from the expected digest), +*and* they match each other directly via `diff`. Either check alone would +be suggestive; both together are the proof this section's opening claim +needed. + +## Where this sits next to the book's other tooling chapters + +Three earlier chapters already covered pieces of this ground, and this +chapter deliberately does not re-teach any of them: + +- **Chapter 31** ("Per-Language Toolbelts") gave C++ one column of a + three-language *profiling* comparison — `perf`, `clang-tidy`, + `-fanalyzer` — next to Go's `pprof` and Rust's `cargo flamegraph`. This + chapter is the opposite shape: one language, covered in depth, and it + never profiles anything. +- **Chapter 28** ("gdb and Remote Debugging") is where `gdb`'s core + mechanics live — reading a core file, `gdbserver`/`target remote`, + `rust-gdb`'s type-aware rendering. This chapter assumes all of that and + adds exactly one new idea: a pretty-printer *you write* for *your own* + type, not one that ships with libstdc++. +- **Chapter 29** ("valgrind, Sanitizers, and Miri") built the full five-bug + ASan/UBSan/TSan/valgrind/miri catch-or-miss matrix. This chapter uses + exactly one corner of that matrix — UBSan on a signed-integer overflow — + and spends its real depth budget on CMake presets and Conan lockfiles + instead, ground Chapter 29 never touches. + +What is genuinely new here — preset inheritance mechanics, a committed +Conan 2 lockfile, cross-compiler byte parity, a hand-written gdb Python +printer, and `.clang-tidy`/`.clang-format` authored rather than merely +invoked — has no earlier chapter to point back to instead. + +## What you learned + +- **`CMakePresets.json`'s inheritance is the whole mechanism**: a hidden + `_base` preset supplies `generator`, {% raw %}`binaryDir: + "${sourceDir}/build/${presetName}"`{% endraw %}, and compile-commands + export once; `release-clang`/`debug-clang` inherit from `release`/`debug` + (not `_base`) and override only the compiler, and `asan` vs `ubsan` + differ by exactly one flag (`-fno-sanitize-recover=undefined`) that turns + "report every violation" into "abort deterministically on the first." +- **A Conan sub-target can be real and still not gate the default build**: + `cpp/conan/`'s `conanfile.py` + committed `conan.lock` (`fmt/11.0.2`, + exact revision) only builds when the isolated `conan` preset turns + `TOOLBOX_ENABLE_CONAN` on — the `release` preset, `./demo.sh cpp build`, + and fedora:44's CI build-smoke never evaluate `cpp/conan/` at all. +- **Byte-identical output and identical diagnostics are different + claims**: GCC 16.1.1 and clang 22.1.8 produced the exact same + `digest=0x481984990deee5ff` for `toolbox report` (empty `diff`), while + disagreeing on where to anchor a missing-semicolon error (line 31 vs. + line 30, column 55) and how to phrase the identical UBSan trap (column + 34 vs. 32, with or without a `SUMMARY:` line) — the standard fixes the + first, not the second. +- **A pretty-printer is a lookup function, not magic**: `toolbox-printers.py`'s + `_lookup` matches on `val.type.unqualified().strip_typedefs().tag == + "Digest"` and hands back an object with a `to_string()` method — the same + three-line contract behind every pretty-printer libstdc++ ships, applied + here to a type this chapter wrote itself. +- **Not every recipe in a toolchain chapter can be verified on every + host**: `ccache` and `mold` are real, documented recipes — a + `CMAKE_CXX_COMPILER_LAUNCHER` cache variable and a `.comment`-section + check — that this chapter shows without a cache hit or a linked binary + to point at, because neither tool is installed on the reference host; + the footer below marks exactly that gap and nothing more. + +Two appendices remain in Part 13: the Go and Rust toolchains get the same +reference-depth treatment this chapter gave C++. + +--- + +

verified — on the Fedora 44 +reference host this session (kernel 7.1.4-204.fc44, GCC 16.1.1, clang +22.1.8, CMake 4.3.0, Ninja, gdb 17.2, Conan 2.30.0): +LSP_LANG=cpp REPO_ROOT=$(cd ../.. && pwd) lua verify.lua reported +PASS 20 / FAIL 0, and +python3 scripts/test-all-examples.py --only 46-cpp-toolbox +reported 1 passed, 0 failed, 0 skipped. Confirmed live and +folded into that PASS count: the release (GCC) and +release-clang builds of toolbox report printed +byte-identical output (digest=0x481984990deee5ff) with an +empty diff; the ubsan preset caught the seeded +overflow at toolbox.cpp:43 with +runtime error: signed integer overflow and exit 1; +gdb -batch -x cpp/.gdbinit ... rendered +Digest(0x481984990deee5ff) via the Python pretty-printer; +clang-tidy flagged performance-unnecessary-value-param +at smell.cpp:3; clang-format --dry-run --Werror +was clean on the tracked sources and nonzero on +fixtures/misformatted.cpp; and +conan install --lockfile=conan/conan.lock plus the +conan preset built and ran +toolbox-conan: fmt sub-target ok. The GCC-vs-clang +diagnostic-wording comparisons (the missing-semicolon compile error and the +ad hoc clang-built UBSan trap) were captured live this session against this +same source but are illustrative asides, not part of verify.lua's +gated count — wording like this is expected to drift across compiler point +releases, which is why the gate itself only matches the fixed substring +runtime error: signed integer overflow. Not exercised: +ccache and mold are both unverified — command -v ccache and +command -v mold both exit 1 on this host, so their recipes +above are shown as documented commands, with no cache-hit or linked-binary +output to quote. examples/manifest.yaml marks this example +mode: local — no VM or LGTM path applies.

diff --git a/_plans/r15-ch46-plan.md b/_plans/r15-ch46-plan.md new file mode 100644 index 0000000..76a2b01 --- /dev/null +++ b/_plans/r15-ch46-plan.md @@ -0,0 +1,98 @@ +--- +title: "r15 / ch46 — cpp-toolbox — plan (internal)" +published: false +--- + +# r15 ch46 — example `46-cpp-toolbox` + chapter + 2 diagrams (lgtm-relay Phase 1) + +Model relay: Opus plan (this file) → Sonnet execute → Opus validate. +First C++ toolchain reference-depth appendix (Part 13 "Appendices: Tooling"). +Single-language `langs: [cpp]`, `mode: local`, no VM/root/podman/LGTM. + +## Approach +One deterministic C++23 `toolbox` binary + toolchain artifacts, engineered so every +tool produces a CHECKABLE effect (not exit-0). Subcommands + auxiliary depth payload +(`.gdbinit`, gdb Python printer, `.clang-tidy`, `.clang-format`, Conan sub-target + +lockfile, misformatted fixture). + +**Hard-gated (tools check-host.sh guarantees; deterministic on pinned toolchain):** +- **A. Dual-compiler byte parity.** `toolbox report` prints an integer/string-only FNV-1a + digest (no floats/addresses/timing/unordered iteration). verify builds `release` (GCC) + + `release-clang`, runs both, asserts byte-identical AND equals an expected literal. + Chapter separately SHOWS GCC-vs-clang diagnostic differences (shown, not gated — wording drifts). +- **B. UBSan recipe.** `toolbox defect overflow` seeds signed-int overflow; `ubsan` preset + catches it; verify asserts exact `runtime error: signed integer overflow`. Defers full + matrix to ch29. +- **C. gdb pretty-printer.** custom `Digest{uint64_t}` + Python printer; verify runs + `gdb -batch -x cpp/.gdbinit ...` and asserts the pretty form. + +**Gated-if-present (checks.skip-guarded):** D clang-tidy (assert pinned check-name TOKEN, +not message text) · E clang-format `--dry-run --Werror` 0 on tracked, nonzero on fixture · +F Conan 2 with committed lockfile, isolated sub-target (NOT in default build → CI stays green). + +**Shown-not-gated (absent even on reference host):** ccache second-build cache-hit; mold in +`.comment`. Footer marks unverified. Accurate host state. + +## Chapter +Single-language spine (ch44 precedent, plain fenced cpp blocks, no codetabs include): +hook → Fig 46.1 → Tools-used box → CMake presets in depth → Conan 2 lockfiles → GCC-vs-clang +parity+diagnostics → How the code works → Errors-three-ways (compile diagnostic / tidy finding / +UBSan abort) → Concurrency lens (build-graph parallelism: Ninja -j, mold parallel linker) → +gdb printers/.gdbinit → lint/format/sanitize/ccache/mold recipes → build/run/observe → cross-check +(the parity diff IS the cross-check) → what you learned → status footer. +Differentiate (cross-ref, don't re-teach): vs ch31 (3-lang profiling breadth), ch28 (gdb remote/core), +ch29 (sanitizer matrix). ch46 = C++ build/debug DEPTH: preset internals, Conan lockfiles, cross-compiler +parity, gdb Python printers, .clang-tidy/.clang-format authoring, ccache/mold. + +Rejected: reuse ch29 bugfarm (re-teaches matrix); Conan mandatory in default build (breaks fedora:44 +CI smoke); hard-gate ccache/mold (absent on host); gate exact tidy/GCC message text (drifts). + +## Steps (Phase-2 parallelism) +1. Mint+strip scaffold `examples/46-cpp-toolbox/` (new-example.sh, delete go/rust, single-lang demo.sh). BLOCKING. Not parallel. +2. Example sources+artifacts: cpp/src/toolbox.cpp (+ custom-type header, tidy-smell TU, defect path), CMakeLists.txt, CMakePresets.json (release/debug/asan/ubsan/release-clang/debug-clang/conan), .clang-tidy, .clang-format, .gdbinit, toolbox-printers.py, fixtures/misformatted.cpp, conan/conanfile.py + lockfile, cpp/demo.sh, README.md. Depends 1. +3. verify.lua (gates A-C hard, D-F skip-if-absent, ccache/mold opportunistic) + single-lang LSP_LANG guard. Depends 2. +4. Local build+verify+transcript capture on host (all presets; hand-run gdb/tidy/format/UBSan/Conan/ccache/mold for REAL output; confirm tidy token fires on host clang-tidy, swap smell if not). Depends 2+3. Gates prose. +5. Chapter `_docs/46-cpp-toolbox.md`. Depends 4. Parallel with 6. +6. 2 diagrams (46-cmake-preset-graph, 46-toolbox-pipeline) + 2 README rows. Depends 2. Parallel with 5. +7. manifest.yaml +entry (langs:[cpp], mode:local, timeout 420). After 1. + +Collisions: assets/diagrams/README.md (step 6) + examples/manifest.yaml (step 7) are the only shared files; one edit each. + +## Acceptance criteria +1. No go/rust dir; manifest langs:[cpp], mode:local, no requires. +2. ./demo.sh cpp build exits 0 (release + release-clang). +3. diff release vs release-clang `report` empty AND == asserted literal. +4. LSP_LANG=cpp lua verify.lua → PASS N/FAIL 0; hard asserts A (parity), B (UBSan signed overflow), C (gdb printer) — none exit-0. +5. clang-tidy: output has pinned check-name token on expected line (skip if absent). +6. clang-format --dry-run --Werror 0 on tracked, nonzero on fixture (skip if absent). +7. Conan install+preset build+run 0, prints expected line (skip if absent); lockfile committed. +8. ccache/mold in chapter, opportunistic only, never in hard PASS, footer unverified. +9. scripts/validate.py → validate: OK. +10. banned-words grep clean (or machine-subject only). +11. every chapter cpp block = verbatim substring of example source. +12. test-all-examples.py --only 46-cpp-toolbox → PASS; footer status--verified with behavioral evidence. + +## Risks +tidy/format version drift (assert token only, confirm on host step 4); parity break from float/addr/timing +(integer/string-only digest); gdb auto-load/ptrace (explicit -x, trivial printer, batch debugs own child); +ccache/mold absent (skip/opportunistic); Conan in CI (isolated sub-target); ninja PATH (sandbox artifact, +check-host gates it). + +## Verification outlook +CLEAN — cleaner than ch45. Local/no-VM/no-root. Hard core A-C deterministic on pinned toolchain, passes on +any conforming host, richer on reference host. Only unverified corners: ccache/mold (absent) + diagnostic-wording +asides — never gated. Should merge on standard host-gate + CI-green, no mixed caveat. + +## Status — DONE +- [x] S1-S4 example (scaffold→sources→verify.lua→build+capture): PASS 20/0, all tools present+firing +- [x] S5 chapter `_docs/46-cpp-toolbox.md` (815 lines) +- [x] S6 diagrams (46-cmake-preset-graph, 46-toolbox-pipeline) + README rows +- [x] S7 manifest (langs:[cpp], mode:local, timeout 420) +- [x] Phase 3 validate (Opus): all 12 criteria MET, verdict **SHIP**, zero MUST-FIX (fixed one `cmd`→`cmake` typo) + +## Gate (host run, 2026-08-01/02) +- `verify.lua` PASS 20/0 · `validate.py` → validate: OK · `test-all-examples --only 46-cpp-toolbox` PASS +- Verification CLEAN (local, no VM). Only ccache/mold shown-not-gated (absent on host); GCC-vs-clang diagnostic asides framed as illustrative live-session, not gated. +- Reference toolchain: GCC 16.1.1, clang 22.1.8, CMake 4.3.0, gdb 17.2, Conan 2.30.0, kernel 7.1.4-204.fc44. + +## Merge: AUTONOMOUS (user authorized for r15). diff --git a/assets/diagrams/46-cmake-preset-graph.excalidraw b/assets/diagrams/46-cmake-preset-graph.excalidraw new file mode 100644 index 0000000..9d59a7c --- /dev/null +++ b/assets/diagrams/46-cmake-preset-graph.excalidraw @@ -0,0 +1,1643 @@ +{ + "type": "excalidraw", + "version": 2, + "source": "https://excalidraw.com", + "elements": [ + { + "id": "r1434053384", + "type": "rectangle", + "x": 20, + "y": 20, + "width": 960, + "height": 460, + "angle": 0, + "strokeColor": "#dddddd", + "backgroundColor": "#fafafa", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "roundness": { + "type": 3 + }, + "seed": 1237382948, + "versionNonce": 1564789581, + "isDeleted": false, + "boundElements": [], + "updated": 1, + "link": null, + "locked": false + }, + { + "id": "t75692286", + "type": "text", + "x": 32, + "y": 26, + "width": 356.40000000000003, + "height": 15.0, + "angle": 0, + "strokeColor": "#555555", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "roundness": null, + "seed": 1571383130, + "versionNonce": 14946091, + "isDeleted": false, + "boundElements": [], + "updated": 1, + "link": null, + "locked": false, + "text": "CMakePresets.json \u2014 configure presets (inherits _base)", + "fontSize": 12, + "fontFamily": 1, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "originalText": "CMakePresets.json \u2014 configure presets (inherits _base)", + "lineHeight": 1.25, + "baseline": 12 + }, + { + "id": "r1334851616", + "type": "rectangle", + "x": 1000, + "y": 20, + "width": 180, + "height": 260, + "angle": 0, + "strokeColor": "#dddddd", + "backgroundColor": "#fafafa", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "roundness": { + "type": 3 + }, + "seed": 1396602690, + "versionNonce": 1806990655, + "isDeleted": false, + "boundElements": [], + "updated": 1, + "link": null, + "locked": false + }, + { + "id": "t288756160", + "type": "text", + "x": 1012, + "y": 26, + "width": 105.60000000000001, + "height": 15.0, + "angle": 0, + "strokeColor": "#555555", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "roundness": null, + "seed": 1797333294, + "versionNonce": 1330437625, + "isDeleted": false, + "boundElements": [], + "updated": 1, + "link": null, + "locked": false, + "text": "Conan sub-target", + "fontSize": 12, + "fontFamily": 1, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "originalText": "Conan sub-target", + "lineHeight": 1.25, + "baseline": 12 + }, + { + "id": "r791557766", + "type": "rectangle", + "x": 380, + "y": 70, + "width": 220, + "height": 60, + "angle": 0, + "strokeColor": "#111111", + "backgroundColor": "#111111", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "roundness": { + "type": 3 + }, + "seed": 1802922116, + "versionNonce": 1342527216, + "isDeleted": false, + "boundElements": [], + "updated": 1, + "link": null, + "locked": false + }, + { + "id": "t1604618913", + "type": "text", + "x": 390, + "y": 78, + "width": 40, + "height": 17.5, + "angle": 0, + "strokeColor": "#ffffff", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "roundness": null, + "seed": 764095333, + "versionNonce": 1387554061, + "isDeleted": false, + "boundElements": [], + "updated": 1, + "link": null, + "locked": false, + "text": "_base", + "fontSize": 14, + "fontFamily": 1, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "originalText": "_base", + "lineHeight": 1.25, + "baseline": 14 + }, + { + "id": "t1915391130", + "type": "text", + "x": 390, + "y": 98, + "width": 121.00000000000001, + "height": 13.75, + "angle": 0, + "strokeColor": "#555555", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "roundness": null, + "seed": 1731706538, + "versionNonce": 573080423, + "isDeleted": false, + "boundElements": [], + "updated": 1, + "link": null, + "locked": false, + "text": "common config preset", + "fontSize": 11, + "fontFamily": 1, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "originalText": "common config preset", + "lineHeight": 1.25, + "baseline": 11 + }, + { + "id": "r1998431994", + "type": "rectangle", + "x": 40, + "y": 200, + "width": 140, + "height": 70, + "angle": 0, + "strokeColor": "#111111", + "backgroundColor": "#ffffff", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "roundness": { + "type": 3 + }, + "seed": 1169586502, + "versionNonce": 1162808667, + "isDeleted": false, + "boundElements": [], + "updated": 1, + "link": null, + "locked": false + }, + { + "id": "t675052109", + "type": "text", + "x": 50, + "y": 208, + "width": 53.900000000000006, + "height": 17.5, + "angle": 0, + "strokeColor": "#111111", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "roundness": null, + "seed": 355237164, + "versionNonce": 1539699049, + "isDeleted": false, + "boundElements": [], + "updated": 1, + "link": null, + "locked": false, + "text": "release", + "fontSize": 14, + "fontFamily": 1, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "originalText": "release", + "lineHeight": 1.25, + "baseline": 14 + }, + { + "id": "t864352110", + "type": "text", + "x": 50, + "y": 228, + "width": 78.65, + "height": 13.75, + "angle": 0, + "strokeColor": "#555555", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "roundness": null, + "seed": 1136539386, + "versionNonce": 1073033465, + "isDeleted": false, + "boundElements": [], + "updated": 1, + "link": null, + "locked": false, + "text": "build/release", + "fontSize": 11, + "fontFamily": 1, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "originalText": "build/release", + "lineHeight": 1.25, + "baseline": 11 + }, + { + "id": "r20541185", + "type": "rectangle", + "x": 192, + "y": 200, + "width": 140, + "height": 70, + "angle": 0, + "strokeColor": "#111111", + "backgroundColor": "#ffffff", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "roundness": { + "type": 3 + }, + "seed": 941930238, + "versionNonce": 493150305, + "isDeleted": false, + "boundElements": [], + "updated": 1, + "link": null, + "locked": false + }, + { + "id": "t325575309", + "type": "text", + "x": 202, + "y": 208, + "width": 40, + "height": 17.5, + "angle": 0, + "strokeColor": "#111111", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "roundness": null, + "seed": 883570978, + "versionNonce": 915124362, + "isDeleted": false, + "boundElements": [], + "updated": 1, + "link": null, + "locked": false, + "text": "debug", + "fontSize": 14, + "fontFamily": 1, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "originalText": "debug", + "lineHeight": 1.25, + "baseline": 14 + }, + { + "id": "t845647779", + "type": "text", + "x": 202, + "y": 228, + "width": 66.55000000000001, + "height": 13.75, + "angle": 0, + "strokeColor": "#555555", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "roundness": null, + "seed": 154207658, + "versionNonce": 298815584, + "isDeleted": false, + "boundElements": [], + "updated": 1, + "link": null, + "locked": false, + "text": "build/debug", + "fontSize": 11, + "fontFamily": 1, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "originalText": "build/debug", + "lineHeight": 1.25, + "baseline": 11 + }, + { + "id": "r52395896", + "type": "rectangle", + "x": 344, + "y": 200, + "width": 140, + "height": 70, + "angle": 0, + "strokeColor": "#111111", + "backgroundColor": "#ffffff", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "roundness": { + "type": 3 + }, + "seed": 1824250153, + "versionNonce": 584196868, + "isDeleted": false, + "boundElements": [], + "updated": 1, + "link": null, + "locked": false + }, + { + "id": "t438251311", + "type": "text", + "x": 354, + "y": 208, + "width": 40, + "height": 17.5, + "angle": 0, + "strokeColor": "#111111", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "roundness": null, + "seed": 1486319419, + "versionNonce": 1528110882, + "isDeleted": false, + "boundElements": [], + "updated": 1, + "link": null, + "locked": false, + "text": "asan", + "fontSize": 14, + "fontFamily": 1, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "originalText": "asan", + "lineHeight": 1.25, + "baseline": 14 + }, + { + "id": "t1594752206", + "type": "text", + "x": 354, + "y": 228, + "width": 60.50000000000001, + "height": 13.75, + "angle": 0, + "strokeColor": "#555555", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "roundness": null, + "seed": 501129919, + "versionNonce": 1267206283, + "isDeleted": false, + "boundElements": [], + "updated": 1, + "link": null, + "locked": false, + "text": "build/asan", + "fontSize": 11, + "fontFamily": 1, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "originalText": "build/asan", + "lineHeight": 1.25, + "baseline": 11 + }, + { + "id": "r127791261", + "type": "rectangle", + "x": 496, + "y": 200, + "width": 140, + "height": 70, + "angle": 0, + "strokeColor": "#111111", + "backgroundColor": "#ffffff", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "roundness": { + "type": 3 + }, + "seed": 1635622671, + "versionNonce": 1771245101, + "isDeleted": false, + "boundElements": [], + "updated": 1, + "link": null, + "locked": false + }, + { + "id": "t531429700", + "type": "text", + "x": 506, + "y": 208, + "width": 40, + "height": 17.5, + "angle": 0, + "strokeColor": "#111111", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "roundness": null, + "seed": 139231960, + "versionNonce": 825648286, + "isDeleted": false, + "boundElements": [], + "updated": 1, + "link": null, + "locked": false, + "text": "ubsan", + "fontSize": 14, + "fontFamily": 1, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "originalText": "ubsan", + "lineHeight": 1.25, + "baseline": 14 + }, + { + "id": "t1243577916", + "type": "text", + "x": 506, + "y": 228, + "width": 66.55000000000001, + "height": 13.75, + "angle": 0, + "strokeColor": "#555555", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "roundness": null, + "seed": 405493844, + "versionNonce": 881836553, + "isDeleted": false, + "boundElements": [], + "updated": 1, + "link": null, + "locked": false, + "text": "build/ubsan", + "fontSize": 11, + "fontFamily": 1, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "originalText": "build/ubsan", + "lineHeight": 1.25, + "baseline": 11 + }, + { + "id": "r725215602", + "type": "rectangle", + "x": 648, + "y": 200, + "width": 140, + "height": 70, + "angle": 0, + "strokeColor": "#2f6db5", + "backgroundColor": "#eef4fb", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "roundness": { + "type": 3 + }, + "seed": 367376758, + "versionNonce": 1915934193, + "isDeleted": false, + "boundElements": [], + "updated": 1, + "link": null, + "locked": false + }, + { + "id": "t680736995", + "type": "text", + "x": 658, + "y": 208, + "width": 100.10000000000001, + "height": 17.5, + "angle": 0, + "strokeColor": "#111111", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "roundness": null, + "seed": 1703292088, + "versionNonce": 1209248436, + "isDeleted": false, + "boundElements": [], + "updated": 1, + "link": null, + "locked": false, + "text": "release-clang", + "fontSize": 14, + "fontFamily": 1, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "originalText": "release-clang", + "lineHeight": 1.25, + "baseline": 14 + }, + { + "id": "t1189226716", + "type": "text", + "x": 658, + "y": 228, + "width": 114.95, + "height": 13.75, + "angle": 0, + "strokeColor": "#555555", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "roundness": null, + "seed": 382872138, + "versionNonce": 1517527381, + "isDeleted": false, + "boundElements": [], + "updated": 1, + "link": null, + "locked": false, + "text": "build/release-clang", + "fontSize": 11, + "fontFamily": 1, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "originalText": "build/release-clang", + "lineHeight": 1.25, + "baseline": 11 + }, + { + "id": "r1500510930", + "type": "rectangle", + "x": 800, + "y": 200, + "width": 140, + "height": 70, + "angle": 0, + "strokeColor": "#2f6db5", + "backgroundColor": "#eef4fb", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "roundness": { + "type": 3 + }, + "seed": 1350345555, + "versionNonce": 1839565767, + "isDeleted": false, + "boundElements": [], + "updated": 1, + "link": null, + "locked": false + }, + { + "id": "t620551357", + "type": "text", + "x": 810, + "y": 208, + "width": 84.7, + "height": 17.5, + "angle": 0, + "strokeColor": "#111111", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "roundness": null, + "seed": 1689021499, + "versionNonce": 1403513634, + "isDeleted": false, + "boundElements": [], + "updated": 1, + "link": null, + "locked": false, + "text": "debug-clang", + "fontSize": 14, + "fontFamily": 1, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "originalText": "debug-clang", + "lineHeight": 1.25, + "baseline": 14 + }, + { + "id": "t677079211", + "type": "text", + "x": 810, + "y": 228, + "width": 102.85000000000001, + "height": 13.75, + "angle": 0, + "strokeColor": "#555555", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "roundness": null, + "seed": 1511011686, + "versionNonce": 1690806338, + "isDeleted": false, + "boundElements": [], + "updated": 1, + "link": null, + "locked": false, + "text": "build/debug-clang", + "fontSize": 11, + "fontFamily": 1, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "originalText": "build/debug-clang", + "lineHeight": 1.25, + "baseline": 11 + }, + { + "id": "r860739810", + "type": "rectangle", + "x": 1030, + "y": 90, + "width": 120, + "height": 60, + "angle": 0, + "strokeColor": "#999999", + "backgroundColor": "#ffffff", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "dashed", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "roundness": { + "type": 3 + }, + "seed": 1431998046, + "versionNonce": 134617043, + "isDeleted": false, + "boundElements": [], + "updated": 1, + "link": null, + "locked": false + }, + { + "id": "t1354874123", + "type": "text", + "x": 1040, + "y": 98, + "width": 40, + "height": 17.5, + "angle": 0, + "strokeColor": "#111111", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "roundness": null, + "seed": 545622653, + "versionNonce": 586020014, + "isDeleted": false, + "boundElements": [], + "updated": 1, + "link": null, + "locked": false, + "text": "conan", + "fontSize": 14, + "fontFamily": 1, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "originalText": "conan", + "lineHeight": 1.25, + "baseline": 14 + }, + { + "id": "t262210598", + "type": "text", + "x": 1040, + "y": 118, + "width": 66.55000000000001, + "height": 13.75, + "angle": 0, + "strokeColor": "#555555", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "roundness": null, + "seed": 1218536933, + "versionNonce": 1064687815, + "isDeleted": false, + "boundElements": [], + "updated": 1, + "link": null, + "locked": false, + "text": "build/conan", + "fontSize": 11, + "fontFamily": 1, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "originalText": "build/conan", + "lineHeight": 1.25, + "baseline": 11 + }, + { + "id": "a1726680438", + "type": "arrow", + "x": 490, + "y": 130, + "width": 380, + "height": 70, + "angle": 0, + "strokeColor": "#555555", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "roundness": { + "type": 2 + }, + "seed": 1292438896, + "versionNonce": 1275226679, + "isDeleted": false, + "boundElements": [], + "updated": 1, + "link": null, + "locked": false, + "points": [ + [ + 0, + 0 + ], + [ + -380, + 70 + ] + ], + "lastCommittedPoint": null, + "startBinding": null, + "endBinding": null, + "startArrowhead": null, + "endArrowhead": "arrow" + }, + { + "id": "a725332934", + "type": "arrow", + "x": 490, + "y": 130, + "width": 228, + "height": 70, + "angle": 0, + "strokeColor": "#555555", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "roundness": { + "type": 2 + }, + "seed": 1819396585, + "versionNonce": 945201357, + "isDeleted": false, + "boundElements": [], + "updated": 1, + "link": null, + "locked": false, + "points": [ + [ + 0, + 0 + ], + [ + -228, + 70 + ] + ], + "lastCommittedPoint": null, + "startBinding": null, + "endBinding": null, + "startArrowhead": null, + "endArrowhead": "arrow" + }, + { + "id": "a1776945595", + "type": "arrow", + "x": 490, + "y": 130, + "width": 76, + "height": 70, + "angle": 0, + "strokeColor": "#555555", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "roundness": { + "type": 2 + }, + "seed": 762505396, + "versionNonce": 1558166855, + "isDeleted": false, + "boundElements": [], + "updated": 1, + "link": null, + "locked": false, + "points": [ + [ + 0, + 0 + ], + [ + -76, + 70 + ] + ], + "lastCommittedPoint": null, + "startBinding": null, + "endBinding": null, + "startArrowhead": null, + "endArrowhead": "arrow" + }, + { + "id": "a990663409", + "type": "arrow", + "x": 490, + "y": 130, + "width": 76, + "height": 70, + "angle": 0, + "strokeColor": "#555555", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "roundness": { + "type": 2 + }, + "seed": 1423764412, + "versionNonce": 1217565210, + "isDeleted": false, + "boundElements": [], + "updated": 1, + "link": null, + "locked": false, + "points": [ + [ + 0, + 0 + ], + [ + 76, + 70 + ] + ], + "lastCommittedPoint": null, + "startBinding": null, + "endBinding": null, + "startArrowhead": null, + "endArrowhead": "arrow" + }, + { + "id": "a861890853", + "type": "arrow", + "x": 490, + "y": 130, + "width": 228, + "height": 70, + "angle": 0, + "strokeColor": "#555555", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "roundness": { + "type": 2 + }, + "seed": 1549622981, + "versionNonce": 621636055, + "isDeleted": false, + "boundElements": [], + "updated": 1, + "link": null, + "locked": false, + "points": [ + [ + 0, + 0 + ], + [ + 228, + 70 + ] + ], + "lastCommittedPoint": null, + "startBinding": null, + "endBinding": null, + "startArrowhead": null, + "endArrowhead": "arrow" + }, + { + "id": "a326818090", + "type": "arrow", + "x": 490, + "y": 130, + "width": 380, + "height": 70, + "angle": 0, + "strokeColor": "#555555", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "roundness": { + "type": 2 + }, + "seed": 197825224, + "versionNonce": 1287678111, + "isDeleted": false, + "boundElements": [], + "updated": 1, + "link": null, + "locked": false, + "points": [ + [ + 0, + 0 + ], + [ + 380, + 70 + ] + ], + "lastCommittedPoint": null, + "startBinding": null, + "endBinding": null, + "startArrowhead": null, + "endArrowhead": "arrow" + }, + { + "id": "a72815045", + "type": "arrow", + "x": 600, + "y": 100, + "width": 430, + "height": 20, + "angle": 0, + "strokeColor": "#555555", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "dashed", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "roundness": { + "type": 2 + }, + "seed": 1786163070, + "versionNonce": 1149790577, + "isDeleted": false, + "boundElements": [], + "updated": 1, + "link": null, + "locked": false, + "points": [ + [ + 0, + 0 + ], + [ + 430, + 20 + ] + ], + "lastCommittedPoint": null, + "startBinding": null, + "endBinding": null, + "startArrowhead": null, + "endArrowhead": "arrow" + }, + { + "id": "t874489228", + "type": "text", + "x": 815.0, + "y": 96.0, + "width": 133.10000000000002, + "height": 13.75, + "angle": 0, + "strokeColor": "#555555", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "roundness": null, + "seed": 836600680, + "versionNonce": 202035891, + "isDeleted": false, + "boundElements": [], + "updated": 1, + "link": null, + "locked": false, + "text": "same file, no inherits", + "fontSize": 11, + "fontFamily": 1, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "originalText": "same file, no inherits", + "lineHeight": 1.25, + "baseline": 11 + }, + { + "id": "t1706827945", + "type": "text", + "x": 110, + "y": 276, + "width": 127.05000000000001, + "height": 13.75, + "angle": 0, + "strokeColor": "#1d1d1d", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "roundness": null, + "seed": 1631415781, + "versionNonce": 830600107, + "isDeleted": false, + "boundElements": [], + "updated": 1, + "link": null, + "locked": false, + "text": "verify: parity gate \u2460", + "fontSize": 11, + "fontFamily": 1, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "originalText": "verify: parity gate \u2460", + "lineHeight": 1.25, + "baseline": 11 + }, + { + "id": "t1797089682", + "type": "text", + "x": 262, + "y": 276, + "width": 145.20000000000002, + "height": 13.75, + "angle": 0, + "strokeColor": "#1d1d1d", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "roundness": null, + "seed": 124274922, + "versionNonce": 1663842830, + "isDeleted": false, + "boundElements": [], + "updated": 1, + "link": null, + "locked": false, + "text": "gdb: .gdbinit + printers", + "fontSize": 11, + "fontFamily": 1, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "originalText": "gdb: .gdbinit + printers", + "lineHeight": 1.25, + "baseline": 11 + }, + { + "id": "t538155679", + "type": "text", + "x": 414, + "y": 276, + "width": 133.10000000000002, + "height": 13.75, + "angle": 0, + "strokeColor": "#1d1d1d", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "roundness": null, + "seed": 330718590, + "versionNonce": 1450723885, + "isDeleted": false, + "boundElements": [], + "updated": 1, + "link": null, + "locked": false, + "text": "cross-ref: ch29 matrix", + "fontSize": 11, + "fontFamily": 1, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "originalText": "cross-ref: ch29 matrix", + "lineHeight": 1.25, + "baseline": 11 + }, + { + "id": "t308794886", + "type": "text", + "x": 566, + "y": 276, + "width": 108.9, + "height": 13.75, + "angle": 0, + "strokeColor": "#1d1d1d", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "roundness": null, + "seed": 1043021687, + "versionNonce": 1783961925, + "isDeleted": false, + "boundElements": [], + "updated": 1, + "link": null, + "locked": false, + "text": "verify: UBSan gate", + "fontSize": 11, + "fontFamily": 1, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "originalText": "verify: UBSan gate", + "lineHeight": 1.25, + "baseline": 11 + }, + { + "id": "t1089862293", + "type": "text", + "x": 718, + "y": 276, + "width": 127.05000000000001, + "height": 13.75, + "angle": 0, + "strokeColor": "#1d1d1d", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "roundness": null, + "seed": 1974310099, + "versionNonce": 467865800, + "isDeleted": false, + "boundElements": [], + "updated": 1, + "link": null, + "locked": false, + "text": "verify: parity gate \u2460", + "fontSize": 11, + "fontFamily": 1, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "originalText": "verify: parity gate \u2460", + "lineHeight": 1.25, + "baseline": 11 + }, + { + "id": "t1173734957", + "type": "text", + "x": 870, + "y": 276, + "width": 151.25, + "height": 13.75, + "angle": 0, + "strokeColor": "#1d1d1d", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "roundness": null, + "seed": 1937687438, + "versionNonce": 1857296111, + "isDeleted": false, + "boundElements": [], + "updated": 1, + "link": null, + "locked": false, + "text": "clang diagnostics (shown)", + "fontSize": 11, + "fontFamily": 1, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "originalText": "clang diagnostics (shown)", + "lineHeight": 1.25, + "baseline": 11 + }, + { + "id": "t795209301", + "type": "text", + "x": 40, + "y": 430, + "width": 356.40000000000003, + "height": 15.0, + "angle": 0, + "strokeColor": "#1d1d1d", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "roundness": null, + "seed": 1764992598, + "versionNonce": 328653095, + "isDeleted": false, + "boundElements": [], + "updated": 1, + "link": null, + "locked": false, + "text": "\u2460 release + release-clang both feed the byte-identical", + "fontSize": 12, + "fontFamily": 1, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "originalText": "\u2460 release + release-clang both feed the byte-identical", + "lineHeight": 1.25, + "baseline": 12 + }, + { + "id": "t1554589779", + "type": "text", + "x": 40, + "y": 446, + "width": 488.40000000000003, + "height": 15.0, + "angle": 0, + "strokeColor": "#1d1d1d", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "roundness": null, + "seed": 1489812272, + "versionNonce": 1448509397, + "isDeleted": false, + "boundElements": [], + "updated": 1, + "link": null, + "locked": false, + "text": "parity gate (Fig 46.2) \u2014 GCC presets vs clang twins are color-coded above.", + "fontSize": 12, + "fontFamily": 1, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "originalText": "parity gate (Fig 46.2) \u2014 GCC presets vs clang twins are color-coded above.", + "lineHeight": 1.25, + "baseline": 12 + }, + { + "id": "t1842334181", + "type": "text", + "x": 1015, + "y": 160, + "width": 133.10000000000002, + "height": 13.75, + "angle": 0, + "strokeColor": "#1d1d1d", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "roundness": null, + "seed": 1061962291, + "versionNonce": 556781145, + "isDeleted": false, + "boundElements": [], + "updated": 1, + "link": null, + "locked": false, + "text": "isolated \u2014 no inherits", + "fontSize": 11, + "fontFamily": 1, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "originalText": "isolated \u2014 no inherits", + "lineHeight": 1.25, + "baseline": 11 + }, + { + "id": "t1914022598", + "type": "text", + "x": 1015, + "y": 176, + "width": 127.05000000000001, + "height": 13.75, + "angle": 0, + "strokeColor": "#1d1d1d", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "roundness": null, + "seed": 1866141650, + "versionNonce": 1832476109, + "isDeleted": false, + "boundElements": [], + "updated": 1, + "link": null, + "locked": false, + "text": "keeps CI's Conan-less", + "fontSize": 11, + "fontFamily": 1, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "originalText": "keeps CI's Conan-less", + "lineHeight": 1.25, + "baseline": 11 + }, + { + "id": "t150545760", + "type": "text", + "x": 1015, + "y": 192, + "width": 102.85000000000001, + "height": 13.75, + "angle": 0, + "strokeColor": "#1d1d1d", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "roundness": null, + "seed": 1153065422, + "versionNonce": 676861504, + "isDeleted": false, + "boundElements": [], + "updated": 1, + "link": null, + "locked": false, + "text": "build-smoke green", + "fontSize": 11, + "fontFamily": 1, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "originalText": "build-smoke green", + "lineHeight": 1.25, + "baseline": 11 + } + ], + "appState": { + "viewBackgroundColor": "#ffffff", + "gridSize": null + }, + "files": {} +} \ No newline at end of file diff --git a/assets/diagrams/46-cmake-preset-graph.svg b/assets/diagrams/46-cmake-preset-graph.svg new file mode 100644 index 0000000..25227c1 --- /dev/null +++ b/assets/diagrams/46-cmake-preset-graph.svg @@ -0,0 +1,51 @@ + + + +CMakePresets.json — configure presets (inherits _base) + +Conan sub-target + +_base +common config preset + +release +build/release + +debug +build/debug + +asan +build/asan + +ubsan +build/ubsan + +release-clang +build/release-clang + +debug-clang +build/debug-clang + +conan +build/conan + + + + + + + +same file, no inherits +same file, no inherits +verify: parity gate ① +gdb: .gdbinit + printers +cross-ref: ch29 matrix +verify: UBSan gate +verify: parity gate ① +clang diagnostics (shown) +① release + release-clang both feed the byte-identical +parity gate (Fig 46.2) — GCC presets vs clang twins are color-coded above. +isolated — no inherits +keeps CI's Conan-less +build-smoke green + \ No newline at end of file diff --git a/assets/diagrams/46-toolbox-pipeline.excalidraw b/assets/diagrams/46-toolbox-pipeline.excalidraw new file mode 100644 index 0000000..15b5719 --- /dev/null +++ b/assets/diagrams/46-toolbox-pipeline.excalidraw @@ -0,0 +1,2602 @@ +{ + "type": "excalidraw", + "version": 2, + "source": "https://excalidraw.com", + "elements": [ + { + "id": "r663302497", + "type": "rectangle", + "x": 20, + "y": 20, + "width": 160, + "height": 810, + "angle": 0, + "strokeColor": "#dddddd", + "backgroundColor": "#fafafa", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "roundness": { + "type": 3 + }, + "seed": 563029696, + "versionNonce": 1482426638, + "isDeleted": false, + "boundElements": [], + "updated": 1, + "link": null, + "locked": false + }, + { + "id": "t1471192503", + "type": "text", + "x": 32, + "y": 26, + "width": 40, + "height": 15.0, + "angle": 0, + "strokeColor": "#555555", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "roundness": null, + "seed": 1210623736, + "versionNonce": 173934726, + "isDeleted": false, + "boundElements": [], + "updated": 1, + "link": null, + "locked": false, + "text": "source", + "fontSize": 12, + "fontFamily": 1, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "originalText": "source", + "lineHeight": 1.25, + "baseline": 12 + }, + { + "id": "r649153690", + "type": "rectangle", + "x": 220, + "y": 20, + "width": 940, + "height": 230, + "angle": 0, + "strokeColor": "#dddddd", + "backgroundColor": "#fff8ef", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "roundness": { + "type": 3 + }, + "seed": 1898743950, + "versionNonce": 1049352439, + "isDeleted": false, + "boundElements": [], + "updated": 1, + "link": null, + "locked": false + }, + { + "id": "t1207525669", + "type": "text", + "x": 232, + "y": 26, + "width": 217.8, + "height": 15.0, + "angle": 0, + "strokeColor": "#555555", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "roundness": null, + "seed": 505000949, + "versionNonce": 32432142, + "isDeleted": false, + "boundElements": [], + "updated": 1, + "link": null, + "locked": false, + "text": "Build / parity arm \u2014 GCC vs clang", + "fontSize": 12, + "fontFamily": 1, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "originalText": "Build / parity arm \u2014 GCC vs clang", + "lineHeight": 1.25, + "baseline": 12 + }, + { + "id": "r339792234", + "type": "rectangle", + "x": 220, + "y": 270, + "width": 940, + "height": 180, + "angle": 0, + "strokeColor": "#dddddd", + "backgroundColor": "#fafafa", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "roundness": { + "type": 3 + }, + "seed": 116718541, + "versionNonce": 1113761288, + "isDeleted": false, + "boundElements": [], + "updated": 1, + "link": null, + "locked": false + }, + { + "id": "t121040518", + "type": "text", + "x": 232, + "y": 276, + "width": 211.20000000000002, + "height": 15.0, + "angle": 0, + "strokeColor": "#555555", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "roundness": null, + "seed": 770501748, + "versionNonce": 1203724978, + "isDeleted": false, + "boundElements": [], + "updated": 1, + "link": null, + "locked": false, + "text": "Static arm \u2014 compile-time checks", + "fontSize": 12, + "fontFamily": 1, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "originalText": "Static arm \u2014 compile-time checks", + "lineHeight": 1.25, + "baseline": 12 + }, + { + "id": "r1753655522", + "type": "rectangle", + "x": 220, + "y": 470, + "width": 940, + "height": 250, + "angle": 0, + "strokeColor": "#dddddd", + "backgroundColor": "#f4f4f4", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "roundness": { + "type": 3 + }, + "seed": 89343796, + "versionNonce": 633274702, + "isDeleted": false, + "boundElements": [], + "updated": 1, + "link": null, + "locked": false + }, + { + "id": "t956813500", + "type": "text", + "x": 232, + "y": 476, + "width": 224.4, + "height": 15.0, + "angle": 0, + "strokeColor": "#555555", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "roundness": null, + "seed": 1294268291, + "versionNonce": 1462445600, + "isDeleted": false, + "boundElements": [], + "updated": 1, + "link": null, + "locked": false, + "text": "Runtime arm \u2014 sanitizer + debugger", + "fontSize": 12, + "fontFamily": 1, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "originalText": "Runtime arm \u2014 sanitizer + debugger", + "lineHeight": 1.25, + "baseline": 12 + }, + { + "id": "r813857862", + "type": "rectangle", + "x": 220, + "y": 740, + "width": 940, + "height": 90, + "angle": 0, + "strokeColor": "#dddddd", + "backgroundColor": "#fafafa", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "roundness": { + "type": 3 + }, + "seed": 1831148616, + "versionNonce": 1027647741, + "isDeleted": false, + "boundElements": [], + "updated": 1, + "link": null, + "locked": false + }, + { + "id": "t1853421402", + "type": "text", + "x": 232, + "y": 746, + "width": 330.0, + "height": 15.0, + "angle": 0, + "strokeColor": "#555555", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "roundness": null, + "seed": 1394207382, + "versionNonce": 622648498, + "isDeleted": false, + "boundElements": [], + "updated": 1, + "link": null, + "locked": false, + "text": "Accelerators \u2014 optional, not verified this session", + "fontSize": 12, + "fontFamily": 1, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "originalText": "Accelerators \u2014 optional, not verified this session", + "lineHeight": 1.25, + "baseline": 12 + }, + { + "id": "r1898185534", + "type": "rectangle", + "x": 40, + "y": 370, + "width": 120, + "height": 80, + "angle": 0, + "strokeColor": "#111111", + "backgroundColor": "#111111", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "roundness": { + "type": 3 + }, + "seed": 109739651, + "versionNonce": 1628495120, + "isDeleted": false, + "boundElements": [], + "updated": 1, + "link": null, + "locked": false + }, + { + "id": "t1543775897", + "type": "text", + "x": 50, + "y": 378, + "width": 84.7, + "height": 17.5, + "angle": 0, + "strokeColor": "#ffffff", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "roundness": null, + "seed": 195149120, + "versionNonce": 1857080254, + "isDeleted": false, + "boundElements": [], + "updated": 1, + "link": null, + "locked": false, + "text": "toolbox.cpp", + "fontSize": 14, + "fontFamily": 1, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "originalText": "toolbox.cpp", + "lineHeight": 1.25, + "baseline": 14 + }, + { + "id": "t1221229154", + "type": "text", + "x": 50, + "y": 398, + "width": 84.7, + "height": 13.75, + "angle": 0, + "strokeColor": "#555555", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "roundness": null, + "seed": 761016129, + "versionNonce": 1967523722, + "isDeleted": false, + "boundElements": [], + "updated": 1, + "link": null, + "locked": false, + "text": "single source,", + "fontSize": 11, + "fontFamily": 1, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "originalText": "single source,", + "lineHeight": 1.25, + "baseline": 11 + }, + { + "id": "t70261493", + "type": "text", + "x": 50, + "y": 413, + "width": 40, + "height": 13.75, + "angle": 0, + "strokeColor": "#555555", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "roundness": null, + "seed": 1203291067, + "versionNonce": 1378839299, + "isDeleted": false, + "boundElements": [], + "updated": 1, + "link": null, + "locked": false, + "text": "3 arms", + "fontSize": 11, + "fontFamily": 1, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "originalText": "3 arms", + "lineHeight": 1.25, + "baseline": 11 + }, + { + "id": "r272900500", + "type": "rectangle", + "x": 250, + "y": 55, + "width": 190, + "height": 60, + "angle": 0, + "strokeColor": "#111111", + "backgroundColor": "#ffffff", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "roundness": { + "type": 3 + }, + "seed": 711452281, + "versionNonce": 169059149, + "isDeleted": false, + "boundElements": [], + "updated": 1, + "link": null, + "locked": false + }, + { + "id": "t75938548", + "type": "text", + "x": 260, + "y": 63, + "width": 69.30000000000001, + "height": 17.5, + "angle": 0, + "strokeColor": "#111111", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "roundness": null, + "seed": 1364198448, + "versionNonce": 637465422, + "isDeleted": false, + "boundElements": [], + "updated": 1, + "link": null, + "locked": false, + "text": "GCC build", + "fontSize": 14, + "fontFamily": 1, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "originalText": "GCC build", + "lineHeight": 1.25, + "baseline": 14 + }, + { + "id": "t118731382", + "type": "text", + "x": 260, + "y": 83, + "width": 90.75000000000001, + "height": 13.75, + "angle": 0, + "strokeColor": "#555555", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "roundness": null, + "seed": 1881205331, + "versionNonce": 923530164, + "isDeleted": false, + "boundElements": [], + "updated": 1, + "link": null, + "locked": false, + "text": "preset: release", + "fontSize": 11, + "fontFamily": 1, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "originalText": "preset: release", + "lineHeight": 1.25, + "baseline": 11 + }, + { + "id": "r1080451548", + "type": "rectangle", + "x": 250, + "y": 150, + "width": 190, + "height": 60, + "angle": 0, + "strokeColor": "#2f6db5", + "backgroundColor": "#eef4fb", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "roundness": { + "type": 3 + }, + "seed": 1107487003, + "versionNonce": 1388287537, + "isDeleted": false, + "boundElements": [], + "updated": 1, + "link": null, + "locked": false + }, + { + "id": "t824784179", + "type": "text", + "x": 260, + "y": 158, + "width": 84.7, + "height": 17.5, + "angle": 0, + "strokeColor": "#111111", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "roundness": null, + "seed": 387298435, + "versionNonce": 528589386, + "isDeleted": false, + "boundElements": [], + "updated": 1, + "link": null, + "locked": false, + "text": "clang build", + "fontSize": 14, + "fontFamily": 1, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "originalText": "clang build", + "lineHeight": 1.25, + "baseline": 14 + }, + { + "id": "t890329532", + "type": "text", + "x": 260, + "y": 178, + "width": 127.05000000000001, + "height": 13.75, + "angle": 0, + "strokeColor": "#555555", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "roundness": null, + "seed": 141579383, + "versionNonce": 920466986, + "isDeleted": false, + "boundElements": [], + "updated": 1, + "link": null, + "locked": false, + "text": "preset: release-clang", + "fontSize": 11, + "fontFamily": 1, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "originalText": "preset: release-clang", + "lineHeight": 1.25, + "baseline": 11 + }, + { + "id": "r705377175", + "type": "rectangle", + "x": 470, + "y": 55, + "width": 210, + "height": 60, + "angle": 0, + "strokeColor": "#111111", + "backgroundColor": "#ffffff", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "roundness": { + "type": 3 + }, + "seed": 1881637092, + "versionNonce": 1252969617, + "isDeleted": false, + "boundElements": [], + "updated": 1, + "link": null, + "locked": false + }, + { + "id": "t1297909640", + "type": "text", + "x": 480, + "y": 63, + "width": 100.10000000000001, + "height": 17.5, + "angle": 0, + "strokeColor": "#111111", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "roundness": null, + "seed": 1595169757, + "versionNonce": 819530275, + "isDeleted": false, + "boundElements": [], + "updated": 1, + "link": null, + "locked": false, + "text": "toolbox (gcc)", + "fontSize": 14, + "fontFamily": 1, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "originalText": "toolbox (gcc)", + "lineHeight": 1.25, + "baseline": 14 + }, + { + "id": "t1776261501", + "type": "text", + "x": 480, + "y": 83, + "width": 90.75000000000001, + "height": 13.75, + "angle": 0, + "strokeColor": "#555555", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "roundness": null, + "seed": 427121032, + "versionNonce": 541712484, + "isDeleted": false, + "boundElements": [], + "updated": 1, + "link": null, + "locked": false, + "text": "report \u2192 digest", + "fontSize": 11, + "fontFamily": 1, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "originalText": "report \u2192 digest", + "lineHeight": 1.25, + "baseline": 11 + }, + { + "id": "r159102534", + "type": "rectangle", + "x": 470, + "y": 150, + "width": 210, + "height": 60, + "angle": 0, + "strokeColor": "#2f6db5", + "backgroundColor": "#eef4fb", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "roundness": { + "type": 3 + }, + "seed": 1422018545, + "versionNonce": 531844434, + "isDeleted": false, + "boundElements": [], + "updated": 1, + "link": null, + "locked": false + }, + { + "id": "t390212487", + "type": "text", + "x": 480, + "y": 158, + "width": 115.50000000000001, + "height": 17.5, + "angle": 0, + "strokeColor": "#111111", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "roundness": null, + "seed": 215824758, + "versionNonce": 534607184, + "isDeleted": false, + "boundElements": [], + "updated": 1, + "link": null, + "locked": false, + "text": "toolbox (clang)", + "fontSize": 14, + "fontFamily": 1, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "originalText": "toolbox (clang)", + "lineHeight": 1.25, + "baseline": 14 + }, + { + "id": "t1130251896", + "type": "text", + "x": 480, + "y": 178, + "width": 90.75000000000001, + "height": 13.75, + "angle": 0, + "strokeColor": "#555555", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "roundness": null, + "seed": 736827621, + "versionNonce": 1236230799, + "isDeleted": false, + "boundElements": [], + "updated": 1, + "link": null, + "locked": false, + "text": "report \u2192 digest", + "fontSize": 11, + "fontFamily": 1, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "originalText": "report \u2192 digest", + "lineHeight": 1.25, + "baseline": 11 + }, + { + "id": "r172790166", + "type": "rectangle", + "x": 760, + "y": 90, + "width": 280, + "height": 90, + "angle": 0, + "strokeColor": "#e8870c", + "backgroundColor": "#fff8ef", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "roundness": { + "type": 3 + }, + "seed": 37940582, + "versionNonce": 345142836, + "isDeleted": false, + "boundElements": [], + "updated": 1, + "link": null, + "locked": false + }, + { + "id": "t1257126485", + "type": "text", + "x": 770, + "y": 98, + "width": 84.7, + "height": 17.5, + "angle": 0, + "strokeColor": "#111111", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "roundness": null, + "seed": 26532021, + "versionNonce": 1431327782, + "isDeleted": false, + "boundElements": [], + "updated": 1, + "link": null, + "locked": false, + "text": "parity gate", + "fontSize": 14, + "fontFamily": 1, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "originalText": "parity gate", + "lineHeight": 1.25, + "baseline": 14 + }, + { + "id": "t566638436", + "type": "text", + "x": 770, + "y": 118, + "width": 78.65, + "height": 13.75, + "angle": 0, + "strokeColor": "#555555", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "roundness": null, + "seed": 1751356187, + "versionNonce": 902520778, + "isDeleted": false, + "boundElements": [], + "updated": 1, + "link": null, + "locked": false, + "text": "diff == empty", + "fontSize": 11, + "fontFamily": 1, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "originalText": "diff == empty", + "lineHeight": 1.25, + "baseline": 11 + }, + { + "id": "t1489263595", + "type": "text", + "x": 770, + "y": 133, + "width": 96.80000000000001, + "height": 13.75, + "angle": 0, + "strokeColor": "#555555", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "roundness": null, + "seed": 1528738055, + "versionNonce": 142042950, + "isDeleted": false, + "boundElements": [], + "updated": 1, + "link": null, + "locked": false, + "text": "(byte-identical)", + "fontSize": 11, + "fontFamily": 1, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "originalText": "(byte-identical)", + "lineHeight": 1.25, + "baseline": 11 + }, + { + "id": "r61217819", + "type": "rectangle", + "x": 250, + "y": 310, + "width": 210, + "height": 60, + "angle": 0, + "strokeColor": "#999999", + "backgroundColor": "#ffffff", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "roundness": { + "type": 3 + }, + "seed": 1663989738, + "versionNonce": 363549750, + "isDeleted": false, + "boundElements": [], + "updated": 1, + "link": null, + "locked": false + }, + { + "id": "t459457602", + "type": "text", + "x": 260, + "y": 318, + "width": 161.70000000000002, + "height": 17.5, + "angle": 0, + "strokeColor": "#111111", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "roundness": null, + "seed": 1989620032, + "versionNonce": 1497486870, + "isDeleted": false, + "boundElements": [], + "updated": 1, + "link": null, + "locked": false, + "text": "compile_commands.json", + "fontSize": 14, + "fontFamily": 1, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "originalText": "compile_commands.json", + "lineHeight": 1.25, + "baseline": 14 + }, + { + "id": "t541465580", + "type": "text", + "x": 260, + "y": 338, + "width": 60.50000000000001, + "height": 13.75, + "angle": 0, + "strokeColor": "#555555", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "roundness": null, + "seed": 455329899, + "versionNonce": 252883, + "isDeleted": false, + "boundElements": [], + "updated": 1, + "link": null, + "locked": false, + "text": "compile DB", + "fontSize": 11, + "fontFamily": 1, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "originalText": "compile DB", + "lineHeight": 1.25, + "baseline": 11 + }, + { + "id": "r737304015", + "type": "rectangle", + "x": 540, + "y": 305, + "width": 260, + "height": 60, + "angle": 0, + "strokeColor": "#111111", + "backgroundColor": "#ffffff", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "roundness": { + "type": 3 + }, + "seed": 948017286, + "versionNonce": 1194912603, + "isDeleted": false, + "boundElements": [], + "updated": 1, + "link": null, + "locked": false + }, + { + "id": "t1984894423", + "type": "text", + "x": 550, + "y": 313, + "width": 77.0, + "height": 17.5, + "angle": 0, + "strokeColor": "#111111", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "roundness": null, + "seed": 1692023683, + "versionNonce": 224615984, + "isDeleted": false, + "boundElements": [], + "updated": 1, + "link": null, + "locked": false, + "text": "clang-tidy", + "fontSize": 14, + "fontFamily": 1, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "originalText": "clang-tidy", + "lineHeight": 1.25, + "baseline": 14 + }, + { + "id": "t1559262713", + "type": "text", + "x": 550, + "y": 333, + "width": 211.75000000000003, + "height": 13.75, + "angle": 0, + "strokeColor": "#555555", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "roundness": null, + "seed": 1281584314, + "versionNonce": 6120895, + "isDeleted": false, + "boundElements": [], + "updated": 1, + "link": null, + "locked": false, + "text": "performance-unnecessary-value-param", + "fontSize": 11, + "fontFamily": 1, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "originalText": "performance-unnecessary-value-param", + "lineHeight": 1.25, + "baseline": 11 + }, + { + "id": "r1501166537", + "type": "rectangle", + "x": 540, + "y": 375, + "width": 260, + "height": 60, + "angle": 0, + "strokeColor": "#111111", + "backgroundColor": "#ffffff", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "roundness": { + "type": 3 + }, + "seed": 836148891, + "versionNonce": 629311749, + "isDeleted": false, + "boundElements": [], + "updated": 1, + "link": null, + "locked": false + }, + { + "id": "t1617560469", + "type": "text", + "x": 550, + "y": 383, + "width": 92.4, + "height": 17.5, + "angle": 0, + "strokeColor": "#111111", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "roundness": null, + "seed": 45737979, + "versionNonce": 503850608, + "isDeleted": false, + "boundElements": [], + "updated": 1, + "link": null, + "locked": false, + "text": "clang-format", + "fontSize": 14, + "fontFamily": 1, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "originalText": "clang-format", + "lineHeight": 1.25, + "baseline": 14 + }, + { + "id": "t805404689", + "type": "text", + "x": 550, + "y": 403, + "width": 108.9, + "height": 13.75, + "angle": 0, + "strokeColor": "#555555", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "roundness": null, + "seed": 1688666973, + "versionNonce": 1872681845, + "isDeleted": false, + "boundElements": [], + "updated": 1, + "link": null, + "locked": false, + "text": "--dry-run --Werror", + "fontSize": 11, + "fontFamily": 1, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "originalText": "--dry-run --Werror", + "lineHeight": 1.25, + "baseline": 11 + }, + { + "id": "r1474187580", + "type": "rectangle", + "x": 250, + "y": 505, + "width": 190, + "height": 60, + "angle": 0, + "strokeColor": "#111111", + "backgroundColor": "#ffffff", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "roundness": { + "type": 3 + }, + "seed": 134722890, + "versionNonce": 1145900663, + "isDeleted": false, + "boundElements": [], + "updated": 1, + "link": null, + "locked": false + }, + { + "id": "t751312398", + "type": "text", + "x": 260, + "y": 513, + "width": 84.7, + "height": 17.5, + "angle": 0, + "strokeColor": "#111111", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "roundness": null, + "seed": 479681175, + "versionNonce": 1957801250, + "isDeleted": false, + "boundElements": [], + "updated": 1, + "link": null, + "locked": false, + "text": "ubsan build", + "fontSize": 14, + "fontFamily": 1, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "originalText": "ubsan build", + "lineHeight": 1.25, + "baseline": 14 + }, + { + "id": "t1968995806", + "type": "text", + "x": 260, + "y": 533, + "width": 78.65, + "height": 13.75, + "angle": 0, + "strokeColor": "#555555", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "roundness": null, + "seed": 1799698386, + "versionNonce": 1344922172, + "isDeleted": false, + "boundElements": [], + "updated": 1, + "link": null, + "locked": false, + "text": "preset: ubsan", + "fontSize": 11, + "fontFamily": 1, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "originalText": "preset: ubsan", + "lineHeight": 1.25, + "baseline": 11 + }, + { + "id": "r334029944", + "type": "rectangle", + "x": 470, + "y": 505, + "width": 290, + "height": 60, + "angle": 0, + "strokeColor": "#111111", + "backgroundColor": "#ffffff", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "roundness": { + "type": 3 + }, + "seed": 1077144403, + "versionNonce": 533976053, + "isDeleted": false, + "boundElements": [], + "updated": 1, + "link": null, + "locked": false + }, + { + "id": "t1081302676", + "type": "text", + "x": 480, + "y": 513, + "width": 115.50000000000001, + "height": 17.5, + "angle": 0, + "strokeColor": "#111111", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "roundness": null, + "seed": 1361797757, + "versionNonce": 1958241505, + "isDeleted": false, + "boundElements": [], + "updated": 1, + "link": null, + "locked": false, + "text": "defect overflow", + "fontSize": 14, + "fontFamily": 1, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "originalText": "defect overflow", + "lineHeight": 1.25, + "baseline": 14 + }, + { + "id": "t1020490426", + "type": "text", + "x": 480, + "y": 533, + "width": 229.9, + "height": 13.75, + "angle": 0, + "strokeColor": "#555555", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "roundness": null, + "seed": 1273683555, + "versionNonce": 188586494, + "isDeleted": false, + "boundElements": [], + "updated": 1, + "link": null, + "locked": false, + "text": "runtime error: signed integer overflow", + "fontSize": 11, + "fontFamily": 1, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "originalText": "runtime error: signed integer overflow", + "lineHeight": 1.25, + "baseline": 11 + }, + { + "id": "r1528781571", + "type": "rectangle", + "x": 250, + "y": 615, + "width": 190, + "height": 60, + "angle": 0, + "strokeColor": "#111111", + "backgroundColor": "#ffffff", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "roundness": { + "type": 3 + }, + "seed": 1290092484, + "versionNonce": 1186763673, + "isDeleted": false, + "boundElements": [], + "updated": 1, + "link": null, + "locked": false + }, + { + "id": "t1825842675", + "type": "text", + "x": 260, + "y": 623, + "width": 84.7, + "height": 17.5, + "angle": 0, + "strokeColor": "#111111", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "roundness": null, + "seed": 1526907697, + "versionNonce": 859781485, + "isDeleted": false, + "boundElements": [], + "updated": 1, + "link": null, + "locked": false, + "text": "debug build", + "fontSize": 14, + "fontFamily": 1, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "originalText": "debug build", + "lineHeight": 1.25, + "baseline": 14 + }, + { + "id": "t1883519983", + "type": "text", + "x": 260, + "y": 643, + "width": 78.65, + "height": 13.75, + "angle": 0, + "strokeColor": "#555555", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "roundness": null, + "seed": 750086247, + "versionNonce": 1642727122, + "isDeleted": false, + "boundElements": [], + "updated": 1, + "link": null, + "locked": false, + "text": "preset: debug", + "fontSize": 11, + "fontFamily": 1, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "originalText": "preset: debug", + "lineHeight": 1.25, + "baseline": 11 + }, + { + "id": "r425413856", + "type": "rectangle", + "x": 470, + "y": 615, + "width": 250, + "height": 60, + "angle": 0, + "strokeColor": "#111111", + "backgroundColor": "#ffffff", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "roundness": { + "type": 3 + }, + "seed": 1260198008, + "versionNonce": 645907839, + "isDeleted": false, + "boundElements": [], + "updated": 1, + "link": null, + "locked": false + }, + { + "id": "t1535124910", + "type": "text", + "x": 480, + "y": 623, + "width": 115.50000000000001, + "height": 17.5, + "angle": 0, + "strokeColor": "#111111", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "roundness": null, + "seed": 394640920, + "versionNonce": 1464647181, + "isDeleted": false, + "boundElements": [], + "updated": 1, + "link": null, + "locked": false, + "text": "gdb -x .gdbinit", + "fontSize": 14, + "fontFamily": 1, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "originalText": "gdb -x .gdbinit", + "lineHeight": 1.25, + "baseline": 14 + }, + { + "id": "t1471587273", + "type": "text", + "x": 480, + "y": 643, + "width": 127.05000000000001, + "height": 13.75, + "angle": 0, + "strokeColor": "#555555", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "roundness": null, + "seed": 460971027, + "versionNonce": 26421375, + "isDeleted": false, + "boundElements": [], + "updated": 1, + "link": null, + "locked": false, + "text": "+ toolbox-printers.py", + "fontSize": 11, + "fontFamily": 1, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "originalText": "+ toolbox-printers.py", + "lineHeight": 1.25, + "baseline": 11 + }, + { + "id": "r981381754", + "type": "rectangle", + "x": 750, + "y": 615, + "width": 170, + "height": 60, + "angle": 0, + "strokeColor": "#111111", + "backgroundColor": "#ffffff", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "roundness": { + "type": 3 + }, + "seed": 128879794, + "versionNonce": 1952501757, + "isDeleted": false, + "boundElements": [], + "updated": 1, + "link": null, + "locked": false + }, + { + "id": "t1873184111", + "type": "text", + "x": 760, + "y": 623, + "width": 53.900000000000006, + "height": 17.5, + "angle": 0, + "strokeColor": "#111111", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "roundness": null, + "seed": 554242715, + "versionNonce": 662038966, + "isDeleted": false, + "boundElements": [], + "updated": 1, + "link": null, + "locked": false, + "text": "print d", + "fontSize": 14, + "fontFamily": 1, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "originalText": "print d", + "lineHeight": 1.25, + "baseline": 14 + }, + { + "id": "t1176212801", + "type": "text", + "x": 760, + "y": 643, + "width": 66.55000000000001, + "height": 13.75, + "angle": 0, + "strokeColor": "#555555", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "roundness": null, + "seed": 1802344726, + "versionNonce": 1403458241, + "isDeleted": false, + "boundElements": [], + "updated": 1, + "link": null, + "locked": false, + "text": "Digest(0x\u2026)", + "fontSize": 11, + "fontFamily": 1, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "originalText": "Digest(0x\u2026)", + "lineHeight": 1.25, + "baseline": 11 + }, + { + "id": "r1711081591", + "type": "rectangle", + "x": 250, + "y": 775, + "width": 200, + "height": 45, + "angle": 0, + "strokeColor": "#999999", + "backgroundColor": "#ffffff", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "dashed", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "roundness": { + "type": 3 + }, + "seed": 1954023858, + "versionNonce": 721790286, + "isDeleted": false, + "boundElements": [], + "updated": 1, + "link": null, + "locked": false + }, + { + "id": "t1986088912", + "type": "text", + "x": 260, + "y": 783, + "width": 46.2, + "height": 17.5, + "angle": 0, + "strokeColor": "#111111", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "roundness": null, + "seed": 611548692, + "versionNonce": 1548263637, + "isDeleted": false, + "boundElements": [], + "updated": 1, + "link": null, + "locked": false, + "text": "ccache", + "fontSize": 14, + "fontFamily": 1, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "originalText": "ccache", + "lineHeight": 1.25, + "baseline": 14 + }, + { + "id": "t632723636", + "type": "text", + "x": 260, + "y": 803, + "width": 133.10000000000002, + "height": 13.75, + "angle": 0, + "strokeColor": "#555555", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "roundness": null, + "seed": 724622610, + "versionNonce": 1537189329, + "isDeleted": false, + "boundElements": [], + "updated": 1, + "link": null, + "locked": false, + "text": "second-build cache hit", + "fontSize": 11, + "fontFamily": 1, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "originalText": "second-build cache hit", + "lineHeight": 1.25, + "baseline": 11 + }, + { + "id": "r835595729", + "type": "rectangle", + "x": 480, + "y": 775, + "width": 200, + "height": 45, + "angle": 0, + "strokeColor": "#999999", + "backgroundColor": "#ffffff", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "dashed", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "roundness": { + "type": 3 + }, + "seed": 1041957930, + "versionNonce": 755718629, + "isDeleted": false, + "boundElements": [], + "updated": 1, + "link": null, + "locked": false + }, + { + "id": "t583990148", + "type": "text", + "x": 490, + "y": 783, + "width": 40, + "height": 17.5, + "angle": 0, + "strokeColor": "#111111", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "roundness": null, + "seed": 1596751279, + "versionNonce": 158737578, + "isDeleted": false, + "boundElements": [], + "updated": 1, + "link": null, + "locked": false, + "text": "mold", + "fontSize": 14, + "fontFamily": 1, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "originalText": "mold", + "lineHeight": 1.25, + "baseline": 14 + }, + { + "id": "t1681745713", + "type": "text", + "x": 490, + "y": 803, + "width": 151.25, + "height": 13.75, + "angle": 0, + "strokeColor": "#555555", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "roundness": null, + "seed": 1656885541, + "versionNonce": 1812668793, + "isDeleted": false, + "boundElements": [], + "updated": 1, + "link": null, + "locked": false, + "text": "parallel linker, .comment", + "fontSize": 11, + "fontFamily": 1, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "originalText": "parallel linker, .comment", + "lineHeight": 1.25, + "baseline": 11 + }, + { + "id": "a868428754", + "type": "arrow", + "x": 160, + "y": 410, + "width": 90, + "height": 325, + "angle": 0, + "strokeColor": "#555555", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "roundness": { + "type": 2 + }, + "seed": 918009456, + "versionNonce": 1879092414, + "isDeleted": false, + "boundElements": [], + "updated": 1, + "link": null, + "locked": false, + "points": [ + [ + 0, + 0 + ], + [ + 90, + -325 + ] + ], + "lastCommittedPoint": null, + "startBinding": null, + "endBinding": null, + "startArrowhead": null, + "endArrowhead": "arrow" + }, + { + "id": "a1009534077", + "type": "arrow", + "x": 160, + "y": 410, + "width": 90, + "height": 230, + "angle": 0, + "strokeColor": "#555555", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "roundness": { + "type": 2 + }, + "seed": 1128107188, + "versionNonce": 115528595, + "isDeleted": false, + "boundElements": [], + "updated": 1, + "link": null, + "locked": false, + "points": [ + [ + 0, + 0 + ], + [ + 90, + -230 + ] + ], + "lastCommittedPoint": null, + "startBinding": null, + "endBinding": null, + "startArrowhead": null, + "endArrowhead": "arrow" + }, + { + "id": "a425966810", + "type": "arrow", + "x": 160, + "y": 410, + "width": 90, + "height": 70, + "angle": 0, + "strokeColor": "#555555", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "roundness": { + "type": 2 + }, + "seed": 1638778748, + "versionNonce": 989465134, + "isDeleted": false, + "boundElements": [], + "updated": 1, + "link": null, + "locked": false, + "points": [ + [ + 0, + 0 + ], + [ + 90, + -70 + ] + ], + "lastCommittedPoint": null, + "startBinding": null, + "endBinding": null, + "startArrowhead": null, + "endArrowhead": "arrow" + }, + { + "id": "a1278273279", + "type": "arrow", + "x": 160, + "y": 410, + "width": 90, + "height": 125, + "angle": 0, + "strokeColor": "#555555", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "roundness": { + "type": 2 + }, + "seed": 392432656, + "versionNonce": 1262964135, + "isDeleted": false, + "boundElements": [], + "updated": 1, + "link": null, + "locked": false, + "points": [ + [ + 0, + 0 + ], + [ + 90, + 125 + ] + ], + "lastCommittedPoint": null, + "startBinding": null, + "endBinding": null, + "startArrowhead": null, + "endArrowhead": "arrow" + }, + { + "id": "a1753124092", + "type": "arrow", + "x": 160, + "y": 410, + "width": 90, + "height": 235, + "angle": 0, + "strokeColor": "#555555", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "roundness": { + "type": 2 + }, + "seed": 1660453895, + "versionNonce": 625184863, + "isDeleted": false, + "boundElements": [], + "updated": 1, + "link": null, + "locked": false, + "points": [ + [ + 0, + 0 + ], + [ + 90, + 235 + ] + ], + "lastCommittedPoint": null, + "startBinding": null, + "endBinding": null, + "startArrowhead": null, + "endArrowhead": "arrow" + }, + { + "id": "a188567064", + "type": "arrow", + "x": 440, + "y": 85, + "width": 30, + "height": 0, + "angle": 0, + "strokeColor": "#555555", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "roundness": { + "type": 2 + }, + "seed": 1635459618, + "versionNonce": 1704145531, + "isDeleted": false, + "boundElements": [], + "updated": 1, + "link": null, + "locked": false, + "points": [ + [ + 0, + 0 + ], + [ + 30, + 0 + ] + ], + "lastCommittedPoint": null, + "startBinding": null, + "endBinding": null, + "startArrowhead": null, + "endArrowhead": "arrow" + }, + { + "id": "a1448307402", + "type": "arrow", + "x": 440, + "y": 180, + "width": 30, + "height": 0, + "angle": 0, + "strokeColor": "#555555", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "roundness": { + "type": 2 + }, + "seed": 792967269, + "versionNonce": 1704982302, + "isDeleted": false, + "boundElements": [], + "updated": 1, + "link": null, + "locked": false, + "points": [ + [ + 0, + 0 + ], + [ + 30, + 0 + ] + ], + "lastCommittedPoint": null, + "startBinding": null, + "endBinding": null, + "startArrowhead": null, + "endArrowhead": "arrow" + }, + { + "id": "a890794680", + "type": "arrow", + "x": 680, + "y": 85, + "width": 80, + "height": 30, + "angle": 0, + "strokeColor": "#b8650a", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "roundness": { + "type": 2 + }, + "seed": 1887119660, + "versionNonce": 1692865105, + "isDeleted": false, + "boundElements": [], + "updated": 1, + "link": null, + "locked": false, + "points": [ + [ + 0, + 0 + ], + [ + 80, + 30 + ] + ], + "lastCommittedPoint": null, + "startBinding": null, + "endBinding": null, + "startArrowhead": null, + "endArrowhead": "arrow" + }, + { + "id": "a47556484", + "type": "arrow", + "x": 680, + "y": 180, + "width": 80, + "height": 25, + "angle": 0, + "strokeColor": "#b8650a", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "roundness": { + "type": 2 + }, + "seed": 223566490, + "versionNonce": 146282412, + "isDeleted": false, + "boundElements": [], + "updated": 1, + "link": null, + "locked": false, + "points": [ + [ + 0, + 0 + ], + [ + 80, + -25 + ] + ], + "lastCommittedPoint": null, + "startBinding": null, + "endBinding": null, + "startArrowhead": null, + "endArrowhead": "arrow" + }, + { + "id": "a1488675709", + "type": "arrow", + "x": 460, + "y": 340, + "width": 80, + "height": 5, + "angle": 0, + "strokeColor": "#555555", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "roundness": { + "type": 2 + }, + "seed": 1188839531, + "versionNonce": 1260215618, + "isDeleted": false, + "boundElements": [], + "updated": 1, + "link": null, + "locked": false, + "points": [ + [ + 0, + 0 + ], + [ + 80, + -5 + ] + ], + "lastCommittedPoint": null, + "startBinding": null, + "endBinding": null, + "startArrowhead": null, + "endArrowhead": "arrow" + }, + { + "id": "a801058851", + "type": "arrow", + "x": 460, + "y": 340, + "width": 80, + "height": 65, + "angle": 0, + "strokeColor": "#555555", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "roundness": { + "type": 2 + }, + "seed": 1613429256, + "versionNonce": 189459271, + "isDeleted": false, + "boundElements": [], + "updated": 1, + "link": null, + "locked": false, + "points": [ + [ + 0, + 0 + ], + [ + 80, + 65 + ] + ], + "lastCommittedPoint": null, + "startBinding": null, + "endBinding": null, + "startArrowhead": null, + "endArrowhead": "arrow" + }, + { + "id": "a1345459336", + "type": "arrow", + "x": 440, + "y": 535, + "width": 30, + "height": 0, + "angle": 0, + "strokeColor": "#555555", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "roundness": { + "type": 2 + }, + "seed": 141639359, + "versionNonce": 1505204414, + "isDeleted": false, + "boundElements": [], + "updated": 1, + "link": null, + "locked": false, + "points": [ + [ + 0, + 0 + ], + [ + 30, + 0 + ] + ], + "lastCommittedPoint": null, + "startBinding": null, + "endBinding": null, + "startArrowhead": null, + "endArrowhead": "arrow" + }, + { + "id": "a419562255", + "type": "arrow", + "x": 440, + "y": 645, + "width": 30, + "height": 0, + "angle": 0, + "strokeColor": "#555555", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "roundness": { + "type": 2 + }, + "seed": 454306248, + "versionNonce": 812575554, + "isDeleted": false, + "boundElements": [], + "updated": 1, + "link": null, + "locked": false, + "points": [ + [ + 0, + 0 + ], + [ + 30, + 0 + ] + ], + "lastCommittedPoint": null, + "startBinding": null, + "endBinding": null, + "startArrowhead": null, + "endArrowhead": "arrow" + }, + { + "id": "a1722908311", + "type": "arrow", + "x": 720, + "y": 645, + "width": 30, + "height": 0, + "angle": 0, + "strokeColor": "#555555", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 2, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "roundness": { + "type": 2 + }, + "seed": 660472067, + "versionNonce": 1210486288, + "isDeleted": false, + "boundElements": [], + "updated": 1, + "link": null, + "locked": false, + "points": [ + [ + 0, + 0 + ], + [ + 30, + 0 + ] + ], + "lastCommittedPoint": null, + "startBinding": null, + "endBinding": null, + "startArrowhead": null, + "endArrowhead": "arrow" + }, + { + "id": "t1886682050", + "type": "text", + "x": 900, + "y": 200, + "width": 229.9, + "height": 13.75, + "angle": 0, + "strokeColor": "#1d1d1d", + "backgroundColor": "transparent", + "fillStyle": "solid", + "strokeWidth": 1, + "strokeStyle": "solid", + "roughness": 1, + "opacity": 100, + "groupIds": [], + "frameId": null, + "roundness": null, + "seed": 530311447, + "versionNonce": 1283201223, + "isDeleted": false, + "boundElements": [], + "updated": 1, + "link": null, + "locked": false, + "text": "same source, two compilers, one digest", + "fontSize": 11, + "fontFamily": 1, + "textAlign": "left", + "verticalAlign": "top", + "containerId": null, + "originalText": "same source, two compilers, one digest", + "lineHeight": 1.25, + "baseline": 11 + } + ], + "appState": { + "viewBackgroundColor": "#ffffff", + "gridSize": null + }, + "files": {} +} \ No newline at end of file diff --git a/assets/diagrams/46-toolbox-pipeline.svg b/assets/diagrams/46-toolbox-pipeline.svg new file mode 100644 index 0000000..2de5679 --- /dev/null +++ b/assets/diagrams/46-toolbox-pipeline.svg @@ -0,0 +1,78 @@ + + + +source + +Build / parity arm — GCC vs clang + +Static arm — compile-time checks + +Runtime arm — sanitizer + debugger + +Accelerators — optional, not verified this session + +toolbox.cpp +single source, +3 arms + +GCC build +preset: release + +clang build +preset: release-clang + +toolbox (gcc) +report → digest + +toolbox (clang) +report → digest + +parity gate +diff == empty +(byte-identical) + +compile_commands.json +compile DB + +clang-tidy +performance-unnecessary-value-param + +clang-format +--dry-run --Werror + +ubsan build +preset: ubsan + +defect overflow +runtime error: signed integer overflow + +debug build +preset: debug + +gdb -x .gdbinit ++ toolbox-printers.py + +print d +Digest(0x…) + +ccache +second-build cache hit + +mold +parallel linker, .comment + + + + + + + + + + + + + + +same source, two compilers, one digest + \ No newline at end of file diff --git a/assets/diagrams/README.md b/assets/diagrams/README.md index 612a771..b433c4e 100644 --- a/assets/diagrams/README.md +++ b/assets/diagrams/README.md @@ -89,3 +89,5 @@ here as you add them: | `44-goroutines-not-threads` | 44 | the netpoller contrast -- 2000 goroutines blocked on pipe reads parked in one shared epoll (netpoller, `epoll_pwait`) holding no M, OS thread count flat at the measured 12 (bound 80), beside a raw blocking `syscall.Read` where each blocked G pins its own M and the thread count climbs toward N via `handoffp`/`startm`/`newm` | | `45-analysis-suite-landscape` | 45 | three fleet-wide observation suites side by side -- Cockpit (browser → cockpit-ws → systemd/podman, socket verified HTTP 200, web panels described only), SystemTap (`.stp` → stap → generated C → kernel module, the verified `stap-module-ok` path amber, needs matching kernel-devel, contrasted with ch30's dyninst), and PCP (`pmcd` fed by `pmda-openmetrics` from `file:///etc/lsp45/lsp45.prom` and `pmda-podman` from `podman.sock`, with `pmda-bcc` a dashed not-shipped ghost) | | `45-pcp-build-gate` | 45 | the PCP image's three Containerfile stages -- builder (dnf install pcp + two PMDAs, `pmcd` started before `./Install`) → smoke (`FROM builder`, the `pcp`/`pminfo` gate proving openmetrics answers `value 42`) → runtime (`FROM smoke`, `EXPOSE 44321`, `ENTRYPOINT pmcd -f`), the amber `FROM smoke` edge that forces podman to build the gate stage, with Cockpit + SystemTap a dashed not-in-this-image box | +| `46-cmake-preset-graph` | 46 | the CMakePresets inheritance graph -- one `_base` config preset fanning out to `release`/`debug`/`asan`/`ubsan` and their `-clang` twins (color-coded GCC vs clang), each into its own `build/`, annotated with which tool consumes which preset (verify's parity gate, the UBSan gate, gdb), with the `conan` sub-target preset held apart and dashed-linked as isolated so the default build needs no Conan | +| `46-toolbox-pipeline` | 46 | the toolbox pipeline -- one `toolbox.cpp` source built by GCC and clang into the amber byte-identical parity gate (`diff == empty`), beside the static arm (`clang-tidy`, `clang-format --dry-run --Werror`) and the runtime arm (`ubsan` build → signed-overflow abort, `debug` build → gdb + Python pretty-printer → `Digest(0x…)`), with `ccache`/`mold` as dashed, not-verified-on-host accelerators | diff --git a/examples/46-cpp-toolbox/README.md b/examples/46-cpp-toolbox/README.md new file mode 100644 index 0000000..aa02156 --- /dev/null +++ b/examples/46-cpp-toolbox/README.md @@ -0,0 +1,87 @@ +# 46 — cpp-toolbox + +A **single-language** example (C++ only): the C++ toolchain itself is the +subject, so a Go or Rust variant would have nothing to show. One `toolbox` +binary plus a full set of toolchain artifacts, engineered so every tool +produces a checkable effect, not just a clean exit. + +- **`toolbox report`** — an FNV-1a digest over a fixed embedded byte array, + printed via a custom `Digest { uint64_t fnv; }` type. Integer/string + output only (no floats, addresses, timing, or unordered-container + iteration), so a GCC build and a clang build print byte-identical output. +- **`toolbox defect overflow`** — deliberately triggers signed-integer + overflow, caught by the `ubsan` CMake preset. +- `src/smell.cpp` — one deliberate, behavior-preserving clang-tidy smell + (`performance-unnecessary-value-param`), compiled into the same binary so + clang-tidy sees it through the compile-commands database. + +## Layout + +``` +46-cpp-toolbox/ +├── demo.sh # dispatcher: ./demo.sh [cpp|all|build] [args...] +├── verify.lua # automated check driven by CI +└── cpp/ + ├── demo.sh # release preset build/run + ├── CMakeLists.txt + ├── CMakePresets.json # release/debug/asan/ubsan/release-clang/debug-clang/conan + ├── .clang-tidy + ├── .clang-format + ├── .gdbinit # loads toolbox-printers.py + ├── toolbox-printers.py # gdb pretty-printer for Digest + ├── src/ + │ ├── toolbox.cpp # subcommands: report, defect overflow + │ ├── digest.{hpp,cpp} # Digest type + FNV-1a + │ └── smell.{hpp,cpp} # the tidy-smell TU + ├── fixtures/ + │ └── misformatted.cpp # NOT built; clang-format nonzero-exit demo + └── conan/ + ├── conanfile.py # isolated sub-target, pulls fmt + ├── conan.lock # committed lockfile + ├── CMakeLists.txt + └── src/main.cpp +``` + +## The demo contract + +- `./demo.sh cpp` — build then run (`release` preset) +- `./demo.sh cpp build` — build only +- `./demo.sh cpp run [args]` — run the built binary +- With env `TARGET` set, `run` deploys the binary to that lab VM via + `scripts/lab/deploy-to-vm.sh "$TARGET" -- [args]` instead of + running locally. + +The default build (`release` preset, what `./demo.sh cpp build` and CI +build-smoke use) never needs Conan, clang-tidy, clang-format, or gdb -- those +are exercised directly by `verify.lua` and the chapter's hand-run recipes. + +## Verify + +```bash +LSP_LANG=cpp REPO_ROOT=$(cd ../.. && pwd) lua verify.lua +``` + +Hard-gated, always asserted: + +- **A.** `release` (GCC) vs `release-clang` builds of `toolbox report` are + byte-identical and equal a known literal. +- **B.** The `ubsan` preset catches the seeded overflow and prints + `runtime error: signed integer overflow`. +- **C.** `gdb -batch -x cpp/.gdbinit ...` renders the pretty-printed + `Digest(0x...)`. + +Gated only if the tool is present on `PATH` (never fails the example if +absent -- degrades to an informational `SKIP:` line): + +- **D.** clang-tidy flags `performance-unnecessary-value-param` at + `src/smell.cpp:3`. +- **E.** `clang-format --dry-run --Werror` is clean on the tracked sources, + nonzero on `fixtures/misformatted.cpp`. +- **F.** `conan install` against the committed lockfile + the `conan` + preset build + run prints the expected line. + +ccache and mold are checked opportunistically and printed for information +only -- both are expected absent on the reference host and are never part +of the pass/fail count. + +Mode: `local`. No root, no VM, no LGTM stack. diff --git a/examples/46-cpp-toolbox/cpp/.clang-format b/examples/46-cpp-toolbox/cpp/.clang-format new file mode 100644 index 0000000..511e918 --- /dev/null +++ b/examples/46-cpp-toolbox/cpp/.clang-format @@ -0,0 +1,8 @@ +--- +BasedOnStyle: LLVM +Language: Cpp +Standard: Latest +IndentWidth: 4 +ColumnLimit: 100 +PointerAlignment: Left +AllowShortFunctionsOnASingleLine: Inline diff --git a/examples/46-cpp-toolbox/cpp/.clang-tidy b/examples/46-cpp-toolbox/cpp/.clang-tidy new file mode 100644 index 0000000..d53e2c7 --- /dev/null +++ b/examples/46-cpp-toolbox/cpp/.clang-tidy @@ -0,0 +1,16 @@ +--- +# Pinned check for the ch46 clang-tidy gate: performance-unnecessary-value-param, +# which src/smell.cpp's decorate_label(std::string label) deliberately trips +# (the parameter is only read, so passing by value forces an avoidable copy). +# verify.lua asserts the check-NAME token, not message wording, so this stays +# stable across clang-tidy versions. +Checks: > + bugprone-*, + modernize-*, + performance-*, + readability-*, + -modernize-use-trailing-return-type, + -readability-identifier-length +WarningsAsErrors: '' +HeaderFilterRegex: '.*' +FormatStyle: file diff --git a/examples/46-cpp-toolbox/cpp/.gdbinit b/examples/46-cpp-toolbox/cpp/.gdbinit new file mode 100644 index 0000000..7d875a7 --- /dev/null +++ b/examples/46-cpp-toolbox/cpp/.gdbinit @@ -0,0 +1,6 @@ +# Loads the Digest pretty-printer (toolbox-printers.py). Invoked from the +# example root (examples/46-cpp-toolbox/) as: +# gdb -batch -x cpp/.gdbinit -ex 'b cmd_report' -ex run \ +# -ex 'p d' cpp/build/debug/toolbox report +set debuginfod enabled off +source cpp/toolbox-printers.py diff --git a/examples/46-cpp-toolbox/cpp/CMakeLists.txt b/examples/46-cpp-toolbox/cpp/CMakeLists.txt new file mode 100644 index 0000000..87a8343 --- /dev/null +++ b/examples/46-cpp-toolbox/cpp/CMakeLists.txt @@ -0,0 +1,25 @@ +cmake_minimum_required(VERSION 3.25) +project(toolbox CXX) + +set(CMAKE_CXX_STANDARD 23) +set(CMAKE_CXX_STANDARD_REQUIRED ON) +set(CMAKE_CXX_EXTENSIONS OFF) +set(CMAKE_EXPORT_COMPILE_COMMANDS ON) + +add_executable(toolbox + src/toolbox.cpp + src/digest.cpp + src/smell.cpp +) +target_include_directories(toolbox PRIVATE src) + +# The Conan sub-target (cpp/conan/) pulls one small dependency (fmt) via a +# Conan-generated CMakeDeps config. It is added ONLY when the "conan" preset +# turns this option on (which also points CMAKE_TOOLCHAIN_FILE at Conan's +# generated toolchain) -- every other preset, including "release" (what +# ./demo.sh cpp build and fedora:44 CI build-smoke use), never evaluates +# this subdirectory and never needs Conan installed. +option(TOOLBOX_ENABLE_CONAN "Build the Conan-provided fmt sub-target" OFF) +if(TOOLBOX_ENABLE_CONAN) + add_subdirectory(conan) +endif() diff --git a/examples/46-cpp-toolbox/cpp/CMakePresets.json b/examples/46-cpp-toolbox/cpp/CMakePresets.json new file mode 100644 index 0000000..490d72c --- /dev/null +++ b/examples/46-cpp-toolbox/cpp/CMakePresets.json @@ -0,0 +1,84 @@ +{ + "version": 6, + "cmakeMinimumRequired": { "major": 3, "minor": 25, "patch": 0 }, + "configurePresets": [ + { + "name": "_base", + "hidden": true, + "generator": "Ninja", + "binaryDir": "${sourceDir}/build/${presetName}", + "cacheVariables": { + "CMAKE_EXPORT_COMPILE_COMMANDS": "ON" + } + }, + { + "name": "release", + "inherits": "_base", + "displayName": "Release (-O2 with debug info, GCC)", + "cacheVariables": { "CMAKE_BUILD_TYPE": "RelWithDebInfo" } + }, + { + "name": "debug", + "inherits": "_base", + "displayName": "Debug (GCC)", + "cacheVariables": { "CMAKE_BUILD_TYPE": "Debug" } + }, + { + "name": "asan", + "inherits": "_base", + "displayName": "ASan + UBSan instrumented build", + "cacheVariables": { + "CMAKE_BUILD_TYPE": "Debug", + "CMAKE_CXX_FLAGS": "-O1 -g -fno-omit-frame-pointer -fsanitize=address,undefined", + "CMAKE_EXE_LINKER_FLAGS": "-fsanitize=address,undefined" + } + }, + { + "name": "ubsan", + "inherits": "_base", + "displayName": "UBSan-only, no-recover instrumented build", + "cacheVariables": { + "CMAKE_BUILD_TYPE": "Debug", + "CMAKE_CXX_FLAGS": "-O1 -g -fno-omit-frame-pointer -fsanitize=undefined -fno-sanitize-recover=undefined", + "CMAKE_EXE_LINKER_FLAGS": "-fsanitize=undefined" + } + }, + { + "name": "release-clang", + "inherits": "release", + "displayName": "Release (clang)", + "cacheVariables": { + "CMAKE_C_COMPILER": "clang", + "CMAKE_CXX_COMPILER": "clang++" + } + }, + { + "name": "debug-clang", + "inherits": "debug", + "displayName": "Debug (clang)", + "cacheVariables": { + "CMAKE_C_COMPILER": "clang", + "CMAKE_CXX_COMPILER": "clang++" + } + }, + { + "name": "conan", + "inherits": "_base", + "displayName": "Conan 2 sub-target (fmt, isolated)", + "cacheVariables": { + "CMAKE_BUILD_TYPE": "Release", + "CMAKE_TOOLCHAIN_FILE": "${sourceDir}/build/conan/generators/conan_toolchain.cmake", + "TOOLBOX_ENABLE_CONAN": "ON" + } + } + ], + "buildPresets": [ + { "name": "release", "configurePreset": "release" }, + { "name": "debug", "configurePreset": "debug" }, + { "name": "asan", "configurePreset": "asan" }, + { "name": "ubsan", "configurePreset": "ubsan" }, + { "name": "release-clang", "configurePreset": "release-clang" }, + { "name": "debug-clang", "configurePreset": "debug-clang" }, + { "name": "conan", "configurePreset": "conan" } + ] +} diff --git a/examples/46-cpp-toolbox/cpp/conan/CMakeLists.txt b/examples/46-cpp-toolbox/cpp/conan/CMakeLists.txt new file mode 100644 index 0000000..ae26a5c --- /dev/null +++ b/examples/46-cpp-toolbox/cpp/conan/CMakeLists.txt @@ -0,0 +1,9 @@ +# Isolated Conan sub-target: only add_subdirectory()'d by the parent +# cpp/CMakeLists.txt when TOOLBOX_ENABLE_CONAN=ON (set by the "conan" +# CMakePresets.json preset). find_package(fmt) resolves against the +# CMakeDeps config Conan generates into build/conan/generators/. +find_package(fmt REQUIRED) + +add_executable(toolbox-conan-demo src/main.cpp) +target_link_libraries(toolbox-conan-demo PRIVATE fmt::fmt) +target_compile_features(toolbox-conan-demo PRIVATE cxx_std_23) diff --git a/examples/46-cpp-toolbox/cpp/conan/conan.lock b/examples/46-cpp-toolbox/cpp/conan/conan.lock new file mode 100644 index 0000000..00a096c --- /dev/null +++ b/examples/46-cpp-toolbox/cpp/conan/conan.lock @@ -0,0 +1,9 @@ +{ + "version": "0.5", + "requires": [ + "fmt/11.0.2#7b5e2770c1ccb3d4af9b4f6762135645%1778145873.016" + ], + "build_requires": [], + "python_requires": [], + "config_requires": [] +} diff --git a/examples/46-cpp-toolbox/cpp/conan/conanfile.py b/examples/46-cpp-toolbox/cpp/conan/conanfile.py new file mode 100644 index 0000000..5c863bf --- /dev/null +++ b/examples/46-cpp-toolbox/cpp/conan/conanfile.py @@ -0,0 +1,28 @@ +"""Conan 2 consumer for the isolated toolbox-conan-demo sub-target (ch46 +"Conan 2 lockfiles" section). Pulls exactly one small dependency (fmt) via +CMakeDeps + CMakeToolchain. Deliberately its own conanfile, separate from +the default cpp/ build -- ./demo.sh cpp build and the release preset never +evaluate this, so fedora:44 CI build-smoke (no Conan installed) stays green. +""" + +from conan import ConanFile +from conan.tools.cmake import CMakeDeps, CMakeToolchain + + +class ToolboxConanDemo(ConanFile): + name = "toolbox-conan-demo" + version = "1.0.0" + settings = "os", "compiler", "build_type", "arch" + + def requirements(self): + self.requires("fmt/11.0.2") + + def layout(self): + # Generated files land in build/conan/generators/ (relative to the + # --output-folder passed on the CLI), matching the "conan" + # CMakePresets.json preset's CMAKE_TOOLCHAIN_FILE path. + self.folders.generators = "generators" + + def generate(self): + CMakeDeps(self).generate() + CMakeToolchain(self).generate() diff --git a/examples/46-cpp-toolbox/cpp/conan/src/main.cpp b/examples/46-cpp-toolbox/cpp/conan/src/main.cpp new file mode 100644 index 0000000..4ecb5c8 --- /dev/null +++ b/examples/46-cpp-toolbox/cpp/conan/src/main.cpp @@ -0,0 +1,10 @@ +// Isolated Conan sub-target (ch46 "Conan 2 lockfiles"): proves the +// CMakeDeps/CMakeToolchain-generated fmt package links and runs. Not +// wired into the toolbox binary or its digest -- this line is not part of +// the GCC-vs-clang parity gate. +#include + +int main() { + fmt::print("toolbox-conan: fmt sub-target ok\n"); + return 0; +} diff --git a/examples/46-cpp-toolbox/cpp/demo.sh b/examples/46-cpp-toolbox/cpp/demo.sh new file mode 100755 index 0000000..af0fd18 --- /dev/null +++ b/examples/46-cpp-toolbox/cpp/demo.sh @@ -0,0 +1,40 @@ +#!/usr/bin/env bash +set -euo pipefail + +cd "$(dirname "${BASH_SOURCE[0]}")" +REPO_ROOT="$(cd ../../.. && pwd)" +BIN=build/release/toolbox + +build() { + cmake --preset release + cmake --build --preset release +} + +run() { + if [[ ! -x "$BIN" ]]; then + build + fi + if [[ -n "${TARGET:-}" ]]; then + "$REPO_ROOT/scripts/lab/deploy-to-vm.sh" "$TARGET" "$BIN" -- "$@" + else + "./$BIN" "$@" + fi +} + +case "${1:-}" in + build) + build + ;; + run) + shift + run "$@" + ;; + "") + build + run + ;; + *) + echo "usage: $0 [build|run [args]]" >&2 + exit 2 + ;; +esac diff --git a/examples/46-cpp-toolbox/cpp/fixtures/misformatted.cpp b/examples/46-cpp-toolbox/cpp/fixtures/misformatted.cpp new file mode 100644 index 0000000..f129223 --- /dev/null +++ b/examples/46-cpp-toolbox/cpp/fixtures/misformatted.cpp @@ -0,0 +1,16 @@ +// Deliberately misformatted (ch46 clang-format gate). NOT part of the +// build -- CMakeLists.txt never lists this file. `clang-format --dry-run +// --Werror` against this file must exit nonzero, in contrast to the tracked +// sources in ../src, which must exit 0. +#include +int add(int a,int b){ + return a+b; +} + +int main(int argc,char**argv) +{ + int x=1; + int y =2; + printf("%d\n",add(x,y)); + return 0 ; +} diff --git a/examples/46-cpp-toolbox/cpp/src/digest.cpp b/examples/46-cpp-toolbox/cpp/src/digest.cpp new file mode 100644 index 0000000..d967563 --- /dev/null +++ b/examples/46-cpp-toolbox/cpp/src/digest.cpp @@ -0,0 +1,15 @@ +#include "digest.hpp" + +namespace { +constexpr std::uint64_t kFnvOffsetBasis = 0xcbf29ce484222325ULL; +constexpr std::uint64_t kFnvPrime = 0x100000001b3ULL; +} // namespace + +Digest fnv1a(const std::uint8_t* data, std::size_t len) { + std::uint64_t h = kFnvOffsetBasis; + for (std::size_t i = 0; i < len; ++i) { + h ^= static_cast(data[i]); + h *= kFnvPrime; + } + return Digest{h}; +} diff --git a/examples/46-cpp-toolbox/cpp/src/digest.hpp b/examples/46-cpp-toolbox/cpp/src/digest.hpp new file mode 100644 index 0000000..6cd1a16 --- /dev/null +++ b/examples/46-cpp-toolbox/cpp/src/digest.hpp @@ -0,0 +1,25 @@ +#pragma once + +#include +#include +#include + +// A custom aggregate wrapping a single 64-bit hash value. Small on purpose: +// it exists so the gdb chapter (`.gdbinit` + `toolbox-printers.py`) has a +// concrete, non-trivial type to pretty-print instead of a bare integer. +struct Digest { + std::uint64_t fnv; +}; + +// FNV-1a over a fixed, embedded byte array. Integer/string-only, no floats, +// no addresses, no timing, no unordered-container iteration -- the same +// input bytes must produce the same digest bit-for-bit on every conforming +// C++23 compiler, which is what the GCC-vs-clang parity gate (ch46 Sec. +// "GCC-vs-clang parity") relies on. +Digest fnv1a(const std::uint8_t* data, std::size_t len); + +// The fixed payload `report` hashes. Extracted so `toolbox.cpp` and any +// future caller share one definition. +inline constexpr std::array kPayload = { + 0x54, 0x68, 0x65, 0x20, 0x71, 0x75, 0x69, 0x63, 0x6b, 0x20, 0x62, 0x72, 0x6f, 0x77, 0x6e, 0x2e, +}; diff --git a/examples/46-cpp-toolbox/cpp/src/smell.cpp b/examples/46-cpp-toolbox/cpp/src/smell.cpp new file mode 100644 index 0000000..32f02f0 --- /dev/null +++ b/examples/46-cpp-toolbox/cpp/src/smell.cpp @@ -0,0 +1,5 @@ +#include "smell.hpp" + +std::string decorate_label(std::string label) { + return "[toolbox] " + label; +} diff --git a/examples/46-cpp-toolbox/cpp/src/smell.hpp b/examples/46-cpp-toolbox/cpp/src/smell.hpp new file mode 100644 index 0000000..950a0c9 --- /dev/null +++ b/examples/46-cpp-toolbox/cpp/src/smell.hpp @@ -0,0 +1,11 @@ +#pragma once + +#include + +// Deliberate, behavior-preserving smell for the clang-tidy gate (ch46 Sec. +// "Errors, three ways" -- the tidy finding). `label` is only ever read, so +// taking it by value forces an avoidable copy on every call; clang-tidy's +// performance-unnecessary-value-param flags this parameter, and the fix is +// `const std::string&`. Left as `std::string` on purpose -- do not "fix" +// this without re-pinning the tidy chapter section. +std::string decorate_label(std::string label); diff --git a/examples/46-cpp-toolbox/cpp/src/toolbox.cpp b/examples/46-cpp-toolbox/cpp/src/toolbox.cpp new file mode 100644 index 0000000..cf9b122 --- /dev/null +++ b/examples/46-cpp-toolbox/cpp/src/toolbox.cpp @@ -0,0 +1,73 @@ +// toolbox -- the reference C++23 program for ch46 (CMake presets, Conan +// lockfiles, GCC/clang parity, gdb pretty-printers, clang-tidy/clang-format, +// ccache/mold). +// +// Subcommands: +// toolbox report -- deterministic FNV-1a digest over a fixed +// embedded payload, integer/string output +// only (no floats, addresses, timing, or +// unordered-container iteration) so GCC and +// clang builds are byte-identical. +// toolbox defect overflow -- deliberately triggers signed-integer +// overflow, for the UBSan recipe. +#include +#include +#include +#include +#include + +#include "digest.hpp" +#include "smell.hpp" + +namespace { + +void print_usage() { + std::fprintf(stderr, "usage: toolbox \n"); +} + +int cmd_report() { + const Digest d = fnv1a(kPayload.data(), kPayload.size()); + const std::string label = decorate_label("report"); + std::printf("toolbox report: label=%s payload_len=%zu digest=0x%016llx\n", label.c_str(), + kPayload.size(), static_cast(d.fnv)); + return 0; +} + +int cmd_defect_overflow() { + // `volatile` blocks the compiler from constant-folding the overflow at + // compile time -- the point is a *runtime* UBSan trap, not a compiler + // diagnostic. This one statement is the entire seeded defect. + volatile int max_value = INT_MAX; + std::printf("toolbox defect overflow: max_value=%d\n", max_value); + std::fflush(stdout); // UBSan's trap handler may skip normal atexit flushing. + int overflowed = max_value + 1; // UB: signed integer overflow. + std::printf("unreachable: overflowed=%d\n", overflowed); + return 0; +} + +} // namespace + +int main(int argc, char** argv) { + if (argc < 2) { + print_usage(); + return 2; + } + const std::string_view cmd = argv[1]; + if (cmd == "report") { + return cmd_report(); + } + if (cmd == "defect") { + if (argc < 3) { + print_usage(); + return 2; + } + const std::string_view sub = argv[2]; + if (sub == "overflow") { + return cmd_defect_overflow(); + } + std::fprintf(stderr, "unknown defect: %.*s\n", static_cast(sub.size()), sub.data()); + return 2; + } + print_usage(); + return 2; +} diff --git a/examples/46-cpp-toolbox/cpp/toolbox-printers.py b/examples/46-cpp-toolbox/cpp/toolbox-printers.py new file mode 100644 index 0000000..dffb7bf --- /dev/null +++ b/examples/46-cpp-toolbox/cpp/toolbox-printers.py @@ -0,0 +1,36 @@ +"""gdb pretty-printer for toolbox's Digest type (ch46 "gdb printers" section). + +Digest is `struct Digest { std::uint64_t fnv; };` -- without this printer gdb +shows the raw aggregate (`{fnv = 12345...}`); with it, `print`/`p` renders +`Digest(0x<16 lowercase hex digits>)`, matching the digest format `toolbox +report` itself prints. +""" + +import gdb + + +class DigestPrinter: + def __init__(self, val): + self.val = val + + def to_string(self): + fnv = int(self.val["fnv"]) & 0xFFFFFFFFFFFFFFFF + return "Digest(0x{:016x})".format(fnv) + + +def _lookup(val): + t = val.type.unqualified().strip_typedefs() + if t.tag == "Digest": + return DigestPrinter(val) + return None + + +def register_printers(): + gdb.pretty_printers.append(_lookup) + + +# `gdb source cpp/toolbox-printers.py` execs this file directly (gdb's +# Python "source" is not the module import system, so the hyphen in this +# filename is fine) -- register on load rather than requiring a separate +# `import`. +register_printers() diff --git a/examples/46-cpp-toolbox/demo.sh b/examples/46-cpp-toolbox/demo.sh new file mode 100755 index 0000000..c071461 --- /dev/null +++ b/examples/46-cpp-toolbox/demo.sh @@ -0,0 +1,26 @@ +#!/usr/bin/env bash +set -euo pipefail +cd "$(dirname "$0")" + +# Single-language example (C++ only): the whole point is the C++ toolchain +# itself (CMake presets, Conan, GCC/clang parity, gdb printers, clang-tidy/ +# clang-format, ccache/mold) -- a Go or Rust variant would have nothing to +# show. +langs=(cpp) + +case "${1:-all}" in + cpp) + shift + exec "./cpp/demo.sh" "$@" + ;; + all) + for lang in "${langs[@]}"; do "./$lang/demo.sh"; done + ;; + build) + for lang in "${langs[@]}"; do "./$lang/demo.sh" build; done + ;; + *) + echo "usage: $0 [cpp|all|build] [args...]" >&2 + exit 2 + ;; +esac diff --git a/examples/46-cpp-toolbox/verify.lua b/examples/46-cpp-toolbox/verify.lua new file mode 100644 index 0000000..40fb123 --- /dev/null +++ b/examples/46-cpp-toolbox/verify.lua @@ -0,0 +1,161 @@ +-- Verify 46-cpp-toolbox (C++ only): the C++ toolchain itself is the subject +-- -- CMake presets, Conan lockfiles, GCC/clang parity, gdb pretty-printers, +-- clang-tidy/clang-format. Every assertion below checks a real, tool-produced +-- effect, never merely a process exit code. +-- +-- Hard-gated (A-C): deterministic on the pinned C++23 toolchain, always run. +-- A. `toolbox report` (FNV-1a digest, integer/string output only) is +-- byte-identical between a GCC build and a clang build, AND equals a +-- known literal. +-- B. The "ubsan" preset catches a deliberately seeded signed-integer +-- overflow (`toolbox defect overflow`) and prints UBSan's +-- "runtime error: signed integer overflow" line. +-- C. gdb, loaded with cpp/.gdbinit's Digest pretty-printer, renders the +-- custom Digest type as "Digest(0x<16 hex digits>)" instead of the raw +-- aggregate. +-- +-- Gated-if-present (D-F): each tool's absence degrades to an informational +-- "SKIP:" print (not a checks.skip(), which would abort the whole script -- +-- A-C must still run even if clang-tidy/clang-format/conan happen to be +-- missing). On the reference host all three are present, so these do run +-- and do count toward PASS/FAIL. +-- D. clang-tidy, via the compile-commands DB, flags src/smell.cpp's +-- deliberate performance-unnecessary-value-param smell. +-- E. clang-format --dry-run --Werror exits 0 on the tracked sources and +-- nonzero on the deliberately misformatted fixture. +-- F. `conan install` (against the committed lockfile) + the "conan" preset +-- build + run produces the expected line. +-- +-- ccache/mold: opportunistic presence check only, printed but never +-- asserted -- both are expected absent on the reference host. + +local script_dir = arg[0]:match("(.*/)") or "./" +local repo_root = os.getenv("REPO_ROOT") or (script_dir .. "../..") +package.path = package.path .. ";" .. repo_root .. "/scripts/lib/?.lua" +local checks = require("checks") + +local lang = os.getenv("LSP_LANG") +if lang ~= "cpp" then + checks.skip("46-cpp-toolbox is C++-only (LSP_LANG=" .. tostring(lang) .. ")") +end + +-- Escape a literal string for use inside a Lua pattern (checks.expect_match +-- takes a pattern, not a plain substring). +local function lit(s) + return (s:gsub("([%(%)%.%%%+%-%*%?%[%]%^%$])", "%%%1")) +end + +local function tool_present(cmd) + return checks.run("command -v " .. cmd .. " >/dev/null 2>&1").exit == 0 +end + +-- ── A. GCC-vs-clang byte parity ────────────────────────────────────────── + +local b = checks.run("./demo.sh cpp build") +checks.expect_exit(b, 0, "cpp: release (GCC) builds via ./demo.sh cpp build") + +local rclang = checks.run( + "cd cpp && cmake --preset release-clang >/dev/null && cmake --build --preset release-clang >/dev/null") +checks.expect_exit(rclang, 0, "cpp: release-clang builds") + +local EXPECTED_REPORT = + "toolbox report: label=[toolbox] report payload_len=16 digest=0x481984990deee5ff" + +local gcc_report = checks.run("./cpp/build/release/toolbox report") +checks.expect_exit(gcc_report, 0, "cpp: GCC-built toolbox report runs") +checks.expect_match(gcc_report.out, lit(EXPECTED_REPORT), + "cpp: GCC-built report equals the expected literal") + +local clang_report = checks.run("./cpp/build/release-clang/toolbox report") +checks.expect_exit(clang_report, 0, "cpp: clang-built toolbox report runs") +checks.expect_match(clang_report.out, lit(EXPECTED_REPORT), + "cpp: clang-built report equals the expected literal") + +local parity = checks.run( + "bash -c 'diff <(./cpp/build/release/toolbox report) <(./cpp/build/release-clang/toolbox report)'") +checks.expect_exit(parity, 0, + "cpp: GCC vs clang report output is byte-identical (empty diff)") + +-- ── B. UBSan recipe ─────────────────────────────────────────────────────── + +local ubsan_build = checks.run( + "cd cpp && cmake --preset ubsan >/dev/null && cmake --build --preset ubsan >/dev/null") +checks.expect_exit(ubsan_build, 0, "cpp: ubsan preset builds") + +local ubsan_run = checks.run("./cpp/build/ubsan/toolbox defect overflow") +checks.expect_exit(ubsan_run, 1, "cpp: ubsan build exits 1 on the seeded overflow") +checks.expect_match(ubsan_run.out, "runtime error: signed integer overflow", + "cpp: UBSan reports 'runtime error: signed integer overflow'") + +-- ── C. gdb pretty-printer ───────────────────────────────────────────────── + +local debug_build = checks.run( + "cd cpp && cmake --preset debug >/dev/null && cmake --build --preset debug >/dev/null") +checks.expect_exit(debug_build, 0, "cpp: debug preset builds") + +local gdb_run = checks.run( + "gdb -batch -x cpp/.gdbinit -ex 'b toolbox.cpp:30' -ex run -ex 'p d' " .. + "--args cpp/build/debug/toolbox report") +checks.expect_exit(gdb_run, 0, "cpp: gdb batch run exits 0") +checks.expect_match(gdb_run.out, lit("Digest(0x481984990deee5ff)"), + "cpp: gdb pretty-printer renders the Digest custom type") + +-- ── D. clang-tidy (skip-if-absent) ─────────────────────────────────────── + +if tool_present("clang-tidy") then + local tidy = checks.run("cd cpp && clang-tidy -p build/release src/smell.cpp 2>&1") + checks.expect_match(tidy.out, "smell%.cpp:3.-performance%-unnecessary%-value%-param", + "cpp: clang-tidy flags performance-unnecessary-value-param at smell.cpp:3") +else + print("SKIP: clang-tidy not found on PATH -- gate D not asserted") +end + +-- ── E. clang-format (skip-if-absent) ───────────────────────────────────── + +if tool_present("clang-format") then + local fmt_tracked = checks.run( + "cd cpp && clang-format --dry-run --Werror src/*.cpp src/*.hpp conan/src/*.cpp") + checks.expect_exit(fmt_tracked, 0, "cpp: clang-format --dry-run --Werror is clean on tracked sources") + + local fmt_fixture = checks.run( + "cd cpp && clang-format --dry-run --Werror fixtures/misformatted.cpp") + checks.expect_exit(fmt_fixture, 1, "cpp: clang-format flags the deliberately misformatted fixture") +else + print("SKIP: clang-format not found on PATH -- gate E not asserted") +end + +-- ── F. Conan 2 sub-target (skip-if-absent) ─────────────────────────────── + +if tool_present("conan") then + local install = checks.run( + "cd cpp && conan install conan --output-folder=build/conan --build=missing " .. + "--lockfile=conan/conan.lock >/dev/null 2>&1") + checks.expect_exit(install, 0, "cpp: conan install (against the committed lockfile) succeeds") + + local conan_build = checks.run( + "cd cpp && cmake --preset conan >/dev/null && cmake --build --preset conan >/dev/null") + checks.expect_exit(conan_build, 0, "cpp: conan preset configures and builds") + + local conan_run = checks.run("./cpp/build/conan/conan/toolbox-conan-demo") + checks.expect_exit(conan_run, 0, "cpp: toolbox-conan-demo runs") + checks.expect_match(conan_run.out, lit("toolbox-conan: fmt sub-target ok"), + "cpp: toolbox-conan-demo prints the expected line") +else + print("SKIP: conan not found on PATH -- gate F not asserted") +end + +-- ── ccache/mold: opportunistic, informational only, never gated ───────── + +if tool_present("ccache") then + print("info: ccache present on PATH (see chapter for the cache-hit recipe)") +else + print("info: ccache absent on this host -- ccache recipe shown in the chapter but not asserted") +end + +if tool_present("mold") then + print("info: mold present on PATH (see chapter for the parallel-linker recipe)") +else + print("info: mold absent on this host -- mold recipe shown in the chapter but not asserted") +end + +checks.finish() diff --git a/examples/manifest.yaml b/examples/manifest.yaml index 6300930..5635919 100644 --- a/examples/manifest.yaml +++ b/examples/manifest.yaml @@ -189,3 +189,7 @@ examples: mode: local requires: [podman] timeout: 600 + - id: 46-cpp-toolbox + langs: [cpp] + mode: local + timeout: 420