]> vilimpoc.org git repositories - dotfiles/blobdiff - README.md
dotfiles: split provisioning between x64 and ARM64
[dotfiles] / README.md
index 794657dc784947785ba0e8ae1c38fb5408718b6a..ed5d49d6ae8cfd9a4025ef6e0dcdb42264dfe88a 100644 (file)
--- a/README.md
+++ b/README.md
@@ -10,15 +10,16 @@ BinSkim, the Windows Performance Toolkit). It also sets the box up to be driven
 remotely: OpenSSH Server plus an rsync build for Windows, which is what makes a
 throwaway VM reachable from a Linux host.
 
-Runs on **x64 and on ARM64** (Windows 11 on Arm). See
-[Running on ARM64](#running-on-arm64) for what differs.
+Runs on **x64 and on ARM64** (Windows 11 on Arm), and installs *different things*
+on each: x64 is the full workstation, ARM64 a lean single-compiler build box. See
+[Running on ARM64](#running-on-arm64) for what differs and why.
 
 ## Files
 
 | File | Purpose |
 | --- | --- |
 | `setup-windows.bat` | Entry point. Runs the winget installs, then launches the elevated half and prints its log, then runs the non-elevated script. |
-| `setup-windows-no-uac.ps1` | The non-elevated, per-user half: WinMerge and BinSkim on the user `PATH`, the global git config (identity, plus `core.sshCommand`), the native `ninja` pinned ahead of the one Visual Studio bundles, and an architecture audit of everything provisioned. Can also be run directly from an ordinary prompt. |
+| `setup-windows-no-uac.ps1` | The non-elevated, per-user half: WinMerge, BinSkim and upstream LLVM on the user `PATH` (x64 only), the global git config (identity, plus `core.sshCommand`), the native `ninja` pinned ahead of the one Visual Studio bundles, and an architecture audit of everything provisioned. Can also be run directly from an ordinary prompt. |
 | `setup-windows-with-uac.ps1` | The elevated half, started via UAC by the batch file. Enables `ssh-agent`, installs the OpenSSH Client and Server capabilities and starts `sshd`, unpacks the `rsync-windows` release zip for this architecture (`rsync.exe` plus the `ssh.exe` it runs) into `C:\Tools\rsync` on the machine `PATH`, then installs Visual Studio Community with the required components, the WDK, and the Windows Performance Toolkit, and reports whether Intel VTune Profiler is present. Can also be run directly from an Administrator prompt. |
 | `setup-windows-7-test-env.bat` | Prepares a **Windows 7 VM** as a test target driven from the host by `VBoxManage guestcontrol`. Copy it into the guest and run it there; it is idempotent, so re-run it after any snapshot restore. The per-user half needs no UAC (crash-dialog suppression, no screen blanking, a staging directory, the shared folder on `Z:`); the machine-wide half is skipped with a notice unless run elevated inside the guest. It then reports what the box can actually test: DWM composition, printers, audio capture devices. |
 
@@ -122,8 +123,9 @@ Runs on **x64 and on ARM64** (Windows 11 on Arm). See
   a box on a known build, pin the tag in `$RsyncUrl`
   (`.../releases/download/<tag>/<asset>`) instead.
 - Visual Studio is installed in three labelled passes (base workload, Clang/LLVM,
-  XP toolset) so a failure identifies which component group is responsible. The
-  last two are optional passes: a failure there warns and provisioning continues,
+  XP toolset) so a failure identifies which component group is responsible. On
+  ARM64 only the first runs — the other two are skipped there, each printing why.
+  The last two are optional passes: a failure there warns and provisioning continues,
   because neither is needed to build with MSVC and losing the whole toolchain
   over a component you can add later from the installer UI is the worse outcome.
 - **Which Visual Studio generation.** `$VsChannel` near the VS step picks it —
@@ -238,14 +240,41 @@ Runs on **x64 and on ARM64** (Windows 11 on Arm). See
 ## Running on ARM64
 
 All three scripts detect the host architecture and adapt. Nothing needs a flag —
-run `setup-windows.bat` exactly as on x64. Both PowerShell halves use
-`RuntimeInformation.OSArchitecture` rather than `%PROCESSOR_ARCHITECTURE%`,
-because an emulated PowerShell reports the *emulated* architecture in the
-environment variable and the real one through the API.
+run `setup-windows.bat` exactly as on x64.
 
-**The build toolchain is fully native.** Visual Studio's ARM64 installer, MSVC
-and clang-cl are all ARM64 binaries, and MSVC cross-compiles every target from
-an ARM64 host with no emulation in the compiler:
+**The two architectures deliberately install different things.** x64 is the full
+workstation; ARM64 is provisioned as a lean, single-compiler build box. See
+[ARM64 installs less, on purpose](#arm64-installs-less-on-purpose) below for the
+list and the reasoning.
+
+### Detecting the architecture
+
+All three scripts read the **machine-level registry value**, not the environment
+and not `RuntimeInformation.OSArchitecture`. Both of those report the *emulated*
+architecture inside an emulated x64 process — which is what you get by launching
+`powershell` or `cmd` from an x64 shell (Git Bash, for one) on an ARM64 box.
+Measured on this machine, from that emulated shell:
+
+| source | reports |
+| --- | --- |
+| `[RuntimeInformation]::OSArchitecture` | `X64` ✗ |
+| `%PROCESSOR_ARCHITECTURE%` | `AMD64` ✗ |
+| `HKLM\SYSTEM\CurrentControlSet\Control\Session Manager\Environment` | `ARM64` ✓ |
+
+`OSArchitecture` is documented as the *OS's* architecture, and on .NET Core it
+is; under .NET Framework on Prism it is not. It is kept only as a fallback. This
+used to be a cosmetic mislabel in a log line — now that the architecture decides
+which packages are installed at all, reading it wrong provisions the wrong
+machine.
+
+> The batch file calls `reg.exe` by full path and parses it **without** piping to
+> `find`/`findstr`. Both are shadowable by anything earlier on the `PATH`, and a
+> POSIX `find` turns the whole detection into a silent no-op that leaves the
+> emulated answer standing. That is not hypothetical; it is how this was found.
+
+**The build toolchain is fully native.** Visual Studio's ARM64 installer and MSVC
+are ARM64 binaries, and MSVC cross-compiles every target from an ARM64 host with
+no emulation in the compiler:
 
 ```bat
 cmake -B build -A ARM64   && cmake --build build --config Release   :: native
@@ -266,24 +295,36 @@ ARM64-targeting toolchain, and the x64 cross-compiler is *not* implied. Spectre
 runtimes and ATL are likewise requested for both target families
 (`VC.ATL.ARM64.Spectre` is a separate component from `VC.ATL.Spectre`).
 
-**Three native compilers, on purpose.** MSVC and `clang-cl` from Visual Studio,
-plus **upstream LLVM** (`winget install LLVM.LLVM`, which resolves to
-`LLVM-<ver>-woa64.exe` on ARM64 — "Windows on Arm 64"). Upstream runs on its own
-schedule and is usually several major versions ahead of the Clang that VS
-bundles, and it installs to `C:\Program Files\LLVM` rather than inside the VS
-tree, so the two are genuinely independent. Two Clang majors plus MSVC over the
-same sources is what catches the bugs a single toolchain agrees with itself
-about. Watch the `PATH` if you use it: a bare `clang-cl` may resolve to upstream
-while CMake's `-T ClangCL` keeps using VS's, so pass a full
-`-DCMAKE_CXX_COMPILER` when it matters.
-
-**Clang/LLVM is installed on ARM64 too, and it is native there** — MSVC and
-`clang-cl` over the same sources is the compiler diversity this box is after.
-Two things establish that it is genuinely native rather than an emulated x64
-compiler: the `VC.Llvm.Clang` VSIX is `productArch=neutral` with no `chip` or
+### ARM64 installs less, on purpose
+
+The ARM64 machine here is a constrained VM, and nearly everything it was
+installing without a native build was going to run under Prism emulation anyway.
+The exceptions were individually defensible and collectively a VM full of x64
+binaries. So the split is now explicit: **ARM64 gets MSVC and nothing that
+duplicates it or that exists only as an x64 binary.**
+
+| dropped on ARM64 | where | why |
+| --- | --- | --- |
+| `Brave.Brave` | `setup-windows.bat` | no ARM64 build; an emulated browser is the slowest thing on the box, and Edge is in-box and native |
+| `WinMerge.WinMerge` | `setup-windows.bat` | ARM64 ships as a **machine-scope** installer only, so an unelevated `winget` can install nothing but the emulated x64 build |
+| `LLVM.LLVM` | `setup-windows.bat` | second Clang, dropped along with VS's `clang-cl` |
+| `NASM.NASM` | `setup-windows.bat` | x86/x86-64 assembler with no ARM64 target; MSVC's `armasm64.exe` is the native one |
+| `Google.AndroidGPUInspector` | `setup-windows.bat` | x64-only, and it profiles Android devices rather than anything compiled here |
+| `OpenCppCoverage` | `setup-windows.bat` | collects coverage by stepping x86/x64 instructions, so it cannot instrument an ARM64 binary at all |
+| VS Clang/LLVM component | `setup-windows-with-uac.ps1` | see below |
+| Windows Driver Kit | `setup-windows-with-uac.ps1` | see below |
+| BinSkim | `setup-windows-no-uac.ps1` | the NuGet package publishes `win-x64` only |
+
+x64 keeps every one of them. `:x64only` at the bottom of `setup-windows.bat` is
+the single place that decision is applied, so each skip prints its reason into
+the run log rather than leaving a silent gap.
+
+**`clang-cl` is dropped by choice, not by limitation.** A native ARM64 `clang-cl`
+*is* offered on Arm and did work here before the split. Two things establish
+that: the `VC.Llvm.Clang` VSIX is `productArch=neutral` with no `chip` or
 `machineArch` restriction, so the Arm installer offers it; and MSVC's
 `VC\Tools\Llvm` tree is partitioned by **host** architecture, with real ARM64
-binaries already in `ARM64\bin`, which is where `clang-cl.exe` lands:
+binaries in `ARM64\bin`, which is where `clang-cl.exe` lands:
 
 | directory | host |
 | --- | --- |
@@ -291,23 +332,54 @@ binaries already in `ARM64\bin`, which is where `clang-cl.exe` lands:
 | `VC\Tools\Llvm\x64\bin` | x64 |
 | `VC\Tools\Llvm\ARM64\bin` | ARM64 |
 
-Unlike the `v141`/XP group, nothing technical is in the way. Upstream LLVM ships
-a Windows-on-Arm build independently too — `winget install LLVM.LLVM` resolves to
-`LLVM-<ver>-woa64.exe` on ARM64 — if you want a Clang outside Visual Studio.
-
 > Watch for a false positive when checking by hand: `VC\Tools\Llvm\*\bin` holds
 > `clang-format.exe` and `clang-tidy.exe` on **any** host, installed or not —
 > those ship with the NativeDesktop workload. Their presence does not mean the
-> compiler is there; look for `clang-cl.exe`. The verification step does exactly
-> that, and warns separately if only a non-native `clang-cl` landed on Arm.
+> compiler is there; look for `clang-cl.exe`.
+
+Note that the VS installer never uninstalls a component you simply stopped
+asking for, so a box provisioned before this split keeps its `clang-cl` until it
+is explicitly removed. The verification step says so and prints the
+`--remove` line.
+
+**The WDK is dropped for two reasons, and the second one bites on x64 too.** The
+ARM64 box builds user-mode software, so it does not need a driver kit — but this
+particular WDK *cannot* install here regardless. The kit requires the **matching
+Windows SDK revision**, and revisions are not side-by-side: `Include\10.0.26100.0`
+is one directory, whichever revision wrote it. VS 2026 installs SDK
+**26100.7705**; `linkid=2335869` is WDK **26100.6584**, the kit paired with VS
+2022. `wdksetup.exe /quiet` therefore aborts:
+
+```
+WDK installer exit code: 15605
+WER: WDK / 10.1.26100.6584 / Install / 0x80070642
+```
+
+`0x642` is `1602`, `ERROR_INSTALL_USEREXIT` — a silent install cancelling itself
+on a failed prerequisite check. Nothing to do with Arm or emulation; the same
+pairing fails on x64. If a driver ever does need building against VS 2026, use
+the kit Microsoft's [supported WDK downloads](https://learn.microsoft.com/en-us/windows-hardware/drivers/other-wdk-downloads)
+table pairs with it — the 28000.x one — not this link. x64 with VS 2022 has the
+matched pair, so it installs there.
+
+**Compiler diversity now lives on the x64 box**, which has room for three
+toolchains: MSVC, VS's `clang-cl`, and **upstream LLVM** (`winget install
+LLVM.LLVM`). Upstream runs on its own schedule, is usually several major versions
+ahead of the Clang VS bundles, and installs to `C:\Program Files\LLVM` rather
+than inside the VS tree, so the two are genuinely independent. Two Clang majors
+plus MSVC over the same sources is what catches the bugs a single toolchain
+agrees with itself about. Watch the `PATH` there: a bare `clang-cl` may resolve
+to upstream while CMake's `-T ClangCL` keeps using VS's, so pass a full
+`-DCMAKE_CXX_COMPILER` when it matters.
 
-What changes, and why:
+What you end up with on ARM64:
 
 | | On ARM64 |
 | --- | --- |
-| **Native ARM64** | Git, Python, .NET SDK, PowerShell, VS Code, Windows Terminal, WinMerge, Brave, Sysinternals, Claude Code, CMake, Ninja, the VS installer, **MSVC, VS clang-cl and upstream LLVM**, MSBuild, the SDK tools (`rc`, `signtool`), the in-box OpenSSH client, and the Windows Performance Toolkit. |
-| **Emulated x64** | `iperf3`, NASM, OpenCppCoverage, BinSkim, `rsync.exe`, Android GPU Inspector, and the WDK/ADK *installers* (the kits they lay down are native). |
+| **Native ARM64** | Git, Python, .NET SDK, PowerShell, VS Code, Windows Terminal, Sysinternals, Claude Code, CMake, Ninja, the VS installer, **MSVC**, MSBuild, the SDK tools (`rc`, `signtool`), the in-box OpenSSH client, and the Windows Performance Toolkit. |
+| **Emulated x64** | `iperf3` and `rsync.exe` — both network-bound — and the ADK *installer* (the toolkit it lays down is native). |
 | **Emulated, minor** | `py.exe` (python.org ships the launcher shim as x86; it execs the native `python.exe`) and `vswhere.exe` (Microsoft ships x86 only; runs once). |
+| **Not installed** | Brave, WinMerge, upstream LLVM, NASM, Android GPU Inspector, OpenCppCoverage, BinSkim, VS `clang-cl`, and the WDK — see the table above. |
 | **Unavailable** | VirtualBox, the Windows 7 x86 test VM, Intel VTune, and the `v141` / Windows XP targeting toolset. |
 
 ### The architecture audit
@@ -426,18 +498,20 @@ Two consequences worth knowing rather than rediscovering:
   Windows XP never ran on ARM64, so the only point of an XP-targeting build here
   would be producing x86 binaries, which the current toolset does natively via
   `-A Win32`.
-- **OpenCppCoverage is installed but limited.** Unlike the rest of the emulated
-  row, this is a real ceiling rather than a slowdown: it collects coverage by
-  debugging the process under test and stepping x86/x64 instructions, so it
-  covers the x86/x64 binaries this box cross-compiles but **not** an ARM64 one.
-  Run coverage against the x64 build. The script prints this rather than leaving
-  you to discover it.
-- **BinSkim is emulated and that is fine.** The NuGet package publishes `win-x64`
-  only (its other RIDs are `linux-x64`, `linux-arm64`, `osx-x64`). BinSkim *reads*
-  PE headers and load configs, so its own architecture is independent of the
-  binaries it analyses — an emulated x64 BinSkim checks ARM64 binaries perfectly
-  well. The RID list is ordered preference, so a future `win-arm64` build is
-  picked up with no further change.
+- **OpenCppCoverage is no longer installed on ARM64.** Unlike the rest of the
+  emulated row this was a real ceiling rather than a slowdown: it collects
+  coverage by debugging the process under test and stepping x86/x64
+  instructions, so it can cover cross-compiled x86/x64 binaries but **not** an
+  ARM64 one. A coverage tool that cannot cover this machine's own output belongs
+  on the x64 box, which is where it still installs. Run coverage there.
+- **BinSkim is no longer installed on ARM64 either**, though the reason is
+  weaker: the NuGet package publishes `win-x64` only (its other RIDs are
+  `linux-x64`, `linux-arm64`, `osx-x64`), but BinSkim *reads* PE headers and load
+  configs, so its own architecture is independent of the binaries it analyses —
+  an emulated x64 BinSkim checks ARM64 binaries perfectly well. It went with the
+  rest of the x64-only set to keep the rule simple, not because it was broken.
+  The RID list is still ordered preference on x64, so a future `win-arm64` build
+  would be picked up with no further change.
 - **`rsync` gets the x64 zip, and its `ssh.exe` is verified by running it.** The
   release publishes x64 and x86 assets and no ARM64 one. x64 is still the right
   pick — a transfer is bounded by the socket, not by emulated CPU, so lifting the