Skip to content

[wasm] Resolve the workload runtime pack for CoreCLR browser-wasm - #133728

Open
maraf with Copilot wants to merge 3 commits into
mainfrom
copilot/remove-extra-items-insert-at-end
Open

maraf with Copilot wants to merge 3 commits into
mainfrom
copilot/remove-extra-items-insert-at-end

Conversation

Copilot AI commented Sep 11, 2026 •

Copy link
Copy Markdown
Contributor

Problem

CoreCLR browser-wasm builds resolved the wrong runtime pack. The build picked the runtime pack bundled with the SDK (12.0.0-alpha.*) instead of the one the workload had just installed (12.0.0-ci), pairing a stale runtime pack with a locally built WebAssembly SDK.

The SDK picks the runtime pack differently per flavour:

  • Mono resolves via the KnownRuntimePack whose RuntimePackLabels == 'Mono'. The workload manifest patches its LatestRuntimeFrameworkVersion to the in-workload version, so Mono gets the right pack.
  • CoreCLR has no workload-labelled KnownRuntimePack. Resolution falls back to KnownFrameworkReference[Microsoft.NETCore.App].LatestRuntimeFrameworkVersion — which the manifest never patched, so it stayed at the SDK-bundled version.

Wasm.Build.Tests papered over this with per-test pack-version overrides injected into every generated project (added in #122646). That kept the test lanes working but left every other CoreCLR wasm consumer with the same latent problem.

Changes

WorkloadManifest.targets.in — patch the pack versions the SDK uses to resolve CoreCLR browser-wasm, alongside the existing TargetingPackVersion and KnownWebAssemblySdkPack overrides:

  • KnownFrameworkReference.LatestRuntimeFrameworkVersion — the runtime pack.
  • KnownCrossgen2Pack.Crossgen2PackVersion — crossgen2 generates the wasm P/Invoke call helpers, which encode struct sizes that have to agree with the headers in the runtime pack, so it must not drift from it.

Both are scoped to browser-wasm with UseMonoRuntime false, leaving Mono wasm and non-wasm ReadyToRun builds untouched.

WasmOverridePacks.targets — the non-workload test path hardcoded Microsoft.NETCore.App.Runtime.Mono.$(RuntimeIdentifier), so CoreCLR misresolved there too. The pack name is now flavour-aware.

WasmTemplateTestsBase.cs — with the manifest fixed, the per-test workaround is redundant and is removed:

  • The KnownFrameworkReference item block — superseded by the manifest fix.
  • The _UpdateKnownCoreClrWebAssemblyPacks target — KnownWebAssemblySdkPack was already covered by the manifest; KnownCrossgen2Pack is covered by the manifest change above.
  • RuntimePackRuntimeIdentifiers — was already redundant; the SDK's bundled value already ends with ;browser-wasm.

AddCoreClrProjectProperties reduces to setting UseMonoRuntime, so it no longer needs extraItems/insertAtEnd. Both call sites updated.

Interaction with #133413

#133413 moved crossgen2 acquisition from the workload to the SDK and extended the per-test override target with a KnownCrossgen2Pack version patch. Merging it here conflicted with the removal above.

Nothing outside that target patched KnownCrossgen2Pack, so removing it alone would have silently regressed #133413 — CoreCLR wasm builds would have resolved the SDK-bundled crossgen2 against a locally built runtime pack. The override moved into the manifest instead, which preserves the behaviour for every CoreCLR wasm consumer rather than only inside Wasm.Build.Tests.

Validation

Root cause was established by diffing MSBuild binlogs from the Mono and CoreCLR WasmBuildTests Helix work items of the same CI run. The evaluations are identical except UseMonoRuntime and the resulting LatestRuntimeFrameworkVersion.

Both manifest overrides were verified against a harness reproducing the SDK's item shape:

Scenario Runtime pack + crossgen2 version
CoreCLR browser-wasm in-workload version (fixed)
Mono browser-wasm unchanged — still resolved via KnownRuntimePack
CoreCLR non-wasm (linux-x64) unchanged — ReadyToRun builds unaffected
Non-current TFM entries untouched

Only the Current manifest is changed; the net6–net10 manifests predate CoreCLR-on-wasm.

CI is the real validation here — a full wasm workload build plus emsdk was not run locally.

Notes

  • Multithread resolution is preserved: PackageDirectory in WasmOverridePacks.targets still uses %(Identity), which is what keeps Mono.multithread.browser-wasm working.
  • WasmOverridePacks.targets is currently unreachable — UseWBTOverridePackTargets defaults to false and nothing sets it — so CI will not exercise that half.
  • This spans a product manifest change plus the test cleanup it enables. They're kept together deliberately: removing the workaround without the manifest fix breaks the CoreCLR wasm lanes.

Note

This PR description was generated with the assistance of GitHub Copilot.

…roperties

Co-authored-by: maraf <10020471+maraf@users.noreply.github.com>
@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines:
Successfully started running 3 pipeline(s).
13 pipeline(s) were filtered out due to trigger conditions.
There may be pipelines that require an authorized user to comment /azp run to run.

CoreCLR browser-wasm has no workload-labelled KnownRuntimePack, so the SDK
resolves its runtime pack from KnownFrameworkReference's
LatestRuntimeFrameworkVersion, which the workload manifest never overrode.
Builds picked the SDK-bundled runtime pack instead of the one the workload had
just installed, pairing a stale runtime pack with the locally built WebAssembly
SDK.

Override LatestRuntimeFrameworkVersion for browser-wasm when UseMonoRuntime is
false, and make the runtime pack name in the non-workload
WasmOverridePacks.targets flavour-aware. This is what the per-test
KnownFrameworkReference workaround in WasmTemplateTestsBase was standing in for.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
@maraf maraf changed the title Remove unused extraItems/insertAtEnd handling from AddCoreClrProjectProperties [browser] Remove unused extraItems/insertAtEnd handling from AddCoreClrProjectProperties Sep 12, 2026
@maraf maraf added arch-wasm WebAssembly architecture os-browser Browser variant of arch-wasm labels Sep 12, 2026
@maraf maraf added this to the 12.0.0 milestone Sep 12, 2026
@maraf
maraf deployed to copilot-pat-pool September 12, 2026 11:58 — with GitHub Actions Active
@dotnet-policy-service

Copy link
Copy Markdown
Contributor

Tagging subscribers to 'arch-wasm': @lewing, @pavelsavara
See info in area-owners.md if you want to be subscribed.

@maraf
maraf marked this pull request as ready for review September 12, 2026 11:58
Copilot AI lite review requested due to automatic review settings September 12, 2026 11:58
@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines:
Successfully started running 3 pipeline(s).
13 pipeline(s) were filtered out due to trigger conditions.
There may be pipelines that require an authorized user to comment /azp run to run.

@maraf
maraf deployed to copilot-pat-pool September 12, 2026 11:59 — with GitHub Actions Active

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.

🔵 Needs a closer look

Unresolved moderate findings concern missing browser RID metadata and insufficient CoreCLR runtime-pack test coverage.

Pull request overview

Simplifies CoreCLR project-property setup and moves browser-Wasm runtime-pack handling into shared targets.

Changes:

  • Removes obsolete extraItems/insertAtEnd mutations and updates callers.
  • Adds runtime-pack selection for CoreCLR and Mono.
  • Adds CoreCLR browser-Wasm framework-version handling.
File summaries
File Changes and final review comments
src/mono/wasm/Wasm.Build.Tests/Templates/WasmTemplateTestsBase.cs Removes obsolete project mutations and simplifies the helper signature.
src/mono/wasm/Wasm.Build.Tests/data/WasmOverridePacks.targets Adds runtime-pack selection. Moderate (1 vote): CoreCLR selection lacks focused automated coverage. Nit (1 vote): Document the behavioral changes and validation.
src/mono/nuget/Microsoft.NET.Workload.Mono.Toolchain.Current.Manifest/WorkloadManifest.targets.in Adds CoreCLR framework-version handling. Moderate (1 vote): Preserve the browser-wasm RuntimePackRuntimeIdentifiers metadata.
Review details

Suppressed comments (3)

src/mono/nuget/Microsoft.NET.Workload.Mono.Toolchain.Current.Manifest/WorkloadManifest.targets.in:260

  • This replacement drops the RuntimePackRuntimeIdentifiers update that the removed helper used to add (browser-wasm;%(RuntimePackRuntimeIdentifiers)). The repository's local KnownFrameworkReference definition does not include browser-wasm (eng/targetingpacks.targets:43-52), so on that SDK path the CoreCLR browser runtime pack is not selected in the no-workload/CoreCLR lane. Preserve the browser RID metadata in this CoreCLR update as well.
    <KnownFrameworkReference Update="Microsoft.NETCore.App"
                             Condition="'$(RuntimeIdentifier)' == 'browser-wasm' and '$(UseMonoRuntime)' == 'false'">
      <LatestRuntimeFrameworkVersion Condition="'%(KnownFrameworkReference.TargetFramework)' == '${NetVersion}.0'">$(_MonoWorkloadRuntimePackPackageVersion)</LatestRuntimeFrameworkVersion>

src/mono/wasm/Wasm.Build.Tests/data/WasmOverridePacks.targets:19

  • The PR description presents this as only a helper/signature cleanup, but this change also alters runtime-pack selection for CoreCLR and the workload manifest adds a new framework-version override. These are behavioral changes rather than incidental cleanup; please document their purpose and validation (or split them) so reviewers can assess the added resolution behavior.
      <_WasmOverrideRuntimePackName Condition="'$(UseMonoRuntime)' == 'false'">Microsoft.NETCore.App.Runtime.$(RuntimeIdentifier)</_WasmOverrideRuntimePackName>
      <_WasmOverrideRuntimePackName Condition="'$(_WasmOverrideRuntimePackName)' == ''">Microsoft.NETCore.App.Runtime.Mono.$(RuntimeIdentifier)</_WasmOverrideRuntimePackName>

src/mono/wasm/Wasm.Build.Tests/data/WasmOverridePacks.targets:19

  • This new CoreCLR/Mono package-name selection is not covered by the current test suite: UseWBTOverridePackTargets is only declared and is never enabled anywhere in the repository, so no automated test exercises the UseMonoRuntime == false branch or verifies the resulting ResolvedRuntimePack path. Add a focused CoreCLR workload test that enables the override and asserts the resolved pack, or otherwise provide equivalent coverage for this target.
      <_WasmOverrideRuntimePackName Condition="'$(UseMonoRuntime)' == 'false'">Microsoft.NETCore.App.Runtime.$(RuntimeIdentifier)</_WasmOverrideRuntimePackName>
      <_WasmOverrideRuntimePackName Condition="'$(_WasmOverrideRuntimePackName)' == ''">Microsoft.NETCore.App.Runtime.Mono.$(RuntimeIdentifier)</_WasmOverrideRuntimePackName>
  • Files reviewed: 3/3 changed files
  • Comments generated: 0
  • Review effort level: Lite

@maraf maraf changed the title [browser] Remove unused extraItems/insertAtEnd handling from AddCoreClrProjectProperties [wasm] Resolve the workload runtime pack for CoreCLR browser-wasm Sep 12, 2026
Conflict in WasmTemplateTestsBase.cs: #133413 extended the per-test pack
override target this branch removes, renaming it to
_UpdateKnownCoreClrWebAssemblyPacks and adding a KnownCrossgen2Pack version
override, because crossgen2 is now resolved through the SDK rather than
installed by the workload.

Resolved by keeping the removal and moving the crossgen2 override into the
workload manifest alongside the runtime pack override, so the behaviour
#133413 added is preserved for every CoreCLR wasm consumer rather than only
inside Wasm.Build.Tests. Nothing else patched KnownCrossgen2Pack, so keeping
the removal alone would have silently regressed it.

The override is scoped to browser-wasm with UseMonoRuntime false, leaving Mono
wasm and non-wasm ReadyToRun builds untouched.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot AI review requested due to automatic review settings September 14, 2026 12:17

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.

🔵 Needs a closer look

One or more issues must be addressed before approval.

Review details

Suppressed comments (1)

src/mono/nuget/Microsoft.NET.Workload.Mono.Toolchain.Current.Manifest/WorkloadManifest.targets.in:260

  • Could we add a regression case that asserts the versions of both the resolved CoreCLR browser-wasm runtime pack and ResolvedCrossgen2Pack? WasmSdkBasedProjectProvider.AssertRuntimePackPath only validates the runtime-pack path in workload lanes, while CoreCLRWasmNativeDefaultsTests.NativeRelinkResolvesCrossgen2WithoutReadyToRun checks that a generator exists but not that its package version matches the runtime pack. A future item-ordering or version regression in either override could therefore pass the current tests.
    <KnownCrossgen2Pack Update="@(KnownCrossgen2Pack)"
                        Condition="'$(RuntimeIdentifier)' == 'browser-wasm' and '$(UseMonoRuntime)' == 'false'">
      <Crossgen2PackVersion Condition="'%(KnownCrossgen2Pack.TargetFramework)' == '${NetVersion}.0'">$(_MonoWorkloadRuntimePackPackageVersion)</Crossgen2PackVersion>
  • Files reviewed: 3/3 changed files
  • Comments generated: 0 new
  • Review effort level: Lite

<KnownCrossgen2Pack Update="@(KnownCrossgen2Pack)"
Condition="'$(RuntimeIdentifier)' == 'browser-wasm' and '$(UseMonoRuntime)' == 'false'">
<Crossgen2PackVersion Condition="'%(KnownCrossgen2Pack.TargetFramework)' == '${NetVersion}.0'">$(_MonoWorkloadRuntimePackPackageVersion)</Crossgen2PackVersion>
</KnownCrossgen2Pack>

@akoeplinger akoeplinger Sep 14, 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 we do this in WasmOverridePacks.targets instead?

I'm fine with merging this to unblock testing but that feels like the more correct spot to me (as we want to ideally get rid of the runtime copy of the workload manifest)

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.

For mono, in production, we needed to enforce that runtime pack, aot compiler and sdk pack, are all in the same version. Because of that we have this "production" override.

I thought we would do the same with CoreCLR. Is that correct or not?

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.

I don't think we have a need to, since coreclr/crossgen doesn't have that tight coupling

@maraf maraf Sep 16, 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.

We are not actually using the WasmOverridePacks.targets, see UseWBTOverridePackTargets = false and also #91350, but if we don't include the crossgen in workload, overriding the version in workload isn't correct.

@maraf maraf added the NO-MERGE The PR is not ready for merge yet (see discussion for detailed reasons) label Sep 17, 2026

This branch was successfully deployed

1 active (outdated) deployment
copilot-pat-pool — fbb5d8a8 Deployed Sep 12, 2026 by maraf via conclusion #8346
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

arch-wasm WebAssembly architecture area-Build-mono NO-MERGE The PR is not ready for merge yet (see discussion for detailed reasons) os-browser Browser variant of arch-wasm

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants