Skip to content

Commit 6469db8

Browse files
Fix XALNS7015: run _LinkAssembliesNoShrink before R2R in non-trimmed CoreCLR builds
In non-trimmed CoreCLR Release builds, PublishReadyToRun=true causes the inner build to compile IL assemblies to R2R images (via crossgen2) before _LinkAssembliesNoShrink runs. R2R assemblies have the ILONLY PE flag cleared, so when FixAbstractMethodsStep detects a missing abstract method and marks the assembly modified, SaveChangedAssemblyStep calls assembly.Write() via Mono.Cecil, which throws: NotSupportedException: Writing mixed-mode assemblies is not supported The fix restructures _LinkAssembliesNoShrink to run inside the inner build (BeforeTargets=_PrepareForReadyToRunCompilation) so assembly modifications happen before R2R compilation: - Xamarin.Android.Common.targets: Rewrite _LinkAssembliesNoShrink to run in the inner build. It copies assemblies to an intermediate directory (linked-noshrink/) instead of modifying in-place, since ResolvedFileToPublish items may point to shared locations (NuGet cache, runtime packs). After the task runs, ResolvedFileToPublish is updated to point to the intermediate copies. Abi metadata is computed via RuntimeIdentifierToAbi since _ResolveAndroidTooling doesn't run in the inner build. - Microsoft.Android.Sdk.AssemblyResolution.targets: In _PrepareAssemblies, populate _ResolvedAssemblies unconditionally from @(ResolvedAssemblies) instead of redirecting through the intermediate directory for non-trimmed builds. - Remove Assert.Ignore workarounds in BuildTest and LinkerTests for the CoreCLR Release non-trimmed case. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
1 parent 12dd07b commit 6469db8

File tree

4 files changed

+51
-55
lines changed

4 files changed

+51
-55
lines changed

src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.AssemblyResolution.targets

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -207,20 +207,18 @@ _ResolveAssemblies MSBuild target.
207207

208208
<Target Name="_PrepareAssemblies"
209209
DependsOnTargets="$(_PrepareAssembliesDependsOnTargets)">
210+
<ItemGroup>
211+
<_ResolvedAssemblies Include="@(ResolvedAssemblies)" />
212+
<_ResolvedUserAssemblies Include="@(ResolvedUserAssemblies)" />
213+
<_ResolvedFrameworkAssemblies Include="@(ResolvedFrameworkAssemblies)" />
214+
<_ResolvedSymbols Include="@(ResolvedSymbols)" />
215+
</ItemGroup>
210216
<ItemGroup Condition=" '$(PublishTrimmed)' != 'true' ">
211-
<_ResolvedAssemblies Include="@(ResolvedAssemblies->'$(MonoAndroidIntermediateAssemblyDir)%(DestinationSubPath)')" Condition=" '%(DestinationSubPath)' != '' " />
212-
<_ResolvedUserAssemblies Include="@(ResolvedUserAssemblies->'$(MonoAndroidIntermediateAssemblyDir)%(DestinationSubPath)')" Condition=" '%(DestinationSubPath)' != '' " />
213-
<_ResolvedFrameworkAssemblies Include="@(ResolvedFrameworkAssemblies->'$(MonoAndroidIntermediateAssemblyDir)%(DestinationSubPath)')" Condition=" '%(DestinationSubPath)' != '' " />
214-
<_ResolvedSymbols Include="@(ResolvedSymbols->'$(MonoAndroidIntermediateAssemblyDir)%(DestinationSubPath)')" Condition=" '%(DestinationSubPath)' != '' " />
215217
<_ShrunkAssemblies Include="@(_ResolvedAssemblies)" />
216218
<_ShrunkUserAssemblies Include="@(_ResolvedUserAssemblies)" />
217219
<_ShrunkFrameworkAssemblies Include="@(_ResolvedFrameworkAssemblies)" />
218220
</ItemGroup>
219221
<ItemGroup Condition=" '$(PublishTrimmed)' == 'true' ">
220-
<_ResolvedAssemblies Include="@(ResolvedAssemblies)" />
221-
<_ResolvedUserAssemblies Include="@(ResolvedUserAssemblies)" />
222-
<_ResolvedFrameworkAssemblies Include="@(ResolvedFrameworkAssemblies)" />
223-
<_ResolvedSymbols Include="@(ResolvedSymbols)" />
224222
<_ShrunkFrameworkAssemblies
225223
Include="@(_ShrunkAssemblies)"
226224
Condition=" '%(_ShrunkAssemblies.FrameworkAssembly)' == 'true' "

