Skip to content

[dotnet] Fix latent trimmable-static registrar bugs on non-NativeAOT runtimes - #26344

Open
rolfbjarne wants to merge 4 commits into
mainfrom
dev/rolf/trimmable-static-latent-fixes
Open

[dotnet] Fix latent trimmable-static registrar bugs on non-NativeAOT runtimes#26344
rolfbjarne wants to merge 4 commits into
mainfrom
dev/rolf/trimmable-static-latent-fixes

Conversation

@rolfbjarne

@rolfbjarne rolfbjarne commented Jul 29, 2026

Copy link
Copy Markdown
Member

Two latent bugs that only show up when the trimmable-static registrar is used on a runtime other than NativeAOT (they were found while measuring app size with Registrar=trimmable-static on CoreCLR and Mono).

1. ObjCRuntime.TrimProtocolMemberAttributes was set too early, and unconditionally

The feature switch that lets the trimmer remove [ProtocolMember] attributes was set in _ComputeLinkerInputs, gated only on Registrar == trimmable-static And PrepareAssemblies == true.

The dynamic registrar reads those attributes reflectively at runtime, so when the dynamic registrar is still present the trimmer errors out with IL2045. Whether the dynamic registrar is present is only known after _SetDynamicRegistrationSupportedFeature has run, so the item is moved into that target and gated on _DynamicRegistrationSupported == false instead.

2. ILStrip failed on the generated TypeMap assemblies

Some ResolvedFileToPublish items don't have OriginalRelativePath metadata — the TypeMap assemblies the trimmable-static registrar generates are one such case. The OutputPath expression then collapsed to the bare stripped directory, and ILStrip failed with Access to the path '.../stripped/' is denied. Fall back to the file name when OriginalRelativePath is empty.

The second commit fixes the batching of that fallback: the condition referenced %(ResolvedFileToPublish.OriginalRelativePath) while modifying @(_AssembliesToBeStripped), which makes MSBuild batch over the wrong item type — a single publish item without OriginalRelativePath would have applied the fallback OutputPath to every assembly.

Notes

🤖 Pull request created by Copilot

…runtimes.

Two fixes for building with an explicit 'Registrar=trimmable-static' on Mono/CoreCLR
(these paths aren't hit by the NativeAOT default, but the registrar is a supported
option on the other runtimes):

- Only tell the trimmer to remove [ProtocolMember] attributes when the dynamic
  registrar has been removed (DynamicRegistrationSupported == false). The dynamic
  registrar reads these attributes via reflection at runtime, so trimming them while
  it's present errors out with IL2045. The option is moved into
  _SetDynamicRegistrationSupportedFeature so the computed _DynamicRegistrationSupported
  value is available (it isn't yet in _ComputeLinkerInputs). NativeAOT is unaffected
  (DynamicRegistrationSupported is always false there, so the attributes are still
  trimmed).

- Fall back to the file name in _StripAssemblyIL when a ResolvedFileToPublish item has
  no OriginalRelativePath (e.g. the generated TypeMap assemblies). Otherwise the strip
  OutputPath collapsed to the bare stripped directory and ILStrip failed with
  'Access to the path .../stripped/ is denied'.

Also updates the SelectRegistrar comment to note NativeAOT defaults to trimmable-static
on .NET 11+ (set earlier, in Xamarin.Shared.Sdk.props).
The condition referenced %(ResolvedFileToPublish.OriginalRelativePath) while
modifying @(_AssembliesToBeStripped), which makes MSBuild batch over
ResolvedFileToPublish instead of the items being modified: a single publish item
without OriginalRelativePath would have applied the fallback OutputPath to every
assembly, throwing away the valid relative paths.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 6aeeddfd-3bd8-4129-ad90-7292860c4b66
@vs-mobiletools-engineering-service2

This comment has been minimized.

@rolfbjarne
rolfbjarne marked this pull request as ready for review July 29, 2026 14:47
Copilot AI review requested due to automatic review settings July 29, 2026 14:47

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 updates the .NET SDK MSBuild targets to fix a couple of issues in the trimmable-static registrar pipeline, particularly around when it’s safe to trim [ProtocolMember] attributes and a publish-time IL stripping failure caused by missing OriginalRelativePath metadata.

Changes:

  • Gate ObjCRuntime.TrimProtocolMemberAttributes on DynamicRegistrationSupported == false (computed from assembly-preparer output) to avoid trimming attributes needed by the dynamic registrar at runtime.
  • Move the TrimProtocolMemberAttributes feature switch configuration to the point where _DynamicRegistrationSupported is known (inside _SetDynamicRegistrationSupportedFeature).
  • Fix _StripAssemblyIL output path computation when ResolvedFileToPublish.OriginalRelativePath is missing by falling back to %(Filename)%(Extension).

@vs-mobiletools-engineering-service2

This comment has been minimized.

@rolfbjarne
rolfbjarne enabled auto-merge (squash) July 29, 2026 17:57
@vs-mobiletools-engineering-service2

This comment has been minimized.

rolfbjarne and others added 2 commits July 30, 2026 09:44
… removed.

The trimmable-static registrar only tells the trimmer to remove the
[ProtocolMember] attributes (which reference generic types like NSSet<T> in
optional protocol members) when the dynamic registrar has been removed - it
reads these attributes via reflection at runtime, so they're kept when it's
present. When the attributes aren't trimmed, NSSet<T> stays too, so the
LinkedAwayGenericTypeAsOptionalMemberInProtocol test has nothing to verify.

Ignore the test in that case (e.g. the prepare-assemblies|coreclr|trimmable-
static-registrar variation on macOS, where DynamicRegistrationSupported is
true), instead of failing.

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

Copy link
Copy Markdown
Collaborator

✅ API diff for current PR / commit

NET (empty diffs)

✅ API diff vs stable

NET (empty diffs)

ℹ️ Generator diff

Generator Diff: vsdrops (html) vsdrops (raw diff) gist (raw diff) - Please review changes)

