From 84d9d666490e2d7044f470b0e50f84171eb9b427 Mon Sep 17 00:00:00 2001 From: Jorijn van der Graaf Date: Sat, 31 Oct 2026 05:10:48 +0100 Subject: [PATCH] docs: correct what the sibling-args docs promise The README suggested giving one sibling a list without a flag only the project reads, so that the sibling would not get a build directory of its own. When another path loads the same sibling with the full list, that filter is what gives it the second directory: two builds of one project, both in the program (#41). It now says to build such a list once and give it to every sibling. It also says the default is read when the spec is made, so a spec made at namespace scope, on another thread or in a script forwards nothing, and that cfg.projectArgs, the part ApplyStandardArgs did not interpret, is no substitute: it drops the target and the build type. The comments on ProjectArgs() and on Configuration::projectArgs say the same. The spec comment named --local as a flag the default carries down a chain of siblings. Through a GitProject hop it breaks: the clone has no checkouts beside it. The GitProject comment said the clone is keyed by the args; only the Configuration is, and every arg list builds in the one clone. AGENTS.md now notes that a stale harness gives no symptom for a changed default member initialiser: project.cpp silently gets the old default. Co-Authored-By: Claude Opus 5.5 --- AGENTS.md | 2 +- README.md | 4 +++- interfaces/Crafter.Build-Clang.cppm | 4 +++- interfaces/Crafter.Build-External.cppm | 23 ++++++++++++++--------- 4 files changed, 21 insertions(+), 12 deletions(-) diff --git a/AGENTS.md b/AGENTS.md index ffd0057..d5227e8 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -45,7 +45,7 @@ Prerequisites on Linux: `clang` (with `libclang`, which the AST lint rules load Three things to know about this loop: - `bin/crafter-build` is the bootstrap binary and the harness for every command below. The self-host build writes to `bin/crafter.build-exe-/crafter-build` and does not replace it. -- Changes under `implementations/` are picked up by the self-host build and by the tests, which link the local library. Changes under `interfaces/` are not: the harness compiles against the copies in `share/crafter-build/` and the PCM cache built from them, so a new or changed declaration is invisible until you run `./build.sh` again. The symptom is `use of undeclared identifier` for the symbol you just added. +- Changes under `implementations/` are picked up by the self-host build and by the tests, which link the local library. Changes under `interfaces/` are not: the harness compiles against the copies in `share/crafter-build/` and the PCM cache built from them, so a new or changed declaration is invisible until you run `./build.sh` again. The symptom is `use of undeclared identifier` for the symbol you just added. A changed default member initialiser has no symptom at all: `project.cpp` compiles against the old one and quietly gets the old default, as `project.cpp`'s sibling loads do with a harness that predates `GitProjectSpec::args = ProjectArgs()`. - A new exported symbol that a `project.cpp` reaches on its default path also needs `./build.sh`: the old binary does not export it, and `LoadProject` fails with an undefined symbol. `./build.sh` clones and builds glslang on first run and takes several minutes; later runs are faster. `./bin/crafter-build clean` deletes `bin/` and `build/` without loading `project.cpp`. That takes `bin/crafter-build` itself with it, and `build/flatpak`, the state of the local Flatpak build (see "CI and publishing"): about 2 GB, and the next `run flatpak` rebuilds LLVM. Set `CRAFTER_BUILD_HOME` only when running a binary from outside this tree; `CRAFTER_BUILD_MARCH` and `CRAFTER_BUILD_MTUNE` default to `native`. diff --git a/README.md b/README.md index 89fc5de..2620f3f 100644 --- a/README.md +++ b/README.md @@ -74,7 +74,9 @@ Configuration* sibling = LocalProject({ .projectFile = "../Crafter.Math/project. cfg.dependencies = { math }; ``` -The sibling's `CrafterBuildProject` gets the args this `project.cpp` was loaded with (`ProjectArgs()`), so `--target=`, `--march=`, `--debug` and the project's own flags reach every sibling down the chain. Set `.args` to send something else: `{}` for nothing, or a list built from the project's args, say one without a flag only this project reads (it would otherwise give the sibling a build directory of its own) or with an extra `--target=`. Releases up to 2.2.0 forward nothing when `.args` is left out. +The sibling's `CrafterBuildProject` gets the args this `project.cpp` was loaded with (`ProjectArgs()`), so `--target=`, `--march=`, `--debug` and the project's own flags reach every sibling down the chain. That is all of them: `cfg.projectArgs` holds only what `ApplyStandardArgs` did not interpret, and passing it on would drop the target and the build type. Set `.args` to send something else: `{}` for nothing, or a list built from the project's args, such as one without a flag only this project reads. Build such a list once and give it to every sibling. A project that two paths load with different lists is built twice, and the program ends up with both builds. Releases up to 2.2.0 forward nothing when `.args` is left out. + +The default is read when the spec is made, so make it inside `CrafterBuildProject`, on the thread that calls it. A spec made at namespace scope, on a thread of your own or in a script forwards nothing. Clones share the external cache and identical specs share one `Configuration`. An unpinned source is `git pull`ed on every invocation, set `.commit` for reproducible, offline-after-first-fetch builds. diff --git a/interfaces/Crafter.Build-Clang.cppm b/interfaces/Crafter.Build-Clang.cppm index 12be520..07a787a 100644 --- a/interfaces/Crafter.Build-Clang.cppm +++ b/interfaces/Crafter.Build-Clang.cppm @@ -483,7 +483,9 @@ export namespace Crafter { // cfg.files, say), and without it both flag settings share one bin dir // and interleave their outputs there. Populated by ApplyStandardArgs; // the args it does recognise are excluded, since their effect already - // shows up in target/march/mtune/debug/sysroot/type. + // shows up in target/march/mtune/debug/sysroot/type. For the same + // reason this is not what to hand a sibling project: ProjectArgs() is + // every arg, the recognised ones included. std::vector projectArgs; std::vector tests; // Lint rules for `crafter-build lint`. Populate via AddLintRule. diff --git a/interfaces/Crafter.Build-External.cppm b/interfaces/Crafter.Build-External.cppm index 317879c..23ebe6e 100644 --- a/interfaces/Crafter.Build-External.cppm +++ b/interfaces/Crafter.Build-External.cppm @@ -93,21 +93,26 @@ export namespace Crafter { // remote's default branch HEAD (sloppy but convenient), set branch to // track a branch tip, or set commit to pin to an immutable SHA. args are // what the dep's CrafterBuildProject receives. They default to this - // project's own, so --target=, --march=, --debug and flags of its own - // such as --local reach a whole chain of sibling projects without being - // passed. Set them to forward something else: a copy without one of this - // project's flags, one with an extra --target=, or {} for nothing. + // project's own, read when the spec is made, so --target=, --march=, + // --debug and the project's own flags reach every sibling down a chain + // without being passed. Set them to forward something else: {} for + // nothing, or a list built from this project's args, such as one without + // a flag only this project reads. Give such a list to every sibling: a + // project that two paths load with two different lists is built twice, + // and the program ends up with both builds. struct GitProjectSpec { GitSource source; fs::path projectFile = "project.cpp"; std::vector args = ProjectArgs(); }; - // Clones the spec's git URL into the per-project external cache (keyed by - // url+branch+commit+args+projectFile), recursively LoadProject's the - // remote's project.cpp, and returns a stable Configuration* you can drop - // into cfg.dependencies. The Configuration is owned by an internal cache - // for the lifetime of the build; identical specs share one Configuration. + // Clones the spec's git URL into the external cache, recursively + // LoadProject's the remote's project.cpp, and returns a stable + // Configuration* you can drop into cfg.dependencies. The clone is keyed by + // url+branch+commit+projectFile alone, so every arg list builds in the + // same working tree, each into variant directories of its own. The + // Configuration is owned by an internal cache for the lifetime of the + // build, keyed by the clone and the args: identical specs share one. Configuration* GitProject(const GitProjectSpec& spec); // Specification for a local sibling crafter-build project (e.g. an