Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
540 changes: 540 additions & 0 deletions .agents/docs/2026-09-29-workspace-build-graph-design.md

Large diffs are not rendered by default.

4 changes: 3 additions & 1 deletion .agents/docs/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ superseded_by: 2026-09-07-....md # when status is superseded
---
```

316 records.
317 records.

## By subject

Expand All @@ -30,6 +30,7 @@ Records that declare one. Everything else is listed by date below.

### design

- [The workspace as the unit of build: one graph per configuration, one scheduler, product directories, and a reusable graph module](2026-09-29-workspace-build-graph-design.md) — active
- [An ecosystem design for mcpp and xlings: one authority per fact, and the work that follows from it](2026-09-28-ecosystem-design-and-optimisation-plan.md) — landed
- [Build cost, foreign toolsets, the build-plugin architecture and the library surface: engine, plugin and index design (#734)](2026-09-28-build-cost-foreign-toolsets-and-library-surface-design.md) — active
- [The compile database, `emit build-database`, and #701/#702: triage against the specifications, and one design](2026-09-26-compile-database-and-issue-699-design.md) — landed
Expand Down Expand Up @@ -107,6 +108,7 @@ Records that declare one. Everything else is listed by date below.

### 2026-09

- [The workspace as the unit of build: one graph per configuration, one scheduler, product directories, and a reusable graph module](2026-09-29-workspace-build-graph-design.md) — active
- [Two days of mcpp and xlings: a review of what merged, what is known, and what is open](2026-09-28-ecosystem-review-of-two-days-of-mcpp-and-xlings.md) — active
- [An ecosystem design for mcpp and xlings: one authority per fact, and the work that follows from it](2026-09-28-ecosystem-design-and-optimisation-plan.md) — landed
- [Build cost, foreign toolsets, the build-plugin architecture and the library surface: engine, plugin and index design (#734)](2026-09-28-build-cost-foreign-toolsets-and-library-surface-design.md) — active
Expand Down
2 changes: 1 addition & 1 deletion .github/actions/bootstrap-mcpp/action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ inputs:
# `package.name`, so one of the two was simply unreachable — and which one
# depended on the machine, which is why CI failed on `compat:lua` on
# Windows and `mcpplibs.capi:lua` on Linux. Never pin below that.
default: '2026.9.28.2'
default: '2026.9.29.1'
cache-target:
description: also restore/save target/ (build artifacts + BMIs)
required: false
Expand Down
2 changes: 1 addition & 1 deletion .github/actions/setup-macos-llvm/action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ inputs:
# Floor imposed by the index, not a routine bump — see
# .github/actions/bootstrap-mcpp/action.yml for why 0.4.69 is required
# (two packages named `lua` in one repo need openxlings/xlings#381).
default: '2026.9.28.2'
default: '2026.9.29.1'
image:
description: >
The runner label the job runs on (macos-15, xcode-27). It is part of the
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/bootstrap-macos.yml
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ jobs:
# Dormant (workflow_dispatch only), but kept in step with the rest —
# check_version_pins.sh holds it there. Floor: 0.4.69, below which the
# index cannot resolve two packages that share a short name.
XLINGS_VERSION: '2026.9.28.2'
XLINGS_VERSION: '2026.9.29.1'
steps:
- uses: actions/checkout@v4

Expand Down
6 changes: 3 additions & 3 deletions .github/workflows/ci-fresh-install.yml
Original file line number Diff line number Diff line change
Expand Up @@ -152,7 +152,7 @@ jobs:
env:
XLINGS_NON_INTERACTIVE: '1'
run: |
curl -fsSL https://raw.githubusercontent.com/openxlings/xlings/main/tools/other/quick_install.sh | bash -s v2026.9.28.2
curl -fsSL https://raw.githubusercontent.com/openxlings/xlings/main/tools/other/quick_install.sh | bash -s v2026.9.29.1
echo "$HOME/.xlings/subos/current/bin" >> "$GITHUB_PATH"

- name: Install mcpp and config mirror
Expand Down Expand Up @@ -315,7 +315,7 @@ jobs:

- name: Install xlings + mcpp
run: |
curl -fsSL https://raw.githubusercontent.com/openxlings/xlings/main/tools/other/quick_install.sh | bash -s v2026.9.28.2
curl -fsSL https://raw.githubusercontent.com/openxlings/xlings/main/tools/other/quick_install.sh | bash -s v2026.9.29.1
# Deliberately NOT writing to $GITHUB_PATH here. On container
# images that declare no PATH in their config (opensuse/
# tumbleweed), appending a single dir to GITHUB_PATH makes the
Expand Down Expand Up @@ -416,7 +416,7 @@ jobs:
# (older ones carry minos=15 and refuse to start).
# v0.4.51+: in-process sha256 — this image has no sha256sum
# binary, so pinned fetches failed before it.
curl -fsSL https://raw.githubusercontent.com/openxlings/xlings/main/tools/other/quick_install.sh | bash -s v2026.9.28.2
curl -fsSL https://raw.githubusercontent.com/openxlings/xlings/main/tools/other/quick_install.sh | bash -s v2026.9.29.1
echo "$HOME/.xlings/subos/current/bin" >> "$GITHUB_PATH"

- name: Install mcpp and config mirror
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/ci-linux-e2e.yml
Original file line number Diff line number Diff line change
Expand Up @@ -384,7 +384,7 @@ jobs:

- name: Bootstrap xlings + released mcpp
run: |
curl -fsSL https://raw.githubusercontent.com/openxlings/xlings/main/tools/other/quick_install.sh | bash -s v2026.9.28.2
curl -fsSL https://raw.githubusercontent.com/openxlings/xlings/main/tools/other/quick_install.sh | bash -s v2026.9.29.1
export PATH="$HOME/.xlings/subos/current/bin:$PATH"
xlings update
xlings install mcpp -y -g
Expand Down
4 changes: 2 additions & 2 deletions .github/workflows/cross-build-test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -135,7 +135,7 @@ jobs:
# release assets were uploaded in a broken state (records present,
# blobs missing → 404 on GET); re-uploaded clean. The stale-INDEX
# half is handled by the marker-clear below.
XLINGS_VERSION: '2026.9.28.2'
XLINGS_VERSION: '2026.9.29.1'
run: |
tarball="xlings-${XLINGS_VERSION}-linux-x86_64.tar.gz"
bash "$GITHUB_WORKSPACE/.github/tools/fetch_release.sh" \
Expand Down Expand Up @@ -289,7 +289,7 @@ jobs:
- name: Bootstrap mcpp via xlings
env:
XLINGS_NON_INTERACTIVE: '1'
XLINGS_VERSION: '2026.9.28.2'
XLINGS_VERSION: '2026.9.29.1'
run: |
tarball="xlings-${XLINGS_VERSION}-linux-x86_64.tar.gz"
bash "$GITHUB_WORKSPACE/.github/tools/fetch_release.sh" \
Expand Down
14 changes: 7 additions & 7 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,7 @@ jobs:
# Pin xlings to a known-good version. The upstream install
# script always grabs `latest` (no version override), so we
# download + self-install manually to avoid broken releases.
XLINGS_VERSION: '2026.9.28.2'
XLINGS_VERSION: '2026.9.29.1'
run: |
if [ ! -x "$HOME/.xlings/subos/default/bin/xlings" ]; then
tarball="xlings-${XLINGS_VERSION}-linux-x86_64.tar.gz"
Expand Down Expand Up @@ -322,7 +322,7 @@ jobs:
- name: Bootstrap mcpp via xlings
env:
XLINGS_NON_INTERACTIVE: '1'
XLINGS_VERSION: '2026.9.28.2'
XLINGS_VERSION: '2026.9.29.1'
run: |
tarball="xlings-${XLINGS_VERSION}-linux-x86_64.tar.gz"
bash "$GITHUB_WORKSPACE/.github/tools/fetch_release.sh" \
Expand Down Expand Up @@ -393,7 +393,7 @@ jobs:
# below are pinned to the same version as XLINGS_VERSION; they are
# NOT interpolated from it, so check_version_pins.sh scans for them
# explicitly (they were absent from the old lock-step comment).
XLA="xlings-2026.9.28.2-linux-aarch64.tar.gz"
XLA="xlings-2026.9.29.1-linux-aarch64.tar.gz"
# NOT fetch_release.sh: this asset is OPTIONAL and the `if` is the
# point — an arch with no prebuilt xlings must fall through quietly,
# while the helper retries a 404 five times before giving up. The one
Expand All @@ -402,9 +402,9 @@ jobs:
# cover it.
if curl -fsSL --retry 3 --retry-delay 2 --retry-all-errors \
--connect-timeout 20 --max-time 600 -o "/tmp/$XLA" \
"https://github.com/openxlings/xlings/releases/download/v2026.9.28.2/$XLA"; then
"https://github.com/openxlings/xlings/releases/download/v2026.9.29.1/$XLA"; then
tar -xzf "/tmp/$XLA" -C /tmp
XLBIN=$(find /tmp/xlings-2026.9.28.2-linux-aarch64 -path '*/bin/xlings' -type f | head -1)
XLBIN=$(find /tmp/xlings-2026.9.29.1-linux-aarch64 -path '*/bin/xlings' -type f | head -1)
if [ -n "$XLBIN" ]; then
mkdir -p "$STAGING/$WRAPPER/registry/bin"
cp "$XLBIN" "$STAGING/$WRAPPER/registry/bin/xlings"
Expand Down Expand Up @@ -482,7 +482,7 @@ jobs:
- name: Bootstrap mcpp via xlings
env:
XLINGS_NON_INTERACTIVE: '1'
XLINGS_VERSION: '2026.9.28.2'
XLINGS_VERSION: '2026.9.29.1'
run: |
if [ ! -x "$HOME/.xlings/subos/default/bin/xlings" ]; then
WORK=$(mktemp -d)
Expand Down Expand Up @@ -665,7 +665,7 @@ jobs:
shell: bash
env:
XLINGS_NON_INTERACTIVE: '1'
XLINGS_VERSION: '2026.9.28.2'
XLINGS_VERSION: '2026.9.29.1'
run: |
# Captured before the `cd` below, in POSIX form: this step never
# returns to the workspace, and GITHUB_WORKSPACE is a backslash
Expand Down
88 changes: 88 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,94 @@
> Each `## [<version>]` section is that release's notes. Entries are written in English
> from 2026.9.28.3 on; earlier entries remain as written.

