Skip to content

Commit 7d70482

Browse files
release: 2026.10.26.2 -- ok images, mcpp over mcpplibs.os 0.2.0 (modules/platform removed), argv-named programs, no signal handlers (#842)
Co-authored-by: speak-agent <248744407+speak-agent@users.noreply.github.com>
1 parent 434b3fb commit 7d70482

283 files changed

Lines changed: 13075 additions & 12268 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

‎.agents/docs/2026-10-26-control-contract-runtime-and-ide-ecosystem-design.md‎

Lines changed: 273 additions & 0 deletions
Large diffs are not rendered by default.

‎.agents/docs/2026-10-26-ecosystem-part2-os-library-over-openkal-design.md‎

Lines changed: 699 additions & 0 deletions
Large diffs are not rendered by default.

‎.agents/docs/README.md‎

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ superseded_by: 2026-09-07-....md # when status is superseded
1818
---
1919
```
2020

21-
337 records.
21+
338 records.
2222

2323
## By subject
2424

@@ -66,6 +66,7 @@ Records that declare one. Everything else is listed by date below.
6666

6767
### ecosystem
6868

69+
- [生态设计 part 2:openkal 的最小原子与二进制映像、其上的 `mcpplibs.os`,以及 part 1 的收尾与回归记录](2026-10-26-ecosystem-part2-os-library-over-openkal-design.md) — active
6970
- [控制契约、并发与性能、单一 C++ 运行时,以及 IDE 生态(生态级,#838、#839)](2026-10-26-control-contract-runtime-and-ide-ecosystem-design.md) — active
7071

7172
### heterogeneous
@@ -143,6 +144,7 @@ Records that declare one. Everything else is listed by date below.
143144

144145
### 2026-10
145146

147+
- [生态设计 part 2:openkal 的最小原子与二进制映像、其上的 `mcpplibs.os`,以及 part 1 的收尾与回归记录](2026-10-26-ecosystem-part2-os-library-over-openkal-design.md) — active
146148
- [控制契约、并发与性能、单一 C++ 运行时,以及 IDE 生态(生态级,#838、#839)](2026-10-26-control-contract-runtime-and-ide-ecosystem-design.md) — active
147149
- [目标基座与执行宿主:sysroot 的通用模型、运行器契约、自备输入,以及同批的发布产物路径(#832)](2026-10-23-target-base-and-execution-host-design.md) — landed
148150
- [依赖 image 的资源归属、模块扫描边界与锁文件稳定写入](2026-10-21-resource-ownership-module-scan-and-lock-write-design.md) — active

‎.github/tools/install_pinned_mcpp.sh‎

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,4 +95,11 @@ GOT=$("$MCPP" --version 2>/dev/null | head -1 \
9595
exit 1; }
9696
echo "bootstrap mcpp: $MCPP ($GOT)" >&2
9797

98+
# The package index the commit builds against is the one published now. The
99+
# sandbox the caller restored holds the index as it was when that cache was
100+
# saved, and the pinned mcpp refreshes on a miss only for the root's own
101+
# [dependencies] (fixed in 2026.10.26.2): a version a path member names --
102+
# a member's `os = "0.1.0"` -- missed against it with no refresh.
103+
"$MCPP" index update >&2 || echo "::warning::the bootstrap mcpp could not refresh its package index" >&2
104+
98105
echo "$MCPP"

‎.github/tools/upgrade_lane.sh‎

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -131,6 +131,31 @@ assert installed.get("revision", 0) == 0, installed
131131
PY
132132
fi
133133
[ "$VARIANT" = orphan ] && { run old-tc-gcc "$W" "$OLD" toolchain install gcc@16.1.0 || fail "the previous release cannot install gcc"; }
134+
# modules_project <dir>: `openkal.timeout` imports `openkal.datagram`, an
135+
# INDIRECT import of the program's unit, found at the path its BMI records.
136+
modules_project() {
137+
mkdir -p "$W/$1/src"
138+
cat > "$W/$1/mcpp.toml" <<'TOML'
139+
[package]
140+
name = "kp"
141+
version = "0.1.0"
142+
143+
[dependencies]
144+
openkal = "0.16.0"
145+
146+
[target.linux.dependencies]
147+
openkal-linux = "0.17.0"
148+
149+
[toolchain]
150+
default = "gcc@16.1.0"
151+
TOML
152+
printf 'import openkal.timeout;\nint main() { return 0; }\n' > "$W/$1/src/main.cpp"
153+
}
154+
if [ "$VARIANT" = modules ]; then
155+
run old-tc-gcc "$W" "$OLD" toolchain install gcc@16.1.0 || fail "the previous release cannot install gcc"
156+
modules_project m-old
157+
run old-modules "$W/m-old" "$OLD" build || fail "the previous release cannot build the module project"
158+
fi
134159
new_project p-old "$OLD"
135160
run old-run "$W/p-old" "$OLD" run || fail "the previous release cannot run a new project"
136161

@@ -192,6 +217,18 @@ if [ "$VARIANT" = snapshot ]; then
192217
grep -q "packaging revision .* available" "$W/new-toolchain-list.log" \
193218
|| fail "toolchain list does not offer the newer packaging"
194219
fi
220+
if [ "$VARIANT" = modules ]; then
221+
# A BMI of the previous spelling is not read: the dependency is rebuilt
222+
# once (its cache key carries the spelling), then served from the cache.
223+
modules_project m-new1
224+
run new-modules1 "$W/m-new1" "$NEW" build -v || fail "the module project does not build over the previous release's cache"
225+
grep -q "STAGE gcm.cache/mcpplibs.openkal/" "$W/new-modules1.log" \
226+
&& fail "a dependency BMI of the previous spelling was taken from the cache"
227+
modules_project m-new2
228+
run new-modules2 "$W/m-new2" "$NEW" build -v || fail "the second module project failed"
229+
grep -q "STAGE gcm.cache/mcpplibs.openkal/" "$W/new-modules2.log" \
230+
|| fail "the rebuilt dependency was not served from the cache"
231+
fi
195232
if [ "$VARIANT" = orphan ]; then
196233
run new-provision "$W" "$NEW" toolchain install "$TC" || fail "toolchain install could not replace the payload"
197234
grep -q "installed asset registration missing" "$W/new-provision.log" \

‎.github/workflows/ci-aarch64-fresh-install.yml‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ on:
3131
branches: [ main ]
3232
paths:
3333
- 'src/build/build_program.cppm'
34-
- 'modules/platform/src/process.cppm'
34+
- 'src/run/run.cpp'
3535
- 'tests/e2e/168_build_mcpp_musl_host_static.sh'
3636
- '.github/workflows/ci-aarch64-fresh-install.yml'
3737
push:

‎.github/workflows/ci-linux-e2e.yml‎

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -421,6 +421,11 @@ jobs:
421421
MCPP_BOOT="$HOME/.xlings/subos/current/bin/mcpp"
422422
"$MCPP_BOOT" --version
423423
"$MCPP_BOOT" self config --mirror GLOBAL
424+
# The restored ~/.mcpp holds the package index as it was when that
425+
# cache was saved; the commit builds against the index as published
426+
# (.github/tools/install_pinned_mcpp.sh says why a miss alone did not
427+
# refresh it before 2026.10.26.2).
428+
"$MCPP_BOOT" index update
424429
echo "MCPP_BOOT=$MCPP_BOOT" >> "$GITHUB_ENV"
425430

426431
# This job builds its own mcpp on purpose: the build is part of what it

‎.github/workflows/ci-macos.yml‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,7 @@ jobs:
8484
run: echo 'APPLE_FLOAT_MACROS=-DINFINITY=HUGE_VALF -DNAN=__builtin_nanf("0x7fc00000")' >> "$GITHUB_ENV"
8585

8686
# THE SDK mcpp'S OWN RESOLUTION NAMES: `xcrun --show-sdk-path`
87-
# (modules/platform/src/macos/macos.cppm). These raw compiles state the
87+
# (modules/toolchain-model/src/apple_sdk.cpp). These raw compiles state the
8888
# SDK the same way, on purpose.
8989
#
9090
# On the 22.1.8 line this was the known-red spot (mcpp#669 has the

‎.github/workflows/ci-upgrade.yml‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ jobs:
2929
- { host: linux-x86_64, runs-on: ubuntu-24.04, variant: plain }
3030
- { host: linux-x86_64, runs-on: ubuntu-24.04, variant: snapshot }
3131
- { host: linux-x86_64, runs-on: ubuntu-24.04, variant: orphan }
32+
- { host: linux-x86_64, runs-on: ubuntu-24.04, variant: modules }
3233
- { host: linux-aarch64, runs-on: ubuntu-24.04-arm, variant: plain }
3334
- { host: macos-arm64, runs-on: macos-15, variant: plain }
3435
- { host: windows-x86_64, runs-on: windows-latest, variant: plain }

‎CHANGELOG.md‎

Lines changed: 166 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,172 @@
44
> Each `## [<version>]` section is that release's notes. Entries are written in English
55
> from 2026.9.28.3 on; earlier entries remain as written.
66

7+
## [2026.10.26.2] - 2026-10-26
8+
9+
### Added
10+
11+
- **`x86_64-openkal` and `aarch64-openkal`: one ok image per architecture**
12+
(openkal SPEC clause 12). The image is compiled for no operating system
13+
with the convention's flags, linked by `ld.lld` into an ET_DYN entered at
14+
`ok_main` (`bin/<name>.oke`, or `lib<name>.okso` for an image another
15+
loads), and published only after `okld note` has written its requirements
16+
note and `okld check` has checked it. `okrun` runs it on Linux, macOS and
17+
Windows and is the target's runner. Both programs come from the dependency
18+
graph: `[build-dependencies] openkal-tools = { tools = ["okld", "okrun"] }`.
19+
The C library and the C++ run-time inside an image are packages; the
20+
payload's libc++ is not offered to an image.
21+
A build that links an image with no `okld` in the graph is refused with
22+
the machine-readable reason `image-tool-absent`.
23+
The tools a workspace's root package declares are its own, as any root's
24+
are.
25+
`mcpp pack --mode self-contained` reads the declaration of openkal-tools a
26+
build resolves: after workspace inheritance and in the target's
27+
`[target.'cfg(os = "openkal")'.build-dependencies]`.
28+
29+
- **A program's beginning can be a dependency's entry target, and a
30+
freestanding image states the symbol it is entered at** (#845). A framework
31+
declares `[targets.<n>] kind = "entry"` with the translation unit that
32+
supplies `main`, and a program selects it with
33+
`main = { from = "<dependency>/<entry>" }` in place of a file of its own; a
34+
test suite does the same with `[test] main`. The entry is compiled in its
35+
package's context with its own flags, linked only into the programs that
36+
select it, gated by its `required_features`, and its `windows_entry` is
37+
inherited. `start = "<symbol>"` on a program, an entry, a row or `[test]`,
38+
and `mcpp:link-start` from a board package's build program (protocol 16),
39+
name the ELF entry of a freestanding image; statements that disagree are
40+
refused naming each, the symbol must be defined (it was a linker warning and
41+
an image entered at address 0), and the build reports it on an `Entry` line
42+
and in the result record's `entry`. A file a target names as `main` on any
43+
row is no longer linked as an ordinary source on the other rows.
44+
45+
### Changed
46+
47+
- **mcpp keeps no operating-system layer of its own.** `modules/platform` is
48+
removed; mcpp reaches the operating system through mcpplibs.os 0.2.0, and
49+
what was mcpp's own meaning under that name now lives in the module that
50+
owns it: the environment of an invocation in the `invocation` package, the
51+
constraints of a run in `mcpp.effects`, every program mcpp starts in
52+
`mcpp.run`, the loader environment and the run-time search in
53+
`src/runtime`, command-line spelling in `mcpp.build.command_line`, the
54+
platform keys and the Apple SDK in `toolchain-model`, the terminal and key
55+
input in `src/ui`, the home's lock and trust check in `mcpp.home.files`.
56+
The one primitive kept per system is the lock every release of mcpp takes
57+
(`src/native/posix`, `src/native/windows`). A program is found on PATH
58+
without a shell, with PATHEXT's suffixes on Windows, and the current
59+
directory is not searched on Windows. A list of directories in an
60+
environment variable (`PATH`, the run-time library path) is read and written
61+
with `mcpplibs.os`'s `split_list` and `join_list`: an empty entry is
62+
skipped, and a quoted entry on Windows is unquoted.
63+
- **A program mcpp starts is named by its argument vector.** Compiler probes,
64+
git, xlings, tar, strip, patchelf, readelf and vswhere are started without a
65+
command interpreter, with their additions to the environment given to them
66+
alone; the interpreter runs only commands that are text by nature (a
67+
`[hooks]` command, an MSVC environment script, and the command lines mcpp
68+
composes and records as text, as ninja's rules are). On Windows the
69+
interpreter receives `cmd.exe /d /s /c "<command>"` as one string. Every
70+
started program reads an empty standard input unless it is the program
71+
`mcpp run` becomes, and runs in a unit that ends with mcpp.
72+
- **No signal handlers.** A request to end (SIGINT, SIGTERM, SIGHUP, a
73+
console's control events) is taken over by mcpplibs.os and read by one
74+
watcher thread, which ends the units of the running programs, writes the
75+
interrupt files, restores the terminal and ends mcpp as the request would
76+
have; the exit codes of §5 are unchanged. A closed standard output ends mcpp
77+
in the same order (`mcpp … | head`: 141 to a shell on POSIX). Every program
78+
mcpp starts begins with SIGPIPE at its default, although openkal ignores it
79+
for its own writes.
80+
- **mcpp does not write its own process environment.** Variables mcpp states
81+
(its home, `--offline`, a hook's variables, xlings' home and PATH) are this
82+
invocation's statements, read by every lookup mcpp makes and given to the
83+
programs it starts; an xlings invocation's environment is the started
84+
program's, on Windows as elsewhere.
85+
86+
### Fixed
87+
88+
- **A dependency upgraded to a cached version replaces the previous version's
89+
files.** A package's BMI and objects are staged from the build cache at paths
90+
named by the module and the source, not by the cache entry, and staging under
91+
`--verify size` took a destination of the source's size as already staged.
92+
After an upgrade the previous version's files are at those paths, and a
93+
change that keeps their sizes (a constant) left them in place: the program
94+
ran the old code, and a unit compiled against the new graph failed with
95+
`CRC mismatch` (GCC). A destination that can be read is now compared by
96+
content under every mode; an equal size is accepted only for one that cannot
97+
be opened (a language server holding it). e2e 948.
98+
- **A compile whose status could not be written fails at once.** A detached
99+
module compile reports its status in `<slot>.rc`, which appears by a rename
100+
after the number is written. On a full disk the file appeared empty and the
101+
build waited for a number until its two-hour limit; an `.rc` with no number is
102+
now a failed unit, said as such.
103+
- **A WebAssembly link writes its `.wasm` again.** 2026.10.26.1 published every
104+
POSIX link through a temporary name, and Emscripten names the file it writes
105+
beside the output after the output: a link to `app.js.tmp` wrote no
106+
`app.wasm`, the edge's implicit output was missing, and `mcpp pack` of a
107+
`wasm32-emscripten` program (mcpp-plugins' `dist-web`) found no stem family.
108+
A WebAssembly link is in place, as a PE link is.
109+
- **A module's indirect import is found whatever map its importer has (GCC).**
110+
A unit that reaches another package's module is compiled with a module map,
111+
and a unit that imports only the root's modules with GCC's own mapper. A BMI
112+
records the paths of its imports as its compile's mapper spelt them, and the
113+
map named no repository, so a unit with a map that imported a root module
114+
compiled without one looked for that module's import beside the build
115+
directory (`failed to read compiled module`, `Bad import dependency`). The
116+
map now names the BMI directory as its repository (`$root gcm.cache`) and
117+
every path below it, as GCC's own mapper does; the dyndep step reads the
118+
same form. The same cause failed `import std.compat` in a unit with a map, in
119+
any project with a dependency. A dependency's BMI that an earlier mcpp put in
120+
the global build cache spells its imports the earlier way, so the cache key
121+
of a package that provides a module under GCC carries the spelling: such a
122+
package is compiled once more after the upgrade, and a package of object
123+
files keeps its entry.
124+
- **`mcpp update` moves a branch dependency forward again.** The record of
125+
the previous build was replayed although mcpp.lock had been cleared, so the
126+
next build kept the old commit and wrote it back. A recorded build is now
127+
replayed only under the lock it was planned with.
128+
- **A git branch reached through another package is locked.** mcpp.lock
129+
recorded only the branches the project itself declared, so a branch two
130+
edges away moved to its tip on every build and stopped an `--offline` build
131+
("mcpp.lock records no commit for branch"). It is now recorded under the
132+
package's qualified name and read back as its anchor.
133+
- **A root's checkout answers a dependency's request by version that no index
134+
carries.** The root's path or git declaration of a package overrides a
135+
dependency's request for it by version, but the request was first given to
136+
the index to select, and a package the index did not carry yet (a root
137+
pinning a checkout ahead of a release) refused the build with "no package
138+
found for exact selector". The root's checkout now answers it; a
139+
requirement the checkout does not satisfy is still refused.
140+
- **A build program compiled against an updated interface of the same mcpp
141+
version reads the new interface.** The compiled `mcpp` module of build
142+
programs was kept by mcpp's version alone, so a build of mcpp between
143+
releases that added a directive served the previous interface. It is kept by
144+
the version and a digest of its text.
145+
- **A request by version the local index cannot answer refreshes the index
146+
wherever it is in the graph.** The refresh before the dependency walk asked
147+
only about the root's and the selected members' `[dependencies]`, so a
148+
version named by a path dependency, by a package's own manifest or in a
149+
conditional table, and published after the local index was fetched, refused
150+
the build ("no package found for exact selector") with no refresh at all.
151+
The miss now asks the refresh policy (offline, `[index] auto_refresh`, the
152+
debounce, one sync per run) and the selection is made again; a namespace the
153+
index cannot refute still never refreshes.
154+
- **A dependency written `workspace = true` under a target selector or behind
155+
a feature receives the workspace's source.** Only `[dependencies]`,
156+
`[dev-dependencies]` and `[build-dependencies]` were merged, so a git or path
157+
dependency of `[workspace.dependencies]` inherited in
158+
`[target.'cfg(...)'.dependencies]` or `[feature-deps.<f>]` kept an empty
159+
version and resolved from the index. Such an entry no workspace declares is
160+
now refused by name, as one in `[dependencies]` is.
161+
- **A branch pushed to between `git ls-remote` and the clone is still
162+
fetched.** The clone of a branch is one commit deep, so a push between the
163+
two left it at a newer tip without the commit the build had resolved, and
164+
the build stopped at `unable to read tree`. That commit is now fetched by
165+
its name, or, from a server that refuses that, with the branch's history.
166+
- **Switching workspace members under `trim_paths` no longer recompiles their
167+
shared dependencies** (#844). The prefix map of the whole plan was part of
168+
the flags every unit shares, so a dependency's command line named the roots
169+
of the members being built, and `--release -p cli` then `-p gui` recompiled
170+
the common packages each time. A unit's map is now the fixed roots and the
171+
roots of its own package's dependency closure.
172+
7173
## [2026.10.26.1] - 2026-10-26
8174

9175
### Added

0 commit comments

Comments
 (0)