Skip to content

[WIP] Enable wasm-tools workload for CoreCLR WASM targets#130226

Draft
lewing wants to merge 7 commits into
dotnet:mainfrom
lewing:lewing-wasm-tools-coreclr-exploration
Draft

[WIP] Enable wasm-tools workload for CoreCLR WASM targets#130226
lewing wants to merge 7 commits into
dotnet:mainfrom
lewing:lewing-wasm-tools-coreclr-exploration

Conversation

@lewing

@lewing lewing commented Jul 5, 2026

Copy link
Copy Markdown
Member

Summary

Prototype enabling the wasm-tools workload infrastructure for CoreCLR browser-wasm targets. This allows CoreCLR WASM apps to use the same native relinking pipeline (emcc compile/link, PInvokeTableGenerator) that Mono uses today, without bundling the Mono runtime pack or AOT compiler.

Architecture

  • Slim workload: wasm-tools-coreclr extends only microsoft-net-sdk-emscripten (Emscripten SDK + build targets). No Mono runtime pack or AOT cross-compiler.
  • Runtime pack: Resolved by SDK via standard KnownRuntimePack — no workload override needed (unlike Mono, which must keep runtime pack in lockstep with AOT compiler).
  • Opt-in: UseMonoRuntime=false in external projects; RuntimeFlavor=CoreCLR in-tree.
  • CoreCLR WASM uses interpreter, not JIT.

Changes

File Description
WorkloadManifest.json.in Added wasm-tools-coreclr workload definition
WorkloadManifest.targets.in CoreCLR import group, guarded Mono imports
Sdk.targets.in Conditional CoreCLR targets import when UseMonoRuntime=false
BrowserWasmApp.CoreCLR.targets Guarded imports, inlined GenerateEmccExports, fixed BeforeTargets ordering for static web assets, added satellite assembly handling for nested publish
eng/liveBuilds.targets Fixed libminipal.a exclusion from CoreCLR browser-wasm runtime pack
PInvokeTableGeneratorTests.cs Fixed CoreCLR pinvoke table filename (callhelpers-pinvoke.cpp)
WebAssembly.Sdk.pkgproj Added BrowserWasmApp.CoreCLR.targets to SDK package

CI Context

