Uh oh!
There was an error while loading. Please reload this page.
Fix XALNS7015: run FixAbstractMethodsStep before R2R in non-trimmed CoreCLR builds - #11027
Fix XALNS7015: run FixAbstractMethodsStep before R2R in non-trimmed CoreCLR builds#11027simonrozsival wants to merge 2 commits into
Conversation
There was a problem hiding this comment.
Pull request overview
Fixes the CoreCLR Release (non-trimmed) PublishReadyToRun=true build failure where FixAbstractMethodsStep tries to rewrite an already-R2R’d assembly and Mono.Cecil throws NotSupportedException for mixed-mode output.
Changes:
- Run
PostTrimmingPipelinebefore crossgen2/ReadyToRun for both trimmed and non-trimmedPublishReadyToRunbuilds, enablingFixAbstractMethodsonly in the non-trimmed path. - Update
PostTrimmingPipelineto optionally includeFixAbstractMethodsStepand mark processed assemblies as Android/user assemblies inStepContext. - Re-enable previously ignored CoreCLR test cases and add a unit regression test for
FixAbstractMethodsbehavior viaPostTrimmingPipeline.
Reviewed changes
Copilot reviewed 4 out of 4 changed files in this pull request and generated 4 comments.
| File | Description |
|---|---|
| src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/Tasks/LinkerTests.cs | Adds a regression unit test validating PostTrimmingPipeline can inject a missing abstract-method stub. |
| src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/BuildTest.cs | Removes the CoreCLR non-trimmed ignore workaround now that the pipeline should run pre-R2R. |
| src/Xamarin.Android.Build.Tasks/Tasks/PostTrimmingPipeline.cs | Adds FixAbstractMethods support and updates StepContext flags so FixAbstractMethodsStep can run. |
| src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.TypeMap.LlvmIr.targets | Extends _PostTrimmingPipeline to also run for non-trimmed R2R builds and wires FixAbstractMethods into the task call. |
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
simonrozsival
commented
Mar 31, 2026
Replying to the Copilot review comments — the implementation was reworked in commits 3-4, so all four comments are now outdated. Resolving them below. |
5e65810 to
6469db8Compare…builds Move _LinkAssembliesNoShrink from the outer build into the inner (per-RID) build using BeforeTargets="_PrepareForReadyToRunCompilation". This ensures assembly modifications (FixAbstractMethods, AddKeepAlives, FindJavaObjects, etc.) operate on pure IL assemblies BEFORE crossgen2 creates R2R images, preventing Mono.Cecil from attempting to write mixed-mode assemblies. Changes: - Rewrite _LinkAssembliesNoShrink to run in the inner build, consuming @(ResolvedFileToPublish) instead of @(ResolvedAssemblies), writing to an intermediate linked-noshrink/ directory - Properly classify framework vs user assemblies by known names (matching the trimmed path in _AfterILLinkAdditionalSteps) - Update ResolvedFileToPublish so R2R and publish consume modified copies - Simplify _PrepareAssemblies: populate _ResolvedAssemblies unconditionally from @(ResolvedAssemblies) (no longer redirect through intermediate dir) - Extend _CopySidecarXmlToAssemblyPaths to handle both trimmed (linked/) and non-trimmed (android/linked-noshrink/) sidecar XML files - Remove _LinkAssembliesNoShrink from _LinkAssemblies DependsOnTargets - Remove Assert.Ignore workarounds in BuildTest.SimilarAndroidXAssemblyNames and LinkerTests.AndroidAddKeepAlives for CoreCLR non-trimmed Release builds Fixes: #11025 Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
6469db8 to
ebcf2bdCompare
simonrozsival
left a comment
There was a problem hiding this comment.
🤖 AI Review Summary
Verdict:
Found 2 issues: 1 warning, 1 suggestion — no blocking bugs.
⚠️ MSBuild targets: MissingInputs/Outputson_LinkAssembliesNoShrink— the target runs every inner build even when assemblies haven't changed (Xamarin.Android.Common.targets:1439)- 💡 MSBuild targets: Duplicate
FileWritesglob — the wildcard glob$(_LinkAssembliesNoShrinkDir)**already covers the per-file FileWrites on subsequent lines (Xamarin.Android.Common.targets:1501)
👍 What's great about this PR:
- Correct root cause fix: running assembly modifications before R2R in the inner build prevents the Mono.Cecil
NotSupportedExceptionon mixed-mode assemblies - Proper framework/user assembly classification matching the trimmed path (4 known framework assembly names)
HasMonoAndroidReference=trueis correctly scoped to only the root assembly (%(Filename) == $(TargetName)) instead of blanket-set on all DLLs- Clean generalization of
_CopySidecarXmlToAssemblyPathswith$(_SidecarSubDir)to handle both trimmed (linked/) and non-trimmed (android/linked-noshrink/) paths - Good simplification of
_PrepareAssemblies— unconditional population of_ResolvedAssembliesremoves the confusingMonoAndroidIntermediateAssemblyDirredirect - Test cleanup: removing
Assert.Ignoreworkarounds confirms the fix addresses the root cause
Review generated by android-reviewer from review guidelines.
| --> | ||
| <Target Name="_LinkAssembliesNoShrink" | ||
| BeforeTargets="_PrepareForReadyToRunCompilation" | ||
| Condition=" '$(PublishTrimmed)' != 'true' and '$(_ComputeFilesToPublishForRuntimeIdentifiers)' == 'true' "> |
There was a problem hiding this comment.
🤖 Inputs/Outputs, so it runs on every inner build even when assemblies haven't changed. The trimmed counterpart (_AfterILLinkAdditionalSteps) uses Inputs="$(_LinkSemaphore)" / Outputs="$(_AdditionalPostLinkerStepsFlag)" for incrementality.
For the non-trimmed path, consider using Inputs="$(_AndroidBuildPropertiesCache)" or a similar stamp, and Outputs="$(_LinkAssembliesNoShrinkDir)noshrink.flag" (touched at the end). Without this, SaveChangedAssemblyStep will re-stamp assembly timestamps on every build, cascading through _GenerateJavaStubs → _CompileJava → _CompileToDalvik → _BuildApkEmbed → _Sign.
Rule: Incremental builds (Inputs/Outputs)
| <ItemGroup> | ||
| <ResolvedFileToPublish Remove="@(_LinkNoShrinkAllAssemblies)" /> | ||
| <ResolvedFileToPublish Include="@(_LinkNoShrinkAllAssemblies->'$(_LinkAssembliesNoShrinkDir)%(RelativePath)')" /> | ||
| <FileWrites Include="$(_LinkAssembliesNoShrinkDir)**" /> |
There was a problem hiding this comment.
🤖 💡 MSBuild targets — The glob $(_LinkAssembliesNoShrinkDir)** already covers all files in the directory, including the DLLs, .jlo.xml, and .typemap.xml files listed in the subsequent <FileWrites> block (lines 1505-1507). The per-file entries are redundant. Consider keeping only the glob, or only the per-file entries (which are more explicit and don't risk over-matching).
Rule: Don't duplicate item group transforms
…ileWrites - Add Inputs/Outputs to _LinkAssembliesNoShrink using @(IntermediateAssembly) and $(_AndroidBuildPropertiesCache) as inputs, and a stamp file as output. This prevents SaveChangedAssemblyStep from re-stamping assembly timestamps on every build, which would cascade through downstream targets. - Touch stamp file after successful completion. - Remove duplicate FileWrites entries — the glob $(_LinkAssembliesNoShrinkDir)** already covers all files in the directory. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
jonathanpeppers
commented
Apr 2, 2026
/azp run Xamarin.Android-PR |
|
No pipelines are associated with this pull request. |
simonrozsival
commented
May 14, 2026
We should revisit this at some point, but this PR is already stale. |
Summary
Fixes#11025
Rebased on top of #10891 + #11058 (branch:
dev/sbomer/merge-pipelines).In non-trimmed CoreCLR Release builds,
PublishReadyToRun=truecauses the inner build to compile IL assemblies to R2R images (via crossgen2) before_LinkAssembliesNoShrinkruns. R2R assemblies have the ILONLY PE flag cleared, so whenFixAbstractMethodsStepdetects a missing abstract method and marks the assembly modified,SaveChangedAssemblyStepcallsassembly.Write()via Mono.Cecil, which throws:Changes
Fix: move
_LinkAssembliesNoShrinkto run before R2R compilation in the inner buildThe previous
_LinkAssembliesNoShrinktarget ran in the outer build using@(ResolvedAssemblies)and copied modified assemblies to an intermediate directory. This happened too late — the inner build had already produced R2R images by that point.The fix restructures
_LinkAssembliesNoShrinkto run inside the inner build (BeforeTargets="_PrepareForReadyToRunCompilation"):Xamarin.Android.Common.targets: Rewrite_LinkAssembliesNoShrinkto run in the inner build when trimming is disabled. It operates on@(ResolvedFileToPublish)(available in the inner build) instead of@(ResolvedAssemblies)(outer build only). Assemblies are copied to an intermediate directory (linked-noshrink/) rather than modified in-place, sinceResolvedFileToPublishitems may point to shared locations (NuGet cache, runtime packs). After the task runs,ResolvedFileToPublishis updated so R2R and publish consume the modified copies._CopySidecarXmlToAssemblyPathsto handle both trimmed (linked/) and non-trimmed (android/linked-noshrink/) sidecar XML files using a$(_SidecarSubDir)property.Microsoft.Android.Sdk.AssemblyResolution.targets: In_PrepareAssemblies, populate_ResolvedAssembliesetc. unconditionally from@(ResolvedAssemblies)(no longer redirecting through the intermediate directory for non-trimmed builds).Tests
Assert.Ignoreworkarounds inBuildTest.SimilarAndroidXAssemblyNamesandLinkerTests.AndroidAddKeepAlivesfor the CoreCLR Release non-trimmed case — these scenarios now pass.Depends on
_AfterILLinkAdditionalSteps(trimmed path) to the inner build