diff --git a/Documentation/docs-mobile/messages/xa1042.md b/Documentation/docs-mobile/messages/xa1042.md new file mode 100644 index 00000000000..f57c6e6cbd2 --- /dev/null +++ b/Documentation/docs-mobile/messages/xa1042.md @@ -0,0 +1,45 @@ +--- +title: .NET for Android warning XA1042 +description: XA1042 warning code +ms.date: 04/02/2026 +f1_keywords: + - "XA1042" +--- + +# .NET for Android warning XA1042 + +## Example messages + +``` +warning XA1042: The MSBuild property 'RunAOTCompilation' is not compatible with the CoreCLR runtime and will be ignored. Either remove the property or guard it with a condition: Condition="'$(UseMonoRuntime)' == 'true'" +``` + +## Issue + +This warning indicates that a Mono-specific MSBuild property is set in +the project file, but the project is configured to use a non-Mono +runtime (such as CoreCLR or NativeAOT). The property will have no +effect with the current runtime and will be ignored. + +Properties that trigger this warning include: +- `RunAOTCompilation` — Mono AOT compilation; CoreCLR uses `PublishReadyToRun` instead. +- `EnableLLVM` — Enables LLVM for the Mono AOT compiler. + +## Solution + +Remove the Mono-specific property from your project file or +`Directory.Build.props`, or guard it with a runtime condition: + +```xml + + true + +``` + +For CoreCLR, use `PublishReadyToRun` instead of `RunAOTCompilation`: + +```xml + + true + +``` diff --git a/src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.Aot.targets b/src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.Aot.targets index d80be84d01c..3537c75fb4b 100644 --- a/src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.Aot.targets +++ b/src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.Aot.targets @@ -21,7 +21,7 @@ They run in a context of an inner build with a single $(RuntimeIdentifier). when $(MonoAOTCompilerTasksAssemblyPath) is blank: https://github.com/dotnet/runtime/blob/69711860262e44458bbe276393ea3eb9f7a2192a/src/mono/nuget/Microsoft.NET.Workload.Mono.Toolchain.Manifest/WorkloadManifest.targets.in#L20-L25 --> - + @@ -39,7 +39,7 @@ They run in a context of an inner build with a single $(RuntimeIdentifier). diff --git a/src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.DefaultProperties.targets b/src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.DefaultProperties.targets index e9c75e1667d..fd8c19234f1 100644 --- a/src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.DefaultProperties.targets +++ b/src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.DefaultProperties.targets @@ -119,6 +119,11 @@ true true false + + <_AndroidXA1042_RunAOTCompilation Condition=" '$(RunAOTCompilation)' == 'true' and '$(_AndroidRuntime)' != 'MonoVM' ">true + <_AndroidXA1042_EnableLLVM Condition=" '$(EnableLLVM)' == 'true' and '$(_AndroidRuntime)' != 'MonoVM' ">true + false + false <_AndroidXA1029 Condition=" '$(AotAssemblies)' != '' ">true <_AndroidXA1030 Condition=" '$(RunAOTCompilation)' == 'true' and '$(PublishTrimmed)' == 'false' ">true $(RunAOTCompilation) diff --git a/src/Xamarin.Android.Build.Tasks/Properties/Resources.Designer.cs b/src/Xamarin.Android.Build.Tasks/Properties/Resources.Designer.cs index bc2d9a7d4d4..4b7c0de91fc 100644 --- a/src/Xamarin.Android.Build.Tasks/Properties/Resources.Designer.cs +++ b/src/Xamarin.Android.Build.Tasks/Properties/Resources.Designer.cs @@ -938,6 +938,15 @@ public static string XA1041 { } } + /// + /// Looks up a localized string similar to The MSBuild property '{0}' is not compatible with the {1} runtime and will be ignored. Either remove the property or guard it with a condition: Condition="'$(UseMonoRuntime)' == 'true'". + /// + public static string XA1042 { + get { + return ResourceManager.GetString("XA1042", resourceCulture); + } + } + /// /// Looks up a localized string similar to Use of AppDomain.CreateDomain() detected in assembly: {0}. .NET 6 and higher will only support a single AppDomain, so this API will no longer be available in .NET for Android once .NET 6 is released.. /// diff --git a/src/Xamarin.Android.Build.Tasks/Properties/Resources.resx b/src/Xamarin.Android.Build.Tasks/Properties/Resources.resx index d1ee02dc051..6d6eb3546f6 100644 --- a/src/Xamarin.Android.Build.Tasks/Properties/Resources.resx +++ b/src/Xamarin.Android.Build.Tasks/Properties/Resources.resx @@ -1007,6 +1007,13 @@ To use a custom JDK path for a command line build, set the 'JavaSdkDirectory' MS The following are literal names and should not be translated: .NET. {0} - The MSBuild property that has the incorrect value. {1} - The current value of the property + + + + The MSBuild property '{0}' is not compatible with the {1} runtime and will be ignored. Either remove the property or guard it with a condition: Condition="'$(UseMonoRuntime)' == 'true'" + The following are literal names and should not be translated: MSBuild, UseMonoRuntime. +{0} - The MSBuild property name (e.g. RunAOTCompilation, EnableLLVM). +{1} - The name of the .NET runtime (e.g. CoreCLR, NativeAOT). diff --git a/src/Xamarin.Android.Build.Tasks/Tasks/CalculateProjectDependencies.cs b/src/Xamarin.Android.Build.Tasks/Tasks/CalculateProjectDependencies.cs index 764129c5574..1473f753a95 100644 --- a/src/Xamarin.Android.Build.Tasks/Tasks/CalculateProjectDependencies.cs +++ b/src/Xamarin.Android.Build.Tasks/Tasks/CalculateProjectDependencies.cs @@ -82,7 +82,7 @@ public override bool RunTask () dependencies.Add (CreateAndroidDependency ($"cmdline-tools/{CommandLineToolsVersion}", CommandLineToolsVersion)); } if (!NdkVersion.IsNullOrEmpty () && NdkRequired) { - dependencies.Add (CreateAndroidDependency ("ndk-bundle", NdkVersion)); + dependencies.Add (CreateAndroidDependency ("ndk", NdkVersion)); } if (!JdkVersion.IsNullOrEmpty () && GetJavaDependencies) { javaDependencies.Add (CreateAndroidDependency ("jdk", JdkVersion)); diff --git a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/AndroidDependenciesTests.cs b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/AndroidDependenciesTests.cs index d150196d51c..b8d09a390b7 100644 --- a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/AndroidDependenciesTests.cs +++ b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/AndroidDependenciesTests.cs @@ -166,6 +166,11 @@ public void GetDependencyNdkRequiredConditions (string property, bool ndkRequire Assert.Ignore ("NativeAOT doesn't support profiled AOT"); } + // NativeAOT always requires the NDK (PublishAot=true), so ndkRequired=false cases don't apply + if (runtime == AndroidRuntime.NativeAOT && !ndkRequired) { + Assert.Ignore ("NativeAOT always requires NDK via PublishAot=true"); + } + var proj = new XamarinAndroidApplicationProject { IsRelease = isRelease, }; @@ -182,9 +187,29 @@ public void GetDependencyNdkRequiredConditions (string property, bool ndkRequire .SkipWhile (x => !x.StartsWith ("Output Item(s):", StringComparison.Ordinal)) .TakeWhile (x => !x.StartsWith ("Done executing task \"CalculateProjectDependencies\"", StringComparison.Ordinal)); if (ndkRequired) - StringAssertEx.Contains ("ndk-bundle", taskOutput, "ndk-bundle should be a dependency."); + StringAssertEx.Contains ("ndk", taskOutput, "ndk should be a dependency."); else - StringAssertEx.DoesNotContain ("ndk-bundle", taskOutput, "ndk-bundle should not be a dependency."); + StringAssertEx.DoesNotContain ("ndk", taskOutput, "ndk should not be a dependency."); + } + } + + [Test] + public void NativeAotRequiresNdk () + { + var proj = new XamarinAndroidApplicationProject { + IsRelease = true, + }; + proj.SetRuntime (AndroidRuntime.NativeAOT); + using (var builder = CreateApkBuilder ()) { + builder.Verbosity = LoggerVerbosity.Detailed; + builder.Target = "GetAndroidDependencies"; + Assert.IsTrue (builder.Build (proj), "Build should have succeeded."); + IEnumerable taskOutput = builder.LastBuildOutput + .Select (x => x.Trim ()) + .SkipWhile (x => !x.StartsWith ("Task \"CalculateProjectDependencies\"", StringComparison.Ordinal)) + .SkipWhile (x => !x.StartsWith ("Output Item(s):", StringComparison.Ordinal)) + .TakeWhile (x => !x.StartsWith ("Done executing task \"CalculateProjectDependencies\"", StringComparison.Ordinal)); + StringAssertEx.Contains ("ndk", taskOutput, "ndk should be a dependency for NativeAOT."); } } diff --git a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/AotTests.cs b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/AotTests.cs index 6a6b91aa900..09d36e7b02a 100644 --- a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/AotTests.cs +++ b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/AotTests.cs @@ -492,5 +492,37 @@ public void CheckWhetherLibcAndLibmAreReferencedInAOTLibraries () } } + [Test] + public void RunAOTCompilationWithCoreClrWarnsAndSkipsMonoAot () + { + var proj = new XamarinAndroidApplicationProject { + IsRelease = true, + }; + proj.SetRuntime (AndroidRuntime.CoreCLR); + proj.SetProperty ("RunAOTCompilation", "true"); + + using var b = CreateApkBuilder (); + Assert.IsTrue (b.Build (proj), "Build should have succeeded."); + StringAssertEx.Contains ("warning XA1042", b.LastBuildOutput, "Build output should contain warning XA1042"); + StringAssertEx.Contains ("RunAOTCompilation", b.LastBuildOutput, "Build output should mention RunAOTCompilation"); + StringAssertEx.Contains ("CoreCLR", b.LastBuildOutput, "Build output should mention CoreCLR"); + } + + [Test] + public void EnableLLVMWithCoreClrWarnsAndIsIgnored () + { + var proj = new XamarinAndroidApplicationProject { + IsRelease = true, + }; + proj.SetRuntime (AndroidRuntime.CoreCLR); + proj.SetProperty ("EnableLLVM", "true"); + + using var b = CreateApkBuilder (); + Assert.IsTrue (b.Build (proj), "Build should have succeeded."); + StringAssertEx.Contains ("warning XA1042", b.LastBuildOutput, "Build output should contain warning XA1042"); + StringAssertEx.Contains ("EnableLLVM", b.LastBuildOutput, "Build output should mention EnableLLVM"); + StringAssertEx.Contains ("CoreCLR", b.LastBuildOutput, "Build output should mention CoreCLR"); + } + } } diff --git a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/Tasks/GetDependenciesTests.cs b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/Tasks/GetDependenciesTests.cs index e466de20a98..4b55dea4fb7 100644 --- a/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/Tasks/GetDependenciesTests.cs +++ b/src/Xamarin.Android.Build.Tasks/Tests/Xamarin.Android.Build.Tests/Tasks/GetDependenciesTests.cs @@ -43,11 +43,11 @@ public void CheckNdkBundle ([Values(true, false)] bool ndkRequred) Assert.IsNotNull (task.Dependencies.FirstOrDefault (x => x.ItemSpec == "platform-tools" && x.GetMetadata ("Version") == "26.0.3"), "Dependencies should contains a platform-tools version 26.0.3"); if (ndkRequred) { - Assert.IsNotNull (task.Dependencies.FirstOrDefault (x => x.ItemSpec == "ndk-bundle" && x.GetMetadata ("Version") == "12.1"), - "Dependencies should contain a ndk-bundle version 12.1"); + Assert.IsNotNull (task.Dependencies.FirstOrDefault (x => x.ItemSpec == "ndk" && x.GetMetadata ("Version") == "12.1"), + "Dependencies should contain a ndk version 12.1"); } else { - Assert.IsNull (task.Dependencies.FirstOrDefault (x => x.ItemSpec == "ndk-bundle"), - "Dependencies should not contain a ndk-bundle item"); + Assert.IsNull (task.Dependencies.FirstOrDefault (x => x.ItemSpec == "ndk"), + "Dependencies should not contain a ndk item"); } Directory.Delete (Path.Combine (Root, path), recursive: true); } @@ -80,8 +80,8 @@ public void ManifestFileDoesNotExist () "Dependencies should contains a platform version android-26"); Assert.IsNotNull (task.Dependencies.FirstOrDefault (x => x.ItemSpec == "platform-tools" && x.GetMetadata ("Version") == "26.0.3"), "Dependencies should contains a platform-tools version 26.0.3"); - Assert.IsNotNull (task.Dependencies.FirstOrDefault (x => x.ItemSpec == "ndk-bundle" && x.GetMetadata ("Version") == "12.1"), - "Dependencies should contains a ndk-bundle version 12.1"); + Assert.IsNotNull (task.Dependencies.FirstOrDefault (x => x.ItemSpec == "ndk" && x.GetMetadata ("Version") == "12.1"), + "Dependencies should contains a ndk version 12.1"); Directory.Delete (Path.Combine (Root, path), recursive: true); } @@ -121,8 +121,8 @@ public void ManifestFileExists () "Dependencies should contains a platform version android-26"); Assert.IsNotNull (task.Dependencies.FirstOrDefault (x => x.ItemSpec == "platform-tools" && x.GetMetadata ("Version") == "26.0.3"), "Dependencies should contains a platform-tools version 26.0.3"); - Assert.IsNotNull (task.Dependencies.FirstOrDefault (x => x.ItemSpec == "ndk-bundle" && x.GetMetadata ("Version") == "12.1"), - "Dependencies should contains a ndk-bundle version 12.1"); + Assert.IsNotNull (task.Dependencies.FirstOrDefault (x => x.ItemSpec == "ndk" && x.GetMetadata ("Version") == "12.1"), + "Dependencies should contains a ndk version 12.1"); Directory.Delete (path, recursive: true); } diff --git a/src/Xamarin.Android.Build.Tasks/Xamarin.Android.Common.targets b/src/Xamarin.Android.Build.Tasks/Xamarin.Android.Common.targets index c2527d1954e..754086557d0 100644 --- a/src/Xamarin.Android.Build.Tasks/Xamarin.Android.Common.targets +++ b/src/Xamarin.Android.Build.Tasks/Xamarin.Android.Common.targets @@ -550,6 +550,16 @@ Copyright (C) 2011-2012 Xamarin. All rights reserved. ResourceName="XA1030" Condition=" $(_AndroidXA1030) == 'true' " /> + + <_ProjectAndroidManifest>$(ProjectDir)$(AndroidManifest) <_NdkRequired Condition="'$(EnableLLVM)' == 'True'">true + <_NdkRequired Condition="'$(PublishAot)' == 'true'">true <_NdkRequired Condition="'$(_NdkRequired)' == ''">false