Skip to content

Commit ff85909

Browse files
committed
Use MSVC for web-runner on Windows
1 parent 7374bd8 commit ff85909

6 files changed

Lines changed: 123 additions & 20 deletions

File tree

.github/workflows/test-msvc.yaml

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
---
2+
name: test-msvc
3+
4+
# Deliberately does NOT use mise, which uses gnullvm target. Instead manually targets the default MSVC.
5+
# And only runs the web-runner tests, as web-runner doesnt work under gnullvm.
6+
"on":
7+
pull_request:
8+
push:
9+
workflow_dispatch:
10+
11+
permissions:
12+
contents: read
13+
14+
# this allows a subsequently queued workflow run to interrupt previous runs in pull requests only
15+
concurrency:
16+
group: "${{ github.workflow }}-${{ github.ref }}"
17+
cancel-in-progress: ${{ startsWith(github.ref, 'refs/pull/') }}
18+
19+
defaults:
20+
run:
21+
shell: bash --noprofile --norc -euo pipefail {0}
22+
23+
jobs:
24+
web-runner-msvc:
25+
runs-on: windows-latest
26+
timeout-minutes: 90
27+
steps:
28+
- name: Checkout
29+
uses: actions/checkout@v4
30+
with:
31+
fetch-depth: 1
32+
persist-credentials: false
33+
34+
- name: Install Rust (x86_64-pc-windows-msvc)
35+
uses: dtolnay/rust-toolchain@stable
36+
37+
- name: Install NASM
38+
# aws-lc-sys (deno_node_crypto -> ... -> aws-lc-sys) assembles BoringSSL's x86_64 .asm with NASM.
39+
uses: ilammy/setup-nasm@v1
40+
41+
- name: Install .NET SDK
42+
uses: actions/setup-dotnet@v4
43+
with:
44+
dotnet-version: "10.0.300"
45+
46+
- name: Build dotnet-data1 WASM module
47+
run: |
48+
set -xeuo pipefail
49+
cd services/ws-modules/dotnet-data1
50+
dotnet workload install wasm-tools --skip-manifest-update
51+
# MSBuild's BrowserWasmApp.targets link step calls bare `emcc` and relies on PATH.
52+
# Surface the workload's emcc dir + EmscriptenLocation ourselves (same approach as the mise build task).
53+
packs="${DOTNET_ROOT:-/c/Program Files/dotnet}/packs"
54+
emcc_bat="$(find "$packs" -name emcc.bat 2>/dev/null | head -1)"
55+
if [ -z "$emcc_bat" ]; then
56+
emcc_bat="$(find "/c/Program Files/dotnet/packs" -name emcc.bat 2>/dev/null | head -1)"
57+
fi
58+
test -n "$emcc_bat" || { echo "emcc.bat not found under dotnet packs"; exit 1; }
59+
emcc_dir="$(dirname "$emcc_bat")"
60+
emsdk_loc="$(dirname "$(dirname "$emcc_dir")")/Sdk"
61+
export PATH="$(cygpath -u "$emcc_dir"):$PATH"
62+
dotnet publish -c Release -p:EmscriptenLocation="$(cygpath -w "$emsdk_loc")"
63+
publish=bin/Release/net10.0/publish/wwwroot/_framework
64+
cp "$publish"/*.js "$publish"/*.wasm "$publish"/*.dat pkg/
65+
66+
- name: Run web-runner dotnet-data1 test
67+
# Filter by the `dotnet` substring, not a positional `case_N_` name, so cargo auto-finds the dotnet case(s).
68+
# rstest numbers cases by declaration order, so a hard-coded index would silently repoint at the wrong test
69+
# when a module is inserted before it.
70+
env:
71+
MISE_ENV: dotnet
72+
run: cargo test -p et-ws-web-runner dotnet -- --nocapture

.mise/config.dotnet.toml

Lines changed: 0 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -27,19 +27,6 @@ description = "Format .NET sources"
2727
description = "Build the dotnet-data1 C# WASM workflow module"
2828
dir = "services/ws-modules/dotnet-data1"
2929
run = '''
30-
# The Windows lane is skipped: no lever the .NET WebAssembly SDK exposes works.
31-
# Neither routes bare-`emcc` in the link <Exec> to the workload-installed pack. MSBuild's BrowserWasmApp.targets
32-
# link step's `<Exec Command="emcc @rsp">` does NOT inherit the bash-level PATH prepend (validated empirically
33-
# -- the emcc-debug step in test.yaml shows `cmd.exe %PATH%` sees the emscripten dir after the prepend, yet the
34-
# link still trips `'emcc' is not recognized` / MSB3073 exit 9009), and `-p:EmscriptenLocation=...\Sdk` fixes
35-
# the compile target but not the link. tests/modules.rs's `dotnet_data1_pkg_built()` matches this skip so the
36-
# downstream test on Windows logs `skipping ...: pkg/ not built` instead of failing. Drop this guard once
37-
# .NET's SDK either honors PATH or documents a property that overrides the link <Exec> command.
38-
if [ "${OS:-}" = "Windows_NT" ]; then
39-
echo "build-ws-dotnet-data1-module: skipped on Windows (MSBuild link <Exec> ignores our PATH; emcc unresolvable)"
40-
exit 0
41-
fi
42-
4330
# `set -x` so every command is echoed to the log.
4431
# That covers the find / dirname chain that resolves $(EmscriptenLocation), the final dotnet publish invocation
4532
# with its -p:EmscriptenLocation=... arg, and the cp of the publish artefacts. The Windows path of this task is

.mise/config.toml

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -599,15 +599,18 @@ description = "Run conftest OPA/Rego policies over the GitHub Actions workflow +
599599
# per-file rules (gha, no_trailing_backslash) over workflow YAML; --combine rules (gha_combined) over
600600
# workflow YAML for cross-cutting invariants where the rule has to compare each workflow's parsed body
601601
# against its own filename (the `paths:` self-reference check; conftest's per-file mode has no `input.path`);
602-
# and gha_action over the composite actions under .github/actions/*/action.yaml (different schema, so its
603-
# own namespace).
602+
# gha_action over the composite actions under .github/actions/*/action.yaml (different schema, so its
603+
# own namespace); and gha_mise over the workflow YAML combined with .mise (auto-detected parsers) so a rule can
604+
# cross-check a hard-coded action-input version against the matching mise [tools] pin (setup-dotnet's
605+
# dotnet-version vs the `dotnet` pin).
604606
run = """
605607
ns="--namespace gha --namespace no_trailing_backslash"
606608
# $ns expands to repeated `--namespace <n>` pairs; word-splitting is intentional.
607609
# shellcheck disable=SC2086
608610
conftest test --parser yaml $ns -p config/conftest/policy .github/workflows
609611
conftest test --parser yaml --combine --namespace gha_combined -p config/conftest/policy .github/workflows
610612
conftest test --parser yaml --namespace gha_action -p config/conftest/policy .github/actions/*/action.yaml
613+
conftest test --combine --namespace gha_mise -p config/conftest/policy .github/workflows .mise
611614
"""
612615
shell = "bash -euo pipefail -c"
613616

README.md

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,8 @@ Please install [`mise`](https://mise.jdx.dev/) (2026.6.5 or later), including th
1616
for all use of this repository.
1717

1818
The `mise` configuration lives under [`.mise/`](.mise/): the always-loaded [`.mise/config.toml`](.mise/config.toml)
19-
holds the Rust/Node tooling and shared tasks, and per-language `.mise/config.<lang>.toml` files (dart, dotnet, java,
20-
python, zig) are selected via `MISE_ENV` so a dev can work on one language without installing the others -- e.g.
19+
holds the Rust/Node tooling and shared tasks, and per-language `.mise/config.<lang>.toml` files are selected via
20+
`MISE_ENV` so a dev can work on one language without installing the others -- e.g.
2121
`MISE_ENV=dart mise install`. CI runs every language; `mise run check-all` (and `install-all`, `test-all`, ...) act
2222
on all of them at once.
2323

@@ -63,6 +63,9 @@ mise.exe links the Microsoft VC++ runtime (`vcruntime140.dll`), so it must be pr
6363
preinstalled on Windows 10/11 and Server, so you already have it -- only Nano Server omits it, and there the
6464
Docker build installs the [VC++ Redistributable](https://aka.ms/vs/17/release/vc_redist.x64.exe).
6565

66+
mise-powered builds use the `x86_64-pc-windows-gnullvm` Rust target (llvm-mingw), which needs no MSVC toolchain or
67+
Windows SDK on disk. The native `x86_64-pc-windows-msvc` target can also be used.
68+
6669
### Windows shell
6770

6871
On Windows, install the shell:
@@ -209,15 +212,23 @@ Modules target one of three runners.
209212

210213
### Browser runner ([ws-web-runner](services/ws-web-runner))
211214

212-
Modules loaded by a web browser, or natively under Deno by `et-ws-web-runner`. Most are Rust built with
213-
`wasm-pack build --target web`; other languages:
215+
Modules loaded by a web browser, or using Deno as the "web browser" in `et-ws-web-runner`.
216+
217+
Most are Rust built with `wasm-pack build --target web`; other languages:
214218

215219
- Dart
216220
- Java
217221
- .Net C#
218222
- Python, using [pyodide](https://pyodide.org/) and [RustPython](https://rustpython.github.io/)
219223
- Zig, including C code
220224

225+
On Windows `et-ws-web-runner` must be built with the MSVC target (`x86_64-pc-windows-msvc`), not the gnullvm
226+
default the rest of the repo uses. It embeds V8 through `deno_core` and the `v8` crate, and gnullvm cannot be
227+
built: there is no `x86_64-pc-windows-gnullvm` `librusty_v8` prebuilt, the gnullvm build path in `rusty_v8` is
228+
still unfinished (open PRs [denoland/rusty_v8#1880](https://github.com/denoland/rusty_v8/pull/1880) and
229+
[#1957](https://github.com/denoland/rusty_v8/pull/1957)), and the MSVC prebuilt can't be linked into a gnullvm
230+
binary because the two ABIs are incompatible.
231+
221232
### WASI runner ([ws-wasi-runner](services/ws-wasi-runner))
222233

223234
Modules built as WASI Preview 2 components and run under wasmtime:

config/conftest/policy/gha/gha.rego

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,8 +34,9 @@ step_shell_allowed(step) if {
3434

3535
# Every workflow must declare MISE_ENV at the workflow level so the set of loaded language envs is visible at a glance.
3636
# This avoids per-job `mise run print-all-langs` runtime resolution. The matching `Show MISE_ENV` step in each job
37-
# echoes the value into the CI log.
37+
# echoes the value into the CI log. Carve-out: test-msvc deliberately doesn't use mise.
3838
deny contains msg if {
39+
input.name != "test-msvc"
3940
not input.env.MISE_ENV
4041
msg := "workflow must set top-level env.MISE_ENV (the comma-separated language list)"
4142
}
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
# Cross-checks for GitHub Actions workflows against the .mise/config*.toml pins, run with `--namespace gha_mise`.
2+
# Evaluated over the workflow YAML plus the .mise/config*.toml files combined (--combine, auto-detected parsers).
3+
# A workflow that hard-codes a toolchain version via an action input (test-msvc.yaml installs the .NET SDK with
4+
# actions/setup-dotnet's `dotnet-version`, deliberately bypassing mise) must match the matching mise [tools] pin, so
5+
# the CI runner SDK and the mise-built modules compile against the same toolchain.
6+
package gha_mise
7+
8+
import data.mise
9+
10+
# The mise-managed .NET SDK pin (.mise/config.dotnet.toml: dotnet = "<ver>").
11+
dotnet_pin := version if {
12+
some file in input
13+
mise.is_mise(file)
14+
version := file.contents.tools.dotnet
15+
}
16+
17+
# Every setup-dotnet `dotnet-version` must equal the mise `dotnet` pin.
18+
deny contains msg if {
19+
some file in input
20+
endswith(file.path, ".yaml")
21+
some job in file.contents.jobs
22+
some step in job.steps
23+
declared := step.with["dotnet-version"]
24+
declared != dotnet_pin
25+
msg := sprintf(
26+
"%s: setup-dotnet dotnet-version %q must match the mise dotnet pin %q in .mise/config.dotnet.toml",
27+
[file.path, declared, dotnet_pin],
28+
)
29+
}

0 commit comments

Comments
 (0)