src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/BuildTest.cs

Lines changed: 0 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -2178,21 +2178,6 @@ public void CheckLintResourceFileReferencesAreFixed ([Values] AndroidRuntime run
21782178
// TODO: [TestCase (false, AndroidRuntime.NativeAOT)]
21792179
public void SimilarAndroidXAssemblyNames (bool publishTrimmed, AndroidRuntime runtime)
21802180
{
2181-
if (!publishTrimmed && runtime == AndroidRuntime.CoreCLR) {
2182-
// This currently fails with the following exception:
2183-
//
2184-
// error XALNS7015: System.NotSupportedException: Writing mixed-mode assemblies is not supported
2185-
// at Mono.Cecil.ModuleWriter.Write(ModuleDefinition module, Disposable`1 stream, WriterParameters parameters)
2186-
// at Mono.Cecil.ModuleWriter.WriteModule(ModuleDefinition module, Disposable`1 stream, WriterParameters parameters)
2187-
// at Mono.Cecil.ModuleDefinition.Write(String fileName, WriterParameters parameters)
2188-
// at Mono.Cecil.AssemblyDefinition.Write(String fileName, WriterParameters parameters)
2189-
// at Xamarin.Android.Tasks.SaveChangedAssemblyStep.ProcessAssembly(AssemblyDefinition assembly, StepContext context) in src/Xamarin.Android.Build.Tasks/Tasks/AssemblyModifierPipeline.cs:line 197
2190-
// at Xamarin.Android.Tasks.AssemblyPipeline.Run(AssemblyDefinition assembly, StepContext context) in src/Xamarin.Android.Build.Tasks/Utilities/AssemblyPipeline.cs:line 26
2191-
// at Xamarin.Android.Tasks.AssemblyModifierPipeline.RunPipeline(AssemblyPipeline pipeline, ITaskItem source, ITaskItem destination) in src/Xamarin.Android.Build.Tasks/Tasks/AssemblyModifierPipeline.cs:line 175
2192-
Assert.Ignore ("CoreCLR: fails because of a Mono.Cecil lack of support");
2193-
return;
2194-
}
2195-
21962181
bool aotAssemblies = runtime == AndroidRuntime.MonoVM && publishTrimmed;
21972182
var proj = new XamarinAndroidApplicationProject {
21982183
IsRelease = true,

src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/Tasks/LinkerTests.cs

Lines changed: 0 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -469,22 +469,6 @@ public void AndroidAddKeepAlives (bool isRelease, bool setAndroidAddKeepAlivesTr
469469
return;
470470
}
471471

472-
if (runtime == AndroidRuntime.CoreCLR && isRelease && !setAndroidAddKeepAlivesTrue && setLinkModeNone && shouldAddKeepAlives) {
473-
// This currently fails with the following exception:
474-
//
475-
// error XALNS7015: System.NotSupportedException: Writing mixed-mode assemblies is not supported
476-
// at Mono.Cecil.ModuleWriter.Write(ModuleDefinition module, Disposable`1 stream, WriterParameters parameters)
477-
// at Mono.Cecil.ModuleWriter.WriteModule(ModuleDefinition module, Disposable`1 stream, WriterParameters parameters)
478-
// at Mono.Cecil.ModuleDefinition.Write(String fileName, WriterParameters parameters)
479-
// at Mono.Cecil.AssemblyDefinition.Write(String fileName, WriterParameters parameters)
480-
// at Xamarin.Android.Tasks.SaveChangedAssemblyStep.ProcessAssembly(AssemblyDefinition assembly, StepContext context) in src/Xamarin.Android.Build.Tasks/Tasks/AssemblyModifierPipeline.cs:line 197
481-
// at Xamarin.Android.Tasks.AssemblyPipeline.Run(AssemblyDefinition assembly, StepContext context) in src/Xamarin.Android.Build.Tasks/Utilities/AssemblyPipeline.cs:line 26
482-
// at Xamarin.Android.Tasks.AssemblyModifierPipeline.RunPipeline(AssemblyPipeline pipeline, ITaskItem source, ITaskItem destination) in src/Xamarin.Android.Build.Tasks/Tasks/AssemblyModifierPipeline.cs:line 175
483-
// at Xamarin.Android.Tasks.AssemblyModifierPipeline.RunTask() in src/Xamarin.Android.Build.Tasks/Tasks/AssemblyModifierPipeline.cs:line 123
484-
Assert.Ignore ("CoreCLR: fails because of a Mono.Cecil lack of support");
485-
return;
486-
};
487-
488472
var proj = new XamarinAndroidApplicationProject {
489473
IsRelease = isRelease,
490474
OtherBuildItems = {

src/Xamarin.Android.Build.Tasks/Xamarin.Android.Common.targets

Lines changed: 45 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1419,47 +1419,76 @@ because xbuild doesn't support framework reference assemblies.
14191419
<Error Text="%24(AndroidGenerateJniMarshalMethods)=True is not supported at this time." />
14201420
</Target>
14211421

1422-
<Target Name="_LinkAssembliesNoShrinkInputs">
1422+
<!--
1423+
Inner build only: runs assembly modifications (FixAbstractMethods, AddKeepAlives, etc.)
1424+
BEFORE crossgen2 creates R2R images. ResolvedAssemblies is empty in the inner build
1425+
because the Android-specific _ResolveAssemblies target only runs in the outer build,
1426+
so we gather assemblies from ResolvedFileToPublish instead.
1427+
1428+
Mark every DLL as HasMonoAndroidReference so FixAbstractMethodsStep inspects them;
1429+
the step's own MightNeedFix() guard (IsSubclassOf("Java.Lang.Object")) filters out
1430+
non-binding types.
1431+
1432+
Assemblies are copied to an intermediate directory (not modified in-place) because
1433+
ResolvedFileToPublish items may point to shared locations (NuGet cache, runtime packs)
1434+
that must not be mutated. After the task runs, ResolvedFileToPublish is updated to
1435+
point to the intermediate copies so that downstream targets (R2R, publish) pick them up.
1436+
-->
1437+
<Target Name="_LinkAssembliesNoShrink"
1438+
BeforeTargets="_PrepareForReadyToRunCompilation"
1439+
Condition=" '$(PublishTrimmed)' != 'true' and '$(_ComputeFilesToPublishForRuntimeIdentifiers)' == 'true' ">
1440+
<PropertyGroup>
1441+
<_LinkAssembliesNoShrinkDir>$(IntermediateOutputPath)android\linked-noshrink\</_LinkAssembliesNoShrinkDir>
1442+
</PropertyGroup>
1443+
<!-- Compute ABI from RuntimeIdentifier since _ResolveAndroidTooling doesn't run in the inner build -->
1444+
<RuntimeIdentifierToAbi RuntimeIdentifier="$(RuntimeIdentifier)">
1445+
<Output TaskParameter="SupportedAbis" PropertyName="_LinkAssembliesNoShrinkAbi" />
1446+
</RuntimeIdentifierToAbi>
14231447
<ItemGroup>
1424-
<!-- We need this in its own item group so it isn't lost during a partial build -->
1425-
<_AllResolvedAssemblies Include="@(ResolvedAssemblies)" />
1448+
<_ResolvedFileToPublishDlls Include="@(ResolvedFileToPublish)" Condition=" '%(Extension)' == '.dll' ">
1449+
<HasMonoAndroidReference>True</HasMonoAndroidReference>
1450+
<Abi>$(_LinkAssembliesNoShrinkAbi)</Abi>
1451+
</_ResolvedFileToPublishDlls>
14261452
</ItemGroup>
1427-
</Target>
14281453

1429-
<Target Name="_LinkAssembliesNoShrink"
1430-
DependsOnTargets="_LinkAssembliesNoShrinkInputs"
1431-
Condition="'$(PublishTrimmed)' != 'true'"
1432-
Inputs="@(ResolvedAssemblies);$(_AndroidBuildPropertiesCache)"
1433-
Outputs="@(ResolvedAssemblies->'$(MonoAndroidIntermediateAssemblyDir)%(DestinationSubPath)')">
14341454
<LinkAssembliesNoShrink
14351455
ApplicationJavaClass="$(AndroidApplicationJavaClass)"
14361456
CodeGenerationTarget="$(AndroidCodegenTarget)"
14371457
Debug="$(AndroidIncludeDebugSymbols)"
14381458
EnableMarshalMethods="$(_AndroidUseMarshalMethods)"
14391459
ErrorOnCustomJavaObject="$(AndroidErrorOnCustomJavaObject)"
14401460
PackageNamingPolicy="$(AndroidPackageNamingPolicy)"
1441-
ResolvedAssemblies="@(_AllResolvedAssemblies)"
1442-
ResolvedUserAssemblies="@(ResolvedUserAssemblies)"
1443-
SourceFiles="@(ResolvedAssemblies)"
1444-
DestinationFiles="@(ResolvedAssemblies->'$(MonoAndroidIntermediateAssemblyDir)%(DestinationSubPath)')"
1461+
ResolvedAssemblies="@(_ResolvedFileToPublishDlls)"
1462+
ResolvedUserAssemblies="@(_ResolvedFileToPublishDlls)"
1463+
SourceFiles="@(_ResolvedFileToPublishDlls)"
1464+
DestinationFiles="@(_ResolvedFileToPublishDlls->'$(_LinkAssembliesNoShrinkDir)%(RelativePath)')"
14451465
TargetName="$(TargetName)"
14461466
AddKeepAlives="$(AndroidAddKeepAlives)"
14471467
UseDesignerAssembly="$(AndroidUseDesignerAssembly)"
14481468
Deterministic="$(Deterministic)"
14491469
ReadSymbols="$(_AndroidLinkAssembliesReadSymbols)">
14501470
</LinkAssembliesNoShrink>
14511471

1472+
<!-- Replace ResolvedFileToPublish DLL items with their intermediate copies.
1473+
The item transform preserves all custom metadata (RelativePath, etc.).
1474+
PDB items are left untouched — CopyAssemblyAndSymbols already wrote updated
1475+
PDBs next to the intermediate DLLs, and the publish pipeline will copy them
1476+
from there via the updated DLL paths. -->
14521477
<ItemGroup>
1453-
<FileWrites Include="$(MonoAndroidIntermediateAssemblyDir)**" />
1478+
<ResolvedFileToPublish Remove="@(_ResolvedFileToPublishDlls)" />
1479+
<ResolvedFileToPublish Include="@(_ResolvedFileToPublishDlls->'$(_LinkAssembliesNoShrinkDir)%(RelativePath)')" />
1480+
<FileWrites Include="$(_LinkAssembliesNoShrinkDir)**" />
14541481
</ItemGroup>
14551482
</Target>
14561483

14571484
<!-- Runs additional steps after ILLink runs (_LinkAssemblies) -->
14581485
<Target Name="_AfterILLinkAdditionalSteps"
1459-
DependsOnTargets="_LinkAssembliesNoShrinkInputs"
14601486
Condition="'$(PublishTrimmed)' == 'true'"
14611487
Inputs="$(_AndroidLinkFlag)"
14621488
Outputs="$(_AdditionalPostLinkerStepsFlag)">
1489+
<ItemGroup>
1490+
<_AllResolvedAssemblies Include="@(ResolvedAssemblies)" />
1491+
</ItemGroup>
14631492
<AssemblyModifierPipeline
14641493
ApplicationJavaClass="$(AndroidApplicationJavaClass)"
14651494
CodeGenerationTarget="$(_AndroidJcwCodegenTarget)"
@@ -2881,7 +2910,7 @@ because xbuild doesn't support framework reference assemblies.
28812910
</Target>
28822911

28832912
<Target Name="_LinkAssemblies"
2884-
DependsOnTargets="_ResolveAssemblies;_CreatePackageWorkspace;$(_BeforeLinkAssemblies);_GenerateJniMarshalMethods;_LinkAssembliesNoShrink"
2913+
DependsOnTargets="_ResolveAssemblies;_CreatePackageWorkspace;$(_BeforeLinkAssemblies);_GenerateJniMarshalMethods"
28852914
/>
28862915

28872916
<!-- TypeMap imports must be last so their target overrides (e.g. _RemoveRegisterAttribute) take precedence -->

0 commit comments

Comments
 (0)