From 4d1cfd6a283910ad867147f560c7c8cc1968419e Mon Sep 17 00:00:00 2001 From: Rolf Bjarne Kvinge Date: Thu, 10 Oct 2024 20:10:04 +0200 Subject: [PATCH 1/2] [net9.0] [msbuild] Improve the error message when the SupportedOSPlatformVersion is lower than the minimum. Fixes #21368. (#21369) This isn't very user friendly: ILLink : unknown error IL7000: An error occurred while executing the custom linker steps. Please review the build log for more information. ILLINK : error MT0073: Microsoft.iOS 18.0.8337 does not support a deployment target of 10.0 for iOS (the minimum is 11.0). Please select a newer deployment target in your project's Info.plist or change the SupportedOSPlatformVersion property in your project file. ILLINK : error MT2301: The linker step 'Setup' failed during processing: Microsoft.iOS 18.0.8337 does not support a deployment target of 10.0 for iOS (the minimum is 11.0). Please select a newer deployment target in your project's Info.plist or change the SupportedOSPlatformVersion property in your project file. [...]/packages/microsoft.net.illink.tasks/8.0.8/build/Microsoft.NET.ILLink.targets(87,5): error NETSDK1144: Optimizing assemblies for size failed. Optimization can be disabled by setting the PublishTrimmed property to false. So improve this to only show a single error message: The SupportedOSPlatformVersion value '10.0' in the project file is lower than the minimum value '11.0'. Fixes https://github.com/xamarin/xamarin-macios/issues/21368. This is a backport of #21369. --- dotnet/generate-target-platforms.csharp | 1 + .../MSBStrings.resx | 13 +++++++++ .../Tasks/CompileAppManifest.cs | 15 ++++++++++ msbuild/Xamarin.Shared/Xamarin.Shared.targets | 1 + tests/Makefile | 14 ++++++---- tests/dotnet/UnitTests/ProjectTest.cs | 28 ++++++++++++++++++- .../TaskTests/CompileAppManifestTaskTests.cs | 20 ++++--------- .../GeneratePlistTaskTests_Core.cs | 4 ++- 8 files changed, 74 insertions(+), 22 deletions(-) diff --git a/dotnet/generate-target-platforms.csharp b/dotnet/generate-target-platforms.csharp index b7a2ed4ad18e..bff196cab8f9 100755 --- a/dotnet/generate-target-platforms.csharp +++ b/dotnet/generate-target-platforms.csharp @@ -50,6 +50,7 @@ using (TextWriter writer = new StreamWriter (outputPath)) { writer.WriteLine ("\t"); writer.WriteLine ("\t"); writer.WriteLine ($"\t\t<{platform}MinSupportedOSPlatformVersion>{minSdkVersionString}"); + writer.WriteLine ($"\t\t$({platform}MinSupportedOSPlatformVersion)"); writer.WriteLine ("\t"); writer.WriteLine (""); } diff --git a/msbuild/Xamarin.Localization.MSBuild/MSBStrings.resx b/msbuild/Xamarin.Localization.MSBuild/MSBStrings.resx index c25833c4c865..b68ef191e2a9 100644 --- a/msbuild/Xamarin.Localization.MSBuild/MSBStrings.resx +++ b/msbuild/Xamarin.Localization.MSBuild/MSBStrings.resx @@ -1563,6 +1563,19 @@ RuntimeIdentifier: don't translate (it's the name of a MSBuild property) + + Unable to parse the value '{0}' for the property '{1}. + + {0}: user-provided value + {1}: name of an MSBuild property + + + + + The SupportedOSPlatformVersion value '{0}' in the project file is lower than the minimum value '{1}'. + SupportedOSPlatformVersion: don't translate (it's the name of an MSBuild property) + + Adding reference to Xcode project output: '{0}'. The '%(CreateNativeReference)' metadata can be set to 'false' to opt out of this behavior. diff --git a/msbuild/Xamarin.MacDev.Tasks/Tasks/CompileAppManifest.cs b/msbuild/Xamarin.MacDev.Tasks/Tasks/CompileAppManifest.cs index 3500599ef23a..7901c1f9f72d 100644 --- a/msbuild/Xamarin.MacDev.Tasks/Tasks/CompileAppManifest.cs +++ b/msbuild/Xamarin.MacDev.Tasks/Tasks/CompileAppManifest.cs @@ -62,6 +62,9 @@ public class CompileAppManifest : XamarinTask, ITaskCallback, ICancelableTask { public bool IsWatchExtension { get; set; } + [Required] + public string MinSupportedOSPlatformVersion { get; set; } = string.Empty; + public ITaskItem [] PartialAppManifests { get; set; } = Array.Empty (); [Required] @@ -302,6 +305,18 @@ bool SetMinimumOSVersion (PDictionary plist) minimumOSVersion = minimumOSVersionInManifest!; } + // Verify that the value is not lower than the minimum + if (!Version.TryParse (MinSupportedOSPlatformVersion, out var minSupportedVersion)) { + Log.LogError (MSBStrings.E7125 /* Unable to parse the value '{0}' for the property '{1}. */, MinSupportedOSPlatformVersion, "MinSupportedOSPlatformVersion"); + return false; + } else if (!Version.TryParse (SupportedOSPlatformVersion, out var supportedVersion)) { + Log.LogError (MSBStrings.E7125 /* Unable to parse the value '{0}' for the property '{1}. */, SupportedOSPlatformVersion, "SupportedOSPlatformVersion"); + return false; + } else if (minSupportedVersion > supportedVersion) { + Log.LogError (MSBStrings.E7126 /* The SupportedOSPlatformVersion value '{0}' in the project file is lower than the minimum value '{1}'." */, SupportedOSPlatformVersion, MinSupportedOSPlatformVersion); + return false; + } + // Write out our value plist [minimumVersionKey] = minimumOSVersion; diff --git a/msbuild/Xamarin.Shared/Xamarin.Shared.targets b/msbuild/Xamarin.Shared/Xamarin.Shared.targets index 9313d69f7241..b1c2747aa339 100644 --- a/msbuild/Xamarin.Shared/Xamarin.Shared.targets +++ b/msbuild/Xamarin.Shared/Xamarin.Shared.targets @@ -570,6 +570,7 @@ Copyright (C) 2018 Microsoft. All rights reserved. IsWatchApp="$(IsWatchApp)" IsWatchExtension="$(IsWatchExtension)" IsXPCService="$(IsXPCService)" + MinSupportedOSPlatformVersion="$(MinSupportedOSPlatformVersion)" PartialAppManifests="@(PartialAppManifest)" ProjectDir="$(MSBuildProjectDirectory)" ResourcePrefix="$(_ResourcePrefix)" diff --git a/tests/Makefile b/tests/Makefile index b242791bc3ff..5c97c55545aa 100644 --- a/tests/Makefile +++ b/tests/Makefile @@ -85,9 +85,10 @@ test.config: Makefile $(TOP)/Make.config $(TOP)/mk/mono.mk $(TOP)/eng/Version.De @printf "$(foreach platform,$(DOTNET_PLATFORMS_UPPERCASE),$(platform)_NUGET_REF_NAME=$($(platform)_NUGET_REF_NAME)\\n)" | sed 's/^ //' >> $@ @printf "$(foreach platform,$(DOTNET_PLATFORMS_UPPERCASE),$(foreach rid,$(DOTNET_$(platform)_RUNTIME_IDENTIFIERS),$(rid)_NUGET_RUNTIME_NAME=$($(rid)_NUGET_RUNTIME_NAME)\\n))" | sed 's/^ //' >> $@ @printf "$(foreach platform,$(DOTNET_PLATFORMS_UPPERCASE),SUPPORTED_API_VERSIONS_$(platform)='$(SUPPORTED_API_VERSIONS_$(platform))'\\n)" | sed 's/^ //' >> $@ - @printf "ENABLE_XAMARIN=$(ENABLE_XAMARIN)" >> $@ - @printf "XCODE_IS_STABLE=$(XCODE_IS_STABLE)" >> $@ - @printf "XCODE_VERSION=$(XCODE_VERSION)" >> $@ + @printf "ENABLE_XAMARIN=$(ENABLE_XAMARIN)\n" >> $@ + @printf "XCODE_IS_STABLE=$(XCODE_IS_STABLE)\n" >> $@ + @printf "XCODE_VERSION=$(XCODE_VERSION)\n" >> $@ + @printf "$(foreach platform,$(DOTNET_PLATFORMS_UPPERCASE),DOTNET_MIN_$(platform)_SDK_VERSION=$(DOTNET_MIN_$(platform)_SDK_VERSION)\\n)" | sed 's/^ //' >> $@ test-system.config: Makefile $(TOP)/Make.config $(TOP)/mk/mono.mk $(TOP)/eng/Version.Details.xml @rm -f $@ @@ -119,9 +120,10 @@ test-system.config: Makefile $(TOP)/Make.config $(TOP)/mk/mono.mk $(TOP)/eng/Ver @printf "$(foreach platform,$(DOTNET_PLATFORMS_UPPERCASE),$(platform)_NUGET_REF_NAME=$($(platform)_NUGET_REF_NAME)\\n)" | sed 's/^ //' >> $@ @printf "$(foreach platform,$(DOTNET_PLATFORMS_UPPERCASE),$(foreach rid,$(DOTNET_$(platform)_RUNTIME_IDENTIFIERS),$(rid)_NUGET_RUNTIME_NAME=$($(rid)_NUGET_RUNTIME_NAME)\\n))" | sed 's/^ //' >> $@ @printf "$(foreach platform,$(DOTNET_PLATFORMS_UPPERCASE),SUPPORTED_API_VERSIONS_$(platform)='$(SUPPORTED_API_VERSIONS_$(platform))'\\n)" | sed 's/^ //' >> $@ - @printf "ENABLE_XAMARIN=$(ENABLE_XAMARIN)" >> $@ - @printf "XCODE_IS_STABLE=$(XCODE_IS_STABLE)" >> $@ - @printf "XCODE_VERSION=$(XCODE_VERSION)" >> $@ + @printf "ENABLE_XAMARIN=$(ENABLE_XAMARIN)\n" >> $@ + @printf "XCODE_IS_STABLE=$(XCODE_IS_STABLE)\n" >> $@ + @printf "XCODE_VERSION=$(XCODE_VERSION)\n" >> $@ + @printf "$(foreach platform,$(DOTNET_PLATFORMS_UPPERCASE),DOTNET_MIN_$(platform)_SDK_VERSION=$(DOTNET_MIN_$(platform)_SDK_VERSION)\\n)" | sed 's/^ //' >> $@ clean-local:: $(Q) $(SYSTEM_XBUILD) /t:Clean /p:Platform=iPhoneSimulator /p:Configuration=$(CONFIG) $(XBUILD_VERBOSITY) tests.sln diff --git a/tests/dotnet/UnitTests/ProjectTest.cs b/tests/dotnet/UnitTests/ProjectTest.cs index cc8541998b91..36e4a0dd8bd4 100644 --- a/tests/dotnet/UnitTests/ProjectTest.cs +++ b/tests/dotnet/UnitTests/ProjectTest.cs @@ -1861,7 +1861,7 @@ public void UnsupportedTargetPlatformVersion (ApplePlatform platform) // Pick a target platform version that we don't really support, // but don't show an error in .NET 8 because of backwards compat. // The earliest target OS version should do. - var minSupportedOSVersion = GetSupportedTargetPlatformVersions (platform).First (); + var minSupportedOSVersion = GetMinSupportedOSPlatformVersion (platform); var targetFrameworks = Configuration.DotNetTfm + "-" + platform.AsString ().ToLowerInvariant () + minSupportedOSVersion; var supportedApiVersions = GetSupportedApiVersions (platform, isCompat: false); @@ -1914,6 +1914,11 @@ string [] GetSupportedTargetPlatformVersions (ApplePlatform platform) .ToArray (); } + string GetMinSupportedOSPlatformVersion (ApplePlatform platform) + { + return Configuration.GetVariable ($"DOTNET_MIN_{platform.AsString ().ToUpperInvariant ()}_SDK_VERSION", "unknown MinSupportedOSPlatformVersion"); + } + [Test] [TestCase (ApplePlatform.MacCatalyst, "MtouchArch", "x86_64")] [TestCase (ApplePlatform.iOS, "MtouchArch", "ARMv7s")] @@ -2837,5 +2842,26 @@ static HashSet GetLinkedWithFrameworks (string path) } return rv; } + + [Test] + [TestCase (ApplePlatform.MacCatalyst, "maccatalyst-x64", "13.1")] + [TestCase (ApplePlatform.iOS, "ios-arm64", "10.0")] + [TestCase (ApplePlatform.TVOS, "tvossimulator-x64", "10.0")] + [TestCase (ApplePlatform.MacOSX, "osx-arm64", "10.0")] + public void InvalidSupportedOSPlatformVersion (ApplePlatform platform, string runtimeIdentifiers, string version) + { + var project = "MySimpleApp"; + Configuration.IgnoreIfIgnoredPlatform (platform); + Configuration.AssertRuntimeIdentifiersAvailable (platform, runtimeIdentifiers); + + var minVersion = GetMinSupportedOSPlatformVersion (platform); + var project_path = GetProjectPath (project, runtimeIdentifiers: runtimeIdentifiers, platform: platform, out var appPath); + Clean (project_path); + var properties = GetDefaultProperties (runtimeIdentifiers); + properties ["SupportedOSPlatformVersion"] = version; + var rv = DotNet.AssertBuildFailure (project_path, properties); + var errors = BinLog.GetBuildLogErrors (rv.BinLogPath).ToArray (); + AssertErrorMessages (errors, $"The SupportedOSPlatformVersion value '{version}' in the project file is lower than the minimum value '{minVersion}'."); + } } } diff --git a/tests/msbuild/Xamarin.MacDev.Tasks.Tests/TaskTests/CompileAppManifestTaskTests.cs b/tests/msbuild/Xamarin.MacDev.Tasks.Tests/TaskTests/CompileAppManifestTaskTests.cs index 94463d1d8ab1..93cc0b5e6d41 100644 --- a/tests/msbuild/Xamarin.MacDev.Tasks.Tests/TaskTests/CompileAppManifestTaskTests.cs +++ b/tests/msbuild/Xamarin.MacDev.Tasks.Tests/TaskTests/CompileAppManifestTaskTests.cs @@ -21,25 +21,15 @@ CompileAppManifest CreateTask (string? tmpdir = null, ApplePlatform platform = A task.AssemblyName = "AssemblyName"; task.AppBundleName = "AppBundleName"; task.CompiledAppManifest = new TaskItem (Path.Combine (tmpdir, "TemporaryAppManifest.plist")); - task.DefaultSdkVersion = Sdks.GetAppleSdk (platform).GetInstalledSdkVersions (false).First ().ToString (); - task.SdkVersion = task.DefaultSdkVersion; + task.DefaultSdkVersion = Sdks.GetAppleSdk (platform).GetInstalledSdkVersions (false).First ().ToString ()!; + task.MinSupportedOSPlatformVersion = "10.0"; + task.SupportedOSPlatformVersion = "15.0"; + task.SdkVersion = task.DefaultSdkVersion ?? string.Empty; task.TargetFrameworkMoniker = TargetFramework.GetTargetFramework (platform, true).ToString (); return task; } - [Test] - public void DefaultMinimumOSVersion () - { - var dir = Cache.CreateTemporaryDirectory (); - var task = CreateTask (dir); - - ExecuteTask (task); - - var plist = PDictionary.FromFile (task.CompiledAppManifest!.ItemSpec)!; - Assert.AreEqual (task.SdkVersion, plist.GetMinimumOSVersion (), "MinimumOSVersion"); - } - [Test] public void MainMinimumOSVersions () { @@ -52,6 +42,7 @@ public void MainMinimumOSVersions () main.Save (mainPath); task.AppManifest = new TaskItem (mainPath); + task.SupportedOSPlatformVersion = "14.0"; ExecuteTask (task); @@ -78,6 +69,7 @@ public void MultipleMinimumOSVersions () task.AppManifest = new TaskItem (mainPath); task.PartialAppManifests = new [] { new TaskItem (partialPath) }; + task.SupportedOSPlatformVersion = "14.0"; ExecuteTask (task); diff --git a/tests/msbuild/Xamarin.MacDev.Tasks.Tests/TaskTests/GeneratePlistTaskTests/GeneratePlistTaskTests_Core.cs b/tests/msbuild/Xamarin.MacDev.Tasks.Tests/TaskTests/GeneratePlistTaskTests/GeneratePlistTaskTests_Core.cs index b82d27061176..85487ed1fb8c 100644 --- a/tests/msbuild/Xamarin.MacDev.Tasks.Tests/TaskTests/GeneratePlistTaskTests/GeneratePlistTaskTests_Core.cs +++ b/tests/msbuild/Xamarin.MacDev.Tasks.Tests/TaskTests/GeneratePlistTaskTests/GeneratePlistTaskTests_Core.cs @@ -50,6 +50,8 @@ protected virtual void ConfigureTask (bool isDotNet) Task.CompiledAppManifest = new TaskItem (Path.Combine (Cache.CreateTemporaryDirectory (), "AppBundlePath", "Info.plist")); Task.AssemblyName = assemblyName; Task.AppManifest = new TaskItem (CreateTempFile ("foo.plist")); + Task.MinSupportedOSPlatformVersion = "10.0"; + Task.SupportedOSPlatformVersion = "15.0"; Task.SdkVersion = "10.0"; Plist = new PDictionary (); @@ -70,7 +72,7 @@ public override void Setup () ConfigureTask (IsDotNet); - Task.Execute (); + ExecuteTask (Task); CompiledPlist = PDictionary.FromFile (Task.CompiledAppManifest.ItemSpec); } From b0d6ac47dcd2ff08b422d826aa40e7e986097dca Mon Sep 17 00:00:00 2001 From: Rolf Bjarne Kvinge Date: Thu, 3 Oct 2024 19:12:57 +0200 Subject: [PATCH 2/2] Fix generator tests. --- tests/generator/BGenTool.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/generator/BGenTool.cs b/tests/generator/BGenTool.cs index 68c3faafe80b..4326c98f24b0 100644 --- a/tests/generator/BGenTool.cs +++ b/tests/generator/BGenTool.cs @@ -247,7 +247,7 @@ public static void AddPreviewNoWarn (IList argumentList) public static string? GetPreviewNoWarn (string? existingNowarn) { if (Configuration.XcodeIsStable) - return null; + return existingNowarn; var previewNoWarn = $"XCODE_{Configuration.XcodeVersion.Major}_{Configuration.XcodeVersion.Minor}_PREVIEW"; if (string.IsNullOrEmpty (existingNowarn)) {