Pipeline on Agent
Hash: 02407bde6ecaa878eb20c1d9987c1639a1b93094 [PR build]

@vs-mobiletools-engineering-service2

Copy link
Copy Markdown
Collaborator

🔥 [CI Build #02407bd] Test results 🔥

Test results

❌ Tests failed on VSTS: test results

0 tests crashed, 6 tests failed, 197 tests passed.

Failures

❌ monotouch tests (iOS)

4 tests failed, 15 tests passed.

Failed tests

  • monotouch-test/iOS - simulator/Release (NativeAOT): Failed
  • monotouch-test/iOS - simulator/Release (managed static registrar, all optimizations): Failed
  • monotouch-test/iOS - simulator/Release (strict inline dlfcn, link sdk): Failed
  • monotouch-test/iOS - simulator/Release (NativeAOT, .NET 11 defaults): Failed

Html Report (VSDrops) Download

❌ monotouch tests (macOS)

2 tests failed, 17 tests passed.

Failed tests

  • monotouch-test/macOS/Debug: Failed (Test run failed.
    Tests run: 3739 Passed: 3608 Inconclusive: 13 Failed: 1 Ignored: 130)
  • monotouch-test/macOS/Debug (PrepareAssemblies, inline dlfcn, dont link): Failed (Test run failed.
    Tests run: 3739 Passed: 3608 Inconclusive: 13 Failed: 1 Ignored: 130)

Html Report (VSDrops) Download

Successes

✅ assembly-processing: All 1 tests passed. Html Report (VSDrops) Download
✅ cecil: All 1 tests passed. Html Report (VSDrops) Download
✅ dotnettests (iOS): All 1 tests passed. Html Report (VSDrops) Download
✅ dotnettests (MacCatalyst): All 1 tests passed. Html Report (VSDrops) Download
✅ dotnettests (macOS): All 1 tests passed. Html Report (VSDrops) Download
✅ dotnettests (Multiple platforms): All 1 tests passed. Html Report (VSDrops) Download
✅ dotnettests (tvOS): All 1 tests passed. Html Report (VSDrops) Download
✅ framework: All 2 tests passed. Html Report (VSDrops) Download
✅ fsharp: All 4 tests passed. Html Report (VSDrops) Download
✅ generator: All 5 tests passed. Html Report (VSDrops) Download
✅ interdependent-binding-projects: All 4 tests passed. Html Report (VSDrops) Download
✅ introspection: All 4 tests passed. Html Report (VSDrops) Download
✅ linker (iOS): All 15 tests passed. Html Report (VSDrops) Download
✅ linker (MacCatalyst): All 15 tests passed. Html Report (VSDrops) Download
✅ linker (macOS): All 21 tests passed. Html Report (VSDrops) Download
✅ linker (tvOS): All 15 tests passed. Html Report (VSDrops) Download
✅ monotouch (MacCatalyst): All 18 tests passed. Html Report (VSDrops) Download
✅ monotouch (tvOS): All 19 tests passed. Html Report (VSDrops) Download
✅ msbuild: All 2 tests passed. Html Report (VSDrops) Download
✅ sharpie: All 1 tests passed. Html Report (VSDrops) Download
✅ windows: All 3 tests passed. Html Report (VSDrops) Download
✅ xcframework: All 4 tests passed. Html Report (VSDrops) Download
✅ xtro: All 1 tests passed. Html Report (VSDrops) Download

macOS tests

✅ Tests on macOS Monterey (12): All 5 tests passed. Html Report (VSDrops) Download
✅ Tests on macOS Ventura (13): All 5 tests passed. Html Report (VSDrops) Download
✅ Tests on macOS Sonoma (14): All 5 tests passed. Html Report (VSDrops) Download
✅ Tests on macOS Sequoia (15): All 5 tests passed. Html Report (VSDrops) Download
✅ Tests on macOS Tahoe (26): All 5 tests passed. Html Report (VSDrops) Download

Linux Build Verification

Linux build succeeded

Pipeline on Agent
Hash: 02407bde6ecaa878eb20c1d9987c1639a1b93094 [PR build]

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants