Skip to content

Commit 929e701

Browse files
authored
[Xamarin.Android.Build.Tasks] Fix XA4215 if AssemblyName is the same (#7477)
Fixes: #7473 Context: xamarin/monodroid@4c697e5a6b Context: https://github.com/dotnet/runtime/blob/27c19c31f574375fd1651207b2dc28d39fe1225c/src/libraries/System.Private.CoreLib/src/ILLink/ILLink.Substitutions.64bit.xml With the .NET 6+ build system, it is possible for an AnyCPU assembly to become a *set* of assemblies, one per `$(RuntimeIdentifiers)` value. In particular, the linker will now *inline* calls to `System.IntPtr.get_Size()`, replacing them with the appropriate architecture-specific value. This means that a single assembly that uses the `IntPtr.Size` property could become *4* assemblies, one each for android-arm, android-arm64, android-x86, and android-x64. Furthermore, each of these assemblies will have a different MVID. This is "fine", until the assembly contains a `Java.Lang.Object` subclass that needs a Java Callable Wrapper generated for it, at which point the `<GenerateJavaStubs/>` task starts emitting XA4214 warnings and XA4215 *errors*: warning XA4214: The managed type `Microsoft.UI.Xaml.Controls.AnimatedIcon` exists in multiple assemblies: Uno.UI, Uno.UI, Uno.UI, Uno.UI. Please refactor the managed type names in these assemblies so that they are not identical. error XA4215: The Java type `crc64a5a37c43dff01024.GridViewHeaderItem` is generated by more than one managed type. Please change the [Register] attribute so that the same Java type is not emitted. **Workaround**: Build with only a single `$(RuntimeIdentifier)`: dotnet build -p:RuntimeIdentifier=android-arm64 … Fix this scenario by updating the XA4214 warning and XA4215 error checks to verify that the module name has changed; if the module name is the same, then it's not a duplicate type.
1 parent 8e8439f commit 929e701

File tree

2 files changed

+45
-8
lines changed

2 files changed

+45
-8
lines changed

src/Xamarin.Android.Build.Tasks/Tasks/GenerateJavaStubs.cs

Lines changed: 11 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -217,7 +217,6 @@ void Run (DirectoryAssemblyResolver res, bool useMarshalMethods)
217217
if ((!useMarshalMethods && !userAssemblies.ContainsKey (td.Module.Assembly.Name.Name)) || JavaTypeScanner.ShouldSkipJavaCallableWrapperGeneration (td, cache)) {
218218
continue;
219219
}
220-
221220
javaTypes.Add (td);
222221
}
223222

@@ -283,16 +282,20 @@ void Run (DirectoryAssemblyResolver res, bool useMarshalMethods)
283282
TypeDefinition conflict;
284283
bool hasConflict = false;
285284
if (managed.TryGetValue (managedKey, out conflict)) {
286-
if (!managedConflicts.TryGetValue (managedKey, out var list))
287-
managedConflicts.Add (managedKey, list = new List<string> { conflict.GetPartialAssemblyName (cache) });
288-
list.Add (type.GetPartialAssemblyName (cache));
285+
if (!conflict.Module.Name.Equals (type.Module.Name)) {
286+
if (!managedConflicts.TryGetValue (managedKey, out var list))
287+
managedConflicts.Add (managedKey, list = new List<string> { conflict.GetPartialAssemblyName (cache) });
288+
list.Add (type.GetPartialAssemblyName (cache));
289+
}
289290
hasConflict = true;
290291
}
291292
if (java.TryGetValue (javaKey, out conflict)) {
292-
if (!javaConflicts.TryGetValue (javaKey, out var list))
293-
javaConflicts.Add (javaKey, list = new List<string> { conflict.GetAssemblyQualifiedName (cache) });
294-
list.Add (type.GetAssemblyQualifiedName (cache));
295-
success = false;
293+
if (!conflict.Module.Name.Equals (type.Module.Name)) {
294+
if (!javaConflicts.TryGetValue (javaKey, out var list))
295+
javaConflicts.Add (javaKey, list = new List<string> { conflict.GetAssemblyQualifiedName (cache) });
296+
list.Add (type.GetAssemblyQualifiedName (cache));
297+
success = false;
298+
}
296299
hasConflict = true;
297300
}
298301
if (!hasConflict) {

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

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -509,5 +509,39 @@ public void AndroidUseNegotiateAuthentication ([Values (true, false, null)] bool
509509
}
510510
}
511511
}
512+
513+
[Test]
514+
public void DoNotErrorOnPerArchJavaTypeDuplicates ()
515+
{
516+
if (!Builder.UseDotNet)
517+
Assert.Ignore ("Test only valid on .NET");
518+
519+
var path = Path.Combine (Root, "temp", TestName);
520+
var lib = new XamarinAndroidLibraryProject { IsRelease = true, ProjectName = "Lib1" };
521+
lib.SetProperty ("IsTrimmable", "true");
522+
lib.Sources.Add (new BuildItem.Source ("Library1.cs") {
523+
TextContent = () => @"
524+
namespace Lib1;
525+
public class Library1 : Java.Lang.Object {
526+
private static bool Is64Bits = IntPtr.Size >= 8;
527+
528+
public static bool Is64 () {
529+
return Is64Bits;
530+
}
531+
}",
532+
});
533+
var proj = new XamarinAndroidApplicationProject { IsRelease = true, ProjectName = "App1" };
534+
proj.References.Add(new BuildItem.ProjectReference (Path.Combine ("..", "Lib1", "Lib1.csproj"), "Lib1"));
535+
proj.MainActivity = proj.DefaultMainActivity.Replace (
536+
"base.OnCreate (bundle);",
537+
"base.OnCreate (bundle);\n" +
538+
"if (Lib1.Library1.Is64 ()) Console.WriteLine (\"Hello World!\");");
539+
540+
541+
using var lb = CreateDllBuilder (Path.Combine (path, "Lib1"));
542+
using var b = CreateApkBuilder (Path.Combine (path, "App1"));
543+
Assert.IsTrue (lb.Build (lib), "build should have succeeded.");
544+
Assert.IsTrue (b.Build (proj), "build should have succeeded.");
545+
}
512546
}
513547
}

0 commit comments

Comments
 (0)