Skip to content

Commit d510b3d

Browse files
committed
docs(plan): round-3 statuses through the release, and the verification script
1 parent 893011b commit d510b3d

2 files changed

Lines changed: 179 additions & 8 deletions

File tree

.agents/docs/2026-09-05-heterogeneous-build-ecosystem-design-v2.md

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -312,34 +312,34 @@ Status is one of `done`, `open`, `deferred (reason)`.
312312
| M2 | Module family `mcpp.rules.*` / `mcpp.tools.*`; specification I8 and section 7 corrected; docs 05 and 07 (both languages); examples 09 and 10 consume `mcpp:plugins` from the index | `grep -r 'mcpp\.build\.\(cuda\|spirv\)'` over docs, examples and tests is empty; the reserved-prefix warning still fires for `mcpplibs` and not for `mcpp` (e2e 309) | M1 | done |
313313
| M3 | Chapter 20 renamed to `20-heterogeneous-builds.md` (both languages); every reference updated | `check_docs_style.sh` passes; no reference to `20-accelerators.md` remains || done |
314314
| M4 | No emoji in docs, README, CHANGELOG, code comments, or the two design documents | a grep over the emoji ranges returns nothing outside program output strings || done |
315-
| M5 | Version 2026.9.5.3 in `mcpp.toml` and `modules/versioning`; CHANGELOG; unit and e2e suites; PR; CI green; self-review | e2e summary has no failure other than 168 (pre-existing on `origin/main`); all CI jobs green on the PR head | M1–M4 | open |
316-
| M6 | Release, mirror, index bump, bootstrap pin | both mirrors return 200 and identical bytes for every asset; `origin/main:pkgs/m/mcpp.lua` in xim-pkgindex names 2026.9.5.3 as `latest`; `.xlings.json` pin bumped | M5 | open |
315+
| M5 | Version 2026.9.5.3 in `mcpp.toml` and `modules/versioning`; CHANGELOG; unit and e2e suites; PR; CI green; self-review | e2e summary has no failure other than 168 (pre-existing on `origin/main`); all CI jobs green on the PR head | M1–M4 | done: unit 102/102, e2e 304 passed with 168 as on main, PR #566 37/37 green, merged as 03b5074 |
316+
| M6 | Release, mirror, index bump, bootstrap pin | both mirrors return 200 and identical bytes for every asset; `origin/main:pkgs/m/mcpp.lua` in xim-pkgindex names 2026.9.5.3 as `latest`; `.xlings.json` pin bumped | M5 | done: release run 33964745434 green (six jobs); four assets on `xlings-res/mcpp` at GitHub and GitCode return 200 with the upstream sha256; bump PR openxlings/xim-pkgindex#763 merged (7cc3f43), `Publish Index Artifact` green (run 33966046795); `xlings install mcpp@2026.9.5.3` yields `mcpp 2026.9.5.3` at the store path; bootstrap pin bumped on main (893011b9) |
317317

318318
#### mcpp-plugins (new repository, single PR, version 0.1.0)
319319

320320
| # | task | criterion | depends on | status |
321321
|---|---|---|---|---|
322322
| P1 | Repository with `mcpp.toml` (`mcpp:plugins`), `src/plugins.cppm` (`mcpp.plugins`), `rules/cuda.cppm` (`mcpp.rules.cuda`), `rules/spirv.cppm` (`mcpp.rules.spirv`), features `rules-cuda`, `rules-spirv`, README stating the naming rule and the mcpp floors | a consumer with `features = ["rules-spirv"]` builds a shader through it | M1 | done (PR #1 open) |
323-
| P2 | CI: one consumer fixture per feature, built with the pinned mcpp | green on the PR head | P1, M6 for the spirv fixture | open |
323+
| P2 | CI: one consumer fixture per feature, built with the pinned mcpp | green on the PR head | P1, M6 for the spirv fixture | in progress: the first run exposed a host leak (clang's CUDA wrapper found `curand_mtgp32_kernel.h` in the host's /usr/include on the developer machine); `mcpp.rules.cuda` now requires and includes `xim:libcurand` and refuses the clang route without it; fixture and example 09 (mcpp#567) declare it; CI rerunning |
324324
| P3 | Release `v0.1.0`; GitHub archive and a GitCode release asset with identical bytes | both URLs return 200 and one sha256 | P2 | open |
325325

326326
#### mcpp-index (PR #349)
327327

328328
| # | task | criterion | depends on | status |
329329
|---|---|---|---|---|
330330
| I1 | `pkgs/m/mcpp.plugins.lua` (GLOBAL and CN URLs, floor 2026.9.5.3); `mcpplibs:rules-cuda` kept, marked superseded | `mcpp add mcpp:plugins` resolves in a sandbox | P3, M6 | open |
331-
| I2 | `compat.vulkan-runtime` 2026.09.05: the pattern list is reduced to proprietary vendor userspace; an ICD's needs are computed by closing over the manifests' libraries; a farmed soname an installed payload also provides is re-pointed at the payload when the payload's versioned symbol set covers the host copy's (the `GLIBCXX`/`CXXABI` nodes of libstdc++ included); `HOST-SURFACE.txt` states the class of every entry | measured on this machine: 37 vendor entries, 20 payload substitutions, 8 host sonames no installed payload provides (`libbsd`, `libedit`, `libicudata`, `libicuuc`, `liblzma`, `libmd`, `libzstd`, `libtinfo`), 8 host Mesa ICDs, 3 host copies newer than the payload (`libdrm_amdgpu`, `libLLVM.so.20.1`, `libxml2`); example 10 still answers `12 24 36 48` || done |
332-
| I3 | `compat.opencl-headers`, `compat.opencl` verified with a probe (`tests/examples/opencl`, a workspace member); `compat.opencl-runtime` 2026.09.05 farms the libraries the host manifests name, their closure and the vendor family, prefers payloads, records the surface; payload entries of `OCL_ICD_FILENAMES` are left to the payload | the probe enumerates the NVIDIA platform on this machine and zero platforms on a runner; the pocl platform once X2 is installed | X2 for the pocl half | open |
331+
| I2 | `compat.vulkan-runtime` 2026.09.05: the pattern list is reduced to proprietary vendor userspace; an ICD's needs are computed by closing over the manifests' libraries; a farmed soname an installed payload also provides is re-pointed at the payload when the payload's versioned symbol set covers the host copy's (the `GLIBCXX`/`CXXABI` nodes of libstdc++ included); `HOST-SURFACE.txt` states the class of every entry | measured on this machine: 37 vendor entries, 20 payload substitutions, 8 host sonames no installed payload provides (`libbsd`, `libedit`, `libicudata`, `libicuuc`, `liblzma`, `libmd`, `libzstd`, `libtinfo`), 8 host Mesa ICDs, 3 host copies newer than the payload (`libdrm_amdgpu`, `libLLVM.so.20.1`, `libxml2`); example 10 still answers `12 24 36 48` | — | done: pattern list reduced to vendor userspace; closure from the manifests; payload-first with the symbol-set criterion; measured here 37 vendor, 20 substitutions, 8 host sonames without payload (`libbsd`, `libedit`, `libicudata`, `libicuuc`, `liblzma`, `libmd`, `libzstd`, `libtinfo`), 8 host Mesa ICDs, 3 host copies newer than the payload; example 10 still `12 24 36 48` |
332+
| I3 | `compat.opencl-headers`, `compat.opencl` verified with a probe (`tests/examples/opencl`, a workspace member); `compat.opencl-runtime` 2026.09.05 farms the libraries the host manifests name, their closure and the vendor family, prefers payloads, records the surface; payload entries of `OCL_ICD_FILENAMES` are left to the payload | the probe enumerates the NVIDIA platform on this machine and zero platforms on a runner; the pocl platform once X2 is installed | X2 for the pocl half | done for the host half: `tests/examples/opencl` lists `NVIDIA CUDA / RTX 4080` here and zero platforms on the Linux runner; with `OCL_ICD_FILENAMES=<pocl>/lib/libpocl.so` the same loader lists `Portable Computing Language` and `NVIDIA CUDA` in one process |
333333
| I4 | CI green; merge; index artifact published | `Publish Index Artifact` green on the merge commit | I1–I3 | open |
334334

335335
#### xim-pkgindex (PR #762)
336336

337337
| # | task | criterion | depends on | status |
338338
|---|---|---|---|---|
339-
| X1 | `zstd`, `xz`, `icu`, `libedit`, `libmd`, `xcb-util`, `xcb-util-image`, `xcb-util-keysyms`, `xcb-util-renderutil`, `xcb-util-wm`, `xcb-util-cursor`: conda-forge repacks for x86_64 and aarch64, published to `xlings-res/<name>` on both mirrors, recipes with `deps`, `exports`, `declare_libs`, headers and `.pc` | each installs; every `DT_NEEDED` of each payload library resolves inside payloads; CI green || open |
339+
| X1 | `zstd`, `xz`, `icu`, `libedit`, `libmd`, `xcb-util`, `xcb-util-image`, `xcb-util-keysyms`, `xcb-util-renderutil`, `xcb-util-wm`, `xcb-util-cursor`: conda-forge repacks for x86_64 and aarch64, published to `xlings-res/<name>` on both mirrors, recipes with `deps`, `exports`, `declare_libs`, headers and `.pc` | each installs; every `DT_NEEDED` of each payload library resolves inside payloads; CI green || done, pending CI: all eleven on both mirrors (44/44 GET checks by the agent, two re-verified by sha256 here); finding: an aarch64 install fails today because `xim:glibc`, `xim:gcc-runtime`, `xim:ncurses`, `xim:libxcb` publish no aarch64 asset and `deps` are per OS |
340340
| X1b | `libbsd` built in the subos harness (not on conda-forge), x86_64 | same | X1 (`libmd`) | open |
341-
| X2 | `pocl` 7.1 (CPU OpenCL) repacked for both architectures; its ICD reached through `OCL_ICD_FILENAMES` in the subos environment | `clinfo`-equivalent probe reports the pocl platform with no GPU || open |
342-
| X3 | `mesa-lavapipe` aarch64 payload | `archs` lists both; the aarch64 tarball is on both mirrors || open |
341+
| X2 | `pocl` 7.1 (CPU OpenCL) repacked for both architectures; its ICD reached through `OCL_ICD_FILENAMES` in the subos environment | `clinfo`-equivalent probe reports the pocl platform with no GPU || done, pending CI: pocl 7.1 for both architectures on both mirrors (x86_64 re-verified by sha256 here); the recipe declares `OCL_ICD_FILENAMES` and never `OCL_ICD_VENDORS` (the agent had wired the latter; corrected); finding: xlings 2026.9.3.2 does not persist a new package's `subos.env` declaration (openxlings/xlings#584), so the verification sets the variable explicitly |
342+
| X3 | `mesa-lavapipe` aarch64 payload | `archs` lists both; the aarch64 tarball is on both mirrors || done, pending CI: the aarch64 lavapipe payload (99,534,504 bytes) on both mirrors; four-file closure difference, none `DT_NEEDED` by `libvulkan_lvp.so` |
343343
| X4 | `xim:mesa` gains the Intel Vulkan driver | on an Intel machine `HOST-SURFACE.txt` has no driver entry | libclc and SPIRV-LLVM-Translator payloads | deferred: anv requires `intel_clc`, which needs a libclc and clang chain this index does not publish yet; the chain is a separate packaging round and is recorded here rather than approximated |
344344
| X5 | CI green; merge; index artifact published | `Publish Index Artifact` green on the merge commit | X1–X3 | open |
345345

Lines changed: 171 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,171 @@
1+
#!/usr/bin/env bash
2+
# Ecosystem verification for mcpp 2026.9.5.3 and the heterogeneous-build round
3+
# (design: 2026-09-05-heterogeneous-build-ecosystem-design-v2.md, section 6.3,
4+
# rows V1 and V2). Run inside a fresh xlings subos:
5+
#
6+
# xlings subos verify-953 --sandbox --cmd "MCPP_VERIFY_VERSION=2026.9.5.3 bash <this file>"
7+
#
8+
# and once more on the host with a GPU (MCPP_VERIFY_HOST=1), where the host
9+
# ICD path and the CUDA lane are exercised as well.
10+
#
11+
# Every assertion carries its own `|| fail`; the closing line is a count.
12+
set -uo pipefail
13+
14+
VER="${MCPP_VERIFY_VERSION:?set MCPP_VERIFY_VERSION}"
15+
STORE="${MCPP_VERIFY_BIN:-$HOME/.xlings/data/xpkgs/xim-x-mcpp/$VER/bin/mcpp}"
16+
SRC="${MCPP_VERIFY_SRC:-}" # a checkout of mcpp at v$VER or later (examples)
17+
XL="${XLINGS_BIN:-$(command -v xlings)}"
18+
19+
fails=0
20+
fail() { printf 'ASSERT-FAIL: %s\n' "$1"; fails=$((fails + 1)); }
21+
ok() { printf 'ok: %s\n' "$1"; }
22+
section() { printf '\n== %s ==\n' "$1"; }
23+
24+
# -- A. identity and mirrors -------------------------------------------------
25+
section "A. identity"
26+
[ -x "$STORE" ] || fail "no released binary at $STORE"
27+
got=$("$STORE" --version 2>&1 | head -1)
28+
[ "$got" = "mcpp $VER" ] && ok "$got from the store path" || fail "version is '$got'"
29+
"$STORE" self config --mirror "${MCPP_VERIFY_MIRROR:-CN}" >/dev/null 2>&1 || fail "mcpp self config --mirror"
30+
"$XL" config --mirror "${MCPP_VERIFY_MIRROR:-CN}" >/dev/null 2>&1 || fail "xlings config --mirror"
31+
ok "mirror ${MCPP_VERIFY_MIRROR:-CN} configured for mcpp and xlings"
32+
33+
# -- B. the plugin collection resolves from the index -------------------------
34+
#
35+
# A consumer that names mcpp:plugins with one feature and imports the member
36+
# under its declared name. The SPIR-V header's first word is the proof that the
37+
# rule ran through the engine path (constrained glob, device source list, a
38+
# `role = "source"` action ordered before compilation).
39+
section "B. mcpp:plugins, feature rules-spirv"
40+
work=$(mktemp -d)
41+
mkdir -p "$work/spv/shaders" "$work/spv/src"
42+
cat > "$work/spv/mcpp.toml" <<'EOT'
43+
[package]
44+
name = "spv-probe"
45+
version = "0.1.0"
46+
[language]
47+
standard = "c++23"
48+
modules = true
49+
import_std = true
50+
[dependencies.mcpp]
51+
plugins = { version = "0.1.0", features = ["rules-spirv"], host-module = true }
52+
[xlings.workspace]
53+
"xim:glslang" = "15.1.0"
54+
[build]
55+
accel = "vulkan1.2"
56+
sources = ["src/*.cpp", { glob = "shaders/*.comp", accel = "vulkan1.2" }]
57+
[targets.spv-probe]
58+
kind = "bin"
59+
main = "src/main.cpp"
60+
EOT
61+
cat > "$work/spv/shaders/scale.comp" <<'EOT'
62+
#version 450
63+
layout(local_size_x = 64) in;
64+
layout(std430, binding = 0) buffer Data { float v[]; };
65+
void main() { v[gl_GlobalInvocationID.x] *= 2.0; }
66+
EOT
67+
cat > "$work/spv/build.mcpp" <<'EOT'
68+
import std;
69+
import mcpp;
70+
import mcpp.rules.spirv;
71+
int main() {
72+
mcpp::rerun_if_changed_glob("shaders/**/*.comp");
73+
mcpp::rules::spirv::options opt;
74+
opt.includes = { "shaders" };
75+
return mcpp::rules::spirv::compile(opt) ? 0 : 1;
76+
}
77+
EOT
78+
cat > "$work/spv/src/main.cpp" <<'EOT'
79+
#include <cstdint>
80+
#include <cstdio>
81+
#include "scale_comp.h"
82+
int main() { std::printf("magic=%08x\n", scale_comp_spv[0]); return scale_comp_spv[0] == 0x07230203u ? 0 : 1; }
83+
EOT
84+
out=$(cd "$work/spv" && "$STORE" build 2>&1 && "$STORE" run 2>&1)
85+
printf '%s\n' "$out" | grep -q '^magic=07230203' && ok "mcpp.rules.spirv from mcpp:plugins produced a SPIR-V header" \
86+
|| fail "spirv consumer: $(printf '%s' "$out" | tail -4 | tr '\n' ' ')"
87+
88+
# -- C. example 10 on the CPU driver payload ------------------------------------
89+
section "C. examples/10-vulkan-compute on xim:mesa-lavapipe"
90+
if [ -n "$SRC" ] && [ -d "$SRC/examples/10-vulkan-compute/app" ]; then
91+
ex10="$work/ex10"; cp -r "$SRC/examples/10-vulkan-compute/app" "$ex10"
92+
out=$(cd "$ex10" && "$STORE" build 2>&1); rc=$?
93+
[ $rc -eq 0 ] && ok "example 10 built" || fail "example 10 build: $(printf '%s' "$out" | tail -4 | tr '\n' ' ')"
94+
icd=$(ls "$ex10"/.mcpp/.xlings/data/xpkgs/xim-x-mesa-lavapipe/*/share/vulkan/icd.d/*.json 2>/dev/null | head -1)
95+
[ -n "$icd" ] || icd=$(ls "$HOME"/.xlings/data/xpkgs/xim-x-mesa-lavapipe/*/share/vulkan/icd.d/*.json 2>/dev/null | head -1)
96+
[ -n "$icd" ] && ok "lavapipe manifest at $icd" || fail "no lavapipe ICD manifest in any store"
97+
out=$(cd "$ex10" && VK_DRIVER_FILES="$icd" "$STORE" run 2>&1)
98+
printf '%s\n' "$out" | grep -q '12 24 36 48' && ok "example 10 answered 12 24 36 48 on the payload driver" \
99+
|| fail "example 10 run on lavapipe: $(printf '%s' "$out" | tail -4 | tr '\n' ' ')"
100+
printf '%s\n' "$out" | grep -qi 'llvmpipe' && ok "the device was llvmpipe" || printf 'note: device name not printed (%s)\n' "$(printf '%s' "$out" | head -2 | tr '\n' ' ')"
101+
out=$(cd "$ex10" && "$STORE" build --no-accel 2>&1 && "$STORE" run --no-accel 2>&1)
102+
printf '%s\n' "$out" | grep -q '12 24 36 48' && ok "example 10 --no-accel answered 12 24 36 48" \
103+
|| fail "example 10 --no-accel: $(printf '%s' "$out" | tail -3 | tr '\n' ' ')"
104+
hs=$(ls "$ex10"/.mcpp/.xlings/data/xpkgs/compat-x-vulkan-runtime/*/mcpp_generated/vulkan_runtime/HOST-SURFACE.txt 2>/dev/null | head -1)
105+
if [ -n "$hs" ]; then
106+
printf -- '--- %s\n' "$hs"; sed -n '/^## farmed/,$p' "$hs" | head -60
107+
hostlines=$(grep -c -- '-- host;' "$hs" || true)
108+
if [ -n "${MCPP_VERIFY_HOST:-}" ]; then ok "host surface recorded ($hostlines host entries, see above)"; else
109+
[ "$hostlines" -eq 0 ] && ok "no host library is on the runtime path in the sandbox" || fail "$hostlines host entries in a sandbox"; fi
110+
else fail "no HOST-SURFACE.txt written by compat.vulkan-runtime"; fi
111+
else
112+
printf 'skip: MCPP_VERIFY_SRC not set or has no examples/10-vulkan-compute\n'
113+
fi
114+
115+
# -- D. example 09, the CPU variant everywhere and the device on a host with one --
116+
section "D. examples/09-cuda-kernel"
117+
if [ -n "$SRC" ] && [ -d "$SRC/examples/09-cuda-kernel/app" ] && [ -n "${MCPP_VERIFY_CUDA:-}" ]; then
118+
ex09="$work/ex09"; cp -r "$SRC/examples/09-cuda-kernel/app" "$ex09"
119+
out=$(cd "$ex09" && "$STORE" build --no-accel 2>&1 && "$STORE" run --no-accel 2>&1)
120+
printf '%s\n' "$out" | grep -q '12 24 36 48' && ok "example 09 --no-accel answered 12 24 36 48" \
121+
|| fail "example 09 --no-accel: $(printf '%s' "$out" | tail -3 | tr '\n' ' ')"
122+
out=$(cd "$ex09" && "$STORE" build 2>&1); rc=$?
123+
[ $rc -eq 0 ] && ok "example 09 device variant compiled through mcpp.rules.cuda" || fail "example 09 build: $(printf '%s' "$out" | tail -4 | tr '\n' ' ')"
124+
if [ -n "${MCPP_VERIFY_HOST:-}" ]; then
125+
out=$(cd "$ex09" && "$STORE" run 2>&1)
126+
printf '%s\n' "$out" | grep -q '12 24 36 48' && ok "example 09 answered 12 24 36 48 on the device" || fail "example 09 device run: $(printf '%s' "$out" | tail -3 | tr '\n' ' ')"
127+
fi
128+
else
129+
printf 'skip: set MCPP_VERIFY_CUDA=1 (and MCPP_VERIFY_SRC) to exercise the CUDA lane\n'
130+
fi
131+
132+
# -- E. OpenCL: the loader, the adapter, and the CPU implementation ---------------
133+
section "E. OpenCL"
134+
mkdir -p "$work/ocl/tests"
135+
cat > "$work/ocl/mcpp.toml" <<'EOT'
136+
[package]
137+
name = "ocl-probe"
138+
version = "0.1.0"
139+
[dependencies.compat]
140+
opencl = "2026.05.29"
141+
EOT
142+
cat > "$work/ocl/tests/platforms.cpp" <<'EOT'
143+
#define CL_TARGET_OPENCL_VERSION 300
144+
#include <CL/cl.h>
145+
#include <CL/cl_ext.h>
146+
#include <cstdio>
147+
int main() {
148+
cl_uint n = 0; const cl_int rc = clGetPlatformIDs(0, nullptr, &n);
149+
if (rc == CL_PLATFORM_NOT_FOUND_KHR || (rc == CL_SUCCESS && n == 0)) { std::printf("platforms=0\n"); return 0; }
150+
if (rc != CL_SUCCESS) { std::printf("clGetPlatformIDs=%d\n", (int)rc); return 1; }
151+
cl_platform_id ids[8]; clGetPlatformIDs(n < 8 ? n : 8, ids, nullptr);
152+
std::printf("platforms=%u\n", n);
153+
for (cl_uint i = 0; i < n && i < 8; ++i) { char name[128] = {}; clGetPlatformInfo(ids[i], CL_PLATFORM_NAME, sizeof name, name, nullptr); std::printf("platform: %s\n", name); }
154+
return 0;
155+
}
156+
EOT
157+
out=$(cd "$work/ocl" && "$STORE" test 2>&1)
158+
printf '%s\n' "$out" | grep -q '^platforms=' && ok "the loader linked and enumerated: $(printf '%s' "$out" | grep '^platform' | tr '\n' ' ')" \
159+
|| fail "opencl probe: $(printf '%s' "$out" | tail -4 | tr '\n' ' ')"
160+
if "$XL" install pocl -y >/dev/null 2>&1; then
161+
ok "xim:pocl installed"
162+
lib=$(ls "$HOME"/.xlings/data/xpkgs/xim-x-pocl/*/lib/libpocl.so 2>/dev/null | head -1)
163+
out2=$(cd "$work/ocl" && OCL_ICD_FILENAMES="$lib" "$STORE" test 2>&1)
164+
printf '%s\n' "$out2" | grep -q 'Portable Computing Language' && ok "the pocl platform is enumerated through OCL_ICD_FILENAMES" \
165+
|| fail "pocl not enumerated: $(printf '%s' "$out2" | grep '^platform' | tr '\n' ' ')"
166+
else
167+
printf 'note: xim:pocl not installable here (not published yet, or this arch)\n'
168+
fi
169+
170+
printf '\n== result: %d assertion(s) failed ==\n' "$fails"
171+
[ "$fails" -eq 0 ]

0 commit comments

Comments
 (0)