Skip to content

[wasm] Emit producers and build_id custom sections (native, webcil, R2R) - #130768

Draft
pavelsavara with Copilot wants to merge 4 commits into
mainfrom
copilot/research-implementation-direction
Draft

pavelsavara with Copilot wants to merge 4 commits into
mainfrom
copilot/research-implementation-direction

Conversation

Copilot AI commented Jul 15, 2026 •

Copy link
Copy Markdown
Contributor

Emits the two WebAssembly tool-conventions custom sections — producers and build_id — into the WebAssembly artifacts produced by the .NET wasm toolchain, for both Mono and CoreCLR.

Where the sections are emitted

Artifact producers build_id
dotnet.native.wasm (app native re-link) small relocatable object passed to wasm-ld wasm-ld build-id linker flag, only when $(WasmNativeBuildId) is set
webcil modules (ConvertDllsToWebcil) appended by WebcilWasmWrapper $(WasmNativeBuildId) if set, otherwise a per-file SHA-256 content hash
R2R webcil (crossgen2) appended by WebCilObjectWriter --wasm-native-build-id if set, otherwise a content hash

All three paths reuse WasmCustomSectionWriter, linked into the Webcil task assembly and the ReadyToRun compiler, so there is one implementation of the section encoding.

build_id

  • Emitted into dotnet.native.wasm only when a value is provided; there is intentionally no implicit random-per-build ID.
  • $(WasmNativeBuildId) accepts a hexadecimal value, pins the ID, and forces a native application re-link.
  • crossgen2 gains a --wasm-native-build-id option for R2R Webcil output.
  • Webcil modules without an explicit ID use a deterministic SHA-256 content hash.

producers

The generated entries are:

  • language=C#
  • processed-by=<Mono|CoreCLR|WebCIL>
  • sdk=.NET

For an application native re-link, WasmEmitProducersObject creates a small relocatable object that is passed to wasm-ld. Emission can be disabled with $(WasmEmitProducersSection)=false.

JavaScript exposure

runtimeBuildInfo.buildId surfaces the native module's build_id on both Mono and CoreCLR:

  • default dotnet.*.js build: a rollup constant (consts:buildId)
  • application re-link: the Emscripten module receives WASM_BUILD_ID and overrides the rollup constant

MSBuild properties

Property Meaning
WasmNativeBuildId Hexadecimal build ID. Pins the value and forces a native re-link. Empty means no build_id for the native module; Webcil modules fall back to a content hash.
WasmEmitProducersSection Emit/merge the producers section. Defaults to true.

Tests

src/mono/wasm/Wasm.Build.Tests/NativeRebuildTests/WasmMetadataSectionsTests.cs covers the sections in dotnet.native.wasm and Webcil modules, with and without an explicitly pinned ID.

Local validation after merging current main:

  • Passed — .\build.cmd -bl -os browser -subset clr+libs+host -c Debug /p:RuntimeFlavor=CoreCLR
    • 0 warnings, 0 errors
  • Passed — .\dotnet.cmd build -bl:artifacts\log\pr130768-sample.binlog /p:TargetOS=browser /p:TargetArchitecture=wasm /p:Configuration=Debug /p:RuntimeFlavor=CoreCLR /p:WasmBuildNative=true /p:WasmNativeBuildId=1a2b3c4d5e6f7788 src\mono\sample\wasm\browser\Wasm.Browser.Sample.csproj
    • verified the relinked dotnet.native.wasm contains build_id bytes 1a2b3c4d5e6f7788
  • Blocked by test infrastructure — .\dotnet.cmd build -bl:artifacts\log\pr130768-wbt.binlog /p:TargetOS=browser /p:TargetArchitecture=wasm /p:Configuration=Debug /p:RuntimeFlavor=CoreCLR /t:Test src\mono\wasm\Wasm.Build.Tests /p:TestUsingWorkloads=false /p:InstallWorkloadForTesting=false /p:XUnitClassName=Wasm.Build.NativeRebuild.Tests.WasmMetadataSectionsTests
    • the generated test projects fail restore with NETSDK1147, requiring the wasm-tools workload before reaching the test targets

Known limitation from local validation: dotnet-producers.o is generated and included in the Emscripten response file, but the final relinked CoreCLR dotnet.native.wasm did not contain a producers section. This still needs investigation before the producers path is considered validated.

Not included / deferred

  • Stamping the default runtime-pack dotnet.native.wasm used by non-relinking applications.
  • Registration of the .NET producer names in the WebAssembly tool-conventions repository.

Design notes: docs/design/mono/wasm-custom-sections.md.

Merged current main at ced3e57460dd57581734dfd4d7888cb3e2eca028 in merge commit c157dd70460071dbb01eb27bda091b0f6262c605.

Resolves #96334
Resolves #91049

Note

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

Copilot AI and others added 2 commits July 15, 2026 10:30
Co-authored-by: pavelsavara <271576+pavelsavara@users.noreply.github.com>
Co-authored-by: pavelsavara <271576+pavelsavara@users.noreply.github.com>
Copilot AI requested review from Copilot and removed request for Copilot July 15, 2026 10:43
@azure-pipelines

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

Copilot AI review requested due to automatic review settings July 15, 2026 20:35
@pavelsavara
pavelsavara temporarily deployed to copilot-pat-pool July 15, 2026 20:35 — with GitHub Actions Inactive
@pavelsavara
pavelsavara temporarily deployed to copilot-pat-pool July 15, 2026 20:36 — with GitHub Actions Inactive

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 emitting WebAssembly tool-conventions custom sections (producers, build_id) and surfacing a buildId value through the browser-wasm JavaScript API, wiring it through the Mono/CoreCLR relink pipelines and stamping WebCIL/R2R wasm outputs.

Changes:

  • Add a reusable managed WasmCustomSectionWriter and an MSBuild task to generate a linkable wasm object contributing .NET entries to the producers section during relink.
  • Plumb WasmNativeBuildId through build targets/tasks and expose runtimeBuildInfo.buildId in the JS public API surface.
  • Add WBT coverage for relink/webcil metadata sections and a design doc describing the approach.

Reviewed changes

Copilot reviewed 38 out of 42 changed files in this pull request and generated 8 comments.

Show a summary per file
File Description
src/tasks/WasmAppBuilder/WebcilConverter.cs Exposes build-id/version passthrough to Webcil converter.
src/tasks/WasmAppBuilder/WasmEmitProducersObject.cs New task writing producers wasm object for linker merge.
src/tasks/Microsoft.NET.WebAssembly.Webcil/WebcilWasmWrapper.cs Appends producers/build_id to wrapped WebCIL wasm.
src/tasks/Microsoft.NET.WebAssembly.Webcil/WebcilConverter.cs Wires metadata options into wrapper output.
src/tasks/Microsoft.NET.WebAssembly.Webcil/Microsoft.NET.WebAssembly.Webcil.csproj Links shared custom-section writer into task assembly.
src/tasks/Microsoft.NET.Sdk.WebAssembly.Pack.Tasks/ConvertDllsToWebCil.cs Passes build-id/product version into WebCIL conversion.
src/native/rollup.config.defines.js Adds buildId rollup constant from env.
src/native/libs/System.Native.Browser/native/index.ts Overrides runtimeBuildInfo.buildId from relinked native module.
src/native/libs/System.Native.Browser/libSystem.Native.Browser.footer.js Exposes WASM_BUILD_ID via $DOTNET during emcc link.
src/native/libs/Common/JavaScript/types/public-api.ts Extends public RuntimeAPI typing with buildId.
src/native/libs/Common/JavaScript/types/ems-ambient.ts Adds buildId to emscripten ambient DOTNET shape.
src/native/libs/Common/JavaScript/loader/index.ts Seeds runtimeBuildInfo.buildId from rollup constant.
src/native/libs/Common/JavaScript/loader/dotnet.d.ts Updates generated public typings for buildId.
src/mono/wasm/Wasm.Build.Tests/NativeRebuildTests/WasmMetadataSectionsTests.cs New tests validating producers/build_id emission.
src/mono/wasm/build/WasmApp.Common.targets Forces native relink when WasmNativeBuildId is set.
src/mono/sample/wasm/Directory.Build.targets Propagates WasmNativeBuildId through nested builds.
src/mono/sample/wasm/browser-advanced/Wasm.Advanced.Sample.csproj Sample configuration updates (currently problematic).
src/mono/nuget/Microsoft.NET.Workload.Mono.Toolchain.Current.Manifest/WorkloadManifest.targets.in Treats WasmNativeBuildId as relink-triggering.
src/mono/nuget/Microsoft.NET.Sdk.WebAssembly.Pack/build/Microsoft.NET.Sdk.WebAssembly.Browser.targets Passes build-id/version into ConvertDllsToWebCIL task.
src/mono/browser/runtime/types/internal.ts Adds buildId to emscriptenBuildOptions typing.
src/mono/browser/runtime/types/index.ts Extends runtime API typing with buildId.
src/mono/browser/runtime/rollup.config.js Adds buildId constant in mono runtime rollup config.
src/mono/browser/runtime/loader/globals.ts Formatting-only changes.
src/mono/browser/runtime/loader/assets.ts Formatting-only changes.
src/mono/browser/runtime/globals.ts Copies buildId from relinked module into runtimeBuildInfo.
src/mono/browser/runtime/exports.ts Seeds runtimeBuildInfo.buildId from rollup constant.
src/mono/browser/runtime/es6/dotnet.es6.lib.js Plumbs WASM_BUILD_ID into emcc-evaluated options blob.
src/mono/browser/runtime/dotnet.d.ts Updates generated public typings for buildId.
src/mono/browser/build/BrowserWasmApp.targets Mono relink: emits producers object + build-id linker/env wiring.
src/mono/browser/build/BrowserWasmApp.CoreCLR.targets CoreCLR relink: emits producers object + build-id linker/env wiring.
src/mono/browser/browser.proj Treats WasmNativeBuildId as runtime-pack defaultable property.
src/coreclr/tools/Common/Wasm/WasmCustomSectionWriter.cs New encoder/merger for producers/build_id custom sections.
src/coreclr/tools/Common/Compiler/ObjectWriter/WasmObjectWriter.cs Stamps producers/build_id into R2R webcil wasm output.
src/coreclr/tools/aot/ILCompiler.ReadyToRun/ILCompiler.ReadyToRun.csproj Links shared custom-section writer into ILC tool.
src/coreclr/tools/aot/ILCompiler.ReadyToRun/Compiler/ReadyToRunCodegenCompilationBuilder.cs Plumbs wasm build-id option through compilation pipeline.
src/coreclr/tools/aot/ILCompiler.ReadyToRun/Compiler/ReadyToRunCodegenCompilation.cs Carries wasm build-id into object emission.
src/coreclr/tools/aot/ILCompiler.ReadyToRun/CodeGen/ReadyToRunObjectWriter.cs Passes wasm build-id through to WasmObjectWriter.
src/coreclr/tools/aot/crossgen2/Properties/Resources.resx Adds help text for new crossgen2 option.
src/coreclr/tools/aot/crossgen2/Program.cs Wires new option into ReadyToRun builder.
src/coreclr/tools/aot/crossgen2/Crossgen2RootCommand.cs Adds --wasm-native-build-id option.
src/coreclr/hosts/corerun/wasm/libCorerun.extpost.js Adds buildId field to corerun runtimeBuildInfo.
docs/design/mono/wasm-custom-sections.md Design doc describing custom section strategy and properties.

