2026.9.28.1: eight reports (#717, #718, #720, #722-#726), one download progress, and an index floor that is a tip - #727
Merged
Conversation
…720) The lib root was placed at the head of the host-module compile list before the list was sorted by imports, so a lib root that imports a sibling unit was compiled first and failed. The lib root is now the first node of the same sort; it is emitted first whenever it imports nothing of its package, so existing packages keep their order. e2e 807 covers an explicit and a conventional lib root.
The read site printed the E0006 text as error: at the start of every run that read such an index, including runs that then resolved every package elsewhere and exited 0. The fact is now recorded without printing: - a run that fails carries the E0006 text in the message that stops it; - a run that refreshed an index and met a floor ends with one tip: line, printed after the command's output (closing notices, mcpp.ui), and an envelope reports it as the note MCPP_INDEX_REQUIRES_NEWER_MCPP; - mcpp self doctor lists every index whose floor this mcpp does not meet; - a tree recorded as unusable answers no later lookup either; - the E0006 upgrade note starts on its own line. Unit tests for the read site, the hint, the notices; e2e 812.
…d -p resolves the package first A rooted workspace (root [package] + [workspace]) built as itself never set state.wsManifest / state.runtimeWorkspaceRoot, so a member reached through the root's own [dependencies] path entry was loaded as an ordinary path dependency: its x.workspace = true entries were refused or silently unresolved, and it received none of [workspace.package] / [workspace.build]. The workspace context is now set in that branch too, before any dependency is loaded, matching the member-switch branch and satisfying "a member is a member however it is reached" (graph.cpp's depIsMember). -p, --package <NAME> promised a package but both resolvers (manifest.cpp's inline loop and project.cppm's resolve_member_dir) matched only a member's directory basename or path. They are now one function in project.cppm, resolving in order: a member's qualified name (<namespace>.<name>), then its bare package name (refused, naming every match, when shared by two or more members), then its directory path or basename (kept as a fallback; a duplicate basename keeps today's first-match selection but now warns naming the others). A value that is one member's package name and a different member's directory selects the package, with a warning naming the other member. SPEC-004 §9 item 1 names the missing position and states that -p resolves the package identity first; docs/07 §5.3 (en, zh) and the four `-p` help strings state the resolution order. Tests: six unit tests for the resolver in test_workspace_inheritance.cpp (package/path/basename all selecting one member, same name under two namespaces, package-outranks-directory with a warning, duplicate-basename warning, the "not found" listing, and the unaffected no-filter cases); e2e 805 (a rooted workspace's own path dependency, with a non-latest pinned version, an omitted package.version, a [workspace.build] flag, and a shared root [toolchain], served from a project-local index so the build touches no network) and e2e 806 (-p's three resolution steps end to end). Both e2e scripts fail on the released 2026.9.27.1 binary and on 2026.9.26.1, and pass with this fix. Co-authored-by: speak-agent <agent@mcpp-community>
Two or more source paths for one deploy destination no longer collide at planning. `add_deploy` (src/build/plan.cppm) merges them into one `DeployFile` entry instead of refusing a second source path; a `BuildPlan` whose deploy has exactly one source still produces the byte-identical `build.ninja` line it always has. The merged destination becomes one `stage_file` edge with every source as an input (src/build/ninja_backend.cppm), and `mcpp stage` places it once all sources agree byte-for-byte (`stage_files`, src/build/stage.cppm), otherwise failing and naming every source and the destination. `cmd_stage` (src/cli/cmd_build.cppm) accepts one or more source positionals. One destination, one writer: `place-dlls`'s post-link DLL placement (src/pack/pack.cppm `place_runtime_dlls`, invoked from src/cli/cmd_publish.cppm `cmd_place_dlls`) now receives the set of names the merged deploy list already places beside a program, computed in ninja_backend.cppm and passed through a per-edge `$placed` ninja variable so the generated graph stays stable. `place_runtime_dlls` skips those names instead of overwriting them, comparing content and reporting a difference as a warning. SPEC-007 R4.2 and R4.3 are amended to state the content check and the single-writer rule; docs/04 (en, zh) is corrected to match. e2e 810 covers the merge and the build-time refusal; e2e 811 (`# requires: windows`, not run here) covers the single-writer rule; e2e 646's collision case is updated for the new build-time message. Unit tests cover `stage_files`'s multi-source behaviour and the deploy-list skip/warn logic in `place_runtime_dlls`. Co-Authored-By: Claude <[email protected]>
…onment as it found it and starts in the registry's home (#726) On Windows, build_command_prefix prepended the registry's subos/default/bin to the process PATH and set XLINGS_HOME process-wide, and ran xlings in mcpp's working directory. After a build installed a payload, every action found xim:llvm's cl/link/lib/rc shims in front of MSVC's tools, and vcpkg's compiler detection failed; a project with a .xlings.json at its root also received the shims of mcpp's toolchain and payloads in its own SubOS. ScopedInvocationEnv now applies XLINGS_HOME, the scope variables and the PATH prefix for the invocation and restores them afterwards, and the Windows prefix starts with `cd /d "<home>" &&`, as the POSIX prefix does. Refs #726.
…uild program's own diagnostic survives; emit writes no project file W3 (src/build/plan.cppm): the compile-unit loop now skips SourceKind::Device graph units, so build.ninja carries no dead cxx_object edge for a rule-claimed device source, and compile_commands.json / the S1 document agree without their own filter (unit_invocations already excluded only NASM; nothing else needed to change). The source stays in `watch` and still reaches the package's build program through MCPP_DEVICE_SOURCES, since both read the manifest's sources glob directly, not plan.compileUnits. Checked every other consumer of plan.compileUnits (prepare/plan.cpp's dependency-cache collection keys by path, not by index, so it is unaffected beyond a smaller artifact set for a package with device sources). W4: a package whose build program failed under `emit`'s plan_only records MCPP_BUILD_DATABASE_PROGRAM_FAILED and applies none of its directives (state.cppm: new PrepareState::programFailedPackages, set at both call sites in target_side.cpp and features.cpp). The device-source orphan check in target_side.cpp now skips such a package outright, instead of reading every device source as unclaimed and failing the whole member. Also: notes a phase recorded before prepare_build's own failing return are no longer silently dropped (driver.cpp: a thread_local sink in the same per-run-sink style as mcpp::build::refusal, exported as mcpp::build::take_notes_on_failure); cmd_build.cppm's emit failure path folds any such note into the one diagnostic SPEC-005 R5.2 allows a wholly- failed member (path stays the member's mcpp.toml, exactly one entry), so the true cause is not lost behind a downstream symptom without violating that invariant. hasProgram's existing exists(build.mcpp) check is now correct by construction, since a failed program's package never reaches it. W5 (src/build/prepare/xlings.cpp): ensure_project_index_dir's two calls under a private work_dir are collapsed into the one call the ownerRoot==workRoot branch always made, targeting workRoot in every case. Previously the runtime-environment half (deps/subos/workspace) went to runtimeSelection.ownerRoot, which is always the real project root regardless of emit's private work_dir -- so `emit build-database` wrote <root>/.mcpp/.xlings.json into a project that declares [xlings] deps. SPEC-005: R3.7 names device sources beside NASM units (both absent from S1 and compile_commands.json, for different reasons -- NASM is a compile unit excluded from export, a device source is never a compile unit at all). R5.2 gains the sentence that a check whose premise is a build program's directives does not run for a package whose program failed in this pass. R2.1 needed no change. Tests: e2e 808 (device source: no dead ninja edge, absent from both databases, and the rule still compiles it and the build still runs), e2e 809 (a device source plus a build.mcpp that does not compile: PROGRAM_FAILED with path build.mcpp, no device-source mention, package still described), e2e 817 (688's project-tree digest repeated on a stub-xlings fixture with [xlings] deps: byte-identical tree, no .mcpp/.xlings.json, no write-project effect, and the private work directory does gain one naming the dependency). Each fails against the released 2026.9.27.1 binary and passes on the fresh build. Full regression: all 15 emit/build-database e2e scripts, 798, and four more that exercise the compile-unit loop (asm/GAS, NASM, object-path-collision, multi-module) all still pass; `mcpp test` (130 unit tests) passes.
Sunrisepeak
added a commit
to Sunrisepeak/GalTranslPP
that referenced
this pull request
Sep 27, 2026
…into feat/eight-reports
A set's ide.generated lists each output of its package's source-role actions (header or source, with the step's id, inputs, arguments and work directory) and each generated include directory its units name, with the path the document names and the path a mcpp build of the same selection writes. The profile version is 0.3.0 (Sunrisepeak/ mcpp-language-server#28); compile_commands.json is unchanged. SPEC-005 R3.12, docs 50; e2e 815, e2e 688 reads the new version.
- ProgressBar prints one start line and one finish line when stdout is not a terminal: no carriage return, no erase sequence, no repaint per frame; an item that does not complete says so instead of reporting it done. - The index refresh runs through xlings interface update_packages and draws its progress and download events with the same renderer; an xlings that emits none shows its status line as before, and its terminal text no longer reaches the output. - The clone of a git dependency passes --progress and draws the download phase, read as it is redrawn (run_streaming_bounded gains an opt-in rule that a lone carriage return ends a line); the output is kept whole for the failure message, and a clone silent for fifteen minutes is stopped. - The sandbox bootstrap's hand-drawn spinner is the shared bar. e2e stubs accept the interface refresh; unit tests for the git progress parser, both render modes and the line splitting; e2e 816; docs 09.
[target.<selector>.build] dialect_cxxflags is now accepted, parsed into a new ConditionalConfig member kept apart from BuildInputs (the key is graph-wide, not a per-package additive input), and merged into the same BuildConfig::dialectCxxflags every consumer already reads: the std BMI prebuild, the scan, every TU and the fingerprint. Only the root of the build renders it; a dependency's own value (conditional or not) reaches no command and is now excluded from its own fingerprint contribution, matching the rule that a key enters a fingerprint only where it reaches a command. The build-program directive is deliberately not added. SPEC-004 SS3.1 and SS9 item 10 state the new rule; docs/04 and docs/zh/04 document the conditional form (since 2026.9.28.1). Unit tests cover parsing, the emptiness gate, and root-only resolution order. e2e 813 covers reach into the std BMI/scan/TUs, a non-matching selector, the A-B-A std BMI rebuild, and a dependency's key being fingerprint-inert; it fails on the released 2026.9.27.1 binary and passes on the fresh one.
The one-writer rule passed the deploy list's names to place-dlls on its command line. The plan's deploy set reads runtime search directories that a prepare action fills, so it differs between the first and the second plan; the command changed and every build after the first re-ran the placement (e2e 797, found by a differential run against 2026.9.27.1). place-dlls now treats a DLL beside the program that it did not place, and that a runtime search directory also offers, as another writer's; the command is the one 2026.9.27.1 wrote.
Every MSVC-ABI row now receives the same CRT model: cl spells it /MT or /MD, clang++ targeting *-windows-msvc spells it -fms-runtime-lib=static or =dll. One helper (msvc_abi_crt_word, dialect.cppm) decides the word for the translation units, the std/std.compat BMIs and the link command alike, closing #649 E10 (a compile-only flag never reached the clang driver's own link-time choice of -defaultlib:). toolchain-coupled (the dynamic CRT, with the toolset's own vcruntime140.dll/msvcp140.dll staged beside the artifact) is now the default for every role on this ABI (dist::msvc_abi_default_contract, ContractStatement::msvcAbiDefault). A toolset with no VC\Redist\MSVC directory defaults to host-coupled silently and refuses an explicit toolchain-coupled, naming the missing directory (prepare/plan.cpp). A free-form CRT word in cxxflags/dialect_cxxflags is checked against the resolved model: agreeing is a warning, contradicting is a refusal (dialect::check_crt_word, wired in prepare/scan.cpp). The toolset's redistributable directory is carried as its own Toolchain field (msvcRedistDir), populated for cl from vc_redist_dir and for the LLVM row from its sysroot's tools directory (vc_redist_dir_for_tools_dir) rather than from linkRuntimeDirs, which holds LLVM's own runtime directories on that row. The staging gate and the mcpp run/test search path both read this field, gated on the MSVC ABI rather than on which compiler is in use. mcpp pack carries the staged DLLs by default; an explicit --mode system now resolves a defaulted (never-declared) toolchain-coupled contract to host-coupled instead of refusing. e2e 703 is inverted to the new default; e2e 814 covers the LLVM row's import table, staged DLL, clean-PATH run, self-contained round trip, BMI switching (A, B, A) and pack modes (Windows-only, unverified here). Unit tests cover the CRT-word derivation, the free-form-word check, the MSVC-ABI default/redistributable resolution and a compute_flags-level property test across both rows; the link-line half of that test is gated on mcpp.platform.is_windows, since link_shape resolves LinkShape::PeLld only when current_link_host() is Windows and a Linux-built mcpp cannot reach that branch regardless of the plan's target triple. docs/20, docs/zh/20 and SPEC-006 record the new default and the upgrade; docs/04 needed no change (it only points at docs/20). 131/131 unit tests pass on Linux (gcc 16.1.0 and llvm 22.1.8 rows); docs structure/style checks pass.
…steps The worklist step for one item is split into identity resolution, the already-resolved / identity-adoption handling (with its own version-merge sub-step), acquiring a fresh dependency's source and manifest, and finalizing it (recording the package, recursing into children); the per-item locals that cross those boundaries move into a phase-local struct, WorklistItemCtx, the same PrepareState pattern one level deeper. The post-loop cycle check is its own function. Preamble closures that captured only `state` (or nothing) become static file-scope functions, called with an explicit PrepareState& where they used to close over it; this also fixes the one comment that had gone factually stale (activateFeatures's group banner said 'defined as local lambdas, not file-scope functions' -- now they are file-scope, and are still safe because a static function carries no external linkage into the module's exported interface). Longest resulting function: 300 lines (step4b_identity_version_merge).
…) into sub-steps Along the sections its own banners already name: feature activation, device extensions and rule application, the graph's [xlings.workspace] provisioned before build.mcpp, host-module registration, host-tool provisioning, the dependencies' build programs, and capability binding. aggregatedRequest (needed by two of these sections) is promoted from a local lambda to a file-scope function of PrepareState&. Two scoping braces that had no matching close within their own section (opened to wrap several sections at once) are dropped as redundant once the content is distributed across separate functions, each of which supplies its own scope. Longest resulting function: 425 lines (step6_provision_host_tools).
…b-steps Gather the graph's target-side candidates into a phase-local struct (TargetSideGather, the PrepareState pattern one level deeper), then resolve and realise [c-abi], broadcast the include set, check kernel-abi interfaces and layer requirements, apply the layer-conditional config (L1b), decide each dependency's link form (#519), define the graph_package_entry closure, run the root build.mcpp (L3), require every device source to reach an action, and handle re-run inputs (R1.3). Two scoping braces that wrapped several sections at once are dropped as redundant, as in the two previous files. Longest resulting function: 404 lines (step9_kernel_abi_interfaces_and_requirements).
…-steps The closures phase4a_graph_load assigns onto state (each captures only state) split into two groups: split/identity closures, and candidate selection closures. LoadedDep is hoisted to file scope so it stays visible to state.loadVersionDep, which remains where it was. state.loadVersionDep itself (509 lines) is not split further: its six local closures (readLuaContent, findRawInstalled, installedLayoutMatchesIndex, revisionIsCurrent, findCompleteInstalled, markInstalled) mutually capture nine-odd shared locals by reference: hoisting them to free functions would mean threading all of that through explicit parameter lists for one closure, judged higher risk than benefit within this round; noted as a residual in the T6 report.
CI (PR #727): - e2e 190/191 select the program by name; bin/ also holds the staged redistributable DLLs on an MSVC-ABI row (#718). - A DLL found in a runtime search directory yields to a declared deploy of the same name, and a difference is warned at planning, where a successful build shows it (SPEC-007 R4.3, e2e 811; e2e 818 is its Linux-hosted form). - build.mcpp that imports only a build rule compiles in the build directory under GCC (e2e 807). - The runtime environment half of .xlings.json goes to the runtime's owner again; only plan_only redirects it to the planning directory (e2e 205, 817). Review: - Every set of a package names what its build program generates (R3.12). - A dependency's contradicting CRT word is refused; debug CRT words are refused; the agreeing-word message names the key of the dynamic model; the dependency cache key carries the CRT word. - PE deploy destinations compare without case; MSVC version directories compare numerically; a missing deploy source is named as missing. - A failed index refresh draws "did not complete"; an automatic refresh that exhausts its retries warns; the floor tip names the version and the install-aware upgrade. - -p compares paths as paths; the help names the qualified form.
…p) into sub-steps Split at phase1's own banner boundaries: the closures phase1 assigns onto state, the target/--static override resolution, and the device axis plus the L1 conditional-section merge. phase2_define_toolchain_resolver is not split: it is a single stored closure, state.resolve_target_toolchain, whose ~1000-line body is one sequential toolchain-resolution flow with dozens of interdependent locals -- the same category of residual as state.loadVersionDep in graph_load.cpp, noted in the T6 report. step1_target_and_static_overrides (524 lines) is a smaller residual of the same kind.
…phase3_xlings_before_graph Both were found over ~400 lines by the same sweep that produced the seven functions #722 named (the issue's own "any other function under src/build/prepare/ over ~400 lines"), and split cleanly along their own banners: phase0's own "Workspace handling" section becomes step0_workspace_handling (108 lines; phase0 itself drops to 372); the host-toolchain closures phase3 assigns onto state, plus the index-refresh section, become step3_define_host_tc_closures_and_refresh_index (298 lines; phase3 itself drops to 235).
…o CI yet .github/tools/check_function_sizes.sh runs clang-tidy's readability-function-size (LineThreshold=400) over the compile database mcpp produces for its own LLVM build (mcpp build --toolchain [email protected]), restricted to files under src/build/prepare/. clang-tidy is not part of the plain xim:llvm payload; it ships in the sibling xim:llvm-tools package at the same version, which the script locates under the xlings store. Measured: at 7ccbc8d (before this round's split) it reports 10 functions over 400 lines -- the seven #722 named, plus phase0_manifest_and_workspace, phase11_scan and phase3_xlings_before_graph, found by the same sweep. After this round's split it reports 6: step6_provision_host_tools (421), phase4a_graph_load (518, its loadVersionDep closure), phase11_scan (773, untouched), step9_kernel_abi_interfaces_and_requirements (401), step1_target_and_static_overrides (522) and phase2_define_toolchain_resolver (1006, untouched) -- see the T6 report for why each remains. Not wired into CI next to check_file_lengths.sh: it does not yet pass, so adding the workflow step now would land a gate red on day one. Wire it once the remaining residuals are split in a follow-up; the file gate stays the only enforced one for this round, per the design's own fallback for a working tool over an incomplete split.
…under the file-length limit after the merge; byte-identical on the seven fixtures)
…tures.cpp) The per-tool body of the outer loop (~421 lines) becomes HostToolCtx, a phase-local struct following the WorklistItemCtx / TargetSideGather pattern, and six sub-steps: target resolution, the override/self-request checks, the store-key/cache-hit resolution, the sub-build, and publish. The `record` closure the single-function version captured per tool is a named helper called from all four sites that used it (an override, a cache hit, a deferred plan-only tool, and a freshly built one). Verified: byte-identical on the seven fixtures; check_function_sizes.sh reports no finding in this file.
…ph_load.cpp) phase4a_graph_load's stored closure state.loadVersionDep (~518 lines) is split the way phase2's single stored closure is: a local struct (LoadVersionDepCtx) holds the parameters and the locals more than one section reads, and the body becomes three named steps (locate an already-installed copy, fetch one if none is installed, then read its manifest) the closure calls in sequence. The stored closure stays the entry point with the same signature, so its own recursive call for a preinstall hook's dependencies is unchanged. Two of its local lambdas (readLuaContent, findRawInstalled) are read from two of the three steps (the initial read and a later re-check, or the initial probe and the post-install one) and become named helpers for the same reason `record` did in the previous commit; a third (markInstalled) is promoted for the same reason though it has only one call site, since the closure it replaced no longer has anywhere to live once the body it was local to is split. Verified: byte-identical on the seven fixtures; check_function_sizes.sh reports no finding in this file.
Split at its own section boundaries into eight named steps (source scan and validation, the dependency-standard scope check, the dialect-flag gate, the MSVC CRT-word check, the package std-module source, the Apple SDK C++ runtime rule, the std-module availability gate, the fingerprint computation, and the std-module prebuild). needsStdModule is the one value several steps read; it is computed by the first step and passed as a plain bool parameter rather than through a struct, since it is the scan's only shared local. Verified: byte-identical on the seven fixtures; check_function_sizes.sh reports no finding in this file.
…rides and phase2_define_toolchain_resolver (toolchain.cpp) step1 (~522 lines): a phase-local struct (TargetOverrideCtx) holding the parsed triple, its vocabulary-table row and the section lookup carries seven sub-steps through one `--target` request's resolution (resolve the request, validate its tier, the Apple SDK check, the wasm shared-lib check, the host_can_serve diagnosis, capturing the display name and canonicalising, and the row-pin/capability check). The `apply_target_section` closure is a named helper, called from the resolved-request branch and from the host-row branch that follows it. phase2 (~1006 lines, a single stored closure, state.resolve_target_toolchain): a phase-local struct (ToolchainResolveCtx) holds only the parsed spec and the Windows installed-toolset probe -- the two locals the branch-selection half of the closure shares. Every other local (the first-run defaults, the explicit-spec resolution's own payload/frontend locals, and so on) stays local to the one step that declares it, as it was in the single function. The closure becomes twelve named steps: parsing the spec, each arm of the compiler-resolution if/else-if chain, the Windows-first-run persist, toolchain detection, the retargetable-driver fixup, the MSVC toolset bind, the Windows runtime identity, the MSVC-ABI-without-MSVC repair, and the musl default linkage. The stored closure stays the entry point with the same signature, so its own recursive call (the target pass) is unchanged. Verified: byte-identical on the seven fixtures; check_function_sizes.sh reports no finding in this file.
…_requirements (target_side.cpp); the gate's own false failure at zero findings step9 (~401 lines) splits into five named steps at its own section boundaries: the kernel-abi interface enumeration, the layering and requirement checks (over TargetSideGather's `requirements`), the pin-and-linkage diagnostics, the same-OS check and report, and the platform-sdk closure visibility check. No phase-local struct is needed: each step reads and writes only `state` (plus `gather` for the one step that needs its `requirements`). This was the last of the six residuals check_function_sizes.sh reported at the base of this round; with it split, the gate ran clean over the whole of src/build/prepare/ for the first time -- and immediately failed for an unrelated reason: `--warnings-as-errors='*'` makes clang-tidy exit non-zero on the two pre-existing readability-function-size findings in the bundled third-party modules/libs/src/json/json.hpp, which the script's own `relevant` filter already excludes from the pass/fail decision but which its exit-code fallback then reads as "a diagnostic tool problem" -- a false failure this repository's own tree could not previously reach, since no earlier revision had zero findings under src/build/prepare itself. Dropping the flag leaves clang-tidy's exit code meaningful only for an actual tool failure (a bad compile command, a crash), which a plain warning never produces; `relevant` remains the sole pass/fail signal, as the surrounding comments already say it is. Verified: check_function_sizes.sh reports "ok" over the whole of src/build/prepare/; byte-identical on the seven fixtures.
… is resolved at the version that wrote the compile database
…th clang (#729); a generated deploy source is compared after the link only - ci-linux.yml: the gate step comes out again. The LLVM toolchain job's [email protected] self-build has never completed (libc++ 20's std module hides directory_iterator's comparison) and the step reads the resolution line, not the build's exit status; clang-tidy crashed over the partial database. Recorded as #729. - check_function_sizes.sh: a finding is a diagnostic line ending in the bracketed check name; a crash dump no longer reads as a finding. - prepare/plan.cpp: a declared deploy source that an action writes is left to the post-link comparison; at planning it may hold the previous build's bytes.
This was referenced Sep 27, 2026
Merged
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Addresses #717, #718, #720, #722, #723, #724, #725 and #726; each is closed after the release is verified in a sandbox. #721 (upstream GCC), #728 (conditional-table order) and #729 (the CI clang self-build, found by this round) stay open.
The round's triage, decisions and implementation readings are in
.agents/docs/2026-09-27-eight-reports-by-home-and-one-optimisation-plan.md(§13.5 and §13.6 record what implementation, review and CI found) and.agents/docs/2026-09-27-eight-reports-implementation-plan.md. The release notes are the 2026.9.28.1 section ofCHANGELOG.md.Defects
[dependencies]path entry now receives the workspace context ([workspace.package],[workspace.build],workspace = truepins), as SPEC-004 §9 item 1 states.-p, --package <NAME>. One resolver answers in the order qualified name, package name, then member path or directory name. A package name shared by two namespaces is refused, with both qualified names given. A value that is one member's package name and another's directory selects the package, with a warning. Paths are compared as paths.emit build-databasewrites nothing into the project (SPEC-005 R2.1, R3.7, R5.2).mcpp buildleaves the registry's shim directory at the front of PATH for every action, so llvm's cl/link/lib shims shadow MSVC #726, Windows xlings invocations.ScopedInvocationEnvapplies and restoresXLINGS_HOME, the scope variables andPATH, and every command starts in the registry's home (cd /d "<home>" &&).tip:after the refresh that met it, naming the version and the install-aware upgrade, andmcpp self doctorlists it. It is no longer anerror:at the start of every command.Features
[target.<selector>.build] dialect_cxxflags: a graph-wide flag under a target condition, reaching the std BMI, the scan and every unit (SPEC-004 §3.1, §9 item 10)./MDand/MT;-fms-runtime-lib=dllandstatic) on compile, the std BMI and link.toolchain-coupled: the dynamic CRT, with the toolset's redistributable DLLs staged beside the program.Internal
src/build/prepare/are split into sub-steps, verbatim. No function there exceeds 400 lines..github/tools/check_function_sizes.sh(clang-tidyreadability-function-size, over the compile database of an LLVM build). It reported 10 functions before the split.resolution.json,build.ninjaand the build-database output of seven fixtures are byte-identical to the pre-split binary.Verification
bin/now also holds the redistributable DLLs.maintoo, because ld64.lld cannot parse the SDK (ci-macos xcode-27: ld64.lld cannot parse arm64e.x1 in either available SDK (upstream, tracked) #669).Compatibility
See the CHANGELOG. In brief:
cxx_runtime = "self-contained"restores the static CRT.toolchain-coupledon a row with no redistributable directory;-pon a package name shared by two namespaces;Ecosystem
latestby bump(xlings): track 2026.9.28.1 as latest openxlings/xim-pkgindex#895 and mirrored to GitCode.latest_mcppmove after this release.