|
4 | 4 | > Each `## [<version>]` section is that release's notes. Entries are written in English |
5 | 5 | > from 2026.9.28.3 on; earlier entries remain as written. |
6 | 6 |
|
| 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 | + |
7 | 173 | ## [2026.10.26.1] - 2026-10-26 |
8 | 174 |
|
9 | 175 | ### Added |
|
0 commit comments