dotnet / dotnet/runtime

[Browser][CoreCLR] publish+workload should not trigger native relink unless there is new UCO/PInvoke

Open
#132,777 4 comments 0 reactions 2 assignees Claimed by @radekdoulik View on GitHub
arch-wasm area-Build-mono
Dominant language
C#
Stars
18.3k
Forks
5.6k
PR merge metrics
PR metrics pending

Description

## Problem

For a trimmed `Release` nested publish (all library-test legs, and any published Browser CoreCLR app), `WasmBuildNative` defaults to `true` in `_CoreCLRSetWasmBuildNativeDefaults` (`src/mono/browser/build/BrowserWasmApp.CoreCLR.targets`):

```xml

false
true

```

This triggers a full `emcc` relink of `dotnet.native.wasm` **and** the `ManagedToNativeGenerator` scan of the entire bundled managed closure.

But the relink only bakes **app-contributed** reverse thunks / module imports. The runtime pack already ships every framework `[UnmanagedCallersOnly]` reverse thunk and P/Invoke table. So when the app adds:

- no `[UnmanagedCallersOnly]` / `[JSExport]` callbacks,
- no `[WasmImportLinkage]` P/Invokes, and
- no `NativeFileReference` / `NativeLibrary`,

…the relinked `dotnet.native.wasm` is effectively identical to the pack's, and both the relink and the scan are wasted work.

### Side effects of the unnecessary relink

- Large build-time cost per test/app (`emcc` relink).
- The closure scan surfaces `WASM0066` for every foreign-platform `DllImport` in the closure (`kernel32`, `ntdll`, `advapi32`, `Security.framework`, `libsecret`, `libc`, …). These are correctly handled at runtime (throw-if-called), but fail the build under warn-as-error.

## Proposed solution

Make the relink **demand-driven**:

1. Add a cheap detection pass over the **app's own assemblies** (not the whole framework closure) for:
- `[UnmanagedCallersOnly]` / `[JSExport]` callbacks, and
- `[WasmImportLinkage]` P/Invokes.
2. Gate `WasmBuildNative` on `(that detection) OR (NativeFileReference/NativeLibrary present)`. The `NativeFileReference` / `NativeLibrary` trigger already exists; this replaces the coarse `Configuration == Release` heuristic with a real "does the app add native surface?" signal.

The detection can reuse `PInvokeCollector` restricted to the app's assemblies, or a lighter attribute-only metadata check — scanning only the app assemblies is sufficient because the pack already contains all framework thunks.

### Where

- `src/mono/browser/build/BrowserWasmApp.CoreCLR.targets` — `_CoreCLRSetWasmBuildNativeDefaults`, `_CoreCLRGenerateManagedToNative`.
- `src/tasks/WasmAppBuilder/coreclr/PInvokeCollector.cs`.
- The WASI sibling `src/mono/wasi/build/WasiApp.CoreCLR.targets` has the same shape and should get the same treatment.

> [!NOTE]
> This issue was drafted with GitHub Copilot.

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.