Skip to content

[wasm] Resolve crossgen2 through the SDK - #133413

Open
radekdoulik wants to merge 8 commits into
dotnet:mainfrom
radekdoulik:wasm-crossgen2-sdk-resolution
Open

[wasm] Resolve crossgen2 through the SDK#133413
radekdoulik wants to merge 8 commits into
dotnet:mainfrom
radekdoulik:wasm-crossgen2-sdk-resolution

Conversation

@radekdoulik

@radekdoulik radekdoulik commented Sep 8, 2026

Copy link
Copy Markdown
Member

Fixes #133353.

Use the SDK to acquire crossgen2 for CoreCLR wasm native relinking without enabling ReadyToRun. Preserve explicit and in-repo generator paths, and remove the obsolete crossgen2 workload declarations and Sdk.props shim.

Request the pack before the first restore. When no pack is resolved, report the missing generator rather than an unrelated ReadyToRun error.

Workload tests use their configured target framework and pack version.

Validation

Four build/publish regression cases passed. A standalone CoreCLR browser app outside the repository built and ran using repo-produced packages and native code passing a 24-byte struct by value.

Validation used official VMR SDK 12.0.100-alpha.1.26458.102, without an SDK code overlay, with the rebuilt native wasm SDK pack and existing repo-produced runtime packs.

