Skip to content

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

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

[wasm] Emit producers and build_id custom sections (native, webcil, R2R)#130768
pavelsavara with Copilot wants to merge 3 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.

Fixes #96334
Fixes #91049

Where the sections are emitted

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

All three reuse a single encoder — WasmCustomSectionWriter, relocated to src/coreclr/tools/Common/Wasm/ and Compile-linked into the webcil task assembly and the ReadyToRun compiler — so there is one implementation of the section encoding.

build_id

  • Emitted only when a value is provided; there is intentionally no implicit random-per-build id.
  • $(WasmNativeBuildId) (hex) pins the value and forces a native re-link for the app native path.
  • crossgen2 gains a --wasm-native-build-id option for the R2R path.

producers

Contributes language=C#, processed-by=<Mono|CoreCLR|WebCIL>, sdk=.NET. For the app native path it is delivered as a tiny relocatable object handed to wasm-ld (which merges it with clang/LLVM's own entries), keeping both sections linker-driven and consistent with how build_id is produced. Toggle with $(WasmEmitProducersSection) (default true).

JavaScript exposure

runtimeBuildInfo.buildId surfaces the native module's build_id on both Mono and CoreCLR, via the same two channels used for options like wasmEnableSIMD:

  • default dotnet.*.js build → rollup constant (consts:buildId)
  • application re-link → emscripten module + WASM_BUILD_ID env var, which overrides the constant

MSBuild properties

Property Meaning
WasmNativeBuildId Hex build id. Pins the value and forces a native re-link. Empty ⇒ no build_id for the native module (webcils fall back to a content hash).
WasmEmitProducersSection Emit/merge the producers section (default true).

Tests

src/mono/wasm/Wasm.Build.Tests/NativeRebuildTests/WasmMetadataSectionsTests.cs verifies the sections in dotnet.native.wasm (with and without a pinned id) and in webcil modules, running on both the Mono and CoreCLR legs.

Not included / deferred

  • Stamping the default runtime-pack dotnet.native.wasm (the prebuilt, non-relinked binary). Today only the app re-link path stamps the native module; non-relinked apps keep the sectionless runtime-pack binary.

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

Note

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

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