The existing CoreCLR_WasmBuildTests CI legs (added by #127073, #128296, #128762) already run DllImportTests, PInvokeTableGeneratorTests, NativeBuildTests, NativeLibraryTests, SatelliteAssembliesTests, IcuTests and more on CoreCLR — all currently passing on main without workloads (using in-tree build targets). The env vars (RUNTIME_FLAVOR_FOR_TESTS, CORECLR_VM_WASM_INCLUDE_DIR, MINIPAL_INCLUDE_DIR, etc.) are properly wired via Wasm.Build.Tests.csproj RunScriptCommands + RunScriptTemplate.sh.

This PR adds the workload packaging so that external consumers (outside the repo) can use the same native relinking pipeline. It also fixes several build pipeline bugs found during validation:

  1. libminipal.a missing from runtime pack — only existed in sharedFramework/ subdir, was excluded by the glob in eng/liveBuilds.targets
  2. Static web asset ordering_ComputeWasmBuildCandidates ran before native relink completed, freezing stale candidates
  3. Satellite assemblies in nested publish_GatherWasmFilesToBuild overwrote WasmAssembliesToBundle during nested publish, dropping app satellite assemblies

Related Work

  • [wasm][wasi] CoreCLR wasi onboarding #130051 — WASI enabling PR with PInvokeTableGenerator and dlopen changes that are relevant to the WasmImportLinkage / native thunk generation pipeline shared between browser-wasm and WASI targets

Test Results (local validation, non-AOT)

Test Suite CoreCLR Notes
DllImportTests 12/12 ✅ Full parity with Mono
PInvokeTableGeneratorTests 23/24 ✅ 1 debug-only assert (Release works)
BuildPublishTests 2/2 ✅ Full parity
NativeBuildTests 2/2 ✅ Template tests pass with proper env setup
NativeLibraryTests 4/4 ✅ SkiaSharp skipped (ActiveIssue#103566, pre-existing, fails Mono too)
SatelliteAssembliesTests 24/24 ✅ Full parity (after fix #3 above)

Known expected failures (not regressions)

  • AOT (12 tests) — out of scope, no AOT compiler for CoreCLR WASM
  • Mono ICall (2 tests) — HandleRef uses Mono-specific ICalls, N/A for CoreCLR
  • runtime#120897 (2 tests) — PORTABILITY_ASSERT: Indirect struct return (known limitation)
  • Debug assert (1 test) — precode_portable.cpp:35 with [UnmanagedCallersOnly] in namespaced types; Release works

Future Work

  • Enable category=workload tests on CoreCLR (currently excluded via -notrait filter in csproj line 109)
  • Blazor WebAssembly integration path with CoreCLR
  • _WasmNativeWorkloadNeeded detection (currently has Mono-specific triggers)

Note

This PR description was generated with assistance from GitHub Copilot.

lewing and others added 5 commits July 5, 2026 12:18
Add a new 'wasm-tools-coreclr' workload that provides native relinking
support for CoreCLR browser-wasm projects without pulling in Mono
dependencies (MonoAOTCompiler, MonoTargets.Sdk, Mono runtime pack).

Unlike Mono, CoreCLR doesn't need its runtime pack bundled in the
workload — the SDK resolves it via the standard KnownRuntimePack
mechanism. The workload only provides:
- Build targets for native relinking (BrowserWasmApp.CoreCLR.targets)
- Emscripten SDK (shared via microsoft-net-sdk-emscripten)

Changes:
- Package BrowserWasmApp.CoreCLR.targets into WebAssembly.Sdk NuGet pack
- Add conditional import in Sdk.targets.in (UseMonoRuntime switches path)
- Add wasm-tools-coreclr workload to manifest (no Mono deps)
- Add CoreCLR import group in WorkloadManifest.targets.in
- Skip MonoAOTCompiler import when UseMonoRuntime=false

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Guard the native.wasm.targets import with a condition so it only loads
when RepositoryEngineeringDir is set (in-tree builds). For the workload
path, inline the GenerateEmccExports target with the required exported
runtime methods and functions. Emscripten SDK acquisition is already
handled by EmSdkRepo.Defaults.props + the emscripten workload extension.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- Include libminipal.a in browser-wasm CoreCLR runtime pack. It was
  excluded from LibrariesSharedFrameworkDir glob but unlike libz.a and
  libSystem.IO.Compression.Native.a it only exists in sharedFramework/
  (not the parent LibrariesNativeArtifactsPath), so the exclusion
  prevented it from shipping at all. libminipal.a is a distinct library
  from libcoreclrminipal.a and is needed by the emcc linker.

- Fix PInvokeTableGeneratorTests to use correct CoreCLR output filename
  callhelpers-pinvoke.cpp instead of pinvoke-table.cpp.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
The _CoreCLRWasmNativeForBuild target must run before _ComputeWasmBuildCandidates
(not just _ResolveWasmOutputs) so the relinked dotnet.native.wasm replaces the
runtime pack version in the static web assets pipeline. Without this, the runtime
pack binary is served and user P/Invoke modules fail with DllNotFoundException.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
During nested publish, _GatherWasmFilesToPublish populates WasmAssembliesToBundle
from ResolvedFileToPublish (which includes app satellite assemblies). The CoreCLR
build pipeline was calling _GatherWasmFilesToBuild which overwrites this list with
build-time items that omit app satellites, causing ComputeWasmPublishAssets to fail.

Introduce _CoreCLRGatherWasmFiles wrapper that skips _GatherWasmFilesToBuild during
nested publish, preserving the publish-time assembly list.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot AI review requested due to automatic review settings July 5, 2026 23:22

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR prototypes enabling a “CoreCLR browser-wasm” path to use the existing WebAssembly workload/tooling pipeline (Emscripten + relinking + P/Invoke table generation) without pulling in Mono runtime/AOT components, primarily by routing imports/targets based on UseMonoRuntime=false.

Changes:

  • Added a new wasm-tools-coreclr workload and updated workload target imports to avoid Mono/AOT packs when UseMonoRuntime == false.
  • Updated the WebAssembly SDK target selection to import a CoreCLR-specific BrowserWasmApp.CoreCLR.targets when UseMonoRuntime == false.
  • Adjusted CoreCLR WASM build/publish orchestration and fixed a CoreCLR test expectation for the generated P/Invoke table filename.

Reviewed changes

Copilot reviewed 7 out of 7 changed files in this pull request and generated no comments.

Show a summary per file
File Description
src/mono/wasm/Wasm.Build.Tests/PInvokeTableGeneratorTests.cs Updates CoreCLR expectation to callhelpers-pinvoke.cpp for the generated P/Invoke table file.
src/mono/nuget/Microsoft.NET.Workload.Mono.Toolchain.Current.Manifest/WorkloadManifest.targets.in Guards Mono/AOT imports behind UseMonoRuntime != false and adds a CoreCLR browser-wasm import group for WebAssembly.Sdk only.
src/mono/nuget/Microsoft.NET.Workload.Mono.Toolchain.Current.Manifest/WorkloadManifest.json.in Adds the wasm-tools-coreclr workload definition (slimmed to SDK/emscripten packs).
src/mono/nuget/Microsoft.NET.Runtime.WebAssembly.Sdk/Sdk/Sdk.targets.in Selects Mono vs CoreCLR browser targets based on UseMonoRuntime.
src/mono/nuget/Microsoft.NET.Runtime.WebAssembly.Sdk/Microsoft.NET.Runtime.WebAssembly.Sdk.pkgproj Ensures BrowserWasmApp.CoreCLR.targets is packed into the SDK.
src/mono/browser/build/BrowserWasmApp.CoreCLR.targets Adds in-tree import guards, inlines emcc exports for workload scenarios, fixes target ordering for build/static web assets, and avoids overwriting publish-time assembly lists during nested publish.
eng/liveBuilds.targets Stops excluding libminipal.a from the CoreCLR browser-wasm runtime pack live-build file set.

@lewing lewing requested a review from pavelsavara July 5, 2026 23:41
@lewing lewing added this to the 11.0.0 milestone Jul 5, 2026
@lewing

lewing commented Jul 5, 2026

Copy link
Copy Markdown
Member Author

We don't really need anything but emsdk for coreclr but I went ahead and matched the wasmsdk logic to avoid getting different versions for the same workload for now.

lewing and others added 2 commits July 5, 2026 18:57
Remove the PORTABILITY_ASSERT for indirect struct returns in the
CoreCLR WASM interp-to-native thunk generator. For struct return
types (S<N> tokens), emit C typedefs of the correct size so emcc
generates the proper sret ABI calling convention. This fixes the
runtime crash when CoreCLR WASM code calls native functions that
return structs.

Also remove the native-mono test category filter from
EnsureWasmAbiRulesAreFollowedInInterpreter since it now works
on CoreCLR.

Fixes dotnet#120897

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Restore the exclusion of libminipal.a from the LibrariesSharedFrameworkDir
glob. The file is already included via CoreCLRSharedFrameworkDir (line 111),
so including it from both locations causes NU5118 duplicate file error
during nupkg creation.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
"packs": [
"Microsoft.NET.Runtime.WebAssembly.Sdk.${NetVersion}",
"Microsoft.NET.Sdk.WebAssembly.Pack.${NetVersion}"
],

@akoeplinger akoeplinger Jul 6, 2026

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should probably add the coreclr browser-wasm runtime pack here
(and as you know this will need to actually be done in the sdk repo as well)

TaskFactory="TaskHostFactory"
Condition="'$(WasmAppBuilderTasksAssemblyPath)' != ''" />

<!-- Exported runtime methods and functions for the emcc link step.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In Mono we store some of the build/link flags as json file and restore it into MSBuild properties. I don't remember what was our original motivation for that. Maybe DRY ?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Define a root README.md

4 participants