[linker] Trim Export attributes after registration. - #26313
Conversation
Remove Export, Action, and Outlet attribute instances after managed registration when static analysis proves runtime metadata fallback is unnecessary. Preserve selector access during post-processing through isolated pre-trim assemblies, and disable or reject removal when safety blockers are found. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 7d63bf91-7585-4d3e-9db4-a17531b71907
Move Export, Action, Outlet, protocol-wrapper, and NSXpc fixtures out of MySimpleApp into a dedicated iOS test application. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 7d63bf91-7585-4d3e-9db4-a17531b71907
There was a problem hiding this comment.
Pull request overview
This PR introduces an optimization to remove Foundation.ExportAttribute, Foundation.ActionAttribute, and Foundation.OutletAttribute instances after managed registration, when static analysis determines runtime metadata fallback isn’t needed. It threads a new TrimExportAttributes decision through assembly preparation/post-processing, emits a feature switch (ObjCRuntime.TrimExportAttributes) to drive ILLink attribute-instance removal, and adds tests + documentation for the new behavior.
Changes:
- Add
TrimExportAttributeseligibility computation (with explicit blockers) in the assembly-preparer pipeline and expose the result back to MSBuild. - Enable ILLink to remove Export/Action/Outlet attribute instances when
ObjCRuntime.TrimExportAttributes=true, while preserving required registrar metadata via pre-trim assemblies during post-processing. - Add unit/integration tests and document the new
TrimExportAttributesMSBuild property.
Reviewed changes
Copilot reviewed 19 out of 20 changed files in this pull request and generated 2 comments.
Show a summary per file
| File | Description |
|---|---|
| tools/mtouch/Errors.resx | Adds new MX4192 localized message for Export-attribute-removal blockers. |
| tools/mtouch/Errors.designer.cs | Adds generated accessor for MX4192. |
| tools/linker/RegistrarRemovalTrackingStep.cs | Detects NSXpcInterface MethodInfo selector-reflection usage as a blocker. |
| tools/dotnet-linker/Steps/ManagedRegistrarStep.cs | Adds blockers when managed registrar must use runtime block wrapper fallback paths. |
| tools/dotnet-linker/LinkerConfiguration.cs | Clarifies comments around DynamicRegistrationSupported and tracking step behavior. |
| tools/common/StaticRegistrar.cs | Extends attribute lookup to consult pre-trim assemblies during post-processing for selected registrar attributes. |
| tools/common/Application.cs | Adds TrimExportAttributes + TrimExportAttributesBlockers state and broadens pre-trim-resolver comments. |
| tools/assembly-preparer/ComputeExportAttributeRemovalStep.cs | New step computing eligibility, setting MSBuild output, and warning/erroring on blockers. |
| tools/assembly-preparer/AssemblyPreparer.cs | Plumbs TrimExportAttributes, adds eligibility step, and enforces registrar compatibility. |
| tests/dotnet/UnitTests/PrepareAssembliesTest.cs | Adds end-to-end build assertions for eligibility + NSXpcInterface blocker behavior. |
| tests/dotnet/ExportAttributeRemovalApp/shared.csproj | New test app shared project to validate attribute removal in assemblies. |
| tests/dotnet/ExportAttributeRemovalApp/iOS/ExportAttributeRemovalApp.csproj | New iOS test app project wrapper. |
| tests/dotnet/ExportAttributeRemovalApp/AppDelegate.cs | New test app code containing Export/Action/Outlet usage + optional NSXpcInterface path. |
| tests/common/DotNet.cs | Extends AssertBuildFailure to support specifying a target. |
| tests/assembly-preparer/ComputeExportAttributeRemovalStepTests.cs | New unit tests covering eligibility computation and blockers. |
| src/ILLink.LinkAttributes.xml.in | Adds feature-gated RemoveAttributeInstances for Export/Action/Outlet. |
| msbuild/Xamarin.Shared/Xamarin.Shared.targets | Passes TrimExportAttributes into assembly-preparer and tracks it in incremental inputs. |
| msbuild/Xamarin.MacDev.Tasks/Tasks/PrepareAssemblies.cs | Adds task plumbing for TrimExportAttributes and MSBuild output file cleanup on failure. |
| dotnet/targets/Xamarin.Shared.Sdk.targets | Enables runtime host config option based on assembly-preparer output; validates TrimExportAttributes usage. |
| docs/building-apps/build-properties.md | Documents the new TrimExportAttributes MSBuild property and behavior. |
Files not reviewed (1)
- tools/mtouch/Errors.designer.cs: Generated file
Comments suppressed due to low confidence (2)
msbuild/Xamarin.Shared/Xamarin.Shared.targets:3694
$(_TrimExportAttributes)isn't set anywhere in this targets file, so the assembly-preparer will always receive an empty value here and won't honor an explicitTrimExportAttributes=true/falseproperty. Pass$(TrimExportAttributes)directly instead.
TrimExportAttributes="$(_TrimExportAttributes)"
msbuild/Xamarin.Shared/Xamarin.Shared.targets:3747
- Same as the preparation path:
TrimExportAttributesis passed as$(_TrimExportAttributes), but that property isn't defined in this targets file, so the post-processing assembly-preparer won't see the user's setting. Pass$(TrimExportAttributes)directly.
TrimExportAttributes="$(_TrimExportAttributes)"
This comment has been minimized.
This comment has been minimized.
Use typed localized blockers, centralize Export trimming state, clarify API detection and MSBuild output ownership, and cover automatic registrar fallback behavior. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 7d63bf91-7585-4d3e-9db4-a17531b71907
✅ API diff for current PR / commitNET (empty diffs)✅ API diff vs stableNET (empty diffs)ℹ️ Generator diffGenerator Diff: vsdrops (html) vsdrops (raw diff) gist (raw diff) - Please review changes) Pipeline on Agent |
🔥 [CI Build #616fa5d] Test results 🔥Test results❌ Tests failed on VSTS: test results 0 tests crashed, 34 tests failed, 169 tests passed. Failures❌ dotnettests tests (iOS)1 tests failed, 0 tests passed.Failed tests
Html Report (VSDrops) Download ❌ linker tests (iOS)5 tests failed, 10 tests passed.Failed tests
Html Report (VSDrops) Download ❌ linker tests (MacCatalyst)5 tests failed, 10 tests passed.Failed tests
Html Report (VSDrops) Download ❌ linker tests (macOS)10 tests failed, 11 tests passed.Failed tests
Html Report (VSDrops) Download ❌ linker tests (tvOS)4 tests failed, 11 tests passed.Failed tests
Html Report (VSDrops) Download ❌ monotouch tests (iOS)2 tests failed, 17 tests passed.Failed tests
Html Report (VSDrops) Download ❌ monotouch tests (MacCatalyst)2 tests failed, 16 tests passed.Failed tests
Html Report (VSDrops) Download ❌ monotouch tests (macOS)3 tests failed, 16 tests passed.Failed tests
Html Report (VSDrops) Download ❌ monotouch tests (tvOS)2 tests failed, 17 tests passed.Failed tests
Html Report (VSDrops) Download Successes✅ assembly-processing: All 1 tests passed. Html Report (VSDrops) Download macOS tests✅ Tests on macOS Monterey (12): All 5 tests passed. Html Report (VSDrops) Download Linux Build VerificationPipeline on Agent |
Summary
Foundation.ExportAttribute,Foundation.ActionAttribute, andFoundation.OutletAttributeinstances through theObjCRuntime.TrimExportAttributesILLink feature after the managed registrar has consumed them.TrimExportAttributesMSBuild property: unset enables automatic removal,truerequires removal, andfalsepreserves the attributes.ExportAttributeRemovalAppintegration-test fixture.Safety
Removal is considered only when
PrepareAssemblies=true,PostProcessAssemblies=true, andRegistrar=trimmable-static. It is enabled only when dynamic registration is unsupported, theblockliteral-setupblockandstatic-block-to-delegate-lookupoptimizations are enabled, the managed registrar emits no reflective block/delegate fallback, and the app does not use theNSXpcInterfaceoverloads that obtain selectors fromMethodInfo.In automatic mode, each blocker emits its corresponding warning (MX4192-MX4197) and preserves the attributes. When removal is explicitly enabled, the same diagnostics are errors. Explicitly disabling removal preserves the existing behavior without diagnostics.
Validation
ComputeExportAttributeRemovalStepTestscases.ExportAttributeRemovalEligibilityandExportAttributeRemovalWithNSXpcInterfaceUsageintegration cases.Xamarin.MacDev.Tasksbuilds fornet10.0andnetstandard2.0.In the test fixture, Export-derived instances drop from 122 to 0 in
Microsoft.iOS.dlland from 3 to 0 in the app assembly. The strippedMicrosoft.iOS.dlldecreases from 130,048 to 81,920 bytes (48,128 bytes, or 37%).Fixes #16678
🤖 Pull request created by Copilot