From a5e6507e3940da2bd88f55c6f42f63bc075618bd Mon Sep 17 00:00:00 2001 From: Daniel Plaisted Date: Tue, 16 Aug 2022 10:51:51 -0400 Subject: [PATCH 1/3] Support different Windows SDK package versions for different target frameworks If there are multiple matching WindowsSdkSupportedTargetPlatformVersion items, choose the one with the highest minimum version. That way it is possible to use older packages when targeting older versions of .NET, and newer packages for newer versions of .NET --- ...reateWindowsSdkKnownFrameworkReferences.cs | 13 ++++- ...ThatWeWantToBuildAWindowsDesktopProject.cs | 54 +++++++++++++++---- 2 files changed, 56 insertions(+), 11 deletions(-) diff --git a/src/Tasks/Microsoft.NET.Build.Tasks/CreateWindowsSdkKnownFrameworkReferences.cs b/src/Tasks/Microsoft.NET.Build.Tasks/CreateWindowsSdkKnownFrameworkReferences.cs index 94a65656ee68..03354607a22a 100644 --- a/src/Tasks/Microsoft.NET.Build.Tasks/CreateWindowsSdkKnownFrameworkReferences.cs +++ b/src/Tasks/Microsoft.NET.Build.Tasks/CreateWindowsSdkKnownFrameworkReferences.cs @@ -55,6 +55,8 @@ protected override void ExecuteCore() else { var normalizedTargetFrameworkVersion = ProcessFrameworkReferences.NormalizeVersion(new Version(TargetFrameworkVersion)); + + var matchingKnownFrameworkReferences = new List<(Version minimumNetVersion, TaskItem knownFrameworkReference)>(); foreach (var supportedWindowsVersion in WindowsSdkSupportedTargetPlatformVersions) { var windowsSdkPackageVersion = supportedWindowsVersion.GetMetadata("WindowsSdkPackageVersion"); @@ -62,18 +64,25 @@ protected override void ExecuteCore() if (!string.IsNullOrEmpty(windowsSdkPackageVersion)) { var minimumNETVersion = supportedWindowsVersion.GetMetadata("MinimumNETVersion"); + Version normalizedMinimumVersion = new Version(0, 0, 0); if (!string.IsNullOrEmpty(minimumNETVersion)) { - var normalizedMinimumVersion = ProcessFrameworkReferences.NormalizeVersion(new Version(minimumNETVersion)); + normalizedMinimumVersion = ProcessFrameworkReferences.NormalizeVersion(new Version(minimumNETVersion)); if (normalizedMinimumVersion > normalizedTargetFrameworkVersion) { continue; } } - knownFrameworkReferences.Add(CreateKnownFrameworkReference(windowsSdkPackageVersion, TargetFrameworkVersion, supportedWindowsVersion.ItemSpec)); + matchingKnownFrameworkReferences.Add((normalizedMinimumVersion, CreateKnownFrameworkReference(windowsSdkPackageVersion, TargetFrameworkVersion, supportedWindowsVersion.ItemSpec))); + } } + + // If there are multiple matching WindowsSdkSupportedTargetPlatformVersion items, choose the one with the highest minimum version. That way it is possible to + // use older packages when targeting older versions of .NET, and newer packages for newer versions of .NET + var highestMinimumVersion = matchingKnownFrameworkReferences.Max(t => t.minimumNetVersion); + knownFrameworkReferences.AddRange(matchingKnownFrameworkReferences.Where(t => t.minimumNetVersion == highestMinimumVersion).Select(t => t.knownFrameworkReference)); } KnownFrameworkReferences = knownFrameworkReferences.ToArray(); diff --git a/src/Tests/Microsoft.NET.Build.Tests/GivenThatWeWantToBuildAWindowsDesktopProject.cs b/src/Tests/Microsoft.NET.Build.Tests/GivenThatWeWantToBuildAWindowsDesktopProject.cs index 267654705889..77502bedb5db 100644 --- a/src/Tests/Microsoft.NET.Build.Tests/GivenThatWeWantToBuildAWindowsDesktopProject.cs +++ b/src/Tests/Microsoft.NET.Build.Tests/GivenThatWeWantToBuildAWindowsDesktopProject.cs @@ -403,6 +403,50 @@ public void ItUsesCorrectWindowsSdkPackVersion(string targetFramework, bool? use var testAsset = _testAssetsManager.CreateTestProject(testProject, identifier: targetFramework + useWindowsSDKPreview + windowsSdkPackageVersion); + string referencedWindowsSdkVersion = GetReferencedWindowsSdkVersion(testAsset); + + // The patch version of the Windows SDK Ref pack will change over time, so we use a '*' in the expected version to indicate that and replace it with + // the 4th part of the version number of the resolved package. + if (expectedWindowsSdkPackageVersion.Contains('*')) + { + expectedWindowsSdkPackageVersion = expectedWindowsSdkPackageVersion.Replace("*", new Version(referencedWindowsSdkVersion).Revision.ToString()); + } + + referencedWindowsSdkVersion.Should().Be(expectedWindowsSdkPackageVersion); + } + + [Theory] + [InlineData("net5.0-windows10.0.22000.0", "10.0.22000.25")] + [InlineData("net6.0-windows10.0.22000.0", "10.0.22000.26")] + public void ItUsesTheHighestMatchingWindowsSdkPackageVersion2(string targetFramework, string expectedWindowsSdkPackageVersion) + { + var testProject = new TestProject() + { + TargetFrameworks = targetFramework + }; + + var testAsset = _testAssetsManager.CreateTestProject(testProject) + .WithProjectChanges(project => + { + // Add items for available SDK versions for test + var testItems = XElement.Parse(@" + + + + + + "); + + project.Root.Add(testItems); + }); + + string referencedWindowsSdkVersion = GetReferencedWindowsSdkVersion(testAsset); + referencedWindowsSdkVersion.Should().Be(expectedWindowsSdkPackageVersion); + + } + + private string GetReferencedWindowsSdkVersion(TestAsset testAsset) + { var getValueCommand = new GetValuesCommand(testAsset, "PackageDownload", GetValuesCommand.ValueType.Item); getValueCommand.ShouldRestore = false; getValueCommand.DependsOnTargets = "_CheckForInvalidConfigurationAndPlatform;CollectPackageDownloads"; @@ -419,15 +463,7 @@ public void ItUsesCorrectWindowsSdkPackVersion(string targetFramework, bool? use packageDownloadVersion[0].Should().Be('['); packageDownloadVersion.Last().Should().Be(']'); - // The patch version of the Windows SDK Ref pack will change over time, so we use a '*' in the expected version to indicate that and replace it with - // the 4th part of the version number of the resolved package. - var trimmedPackageDownloadVersion = packageDownloadVersion.Substring(1, packageDownloadVersion.Length - 2); - if (expectedWindowsSdkPackageVersion.Contains('*')) - { - expectedWindowsSdkPackageVersion = expectedWindowsSdkPackageVersion.Replace("*", new Version(trimmedPackageDownloadVersion).Revision.ToString()); - } - - trimmedPackageDownloadVersion.Should().Be(expectedWindowsSdkPackageVersion); + return packageDownloadVersion.Substring(1, packageDownloadVersion.Length - 2); } private string GetPropertyValue(TestAsset testAsset, string propertyName) From c3fcc83b7cc09fccf0309bb5f133ac37be5d06c4 Mon Sep 17 00:00:00 2001 From: Daniel Plaisted Date: Tue, 16 Aug 2022 13:12:08 -0400 Subject: [PATCH 2/3] Fix logic to handle different Windows SDK versions correctly --- ...reateWindowsSdkKnownFrameworkReferences.cs | 28 ++++++++++++++----- ...ThatWeWantToBuildAWindowsDesktopProject.cs | 9 ++++-- 2 files changed, 28 insertions(+), 9 deletions(-) diff --git a/src/Tasks/Microsoft.NET.Build.Tasks/CreateWindowsSdkKnownFrameworkReferences.cs b/src/Tasks/Microsoft.NET.Build.Tasks/CreateWindowsSdkKnownFrameworkReferences.cs index 03354607a22a..7b2e2a433f50 100644 --- a/src/Tasks/Microsoft.NET.Build.Tasks/CreateWindowsSdkKnownFrameworkReferences.cs +++ b/src/Tasks/Microsoft.NET.Build.Tasks/CreateWindowsSdkKnownFrameworkReferences.cs @@ -56,7 +56,8 @@ protected override void ExecuteCore() { var normalizedTargetFrameworkVersion = ProcessFrameworkReferences.NormalizeVersion(new Version(TargetFrameworkVersion)); - var matchingKnownFrameworkReferences = new List<(Version minimumNetVersion, TaskItem knownFrameworkReference)>(); + var knownFrameworkReferencesByWindowsSdkVersion = new Dictionary>(); + foreach (var supportedWindowsVersion in WindowsSdkSupportedTargetPlatformVersions) { var windowsSdkPackageVersion = supportedWindowsVersion.GetMetadata("WindowsSdkPackageVersion"); @@ -74,15 +75,28 @@ protected override void ExecuteCore() } } - matchingKnownFrameworkReferences.Add((normalizedMinimumVersion, CreateKnownFrameworkReference(windowsSdkPackageVersion, TargetFrameworkVersion, supportedWindowsVersion.ItemSpec))); - + if (!Version.TryParse(supportedWindowsVersion.ItemSpec, out var windowsSdkVersionParsed)) + { + continue; + } + + if (!knownFrameworkReferencesByWindowsSdkVersion.ContainsKey(windowsSdkVersionParsed)) + { + knownFrameworkReferencesByWindowsSdkVersion[windowsSdkVersionParsed] = new(); + } + + knownFrameworkReferencesByWindowsSdkVersion[windowsSdkVersionParsed].Add((normalizedMinimumVersion, CreateKnownFrameworkReference(windowsSdkPackageVersion, TargetFrameworkVersion, supportedWindowsVersion.ItemSpec))); + } } - // If there are multiple matching WindowsSdkSupportedTargetPlatformVersion items, choose the one with the highest minimum version. That way it is possible to - // use older packages when targeting older versions of .NET, and newer packages for newer versions of .NET - var highestMinimumVersion = matchingKnownFrameworkReferences.Max(t => t.minimumNetVersion); - knownFrameworkReferences.AddRange(matchingKnownFrameworkReferences.Where(t => t.minimumNetVersion == highestMinimumVersion).Select(t => t.knownFrameworkReference)); + foreach (var knownFrameworkReferencesForSdkVersion in knownFrameworkReferencesByWindowsSdkVersion.Values) + { + // If there are multiple WindowsSdkSupportedTargetPlatformVersion items for the same Windows SDK version, choose the one with the highest minimum version. + // That way it is possible to use older packages when targeting older versions of .NET, and newer packages for newer versions of .NET + var highestMinimumVersion = knownFrameworkReferencesForSdkVersion.Max(t => t.minimumNetVersion); + knownFrameworkReferences.AddRange(knownFrameworkReferencesForSdkVersion.Where(t => t.minimumNetVersion == highestMinimumVersion).Select(t => t.knownFrameworkReference)); + } } KnownFrameworkReferences = knownFrameworkReferences.ToArray(); diff --git a/src/Tests/Microsoft.NET.Build.Tests/GivenThatWeWantToBuildAWindowsDesktopProject.cs b/src/Tests/Microsoft.NET.Build.Tests/GivenThatWeWantToBuildAWindowsDesktopProject.cs index 77502bedb5db..75e52af93b8f 100644 --- a/src/Tests/Microsoft.NET.Build.Tests/GivenThatWeWantToBuildAWindowsDesktopProject.cs +++ b/src/Tests/Microsoft.NET.Build.Tests/GivenThatWeWantToBuildAWindowsDesktopProject.cs @@ -415,10 +415,11 @@ public void ItUsesCorrectWindowsSdkPackVersion(string targetFramework, bool? use referencedWindowsSdkVersion.Should().Be(expectedWindowsSdkPackageVersion); } - [Theory] + [WindowsOnlyTheory] [InlineData("net5.0-windows10.0.22000.0", "10.0.22000.25")] [InlineData("net6.0-windows10.0.22000.0", "10.0.22000.26")] - public void ItUsesTheHighestMatchingWindowsSdkPackageVersion2(string targetFramework, string expectedWindowsSdkPackageVersion) + [InlineData("net6.0-windows10.0.19041.0", "10.0.19041.25")] + public void ItUsesTheHighestMatchingWindowsSdkPackageVersion(string targetFramework, string expectedWindowsSdkPackageVersion) { var testProject = new TestProject() { @@ -433,8 +434,12 @@ public void ItUsesTheHighestMatchingWindowsSdkPackageVersion2(string targetFrame + + + + "); project.Root.Add(testItems); From 492d770d2dfecb6f31b9dab5f08849eaa5fff066 Mon Sep 17 00:00:00 2001 From: Daniel Plaisted Date: Tue, 16 Aug 2022 16:06:32 -0400 Subject: [PATCH 3/3] Use separate test folders --- .../GivenThatWeWantToBuildAWindowsDesktopProject.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Tests/Microsoft.NET.Build.Tests/GivenThatWeWantToBuildAWindowsDesktopProject.cs b/src/Tests/Microsoft.NET.Build.Tests/GivenThatWeWantToBuildAWindowsDesktopProject.cs index 75e52af93b8f..b6a6ec6e22a4 100644 --- a/src/Tests/Microsoft.NET.Build.Tests/GivenThatWeWantToBuildAWindowsDesktopProject.cs +++ b/src/Tests/Microsoft.NET.Build.Tests/GivenThatWeWantToBuildAWindowsDesktopProject.cs @@ -426,7 +426,7 @@ public void ItUsesTheHighestMatchingWindowsSdkPackageVersion(string targetFramew TargetFrameworks = targetFramework }; - var testAsset = _testAssetsManager.CreateTestProject(testProject) + var testAsset = _testAssetsManager.CreateTestProject(testProject, identifier: targetFramework) .WithProjectChanges(project => { // Add items for available SDK versions for test