-
Notifications
You must be signed in to change notification settings - Fork 294
Make samples/WasiPlayground actually publish and boot MTP on wasi-wasm #8558
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
Show all changes
6 commits
Select commit
Hold shift + click to select a range
23e5f80
Make samples/WasiPlayground actually publish and boot MTP on wasi-wasm
Evangelink dd41c90
CI: install wasi-experimental-net10 workload via restore-toolset.ps1
Evangelink 72e6094
Address review comments and fix CA1416 on wasi target
Evangelink f7f8c46
Merge branch 'main' into dev/amauryleve/wasi-playground-fixups
Evangelink 95a79bf
Address PR review and fix CI
Evangelink cfa5ec1
Address PR review
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
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
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,46 @@ | ||
| # Installs .NET SDK workloads needed by projects in this repository. | ||
| # | ||
| # This script is dot-sourced by eng/common/build.ps1's InitializeCustomToolset | ||
| # AFTER InitializeDotNetCli has bootstrapped the repo-local .dotnet/ SDK, so | ||
| # $RepoRoot and the helpers from eng/common/tools.ps1 are in scope. | ||
| # | ||
| # Currently required by samples/WasiPlayground/WasiPlayground.csproj which | ||
| # targets net10.0 with <UsingWasiRuntimeWorkload>true</UsingWasiRuntimeWorkload> | ||
| # and would otherwise fail with NETSDK1147 in CI. | ||
|
|
||
| $RequiredWorkloads = @('wasi-experimental-net10') | ||
|
|
||
| # Note: `wasm-tools-net10` is documented in samples/WasiPlayground/README.md | ||
| # as a prerequisite for `dotnet publish`, but it is not needed by the repo's | ||
| # `dotnet build` so we keep the CI install minimal. | ||
|
|
||
|
Evangelink marked this conversation as resolved.
|
||
| $dotnetRoot = if (-not [string]::IsNullOrEmpty($env:DOTNET_INSTALL_DIR)) { | ||
| $env:DOTNET_INSTALL_DIR | ||
| } else { | ||
| Join-Path $RepoRoot '.dotnet' | ||
| } | ||
|
|
||
| $dotnet = Join-Path $dotnetRoot (GetExecutableFileName 'dotnet') | ||
|
|
||
| if (-not (Test-Path $dotnet)) { | ||
| Write-PipelineTelemetryError -Category 'InitializeToolset' -Message "restore-toolset.ps1: dotnet executable not found at '$dotnet'." | ||
| ExitWithExitCode 1 | ||
| } | ||
|
|
||
| # Cheap, network-free probe: parse `dotnet workload list` text to skip already-installed workloads. | ||
| $listOutput = & $dotnet workload list 2>&1 | Out-String | ||
| $missing = @($RequiredWorkloads | Where-Object { | ||
| -not ($listOutput -match "(?m)^\s*$([regex]::Escape($_))\s") | ||
| }) | ||
|
|
||
| if ($missing.Count -eq 0) { | ||
| Write-Host "All required workloads already installed: $($RequiredWorkloads -join ', ')" | ||
| return | ||
| } | ||
|
|
||
| Write-Host "Installing .NET SDK workloads: $($missing -join ', ')" | ||
| & $dotnet workload install @missing | ||
| if ($LASTEXITCODE -ne 0) { | ||
| Write-PipelineTelemetryError -Category 'InitializeToolset' -Message "Failed to install workloads '$($missing -join ', ')' (dotnet workload install exit code $LASTEXITCODE)." | ||
| ExitWithExitCode $LASTEXITCODE | ||
|
Evangelink marked this conversation as resolved.
|
||
| } | ||
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
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,52 @@ | ||
| #!/usr/bin/env bash | ||
|
|
||
| # Installs .NET SDK workloads needed by projects in this repository. | ||
| # | ||
| # This script is dot-sourced by eng/common/build.sh's InitializeCustomToolset | ||
| # AFTER InitializeDotNetCli has bootstrapped the repo-local .dotnet/ SDK, so | ||
| # $repo_root and the helpers from eng/common/tools.sh are in scope. | ||
| # | ||
| # Currently required by samples/WasiPlayground/WasiPlayground.csproj which | ||
| # targets net10.0 with <UsingWasiRuntimeWorkload>true</UsingWasiRuntimeWorkload> | ||
| # and would otherwise fail with NETSDK1147 in CI. | ||
|
|
||
| required_workloads=('wasi-experimental-net10') | ||
|
|
||
| # Note: `wasm-tools-net10` is documented in samples/WasiPlayground/README.md | ||
| # as a prerequisite for `dotnet publish`, but it is not needed by the repo's | ||
| # `dotnet build` so we keep the CI install minimal. | ||
|
|
||
| if [[ -n "${DOTNET_INSTALL_DIR:-}" ]]; then | ||
| dotnet_root="$DOTNET_INSTALL_DIR" | ||
| else | ||
| dotnet_root="${repo_root}.dotnet" | ||
| fi | ||
|
|
||
| dotnet_exe="$dotnet_root/dotnet" | ||
|
|
||
| if [[ ! -x "$dotnet_exe" ]]; then | ||
| Write-PipelineTelemetryError -category 'InitializeToolset' "restore-toolset.sh: dotnet executable not found at '$dotnet_exe'." | ||
| ExitWithExitCode 1 | ||
| fi | ||
|
|
||
| # Cheap, network-free probe: parse `dotnet workload list` text to skip already-installed workloads. | ||
| list_output=$("$dotnet_exe" workload list 2>&1) | ||
| missing=() | ||
| for workload in "${required_workloads[@]}"; do | ||
| if ! grep -qE "^[[:space:]]*${workload}[[:space:]]" <<<"$list_output"; then | ||
| missing+=("$workload") | ||
| fi | ||
| done | ||
|
|
||
| if [[ ${#missing[@]} -eq 0 ]]; then | ||
| echo "All required workloads already installed: ${required_workloads[*]}" | ||
| return 0 | ||
| fi | ||
|
|
||
| echo "Installing .NET SDK workloads: ${missing[*]}" | ||
| "$dotnet_exe" workload install "${missing[@]}" | ||
| workload_install_exit_code=$? | ||
| if [[ $workload_install_exit_code -ne 0 ]]; then | ||
| Write-PipelineTelemetryError -category 'InitializeToolset' "Failed to install workloads '${missing[*]}' (dotnet workload install exit code $workload_install_exit_code)." | ||
| ExitWithExitCode $workload_install_exit_code | ||
| fi |
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
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
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,21 +1,85 @@ | ||
| # WasiPlayground | ||
|
|
||
| To run this project: | ||
| Demonstrates hosting [Microsoft.Testing.Platform](https://aka.ms/testingplatform/) on the WebAssembly System Interface (WASI). | ||
|
|
||
| 1. Run `dotnet workload install wasi-experimental` | ||
| 2. Run `dotnet build` | ||
| 3. Install wasmtime. See docs at <https://docs.wasmtime.dev/cli-install.html>. | ||
| 4. Open command-line in AppBundle directory (`artifacts\bin\WasiPlayground\Debug\net10.0\wasi-wasm\AppBundle`) | ||
| 5. Run `wasmtime run --wasi http --dir . -- dotnet.wasm WasiPlayground` | ||
| ## Build & run | ||
|
|
||
| Prerequisites: | ||
|
|
||
| - The repo-local .NET SDK at `.dotnet\dotnet.exe`. Bootstrap it once by running | ||
| `.\build.cmd` (Windows) or `./build.sh` (Linux/macOS) from the repo root; | ||
| this also installs the `wasi-experimental-net10` workload required to build | ||
| the sample (see [`eng/restore-toolset.ps1`](../../eng/restore-toolset.ps1) | ||
| / [`eng/restore-toolset.sh`](../../eng/restore-toolset.sh)). | ||
| - The `wasm-tools-net10` workload, which is only needed for `dotnet publish` | ||
| (not by the repo's `dotnet build`), so install it manually: | ||
|
|
||
| ```cmd | ||
| .\.dotnet\dotnet.exe workload install wasm-tools-net10 | ||
| ``` | ||
|
|
||
| - [wasmtime](https://docs.wasmtime.dev/cli-install.html) on `PATH`. | ||
|
|
||
| > All commands below use `.\.dotnet\dotnet.exe` so that the `.dotnet\packs` | ||
| > lookup in step 2 resolves. If you prefer a machine-installed SDK, swap | ||
| > `dotnet` in and replace `.dotnet\packs` with the corresponding `packs` | ||
| > folder reported by `dotnet --info` (look for *.NET SDKs installed*). | ||
|
|
||
| Then: | ||
|
|
||
| 1. From the repo root, publish the sample: | ||
|
|
||
| ```cmd | ||
| .\.dotnet\dotnet.exe publish samples\WasiPlayground\WasiPlayground.csproj -c Debug -f net10.0 | ||
| ``` | ||
|
|
||
| 2. The pre-built `dotnet.wasm` does not embed the ICU data file, so copy it | ||
| next to the bundle. First list the installed runtime-pack version (a | ||
| single folder name such as `10.0.8`), then substitute it into the copy | ||
| command: | ||
|
|
||
| ```cmd | ||
| dir /b .dotnet\packs\Microsoft.NETCore.App.Runtime.Mono.wasi-wasm | ||
|
|
||
| copy .dotnet\packs\Microsoft.NETCore.App.Runtime.Mono.wasi-wasm\<runtime-version>\runtimes\wasi-wasm\native\icudt.dat ^ | ||
| artifacts\bin\WasiPlayground\Debug\net10.0\wasi-wasm\AppBundle\ | ||
| ``` | ||
|
|
||
|
Evangelink marked this conversation as resolved.
|
||
| 3. Switch to the bundle directory and invoke `wasmtime` (the `-S http` flag is required because the runtime imports `wasi:http`): | ||
|
|
||
| ```cmd | ||
| cd artifacts\bin\WasiPlayground\Debug\net10.0\wasi-wasm\AppBundle | ||
| wasmtime run -S http --dir . -- dotnet.wasm WasiPlayground | ||
| ``` | ||
|
|
||
| ## Status | ||
|
|
||
| As of today, this will produce this exception (it's not yet supported by MTP). | ||
| After publishing, Microsoft.Testing.Platform now boots on `wasi-wasm` (the | ||
| banner reads `[wasi-wasm - net10.0]`) thanks to [#7137](https://github.com/microsoft/testfx/pull/7137). | ||
| Test execution itself currently fails with: | ||
|
|
||
| ```console | ||
| Microsoft.Testing.Platform v2.3.0-dev (UTC ...) [wasi-wasm - net10.0] | ||
| ... | ||
| Unhandled Exception: | ||
| System.PlatformNotSupportedException: Arg_PlatformNotSupported | ||
| at System.Threading.Tasks.Task.InternalWaitCore(Int32 millisecondsTimeout, CancellationToken cancellationToken) | ||
| at System.Threading.Tasks.Task.InternalWait(Int32 millisecondsTimeout, CancellationToken cancellationToken) | ||
| at System.Threading.Tasks.Task.InternalWaitCore(...) | ||
| at System.Threading.Tasks.Task.InternalWait(...) | ||
| at Program.<Main>(String[] args) | ||
| ``` | ||
|
|
||
| The exception comes from the C# compiler's synthetic `Main` wrapper for | ||
| `async Task Main`, which calls `Task.GetAwaiter().GetResult()` → | ||
| `Task.Wait()`. On single-threaded `wasi-wasm` (no thread pool) this throws | ||
| `PlatformNotSupportedException`. Tracked in [#5366](https://github.com/microsoft/testfx/issues/5366) | ||
| so this sample can act as the canonical repro. | ||
|
|
||
| ## Build configuration notes | ||
|
|
||
| `WasiPlayground.csproj` ships with a few non-obvious switches: | ||
|
|
||
| | Property | Reason | | ||
| | --- | --- | | ||
| | `UsingWasiRuntimeWorkload=true` | Workaround for an SDK manifest bug in `11.0.100-preview.5` where `$(UsingWasiRuntimeWorkload)` never resolves to `true` for net10.0 projects, so the WASI Sdk targets are never imported and no `dotnet.wasm` is produced. | | ||
| | `WasmSingleFileBundle=false` | Single-file bundling requires the [wasi-sdk](https://github.com/WebAssembly/wasi-sdk) (clang) toolchain to relink the native runtime. Keeping the managed assemblies on disk avoids that requirement. | | ||
| | `InvariantGlobalization=true` | Prevents the trimmer from crashing during publish, but the pre-built `dotnet.wasm` still loads ICU at runtime, so `icudt.dat` must still be staged next to the bundle (see step 2). | | ||
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
Oops, something went wrong.
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.
Uh oh!
There was an error while loading. Please reload this page.