## [2026.9.29.1] - 2026-09-29

This release builds a workspace as one graph per configuration. The selected
members and everything they depend on are planned together under a virtual
root, so a member that several members use is compiled once; each member's
products are placed in its own product directory. It also fixes the planning
regression of 2026.9.28.3. The design, its readings and the task plan are in
`.agents/docs/2026-09-29-workspace-build-graph-design.md`. The xlings pin moves
to 2026.9.29.1.

### Fixed

- **Planning a workspace no longer grows with the length of its dependency
chains (2026.9.28.3 only).** E1 planned a shared member as the root of a
nested build, and the nested build met the same condition again, so a chain
of n members cost 2^n plans: a nine-member workspace with nothing to build
took 79 s instead of 6.3 s, and a chain of five libraries and a program took
36.8 s for `--workspace`. E1 is removed. The same chain now plans once
(0.5 s), and with nothing changed `--workspace`, `-p app` and a build inside
the member are each answered by the fast path in a few milliseconds (e2e
834).

### Behaviour changes

- **A workspace is one graph per configuration.** A command on a workspace
plans its selected members together: `--workspace`, and a virtual root
without `-p`, select every member (a rooted workspace's own package
included); `-p X`, and a command in X's directory, select X; a command at a
rooted workspace's root selects its own package. Members that share their
toolchain request, target, C++ standard and the other values that apply to a
whole graph are one plan, with one `build.ninja`; members that differ are
separate plans, built at the same time under a static share of the jobs. A
member used by several members is compiled once (e2e 833).
- **Build directories are at the workspace root.** A member builds in
`<workspace>/target/<triple>/<configuration>/` instead of its own `target/`.
Its programs and shared libraries are in its product directory,
`bin/<package name>/` (`bin/<namespace>.<name>/` when two members share a
name; a rooted workspace's own package keeps `bin/`), with the shared
libraries and runtime files its programs load beside them. The first build
after the upgrade is a full build; `mcpp clean --stale` removes the build
directories members held under their own `target/`. A member's build program
still writes to `<member>/target/.build-mcpp/`.
- **`-p X` plans X and what X reaches, in the shared build directory.**
`mcpp build --workspace` followed by `mcpp build -p X` compiles nothing; a
package is compiled again only when its active features differ between the
two commands.
- **The directory name is the configuration.** It hashes the toolchain, the
target, the standard library, the runtime contract, the C++ standard, the
dialect flags, the profile and the other values every node of one graph
shares. A package's own `cflags`, `cxxflags`, `ldflags`, defines, sources and
include directories reach its commands instead: editing them recompiles that
package and what imports it, in the same directory, rather than moving the
whole graph to a new one. This holds for single-package projects as well.
- **One lock and one compile database per workspace.** `mcpp.lock` is at the
workspace root, as it already was for a rooted workspace; `--workspace`
writes the whole record and `-p X` updates the entries of X's graph. Where
the workspace has no lock yet, a selected member's own lock supplies the
git commits. The workspace root's `compile_commands.json` covers every member
that has been built or configured.
- **A member keeps its duties as the project being developed.** Its targets
are built, its `[dev-dependencies]` are loaded under `mcpp test`, its
`[hooks]` run around the build, its `[xlings]` entries with `when = "dev"` are
installed, and its build program runs after every dependency's program with
the graph document of what it reaches (in which it is the `root`) and the
dependencies' link forms. `--features f` activates `f` in each selected
member that declares it and is refused when none does.
- **Each member links its own closure.** A member's programs link the flags of
the packages they reach and place the runtime files of those packages, never
another member's.
- **Shared libraries are placed by a hard link.** A shared library placed
beside several programs is one file with several names where the file system
supports links, and a copy elsewhere. Other deployed files are copied, since
a program may write a file beside itself (e2e 835).
- **Files served from the global cache are staged by a ninja pass of their
own**, before the build that reads them. ninja 1.12.1 crashed when a cached
dependency was staged again in a directory whose scans were current
(ninja-build/ninja#2662); a directory named by its configuration makes that
the ordinary case of a dependency upgrade.
- **The fast path records the request.** `build.ninja` states the workspace
members and the features it was planned for, and a fast path replays it only
for the same request; one record is kept per selection and configuration.
- **`mcpp.graph`.** One module holds the engine's graph algorithms: the
topological orders the engine uses, dependency levels and the transitive
closure. Module order, host-module order, unit order by imports, the
dependency closure, the package-cycle check and the build-key fold use it,
each with the order it had, so no compile or link order changes; a cycle of
modules is now reported as `a -> b -> a`.

## [2026.9.28.3] - 2026-09-28

This release implements mcpp's part of the #734 design: the three layers of the
Expand Down
Empty file added cdb.json
Empty file.
Loading
Loading