The required SDK support (dotnet/sdk#56119 and dotnet/sdk#55785) reached runtime through #133344.

Note

This PR description was drafted with GitHub Copilot.

radekdoulik and others added 3 commits September 8, 2026 09:10
Fixes dotnet#133353

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: f6d6e5a4-5b25-4198-b42d-d5b2dc781f47
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: f6d6e5a4-5b25-4198-b42d-d5b2dc781f47
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: f6d6e5a4-5b25-4198-b42d-d5b2dc781f47
@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.

@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.

@radekdoulik radekdoulik moved this to In Progress in Runtime Infra Sep 8, 2026
@radekdoulik radekdoulik added this to the 12.0.0 milestone Sep 8, 2026
@radekdoulik radekdoulik added the NO-MERGE The PR is not ready for merge yet (see discussion for detailed reasons) label Sep 8, 2026
@dotnet-policy-service

Copy link
Copy Markdown
Contributor

Tagging subscribers to this area: @dotnet/runtime-infrastructure
See info in area-owners.md if you want to be subscribed.

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

It changes SDK/workload MSBuild resolution and packaging behavior for WebAssembly relinking, which has broad restore/build impact that’s hard to fully validate from diff-only review.

Pull request overview

Updates the CoreCLR WebAssembly (browser-wasm and WASI) native relink pipeline to resolve crossgen2 via the .NET SDK pack mechanism (without enabling ReadyToRun), and removes the older workload-based crossgen2 plumbing used by workload tests.

Changes:

  • Request the crossgen2 pack via RequiresCrossgen2Pack and resolve @(Crossgen2Tool) as a fallback generator path for portable call-helper table generation.
  • Remove workload manifest references/imports for the crossgen2 pack, plus the obsolete Sdk.props shim packaging route.
  • Update workload tests to use their configured target framework/pack versions and add regression coverage for “native relink resolves crossgen2 without ReadyToRun” and “missing pack reports missing generator (not NETSDK1094)”.
File summaries
File Description
src/mono/wasm/Wasm.Build.Tests/Templates/WasmTemplateTestsBase.cs Uses runtime pack version for KnownFrameworkReference and updates KnownWebAssemblySdkPack/KnownCrossgen2Pack versions for CoreCLR test projects.
src/mono/wasm/Wasm.Build.Tests/CoreCLRWasmNativeDefaultsTests.cs Adds tests validating SDK crossgen2 resolution without ReadyToRun and improved missing-generator error reporting.
src/mono/wasi/build/WasiApp.CoreCLR.targets Requests crossgen2 pack and adds SDK-based fallback resolution via ResolveReadyToRunCompilers + @(Crossgen2Tool) for generator execution.
src/mono/nuget/Microsoft.NET.Workload.Mono.Toolchain.Current.Manifest/WorkloadManifest.targets.in Removes the workload Sdk.props import for the crossgen2 pack in the CoreCLR browser-wasm workload path.
src/mono/nuget/Microsoft.NET.Workload.Mono.Toolchain.Current.Manifest/WorkloadManifest.json.in Drops the crossgen2 pack from the wasm-tools workload pack list.
src/mono/browser/build/BrowserWasmApp.CoreCLR.targets Requests crossgen2 pack early and adds SDK-based generator resolution via ResolveReadyToRunCompilers + @(Crossgen2Tool); improves related error messages.
src/installer/pkg/sfx/Microsoft.NETCore.App/Microsoft.NETCore.App.Crossgen2.props Stops packaging the removed Crossgen2/Sdk.props into the pack.
src/installer/pkg/sfx/Microsoft.NETCore.App/Crossgen2/Sdk.props Removes the obsolete Sdk.props shim that set $(Crossgen2ToolPath) for workload-based acquisition.
eng/Subsets.props Updates rationale/comments for producing the crossgen2 host pack for CoreCLR wasm workload test legs.
Review details
  • Files reviewed: 9/9 changed files
  • Comments generated: 0
  • Review effort level: Lite

Keep the crossgen2 publish-reference fix and scoped runtime-pack
overrides while retaining SDK-based crossgen2 resolution.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: f6d6e5a4-5b25-4198-b42d-d5b2dc781f47

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

It modifies WASM build/workload acquisition behavior and MSBuild target orchestration in ways that are difficult to fully validate for all restore/build permutations without human review and broader CI signal.

Review details
  • Files reviewed: 9/9 changed files
  • Comments generated: 1
  • Review effort level: Lite

Comment thread src/mono/wasm/Wasm.Build.Tests/Templates/WasmTemplateTestsBase.cs
Name the test-only target for both packs it updates.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: f6d6e5a4-5b25-4198-b42d-d5b2dc781f47
Copilot AI review requested due to automatic review settings September 9, 2026 18:54

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

RequiresCrossgen2Pack is currently requested unconditionally for CoreCLR-WASI projects, which can force unnecessary crossgen2 pack acquisition in configurations that will never run the generator.

Review details

Suppressed comments (1)

Previously missed (1) — in code that hasn't changed since the last review.

src/mono/wasi/build/WasiApp.CoreCLR.targets:29

  • RequiresCrossgen2Pack is being set unconditionally for all CoreCLR-WASI projects, even though this file only uses crossgen2 when generating an app bundle (and not for single-file bundles). This can force an unnecessary crossgen2 pack acquisition during restore for library/other configurations that will never invoke the call-helper generator.
  • Files reviewed: 9/9 changed files
  • Comments generated: 0 new
  • Review effort level: Lite

Preserve the upstream Crossgen2Path rename while retaining SDK-based
acquisition. Update resolver guards, diagnostics, and test assertions
to use the same override name.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: f6d6e5a4-5b25-4198-b42d-d5b2dc781f47
Copilot AI review requested due to automatic review settings September 9, 2026 19:45
@radekdoulik radekdoulik removed the NO-MERGE The PR is not ready for merge yet (see discussion for detailed reasons) label Sep 9, 2026

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.

🟡 Changes recommended

The new unconditional RequiresCrossgen2Pack defaults can trigger unnecessary crossgen2 pack acquisition during restore for configurations that won’t invoke crossgen2, and should be gated to avoid restore overhead.

Once you've addressed the issues Copilot identified, you can request another Copilot review.

Review details

Suppressed comments (1)

src/mono/wasi/build/WasiApp.CoreCLR.targets:33

  • RequiresCrossgen2Pack is set to true by default even when WasmGenerateAppBundle is false (e.g., library builds), but this targets file only uses crossgen2 when generating an app bundle (and not in single-file mode). Gating the pack request to the same condition avoids unnecessary pack acquisition during restore for configurations that will never invoke crossgen2.
  <PropertyGroup>
    <WasmAppRuntimeFlavor>CoreCLR</WasmAppRuntimeFlavor>
    <UseMonoRuntime>false</UseMonoRuntime>
    <RequiresCrossgen2Pack Condition="'$(RequiresCrossgen2Pack)' == ''">true</RequiresCrossgen2Pack>
    <!-- The Mono per-app clang relink (WasmBuildNative) is not used; CoreCLR links the
         wasihost corehost (libWasiHost.a) per-app through its own targets below. -->
    <WasmBuildNative>false</WasmBuildNative>
    <WasmSingleFileBundle Condition="'$(WasmSingleFileBundle)' == ''">false</WasmSingleFileBundle>
  • Files reviewed: 9/9 changed files
  • Comments generated: 1
  • Review effort level: Lite

Comment thread src/mono/browser/build/BrowserWasmApp.CoreCLR.targets Outdated
Keep the early request for implicit relinking, but honor an explicit
WasmBuildNative=false. Preserve explicit pack requests and independent
SDK acquisition for ReadyToRun.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: f6d6e5a4-5b25-4198-b42d-d5b2dc781f47
Copilot AI review requested due to automatic review settings September 10, 2026 10:19

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

The WASI targets currently request the crossgen2 pack unconditionally, which can force unnecessary restore/download work in configurations where the relink/generator targets won’t run.

Review details

Suppressed comments (1)

Previously missed (1) — in code that hasn't changed since the last review.

src/mono/wasi/build/WasiApp.CoreCLR.targets:29

  • RequiresCrossgen2Pack is requested unconditionally for WASI CoreCLR. When WasmGenerateAppBundle is explicitly disabled (or WasmSingleFileBundle=true), the per-app relink/generator targets in this file won’t run, so forcing the SDK to acquire the crossgen2 pack adds avoidable restore/download cost.
  • Files reviewed: 9/9 changed files
  • Comments generated: 0 new
  • Review effort level: Lite

@radekdoulik
radekdoulik enabled auto-merge (squash) September 10, 2026 12:26
native.wasm.targets uses RuntimeFlavor to gate the CoreCLR-only relink registry. -->
<RuntimeFlavor Condition="'$(RuntimeFlavor)' == ''">CoreCLR</RuntimeFlavor>

<!-- Request crossgen2 here: WebAssembly.Pack is not imported before the first restore.

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.

This means the crossgen2 will be required only when the workload is installed, but according to discussion with Pavel, R2R should work even without workload. Is that true?

If that's the case, we need to more this to dotnet/sdk where root skeleton for the SDK lives. Putting it there results in requesting the crossgen2 before nuget restore.

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.

R2R should work even without workload. Is that true?

still yes

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

This is independent from R2R compilation and this path is generator specific. R2R compilation adds the pack when ReadyToRunEnabled && ReadyToRunUseCrossgen2. https://github.com/dotnet/sdk/blob/02d39b6a25a62e5ac313ab8449704c4428fa68f3/src/Tasks/Microsoft.NET.Build.Tasks/ProcessFrameworkReferences.cs#L482

The relinking with generator currently needs workload as it still produces C files.

""";
insertAtEnd +=
$$"""
<Target Name="_UpdateKnownWebAssemblySdkPack" BeforeTargets="ProcessFrameworkReferences"

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.

This target is already removed on main. The packs are correctly resolved from the installed workload in dotnet-latest

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

I still see it on main

<Target Name="_UpdateKnownWebAssemblySdkPack" BeforeTargets="ProcessFrameworkReferences"
Condition="'$(RuntimeIdentifier)' == 'browser-wasm'">
<ItemGroup>
<KnownWebAssemblySdkPack Update="@(KnownWebAssemblySdkPack)">
<WebAssemblySdkPackVersion Condition="'%(KnownWebAssemblySdkPack.TargetFramework)' == '{{DefaultTargetFramework}}'">{{runtimePackVersion}}</WebAssemblySdkPackVersion>
</KnownWebAssemblySdkPack>
</ItemGroup>
</Target>

Comment thread src/mono/wasm/Wasm.Build.Tests/CoreCLRWasmNativeDefaultsTests.cs Outdated
Remove redundant WasmBuildOnlyAfterPublish settings from both SDK
acquisition theories. Retain the assertion that helper generation runs
in nested publish.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: f6d6e5a4-5b25-4198-b42d-d5b2dc781f47
Copilot AI review requested due to automatic review settings September 11, 2026 08:11

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 crossgen2 resolution issues remain for R2R-enabled and disabled scenarios, including WASI SDK packaging.

Review details

Suppressed comments (5)

src/mono/browser/build/BrowserWasmApp.CoreCLR.targets:653

  • ResolveReadyToRunCompilers does not always produce a Crossgen2Tool: when PublishReadyToRunUseCrossgen2 is false it validates/emits the crossgen tool instead (see src/tasks/Crossgen2Tasks/ResolveReadyToRunCompilers.cs:63-83,140-180). This target forwards that project setting unchanged even though the native relink always invokes crossgen2, so a project that disables R2R's crossgen2 selection reaches the fallback with no @(Crossgen2Tool) and then fails with the missing-generator error. Resolve crossgen2 independently of the R2R compiler preference, without changing whether ReadyToRun runs.

[!NOTE] This review comment was generated by GitHub Copilot.

    <CallTarget Targets="ResolveReadyToRunCompilers"
                Condition="'$(Crossgen2Path)' == '' and '$(Crossgen2InBuildDir)' == '' and '$(Crossgen2ToolPath)' == '' and '@(ResolvedCrossgen2Pack)' != ''" />

src/mono/browser/build/BrowserWasmApp.CoreCLR.targets:653

  • When PublishReadyToRun=true, CreateReadyToRunImages already runs ResolveReadyToRunCompilers through _PrepareForReadyToRunCompilation (src/tasks/Crossgen2Tasks/Microsoft.NET.CrossGen.targets:362-403), which leaves @(Crossgen2Tool) populated. This guard does not check that item, so it invokes the resolver a second time; the later assignment at line 715 can then produce a semicolon-separated Crossgen2Path, which is not an executable path. Skip this call when @(Crossgen2Tool) is already available, and add coverage for R2R-enabled publish.
                Condition="'$(Crossgen2Path)' == '' and '$(Crossgen2InBuildDir)' == '' and '$(Crossgen2ToolPath)' == '' and '@(ResolvedCrossgen2Pack)' != ''" />

src/mono/wasi/build/WasiApp.CoreCLR.targets:29

  • This target is only imported from WasiApp.InTree.targets; Microsoft.NET.Runtime.WebAssembly.Wasi.Sdk.pkgproj does not package it, and the packaged SDK imports WasiApp.targets instead. Consequently, an out-of-repo CoreCLR-WASI project never sees this RequiresCrossgen2Pack/Crossgen2Tool path and still cannot resolve the generator through the SDK. If WASI is in scope, package and select the CoreCLR target for the SDK; otherwise keep this explicitly in-tree rather than presenting it as the WASI equivalent of the browser fix.

[!NOTE] This review comment was created by GitHub Copilot.

    <RequiresCrossgen2Pack Condition="'$(RequiresCrossgen2Pack)' == ''">true</RequiresCrossgen2Pack>

src/mono/wasi/build/WasiApp.CoreCLR.targets:97

  • ResolveReadyToRunCompilers does not always produce a Crossgen2Tool: when PublishReadyToRunUseCrossgen2 is false it validates/emits the crossgen tool instead (see src/tasks/Crossgen2Tasks/ResolveReadyToRunCompilers.cs:63-83,140-180). This target forwards that project setting unchanged even though the WASI relink always invokes crossgen2, so a project that disables R2R's crossgen2 selection reaches the fallback with no @(Crossgen2Tool) and then fails with the missing-generator error. Resolve crossgen2 independently of the R2R compiler preference, without changing whether ReadyToRun runs.

[!NOTE] This review comment was generated by GitHub Copilot.

    <CallTarget Targets="ResolveReadyToRunCompilers"
                Condition="'$(Crossgen2Path)' == '' and '$(Crossgen2InBuildDir)' == '' and '$(Crossgen2ToolPath)' == '' and '@(ResolvedCrossgen2Pack)' != ''" />

src/mono/wasi/build/WasiApp.CoreCLR.targets:97

  • When PublishReadyToRun=true, the SDK publish path can already have run ResolveReadyToRunCompilers through _PrepareForReadyToRunCompilation (src/tasks/Crossgen2Tasks/Microsoft.NET.CrossGen.targets:362-403), leaving @(Crossgen2Tool) populated. Because this guard ignores that item, it can resolve the compiler again and the fallback at line 171 can turn multiple item identities into an invalid semicolon-separated Crossgen2Path. Skip the call when @(Crossgen2Tool) is already populated, and add an R2R-enabled regression case.
                Condition="'$(Crossgen2Path)' == '' and '$(Crossgen2InBuildDir)' == '' and '$(Crossgen2ToolPath)' == '' and '@(ResolvedCrossgen2Pack)' != ''" />
  • Files reviewed: 9/9 changed files
  • Comments generated: 0 new
  • Review effort level: Lite

pavelsavara added a commit to Blazor-Playground/macro-benchmarks that referenced this pull request Sep 11, 2026
The stock wasm-tools workload does not acquire a browser-wasm crossgen2 nor set Crossgen2ToolPath, so BrowserWasmApp.CoreCLR.targets errors with 'crossgen2 was not found' for CoreCLR native-relink. The host crossgen2 pack already ships a wasm-capable crossgen2 (clrjit_universal_wasm), so reference it and point PortableCallHelpersGeneratorPath at it. Skipped for the from-source path (Crossgen2InBuildDir) and once the SDK provides crossgen2. Temporary until dotnet/runtime#133413 + dotnet/sdk#55785 flow into the daily SDK.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

arch-wasm WebAssembly architecture area-Infrastructure

Projects

Status: In Progress

Development

Successfully merging this pull request may close these issues.

[wasm][coreCLR] Out-of-repo relink cannot find crossgen2; acquire it through the SDK

4 participants