Skip to content

feat(windows): install-tools.ps1 — Rust / Go / TinyGo (W52)#74

Merged
chaploud merged 5 commits intomainfrom
develop/w52-windows-realworld-toolchain
Apr 29, 2026
Merged

feat(windows): install-tools.ps1 — Rust / Go / TinyGo (W52)#74
chaploud merged 5 commits intomainfrom
develop/w52-windows-realworld-toolchain

Conversation

@chaploud
Copy link
Copy Markdown
Contributor

Summary

`scripts/windows/install-tools.ps1` now provisions the realworld toolchains (Rust + Go + TinyGo) alongside the core (Zig + wasm-tools + wasmtime + WASI SDK), all pinned via `.github/versions.lock`. The Windows side now matches what `flake.nix` delivers on Linux/macOS.

Tool Install path
go `%LOCALAPPDATA%\zwasm-tools\go-\bin\go.exe`
tinygo `%LOCALAPPDATA%\zwasm-tools\tinygo-\bin\tinygo.exe`
rust `%LOCALAPPDATA%\zwasm-tools\rust-\cargo\bin{cargo,rustup}.exe`

Rust is special-cased: `rustup-init.exe` runs non-interactively with `--no-modify-path` and `--default-host x86_64-pc-windows-msvc`. `CARGO_HOME` and `RUSTUP_HOME` are set in user-scope env so the install is self-contained and does not write into `%USERPROFILE%.cargo`. The `wasm32-wasip1` target is added automatically.

`-OnlyTool` accepts `rust`, `go`, `tinygo` in addition to the existing values. Idempotent: re-running on the same pins skips downloads.

Closes the local-realworld 25/50 → 50/50 gap on Windows (W52). CI Windows runner stays at 25/25 because it uses its own `Setup Rust` step and does not install Go / TinyGo; switching CI to this installer is tracked separately under W50 / Plan B sub-3.

Test plan

  • CI `versions-lock-sync` green (no version touch).
  • CI `test` matrix passes (the script is not exercised on the GitHub-hosted Windows runner — that step is a CI-only invocation; this PR is consumed by self-hosted Windows + manual local installs).
  • Manual on Windows mini-PC: `pwsh -NoLogo -ExecutionPolicy Bypass -File scripts\windows\install-tools.ps1 -Force` → all 7 tools install; `go version` / `tinygo version` / `cargo --version` / `rustup --version` all resolve in a fresh shell.
  • Manual: `python test/realworld/build_all.py && python test/realworld/run_compat.py` on Windows mini-PC reaches 50/50 PASS.
  • Verify CARGO_HOME / RUSTUP_HOME point inside `%LOCALAPPDATA%\zwasm-tools\rust-` and not into `%USERPROFILE%`.

@chaploud chaploud force-pushed the develop/w52-windows-realworld-toolchain branch from 87a271b to 0830a57 Compare April 29, 2026 02:55
`scripts/windows/install-tools.ps1` now provisions Rust (via
`rustup-init.exe` with the `wasm32-wasip1` target), Go, and TinyGo
alongside the original core (Zig + wasm-tools + wasmtime + WASI SDK)
— i.e. the same set Linux/macOS get from `flake.nix`, all pinned via
`versions.lock`.

Layout: Rust installs into `%LOCALAPPDATA%\zwasm-tools\rust-<toolchain>\`
with `CARGO_HOME` and `RUSTUP_HOME` set in user-scope env so the
install does not pollute `%USERPROFILE%\.cargo` and is reversible by
deleting the stamped directory. Go and TinyGo follow the existing
Install-Tool path with a `bin/` subdirectory added to user PATH.

`-OnlyTool` accepts `rust`, `go`, `tinygo` in addition to the
existing values. The script remains idempotent — re-running on the
same versions skips downloads.

Closes the local-realworld 25/50 → 50/50 gap on Windows. CI Windows
runner stays at 25/25 because it provisions Rust per-job via the
`Setup Rust` step and does not install Go / TinyGo; switching CI to
this installer is tracked separately under W50 / Plan B sub-3.
@chaploud chaploud force-pushed the develop/w52-windows-realworld-toolchain branch from 0830a57 to 4c83199 Compare April 29, 2026 02:57
These pins are now read by scripts:
- HYPERFINE_VERSION: ci.yml `Install hyperfine` (since #65).
- GO_VERSION / TINYGO_VERSION: install-tools.ps1 (this PR / W52).
- RUST_VERSION already enforced via ci.yml + install-tools.ps1.

Promote them into the [enforced] section so the file's category
labelling matches reality. NODEJS / BUN / PYTHON stay [planned] —
flake-only on the consumer side, no script reads them yet.
@chaploud chaploud merged commit 6b89d0c into main Apr 29, 2026
8 checks passed
@chaploud chaploud deleted the develop/w52-windows-realworld-toolchain branch April 29, 2026 03:13
chaploud added a commit that referenced this pull request Apr 29, 2026
chaploud added a commit that referenced this pull request Apr 29, 2026
Sweep doc drift surfaced by the post-Plan-C / W52 / D137 landing of
PRs #68..#74. CLAUDE.md is the authoritative gate spec; the four
audience-facing surfaces below now agree with it.

- ARCHITECTURE.md test-suites table: real-world 30 → 50 (Mac/Ubuntu)
  + 25 (Windows C+C++ subset); switched to `python3 ...py` form to
  match CLAUDE.md and gate-commit.sh; added FFI tests row.
- CONTRIBUTING.md CI checks: added real-world / FFI / minimal build /
  versions.lock-sync rows; binary size moved to per-OS ceilings
  (Mac 1.30 / Linux 1.60 / Windows 1.80 MB) reflecting D137.
- .dev/roadmap.md Merge Gate Checklist: pointed at CLAUDE.md as the
  authoritative source; switched e2e/realworld to the python3 form;
  added versions.lock-sync, FFI, post-merge bench-record, and per-OS
  size ceilings to match CLAUDE.md.
- .claude/skills/release/SKILL.md Phase 1 + Phase 2 + Checklist
  Summary: realworld 30 → 50; added FFI; per-OS size ceilings; runner
  forms aligned with the python3 .py runners CI exercises.

No functional changes — pure documentation alignment.
chaploud added a commit that referenced this pull request Apr 29, 2026
…fresh (#77)

- CHANGELOG.md [Unreleased]: tag the Plan C-a/b/c/d/e/f and W52
  entries with their PR numbers (#68/#69/#71/#70/#72/#74) so the
  next /release roll-up has authoritative provenance; add D137 to
  the Internal section (cross-platform stripping + per-OS size
  ceilings, recorded post-#73); add one-line entries for the
  doc-alignment sweep (#75) and the obsolete-checklist drop (#76).
- .dev/memo.md ## Current Task: append #74/#75/#76 to the post-
  morning PR list (was "Six new PRs", now "Nine"); replace the
  "in flight: #74" paragraph with #74 in the merged list; bump
  bench-record range to #68..#76. The "Plan B sub-3 / W50 still
  pending" pointer through resume-guide.md remains intact.

No behaviour change. Doc-only.
chaploud added a commit that referenced this pull request Apr 29, 2026
- "Spec conformance" bullet: W52 has shipped (PR #74). Local Windows
  reaches 50/50 realworld via `pwsh scripts/windows/install-tools.ps1`
  (Rust + Go + TinyGo); CI Windows still runs 25/25 because the
  GitHub-hosted runner uses its own per-job `Setup Rust` step. CI
  parity is tracked as W50 (CI Nix-ify), not W52.
- "Variant size table" tail: replaced the single 1.60 MB Linux
  ceiling with the per-OS ceilings (Mac 1.30 / Linux 1.60 / Windows
  1.80 MB) and pointed at D137 for the cross-platform stripping
  rationale.

Doc-only.
chaploud added a commit that referenced this pull request Apr 29, 2026
Windows CI surfaced an existing bug in install-tools.ps1's rust
install path — `rustup target add wasm32-wasip1` (run after
rustup-init) errored partway through downloading rust-std, with a
PowerShell "Cannot bind argument to parameter 'Path' because it is
an empty string" trace. The local-Windows path that has been
exercised by W52 / PR #74 does not hit it, but the GitHub-hosted
Windows runner does (different LOCALAPPDATA layout / pre-existing
rustup state).

Workaround: skip the install-tools.ps1 rust install on CI and use
the runner's pre-installed rustup directly, matching the Linux /
macOS test-nix pattern. The deeper fix is left as a follow-up
(needs a local Windows repro) — local Windows installs that want a
self-contained rustup tree under %LOCALAPPDATA%\zwasm-tools\rust-*
still work as before; CI just opts out via -SkipRust.

- install-tools.ps1: new `-SkipRust` switch. When set, the rust
  install block is bypassed (PATH wiring for rust still skipped
  because $paths['rust'] never gets populated).
- ci.yml `test (windows-latest)`: invoke install-tools.ps1
  -SkipRust; add a separate `Setup Rust` step that uses the
  runner's pre-installed rustup. Same shape as test-nix's Setup
  Rust step; no behaviour difference from a developer perspective.
chaploud added a commit that referenced this pull request Apr 29, 2026
…-D) (#83)

* ci: complete W50 — Windows install-tools.ps1 + restore extras (W50 PR-D)

Final step in W50 / Plan B sub-3 (CI Nix-ify). Two changes that
together close the per-tool-install path on every CI runner:

1. Windows test job now uses scripts/windows/install-tools.ps1 +
   scripts/gate-commit.sh, mirroring the local-Windows developer
   experience. Drops ~272 lines of bespoke install/test steps in
   ci.yml.

2. test-nix (Linux+Mac, PR-B + PR-C) regains the extras that the
   pre-Nix `test` job ran but gate-commit.sh intentionally omits:
   c-test, static-lib + static-link, Rust example, memory check.
   These are CI-specific quality gates, not Commit Gate items, so
   they live as ci.yml steps after the gate-commit step rather
   than inside gate-commit.sh.

## Changes

- `scripts/windows/install-tools.ps1`: gained `Append-GithubPath`
  and `Append-GithubEnv` helpers. When `$GITHUB_PATH` /
  `$GITHUB_ENV` are set (CI mode), the script appends entries to
  those files in addition to the User-scope environment. Local
  Windows installs are unaffected (the env vars aren't set).
- `.github/workflows/ci.yml`:
  - `test-nix` job: appended five "extras" steps after the gate
    (c-test / static-lib / static-link / Rust example / memory).
    All run inside `nix develop --command` for tool consistency.
  - `test` job: replaced the multi-step Windows install path with
    `pwsh install-tools.ps1` + `bash gate-commit.sh` + same five
    extras. Memory check stays as pwsh (Windows lacks
    /usr/bin/time). Binary size check dropped because size-matrix
    already covers Windows. Single-element matrix simplified to a
    plain runs-on.
- nightly.yml left untouched (mirroring it to nix-installer is a
  natural follow-up but out of scope here — its sanitizer + fuzz
  jobs are Linux-only and don't surface on PR CI).

Net diff: -184 lines, but the size-matrix and benchmark coverage
is unchanged, and all five extras now run on all three OSes.

CI is the test plan — no local pre-flight possible for ci.yml
changes.

* ci/install-tools: -SkipRust switch + use runner's rustup on CI

Windows CI surfaced an existing bug in install-tools.ps1's rust
install path — `rustup target add wasm32-wasip1` (run after
rustup-init) errored partway through downloading rust-std, with a
PowerShell "Cannot bind argument to parameter 'Path' because it is
an empty string" trace. The local-Windows path that has been
exercised by W52 / PR #74 does not hit it, but the GitHub-hosted
Windows runner does (different LOCALAPPDATA layout / pre-existing
rustup state).

Workaround: skip the install-tools.ps1 rust install on CI and use
the runner's pre-installed rustup directly, matching the Linux /
macOS test-nix pattern. The deeper fix is left as a follow-up
(needs a local Windows repro) — local Windows installs that want a
self-contained rustup tree under %LOCALAPPDATA%\zwasm-tools\rust-*
still work as before; CI just opts out via -SkipRust.

- install-tools.ps1: new `-SkipRust` switch. When set, the rust
  install block is bypassed (PATH wiring for rust still skipped
  because $paths['rust'] never gets populated).
- ci.yml `test (windows-latest)`: invoke install-tools.ps1
  -SkipRust; add a separate `Setup Rust` step that uses the
  runner's pre-installed rustup. Same shape as test-nix's Setup
  Rust step; no behaviour difference from a developer perspective.

* ci/install-tools: install binaryen for TinyGo wasm-opt (W50 PR-D)

Second CI failure on PR-D surfaced TinyGo's wasm-opt dependency:

  FAIL: tinygo_fib - error: could not find wasm-opt, set the WASMOPT
  environment variable to override

On Linux/macOS the Nix `tinygo` derivation is wrapped to prepend
`binaryen-125`'s bin/ to PATH automatically (verified via
`realpath $(which tinygo)` showing the wrapper script). On the
GitHub-hosted Windows runner there's no such wrapper, so wasm-opt
isn't found and the four `tinygo_*` realworld programs fail to
build.

- versions.lock: added BINARYEN_VERSION=125 (matches the binaryen
  version that Nix's tinygo 0.40.1 wrapper uses).
- install-tools.ps1:
  - new `binaryen` install case (`OnlyTool -in 'all' / 'binaryen' /
    'tinygo'`) — the tinygo trigger ensures `-OnlyTool tinygo`
    automatically pulls binaryen too.
  - `binaryen` added to ValidateSet of -OnlyTool plus param doc.
  - `realworldKeys` now includes binaryen with the special-case
    that `-OnlyTool tinygo` also requires BINARYEN_VERSION.
  - PATH wiring: bin/ subdir of the binaryen install added to
    User PATH and (in CI) GITHUB_PATH.

No CI YAML change in this commit — the Windows test job already
calls `install-tools.ps1 -SkipRust` which now also installs
binaryen as part of `-OnlyTool all`.

* ci: reorder cargo run before static-lib build (W50 PR-D)

Third CI failure on PR #83 surfaced a Windows-specific filename
collision that pre-existed but was masked by the old `test` job
order:

- `zig build shared-lib` writes both `zwasm.dll` and an MSVC-
  compatible import library `zwasm.lib` to `zig-out/lib/`.
- `zig build static-lib -Dpic=true -Dcompiler-rt=true` writes a
  static archive *also named* `zwasm.lib` to the same directory,
  *overwriting* the import library.
- A subsequent `cargo run` on the rust example then tries to link
  the static archive via MSVC `link.exe`, which fails with
  `LNK1143: invalid or corrupt file: no symbol for COMDAT section`
  (Zig's static archive uses MinGW-style COMDAT that MSVC link.exe
  doesn't accept).

Linux / macOS don't have this collision because their archive
extensions are distinct (`libzwasm.a` vs `libzwasm.so` /
`libzwasm.dylib`).

Fix: in both `test-nix` and `test (windows-latest)` extras blocks,
move the `Run Rust FFI example (dynamic)` step BEFORE
`Build static library`. The pre-PR-D test job had this order
naturally; PR-D's first cut grouped the two zig-build steps
together which broke Windows. Comment in the workflow explains
the constraint.

CI is the test plan.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant