Conversation
Implement per-app native relinking via emcc for CoreCLR browser-wasm, matching the capability Mono already has. Unlike Mono, CoreCLR has no C source files in the runtime pack, so the native build is link-only. Key changes: - BrowserWasmApp.CoreCLR.targets: Complete implementation replacing stubs - Emscripten toolchain setup (_CoreCLRSetupEmscripten, _CoreCLRSetupToolchain) - Build native defaults (WasmBuildNative=false for build, true for publish) - emcc link target with all CoreCLR .a libraries + JS library files - Heap size calculation (default 128MB matching CMakeLists.txt) - WasmBuildApp/WasmTriggerPublishApp/WasmNestedPublishApp target chain - wasm-opt post-link optimization - corehost.proj: Copy libSystem.Native.Browser.extpost.js to runtime pack The implementation is self-contained and does not import WasmApp.Common.targets or BrowserWasmApp.targets. It reuses MSBuild task assemblies via UsingTask. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
When WasmBuildNative=true, re-link dotnet.native.wasm from CoreCLR static libraries using emcc, allowing apps to include custom native code via NativeFileReference items. The implementation: - Imports eng/native.wasm.targets for shared Emscripten/ICU/export properties - Sets up Emscripten toolchain and environment - Compiles user native sources (NativeFileReference .c/.cpp) with EmccCompile - Links all CoreCLR .a libraries + user objects into dotnet.native.wasm - Handles both build and publish (nested publish) flows - Link flags mirror src/native/corehost/browserhost/CMakeLists.txt - Gates ICU libraries on InvariantGlobalization - Supports WasmEnableExceptionHandling, WasmEnableSIMD, custom EmccFlags Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Integrate the CoreCLR ManagedToNativeGenerator MSBuild task into the native re-link pipeline. This generates P/Invoke dispatch tables, reverse P/Invoke tables, and interpreter-to-native thunks that are compiled and linked into dotnet.native.wasm. Key changes: - Add _CoreCLRGenerateManagedToNative target that scans managed assemblies for P/Invoke signatures and generates C++ source files - Generate coreclr_compat.h shim header providing type/macro stubs (MethodDesc, PCODE, ULONG, LOG, PORTABILITY_ASSERT) so generated files compile outside the full CoreCLR build context - Use .cpp extensions for generated files (they contain extern "C", namespaces, and other C++ constructs) - Fix CoreLib discovery to check native/ dir first (CoreCLR WASM ships CoreLib there, not in lib/net11.0/) - Fix UsingTask assembly paths: EmccCompile and ManagedToNativeGenerator both live in WasmAppBuilder.dll, not WasmBuildTasks.dll Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- Don't compile reverse-pinvoke-table.cpp separately to avoid duplicate symbols with callhelpers-reverse.cpp.o in libcoreclr_static.a - Condition LLD_REPORT_UNDEFINED and ERROR_ON_UNDEFINED_SYMBOLS to Debug only, matching CMakeLists.txt behavior - Add Dependencies metadata to generated source files for incremental builds - Use node$(_ExeExt) for cross-platform compat - Reorder link libraries: libBrowserHost.a first, matching CMakeLists.txt Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…t string - Remove MAXIMUM_MEMORY from _EmccCommonFlags (compile+link shared flags); it only belongs in the link step's _EmccLinkStepArgs - Fix PORTABILITY_ASSERT fprintf format: use %25s MSBuild encoding to produce correct %s printf format specifier Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…jection - Add SimpleNativeBuildForCoreCLR test that publishes WasmBrowserRunMainOnly with WasmBuildNative=true, verifying the CoreCLR native build pipeline works - Add CoreCLR property injection to CreateWasmTemplateProject (was missing, only CopyTestAsset had it), enabling template-based tests on CoreCLR - Add UsingBrowserRuntimeWorkload=false to both CoreCLR injection blocks to bypass the wasm-tools workload check (NETSDK1147) that fires when WasmBuildNative=true triggers _WasmNativeWorkloadNeeded Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
|
Tagging subscribers to 'arch-wasm': @lewing, @pavelsavara |
There was a problem hiding this comment.
Pull request overview
This PR enables CoreCLR browser-wasm per-app native re-linking (via emcc) in-tree, aligning CoreCLR’s WASM app pipeline more closely with Mono’s ability to incorporate app-provided native code (NativeFileReference). It also adjusts WASM build tests to target the CoreCLR browser runtime packs/SDK packs and adds research notes documenting the build pipeline.
Changes:
- Copy
libSystem.Native.Browser.extpost.jsinto the CoreCLR browser runtime pack native directory for app relinking. - Replace the CoreCLR WASM targets stub with a full
WasmBuildApp/ nested publish relink pipeline usingemcc+ManagedToNativeGenerator. - Update WASM template/build tests to use CoreCLR settings and force the right runtime/workload pack versions; add supporting build analysis docs under
.research/.
Reviewed changes
Copilot reviewed 9 out of 9 changed files in this pull request and generated 7 comments.
Show a summary per file
| File | Description |
|---|---|
| src/native/corehost/corehost.proj | Adds extpost.js to the files copied into the runtime pack for CoreCLR browser-wasm. |
| src/mono/wasm/Wasm.Build.Tests/Templates/WasmTemplateTestsBase.cs | Adjusts template/test-asset project generation to use CoreCLR runtime settings and override known pack versions. |
| src/mono/browser/build/BrowserWasmApp.CoreCLR.targets | Implements CoreCLR WASM native relink (compile generated sources + link with emcc) for build and publish. |
| src/mono/browser/build/BrowserWasmApp.CoreCLR.targets.backup | Adds a backup copy of the CoreCLR targets file. |
| .research/wasm-native-build-binlog-analysis.md | Documents WASM native build behavior inferred from binlogs. |
| .research/wasm-native-build-analysis.md | Expanded WASM native build pipeline analysis and comparison notes. |
| .research/runtime-native-build-analysis.md | Compares Mono vs CoreCLR runtime native build behavior/timings. |
| .research/native-build-analysis.md | Summarizes timings and phases for WasmBuildNative=true scenarios. |
| .research/build-wasm-browser-sample.md | Documents steps and properties for building the CoreCLR WASM browser sample in-tree. |
You can also share your feedback on Copilot code review. Take the survey.
| <!-- Symbol handling (strict undefined checks in Debug only, matching CMakeLists.txt) --> | ||
| <_EmccLinkStepArgs Condition="'$(Configuration)' == 'Debug'" Include="-s LLD_REPORT_UNDEFINED" /> | ||
| <_EmccLinkStepArgs Condition="'$(Configuration)' == 'Debug'" Include="-s ERROR_ON_UNDEFINED_SYMBOLS=1" /> | ||
| <_EmccLinkStepArgs Include="--emit-symbol-map" /> |
src/native/corehost/corehost.proj
Outdated
| <_MicrosoftNetCoreAppRuntimePackNativeDirFiles Include="$(HostSharedFrameworkDir)dotnet.native.js.symbols" /> | ||
| <_MicrosoftNetCoreAppRuntimePackNativeDirFiles Include="$(HostSharedFrameworkDir)dotnet.native.wasm" /> | ||
| <!-- extpost.js is needed for per-app native relinking via emcc --> | ||
| <_MicrosoftNetCoreAppRuntimePackNativeDirFiles Include="$(MSBuildThisFileDirectory)..\..\libs\System.Native.Browser\libSystem.Native.Browser.extpost.js" /> |
src/mono/wasm/Wasm.Build.Tests/Templates/WasmTemplateTestsBase.cs
Outdated
Show resolved
Hide resolved
| DependsOnTargets="GenerateEmccExports"> | ||
|
|
||
| <PropertyGroup> | ||
| <_EmccExportedRuntimeMethods>"[BROWSER_HOST,@(EmccExportedRuntimeMethod -> '%27%(Identity)%27', ',')]"</_EmccExportedRuntimeMethods> |
| <!-- Locate System.Private.CoreLib in runtime pack if not already bundled --> | ||
| <PropertyGroup> | ||
| <_HasCoreLib Condition="'%(_WasmManagedAssemblies.FileName)%(_WasmManagedAssemblies.Extension)' == 'System.Private.CoreLib.dll'">true</_HasCoreLib> |
There was a problem hiding this comment.
Pull request overview
Adds CoreCLR browser-wasm “in-tree relink” support so apps can re-link dotnet.native.wasm with emcc (e.g., to include custom native code), and adjusts build/test plumbing to support that flow.
Changes:
- Copy
libSystem.Native.Browser.extpost.jsinto the CoreCLR browser-wasm runtime pack native directory for emcc relinking. - Implement CoreCLR-specific
WasmBuildApp/publish targets to compile/link native inputs with emcc and register outputs. - Refactor WASM template tests to consistently inject CoreCLR-specific project properties/items.
Reviewed changes
Copilot reviewed 9 out of 9 changed files in this pull request and generated 5 comments.
Show a summary per file
| File | Description |
|---|---|
| src/native/corehost/corehost.proj | Copies libSystem.Native.Browser.extpost.js into the runtime pack output. |
| src/mono/wasm/Wasm.Build.Tests/Templates/WasmTemplateTestsBase.cs | Centralizes CoreCLR-specific project property/item injection for template/test assets. |
| src/mono/browser/build/BrowserWasmApp.CoreCLR.targets | Replaces stub with a full CoreCLR emcc compile/link pipeline + nested publish support. |
| src/mono/browser/build/BrowserWasmApp.CoreCLR.targets.backup | Adds a backup copy of targets content (appears non-production). |
| .research/*.md | Adds analysis notes/binlog investigations for WASM native build/relink flows. |
You can also share your feedback on Copilot code review. Take the survey.
| DependsOnTargets="GenerateEmccExports"> | ||
|
|
||
| <PropertyGroup> | ||
| <_EmccExportedRuntimeMethods>"[BROWSER_HOST,@(EmccExportedRuntimeMethod -> '%27%(Identity)%27', ',')]"</_EmccExportedRuntimeMethods> |
| <_EmccCommonFlags Include="-v" Condition="'$(EmccVerbose)' == 'true'" /> | ||
| <_EmccCommonFlags Include="-g" Condition="'$(WasmNativeDebugSymbols)' == 'true'" /> | ||
| <_EmccCommonFlags Include="-fwasm-exceptions" Condition="'$(WasmEnableExceptionHandling)' == 'true'" /> | ||
| <_EmccCommonFlags Include="-s DISABLE_EXCEPTION_CATCHING=0" Condition="'$(WasmEnableExceptionHandling)' == 'false'" /> |
| </ItemGroup> | ||
|
|
||
| <!-- Include user JS files marked explicitly for native link --> | ||
| <ItemGroup> |
| <Project> | ||
| <!-- | ||
| CoreCLR WASM native build targets. | ||
|
|
||
| Unlike Mono, CoreCLR has no C source files in the runtime pack to compile per-app. | ||
| The native build is link-only: emcc links pre-built .a static libraries + JS library |
| <ItemGroup Condition="'$(MicrosoftNetCoreAppRuntimePackRidLibTfmDir)' == ''"> | ||
| <_SystemRuntimePathItem Include="$(MicrosoftNetCoreAppRuntimePackRidDir)lib$(WasmDirSep)net*$(WasmDirSep)System.Runtime.dll" /> | ||
| </ItemGroup> |
On Windows, the EmccCompile task's CompilerBinaryPath was set to bare 'emcc', which relies on the PATH environment variable to resolve. However, the PATH constructed in _CoreCLRSetupEmscripten was fragmented by MSBuild item-separator splitting on semicolons, so only the emsdk root directory ended up in PATH — not the emscripten subdirectory where emcc lives. Fix by setting WasmClang to an absolute path using EmscriptenUpstreamEmscriptenPath, matching the existing pattern in the Mono targets (BrowserWasmApp.targets line 173). Also update the link step Exec command to use $(WasmClang) instead of bare 'emcc'. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
1. WasmTriggerPublishApp — removed the WasmBuildNative == 'true' gate so the publish pipeline runs for all browser-wasm projects (matching Mono behavior) 2. WasmNestedPublishApp — switched from hardcoded ComputeFilesToPublish to $(_WasmNestedPublishAppPreTarget);$(WasmNestedPublishAppDependsOn) so that PrepareForWasmBuildApp and _GatherWasmFilesToPublish run (setting WasmMainJSPath, populating StaticWebAssets) 3. _CoreCLRWasmBuildAppCore — added WasmBuildNative == 'true' condition so the emcc native linking is skipped when not needed, but the rest of the publish pipeline still runs
There was a problem hiding this comment.
Pull request overview
This PR adds an in-tree MSBuild pipeline for CoreCLR browser-wasm per-app native re-linking (via emcc), and wires in the missing JS asset required for the link step. It also updates WASM build tests to configure CoreCLR-specific framework/workload properties and includes research notes documenting the existing WASM native build pipeline.
Changes:
- Package
libSystem.Native.Browser.extpost.jsinto the browser-wasm runtime pack so CoreCLR app re-link can use it. - Replace the CoreCLR browser-wasm stub targets with a full compile/link pipeline that can consume
NativeFileReferenceand re-linkdotnet.native.*. - Refactor WASM template test setup to apply CoreCLR-specific project properties consistently; add
.research/*build analysis docs.
Reviewed changes
Copilot reviewed 9 out of 9 changed files in this pull request and generated 2 comments.
Show a summary per file
| File | Description |
|---|---|
| src/native/corehost/corehost.proj | Adds libSystem.Native.Browser.extpost.js to the set of runtime-pack native files copied for browser-wasm. |
| src/mono/wasm/Wasm.Build.Tests/Templates/WasmTemplateTestsBase.cs | Refactors CoreCLR-specific msbuild property/item injection into a helper and applies it for template and test-asset projects. |
| src/mono/browser/build/BrowserWasmApp.CoreCLR.targets.backup | Adds a full CoreCLR WASM targets file as a “backup” copy. |
| src/mono/browser/build/BrowserWasmApp.CoreCLR.targets | Implements the CoreCLR browser-wasm native compile/link/relink target chain (replacing the previous stub). |
| .research/wasm-native-build-binlog-analysis.md | New documentation: binlog-based WASM native build pipeline analysis. |
| .research/wasm-native-build-analysis.md | New documentation: WASM native build analysis and comparison notes. |
| .research/runtime-native-build-analysis.md | New documentation: runtime CI native build analysis for Mono vs CoreCLR. |
| .research/native-build-analysis.md | New documentation: native-build timing/target breakdown for WASM. |
| .research/build-wasm-browser-sample.md | New documentation: steps and notes for building the CoreCLR WASM browser sample. |
You can also share your feedback on Copilot code review. Take the survey.
| DependsOnTargets="GenerateEmccExports"> | ||
|
|
||
| <PropertyGroup> | ||
| <_EmccExportedRuntimeMethods>"[BROWSER_HOST,@(EmccExportedRuntimeMethod -> '%27%(Identity)%27', ',')]"</_EmccExportedRuntimeMethods> |
| <Project> | ||
| <!-- | ||
| CoreCLR WASM native build targets. | ||
|
|
||
| Unlike Mono, CoreCLR has no C source files in the runtime pack to compile per-app. | ||
| The native build is link-only: emcc links pre-built .a static libraries + JS library | ||
| files to produce dotnet.native.wasm + dotnet.native.js. | ||
|
|
||
| This file is self-contained and does NOT import WasmApp.Common.targets or BrowserWasmApp.targets. | ||
| It reuses MSBuild tasks (EmccCompile, WasmCalculateInitialHeapSize) via UsingTask declarations. | ||
| --> | ||
|
|
||
| <UsingTask TaskName="Microsoft.WebAssembly.Build.Tasks.WasmCalculateInitialHeapSize" AssemblyFile="$(WasmAppBuilderTasksAssemblyPath)" TaskFactory="TaskHostFactory" /> | ||
|
|
||
| <PropertyGroup> |
|
Checked build failure analysis Single error in the entire build (21 min total): Error: Manifest file at Failing project: src/tests/FunctionalTests/WebAssembly/Browser/RuntimeConfig/WebAssembly.Browser.RuntimeConfig.Test.csproj Failing target: _CleanupReferencedProjectItemGroups (in Microsoft.NET.Sdk.StaticWebAssets.References.targets:16) Root cause: The test project references a static web assets project (likely WasmAppHost), but the build manifest for the WebAssembly.Browser.RuntimeConfig.Test project was never generated. This typically happens when:
The successful WasmAppHost manifest lives under artifacts/obj/mono/WasmAppHost/browser.wasm.Checked/, but the test expects its own at artifacts/obj/WebAssembly.Browser.RuntimeConfig.Test/Release/net11.0/browser-wasm/. This suggests the test is being published/resolved in a |
No description provided.