Comment on lines +113 to +114
if (moduleBytes.Length < 8 || BitConverter.ToUInt32(moduleBytes, 0) != WasmMagic)
throw new InvalidDataException("Not a WebAssembly module (bad magic).");
Comment on lines +116 to +118
uint version = BitConverter.ToUInt32(moduleBytes, 4);
if (version != 1)
throw new InvalidDataException($"Unsupported WebAssembly module version {version}.");
Comment on lines +181 to +186
if (mergedProducers is not null)
WriteProducersSection(ms, mergedProducers);

if (buildId is not null)
WriteBuildIdSection(ms, buildId);

Comment on lines 91 to 95
`runAOTCompilation: ${RUN_AOT_COMPILATION}, ` +
`wasmEnableThreads: ${!!PTHREADS}, ` +
`gitHash: "${gitHash}", ` +
`buildId: "${WASM_BUILD_ID}", ` +
`});`;
Comment on lines +61 to +65
catch (Exception ex)
{
Log.LogError($"Failed to write producers object '{OutputPath}': {ex.Message}");
return false;
}
Comment on lines 19 to 21
<WasmProfilers>browser:callspec=N:Sample</WasmProfilers>
<WasmNativeBuildId>Advanced-1a2b3c4d5e6f7788-ID</WasmNativeBuildId>

Comment on lines +444 to +445
<!-- build_id value exposed on runtimeBuildInfo.buildId; kept in sync with the wasm-ld - -build-id flag. -->
<EmscriptenEnvVars Include="WASM_BUILD_ID=$(_WasmNormalizedBuildId)" Condition="'$(_WasmNormalizedBuildId)' != ''" />
Comment on lines 147 to 150
var webcilWriter = Microsoft.WebAssembly.Build.Tasks.WebcilConverter.FromPortableExecutable(inputPath: dllFilePath, outputPath: tmpWebcil, logger: logAdapter, webcilVersion: WebcilVersion);
webcilWriter.ProductVersion = ProductVersion ?? string.Empty;
webcilWriter.BuildId = ParseBuildId(WasmNativeBuildId);
webcilWriter.ConvertToWebcil();
@pavelsavara pavelsavara changed the title [wasm] Emit producers and build_id custom sections (prototype) [wasm] Emit producers and build_id custom sections (native, webcil, R2R) Jul 15, 2026
Resolve Browser WASM custom-section conflicts with the current WebCIL writer and app-relink infrastructure.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

This branch was previously deployed

1 inactive (outdated) deployment
copilot-pat-pool — 457c3749 Deployed Jul 15, 2026 by pavelsavara via pat_pool #15245
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.

Emit Producers section when compiling to wasm Blazor - WebAssembly build_id section

3 participants