Commit 26b26ec
* feat(toolchain): MSVC gets a version axis -- `msvc@<toolset>` alongside `msvc@system` (2026.8.16.1)
gcc and llvm are installed by mcpp and resolved from what the manifest
declares. MSVC was the one exception: EVERY msvc spec was a system spec, so a
manifest could name a toolset and have that name discarded.
The consequence is not inelegance. It is that the same source compiles with
different compilers on different machines, and nothing says so. Measured on
xrgui#3: in ONE CI run mcpp used 14.51 and xmake used 14.52, and it stayed
invisible until 14.51 hit an ICE. Exporting a complete vcvars environment did
not help -- the only way out was to move `vswhere.exe` aside so mcpp would
fall through to VSINSTALLDIR, and that workaround is still in xrgui's
workflow.
## The version axis decides the origin
msvc@system (or bare msvc) the machine's own Visual Studio -- UNCHANGED
msvc@<toolset> an xlings payload mcpp installs and pins
`msvc@14.44.35207` is isomorphic to `gcc@16.1.0` in every respect:
coexisting versions, `toolchain remove msvc@<toolset>`, auto-install from a
manifest. The payload brings the compiler, the STL, and -- through its
`xim:windows-sdk` dependency -- the ucrt/um headers and libs, so nothing has
to be preinstalled.
Structurally, ACQUISITION and RESOLUTION are separated: acquisition is shared
with gcc (the xim install), resolution is shared with `msvc@system`
(`installation_from_tools_dir`). A pinned toolset is therefore not a second
code path, and cannot grow its own bugs. What it does not share is the
bin/-shaped frontend lookup (cl.exe is four levels deeper) and the ELF
post-install fixup (there is nothing to patchelf on a PE toolchain).
BREAKING: `msvc@19.44` was a pin-verify against the system install's cl
banner -- checked by `toolchain default` and silently ignored by builds. The
version axis now names a toolset everywhere. A `19.x` spelling errors out
with this machine's actual cl version and both replacements.
## VSINSTALLDIR now outranks vswhere
vswhere returns something on nearly every developer machine, which made
VSINSTALLDIR effectively unreachable -- a build that had exported a complete
vcvars environment still compiled with whatever vswhere ranked first. A guess
must not silently override an answer.
vswhere also gains `-prerelease`: without it a machine with only an Insiders
VS is reported as "MSVC not found" while a perfectly good cl.exe sits on
disk.
VS*COMNTOOLS stays BELOW vswhere. Those are machine-wide leftovers -- a 2017
VS150COMNTOOLS must not outrank a current install -- whereas VSINSTALLDIR is
someone setting it for this shell. The old `find_vs_via_env()` conflated the
two, so promoting it would have promoted the leftovers too.
## The Windows SDK stops being two absolute paths
Order: WindowsSdkDir (+ WindowsSdkVersion, both exported by vcvars) -> the
`xim:windows-sdk` payload beside a pinned toolset in mcpp's own store -> the
hardcoded roots, now a fallback.
The second source needs no configuration and hardcodes no version: the
COMPILER'S OWN PATH says which store it came from, and the SDK is its
neighbour there. `sibling_sdk_roots()` returns empty for a system cl, so the
two origins stay separate.
## cxx_runtime = "self-contained" now actually does something on MSVC
Two knobs, one working: `linkage = "static"` really emitted /MT while
`cxx_runtime = "self-contained"` reported "not implemented" -- for the same
physical switch. Two comments contradicted each other about it
(flags.cppm:605 vs distribution.cppm:202).
On the MSVC ABI these are not alternatives: /MT links the C runtime and the
C++ runtime out of the same library. Both spellings now select it through one
`msvc_wants_static_crt()`, which the project's TUs and the std module both
ask -- rather than each spelling out `linkage == "static"`, which is exactly
how they diverged in #422.
The default stays /MD: the predicate reads the WRITTEN manifest scalar, not
the resolved contract, because most roles default to self-contained and
keying off that would flip every Windows build to /MT.
The CRT model is a whole-PROJECT property (one std module per project, and cl
bakes _MSVC_MT/_MSVC_MD into it), so a per-role override is now refused with
a message that says why, instead of failing later inside the ucrt headers.
## Tests
MSVC discovery is testable off Windows for the first time: `installation_at()`
takes a directory instead of probing, `find_windows_sdk()` takes a list of
roots, and neither is behind a platform macro. Six new unit tests drive real
fixture trees on Linux CI -- including "both toolsets present, ask for the
OLDER one", which a latest-wins implementation fails and a real machine might
pass by accident.
New e2e `239_msvc_managed_toolset.sh`, written so that the SYSTEM compiler
answering would FAIL rather than pass quietly: cl.exe must be inside mcpp's
store, the toolset directory must be the one named, and switching the same
project back to `msvc@system` must resolve to the system cl again.
83/83 unit targets pass; 95/96/103/183 e2e pass on Linux.
Closes #432
* test(e2e): 239 asked for a flag that does not exist
`toolchain list --available` is not a thing -- `toolchain list` already
prints an "Available toolchains" section. Caught by ci-windows on the first
run, which is the right place for it: this test only ever executes there.
Also reordered: the install now runs BEFORE the discoverability check, so a
runner that cannot reach the index skips cleanly instead of failing an
assertion about a list the index would have filled in. And the check became
stronger than the one it replaces -- it asserts the INSTALLED toolset shows
up, not merely that some msvc row exists, because a toolset that installs and
then never appears is indistinguishable from one that did not install.
* docs: the cross-repo plan, its one hard dependency, and which claims can self-certify
Four repos, five changes, ONE real dependency edge: the packages must be
published before mcpp can install them and before xrgui can use them.
Everything else is parallel, and stringing it into a line is the usual waste
in work shaped like this.
The part worth reading is §4: which acceptance criteria a person could
satisfy by adjusting a test, and which they could not. The mirror is the
example that earned the distinction -- the criterion is not "the upload
succeeded" but "the bytes came back with Microsoft's sha256", and that
caught a real failure where the tool reported 16 files as failed while the
release listing showed them present and they were in fact absent.
* fix(toolchain): a managed toolset without its SDK reported success
Self-review catch. `installation_at()` succeeding means cl.exe is where the
declared version says it should be -- it says nothing about the ucrt/um
headers, which arrive as a separate package dependency and can therefore fail
on their own. The install printed "Installed", and the build died inside the
ucrt headers much later.
That is the half-installed state `has_usable_msvc()` was written for; this
applies the same judgement to the managed origin, and names the dependency
that must have failed rather than leaving the reader to work it out.
Also: `msvc_print_detected` now takes the label. "Detected" is a claim about
probing the machine, and printing it after unpacking a payload the caller
NAMED describes the wrong thing -- quietly, and in exactly the direction this
whole change is about.
---------
Co-authored-by: speak-agent <248744407+speak-agent@users.noreply.github.com>
1 parent f4b64a1 commit 26b26ec
17 files changed
Lines changed: 1690 additions & 207 deletions
File tree
- .agents/docs
- docs
- src
- build
- toolchain
- tests
- e2e
- unit
Large diffs are not rendered by default.
Lines changed: 93 additions & 0 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
| 20 | + | |
| 21 | + | |
| 22 | + | |
| 23 | + | |
| 24 | + | |
| 25 | + | |
| 26 | + | |
| 27 | + | |
| 28 | + | |
| 29 | + | |
| 30 | + | |
| 31 | + | |
| 32 | + | |
| 33 | + | |
| 34 | + | |
| 35 | + | |
| 36 | + | |
| 37 | + | |
| 38 | + | |
| 39 | + | |
| 40 | + | |
| 41 | + | |
| 42 | + | |
| 43 | + | |
| 44 | + | |
| 45 | + | |
| 46 | + | |
| 47 | + | |
| 48 | + | |
| 49 | + | |
| 50 | + | |
| 51 | + | |
| 52 | + | |
| 53 | + | |
| 54 | + | |
| 55 | + | |
| 56 | + | |
| 57 | + | |
| 58 | + | |
| 59 | + | |
| 60 | + | |
| 61 | + | |
| 62 | + | |
| 63 | + | |
| 64 | + | |
| 65 | + | |
| 66 | + | |
| 67 | + | |
| 68 | + | |
| 69 | + | |
| 70 | + | |
| 71 | + | |
| 72 | + | |
| 73 | + | |
| 74 | + | |
| 75 | + | |
| 76 | + | |
| 77 | + | |
| 78 | + | |
| 79 | + | |
| 80 | + | |
| 81 | + | |
| 82 | + | |
| 83 | + | |
| 84 | + | |
| 85 | + | |
| 86 | + | |
| 87 | + | |
| 88 | + | |
| 89 | + | |
| 90 | + | |
| 91 | + | |
| 92 | + | |
| 93 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
3 | 3 | | |
4 | 4 | | |
5 | 5 | | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
| 20 | + | |
| 21 | + | |
| 22 | + | |
| 23 | + | |
| 24 | + | |
| 25 | + | |
| 26 | + | |
| 27 | + | |
| 28 | + | |
| 29 | + | |
| 30 | + | |
| 31 | + | |
| 32 | + | |
| 33 | + | |
| 34 | + | |
| 35 | + | |
| 36 | + | |
| 37 | + | |
| 38 | + | |
| 39 | + | |
| 40 | + | |
| 41 | + | |
| 42 | + | |
| 43 | + | |
| 44 | + | |
| 45 | + | |
| 46 | + | |
| 47 | + | |
| 48 | + | |
| 49 | + | |
| 50 | + | |
| 51 | + | |
| 52 | + | |
| 53 | + | |
| 54 | + | |
| 55 | + | |
| 56 | + | |
| 57 | + | |
| 58 | + | |
| 59 | + | |
| 60 | + | |
| 61 | + | |
| 62 | + | |
| 63 | + | |
| 64 | + | |
| 65 | + | |
| 66 | + | |
| 67 | + | |
| 68 | + | |
| 69 | + | |
| 70 | + | |
| 71 | + | |
| 72 | + | |
| 73 | + | |
| 74 | + | |
| 75 | + | |
| 76 | + | |
| 77 | + | |
| 78 | + | |
| 79 | + | |
| 80 | + | |
| 81 | + | |
| 82 | + | |
| 83 | + | |
| 84 | + | |
| 85 | + | |
| 86 | + | |
| 87 | + | |
| 88 | + | |
| 89 | + | |
| 90 | + | |
| 91 | + | |
| 92 | + | |
| 93 | + | |
| 94 | + | |
| 95 | + | |
6 | 96 | | |
7 | 97 | | |
8 | 98 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
213 | 213 | | |
214 | 214 | | |
215 | 215 | | |
216 | | - | |
| 216 | + | |
217 | 217 | | |
218 | | - | |
219 | | - | |
220 | | - | |
| 218 | + | |
| 219 | + | |
| 220 | + | |
| 221 | + | |
| 222 | + | |
| 223 | + | |
| 224 | + | |
| 225 | + | |
| 226 | + | |
| 227 | + | |
| 228 | + | |
| 229 | + | |
| 230 | + | |
| 231 | + | |
| 232 | + | |
| 233 | + | |
| 234 | + | |
221 | 235 | | |
222 | 236 | | |
223 | 237 | | |
224 | 238 | | |
225 | 239 | | |
226 | | - | |
227 | | - | |
228 | | - | |
| 240 | + | |
| 241 | + | |
| 242 | + | |
| 243 | + | |
| 244 | + | |
| 245 | + | |
| 246 | + | |
| 247 | + | |
| 248 | + | |
| 249 | + | |
229 | 250 | | |
230 | 251 | | |
231 | 252 | | |
| |||
234 | 255 | | |
235 | 256 | | |
236 | 257 | | |
237 | | - | |
238 | | - | |
239 | | - | |
240 | | - | |
| 258 | + | |
| 259 | + | |
| 260 | + | |
241 | 261 | | |
242 | 262 | | |
243 | | - | |
244 | | - | |
| 263 | + | |
245 | 264 | | |
246 | 265 | | |
247 | 266 | | |
248 | 267 | | |
249 | 268 | | |
250 | 269 | | |
251 | | - | |
252 | | - | |
253 | | - | |
254 | | - | |
255 | | - | |
256 | | - | |
257 | | - | |
258 | | - | |
259 | | - | |
260 | | - | |
261 | | - | |
262 | | - | |
263 | | - | |
264 | | - | |
| 270 | + | |
| 271 | + | |
| 272 | + | |
| 273 | + | |
| 274 | + | |
| 275 | + | |
| 276 | + | |
| 277 | + | |
| 278 | + | |
| 279 | + | |
| 280 | + | |
| 281 | + | |
| 282 | + | |
| 283 | + | |
| 284 | + | |
| 285 | + | |
| 286 | + | |
| 287 | + | |
| 288 | + | |
| 289 | + | |
| 290 | + | |
| 291 | + | |
| 292 | + | |
| 293 | + | |
| 294 | + | |
| 295 | + | |
| 296 | + | |
| 297 | + | |
| 298 | + | |
| 299 | + | |
| 300 | + | |
| 301 | + | |
| 302 | + | |
| 303 | + | |
| 304 | + | |
| 305 | + | |
| 306 | + | |
| 307 | + | |
| 308 | + | |
| 309 | + | |
| 310 | + | |
| 311 | + | |
| 312 | + | |
| 313 | + | |
| 314 | + | |
| 315 | + | |
| 316 | + | |
| 317 | + | |
| 318 | + | |
| 319 | + | |
| 320 | + | |
| 321 | + | |
| 322 | + | |
| 323 | + | |
| 324 | + | |
| 325 | + | |
| 326 | + | |
265 | 327 | | |
266 | 328 | | |
267 | 329 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
1 | 1 | | |
2 | 2 | | |
3 | | - | |
| 3 | + | |
4 | 4 | | |
5 | 5 | | |
6 | 6 | | |
| |||
0 commit comments