From 9fa393b0afa2b4298535f43b7de9a9dd26eefcd8 Mon Sep 17 00:00:00 2001 From: Jeremy Koritzinsky Date: Fri, 31 Jan 2025 15:04:17 -0800 Subject: [PATCH 1/5] Select the NativeAOT runtime pack as the target package when it's provided as part of the KnownILCompilerPack metadata. Depends on https://github.com/dotnet/runtime/pull/111876 --- .../targets/GenerateBundledVersions.targets | 1 + .../ProcessFrameworkReferences.cs | 15 +++++++++++++-- 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/src/Installer/redist-installer/targets/GenerateBundledVersions.targets b/src/Installer/redist-installer/targets/GenerateBundledVersions.targets index 3d0600418a92..2f51499049f5 100644 --- a/src/Installer/redist-installer/targets/GenerateBundledVersions.targets +++ b/src/Installer/redist-installer/targets/GenerateBundledVersions.targets @@ -572,6 +572,7 @@ Copyright (c) .NET Foundation. All rights reserved. diff --git a/src/Tasks/Microsoft.NET.Build.Tasks/ProcessFrameworkReferences.cs b/src/Tasks/Microsoft.NET.Build.Tasks/ProcessFrameworkReferences.cs index e494e717d04f..0c09043f6722 100644 --- a/src/Tasks/Microsoft.NET.Build.Tasks/ProcessFrameworkReferences.cs +++ b/src/Tasks/Microsoft.NET.Build.Tasks/ProcessFrameworkReferences.cs @@ -846,9 +846,20 @@ private ToolPackSupport AddToolPack( { return ToolPackSupport.UnsupportedForTargetRuntimeIdentifier; } - if (!hostRuntimeIdentifier.Equals(targetRuntimeIdentifier)) + + // If we have a separate pack pattern for the runtime pack, + // we should always use the runtime pack (the host pack may not have the tooling we need for the target). + bool useRuntimePackForAllTargets = false; + string targetPackNamePattern = packNamePattern; + if (knownPack.GetMetadata("ILCompilerRuntimePackNamePattern") is string runtimePackNamePattern) + { + targetPackNamePattern = runtimePackNamePattern; + useRuntimePackForAllTargets = true; + } + + if (useRuntimePackForAllTargets || !hostRuntimeIdentifier.Equals(targetRuntimeIdentifier)) { - var targetIlcPackName = packNamePattern.Replace("**RID**", targetRuntimeIdentifier); + var targetIlcPackName = targetPackNamePattern.Replace("**RID**", targetRuntimeIdentifier); var targetIlcPack = new TaskItem(targetIlcPackName); targetIlcPack.SetMetadata(MetadataKeys.NuGetPackageId, targetIlcPackName); targetIlcPack.SetMetadata(MetadataKeys.NuGetPackageVersion, packVersion); From ec7b0a0e2ef420997743c8f4a4fd8f367904ba5e Mon Sep 17 00:00:00 2001 From: Jeremy Koritzinsky Date: Fri, 14 Mar 2025 16:16:38 -0700 Subject: [PATCH 2/5] Use Sven's comment wording --- .../Microsoft.NET.Build.Tasks/ProcessFrameworkReferences.cs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/Tasks/Microsoft.NET.Build.Tasks/ProcessFrameworkReferences.cs b/src/Tasks/Microsoft.NET.Build.Tasks/ProcessFrameworkReferences.cs index 0c09043f6722..3bd0e06f398a 100644 --- a/src/Tasks/Microsoft.NET.Build.Tasks/ProcessFrameworkReferences.cs +++ b/src/Tasks/Microsoft.NET.Build.Tasks/ProcessFrameworkReferences.cs @@ -847,8 +847,7 @@ private ToolPackSupport AddToolPack( return ToolPackSupport.UnsupportedForTargetRuntimeIdentifier; } - // If we have a separate pack pattern for the runtime pack, - // we should always use the runtime pack (the host pack may not have the tooling we need for the target). + // If there's an available runtime pack, use it instead of the ILCompiler package for target-specific bits. bool useRuntimePackForAllTargets = false; string targetPackNamePattern = packNamePattern; if (knownPack.GetMetadata("ILCompilerRuntimePackNamePattern") is string runtimePackNamePattern) From ce791be278e5e11f5cc9e62842a8719a1ffcaf6b Mon Sep 17 00:00:00 2001 From: Jeremy Koritzinsky Date: Tue, 18 Mar 2025 12:08:38 -0700 Subject: [PATCH 3/5] Check for an empty string, not just null. --- .../Microsoft.NET.Build.Tasks/ProcessFrameworkReferences.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Tasks/Microsoft.NET.Build.Tasks/ProcessFrameworkReferences.cs b/src/Tasks/Microsoft.NET.Build.Tasks/ProcessFrameworkReferences.cs index 3bd0e06f398a..764bd5b295f9 100644 --- a/src/Tasks/Microsoft.NET.Build.Tasks/ProcessFrameworkReferences.cs +++ b/src/Tasks/Microsoft.NET.Build.Tasks/ProcessFrameworkReferences.cs @@ -850,7 +850,7 @@ private ToolPackSupport AddToolPack( // If there's an available runtime pack, use it instead of the ILCompiler package for target-specific bits. bool useRuntimePackForAllTargets = false; string targetPackNamePattern = packNamePattern; - if (knownPack.GetMetadata("ILCompilerRuntimePackNamePattern") is string runtimePackNamePattern) + if (knownPack.GetMetadata("ILCompilerRuntimePackNamePattern") is string runtimePackNamePattern && runtimePackNamePattern != string.Empty) { targetPackNamePattern = runtimePackNamePattern; useRuntimePackForAllTargets = true; From 2cc9b5ab3f9092a67c3f370b4eaee371c02b047f Mon Sep 17 00:00:00 2001 From: Jeremy Koritzinsky Date: Tue, 25 Mar 2025 15:15:00 -0700 Subject: [PATCH 4/5] Download the Target ILC pack if it's not available on disk (the most common case) --- .../ProcessFrameworkReferences.cs | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/src/Tasks/Microsoft.NET.Build.Tasks/ProcessFrameworkReferences.cs b/src/Tasks/Microsoft.NET.Build.Tasks/ProcessFrameworkReferences.cs index 764bd5b295f9..3f88eb1486c8 100644 --- a/src/Tasks/Microsoft.NET.Build.Tasks/ProcessFrameworkReferences.cs +++ b/src/Tasks/Microsoft.NET.Build.Tasks/ProcessFrameworkReferences.cs @@ -863,6 +863,19 @@ private ToolPackSupport AddToolPack( targetIlcPack.SetMetadata(MetadataKeys.NuGetPackageId, targetIlcPackName); targetIlcPack.SetMetadata(MetadataKeys.NuGetPackageVersion, packVersion); TargetILCompilerPacks = new[] { targetIlcPack }; + + string targetILCompilerPackPath = GetPackPath(targetIlcPackName, packVersion); + if (targetILCompilerPackPath != null) + { + targetIlcPack.SetMetadata(MetadataKeys.PackageDirectory, targetILCompilerPackPath); + } + else if (EnableRuntimePackDownload) + { + // We need to download the runtime pack + var targetIlcPackToDownload = new TaskItem(targetIlcPackName); + targetIlcPackToDownload.SetMetadata(MetadataKeys.Version, packVersion); + packagesToDownload.Add(targetIlcPackToDownload); + } } } From a11064533d4c1f4bd38fde5ff0e7cc2620f91e27 Mon Sep 17 00:00:00 2001 From: Jeremy Koritzinsky Date: Thu, 19 Jun 2025 13:00:46 -0700 Subject: [PATCH 5/5] Fix tests and stop testing referencing a downlevel NativeAOT package --- .../GivenThatWeWantToPublishAnAotApp.cs | 56 +++++++++++++------ 1 file changed, 39 insertions(+), 17 deletions(-) diff --git a/test/Microsoft.NET.Publish.Tests/GivenThatWeWantToPublishAnAotApp.cs b/test/Microsoft.NET.Publish.Tests/GivenThatWeWantToPublishAnAotApp.cs index 9355be163c3f..7963c9924869 100644 --- a/test/Microsoft.NET.Publish.Tests/GivenThatWeWantToPublishAnAotApp.cs +++ b/test/Microsoft.NET.Publish.Tests/GivenThatWeWantToPublishAnAotApp.cs @@ -15,7 +15,7 @@ public class GivenThatWeWantToPublishAnAotApp : SdkTest { private readonly string RuntimeIdentifier = $"/p:RuntimeIdentifier={RuntimeInformation.RuntimeIdentifier}"; - private readonly string ExplicitPackageVersion = "7.0.0-rc.2.22456.11"; + private const string NetCurrentExplicitPackageVersion = "10.0.0-preview.6.25316.103"; public GivenThatWeWantToPublishAnAotApp(ITestOutputHelper log) : base(log) { @@ -67,8 +67,10 @@ public void NativeAot_hw_runs_with_no_warnings_when_PublishAot_is_enabled(string DoSymbolsExist(publishDirectory, testProject.Name).Should().BeTrue($"{publishDirectory} should contain {testProject.Name} symbol"); IsNativeImage(publishedExe).Should().BeTrue(); + bool useRuntimePackLayout = targetFramework is not ("net7.0" or "net8.0" or "net9.0"); + GetKnownILCompilerPackVersion(testAsset, targetFramework, out string expectedVersion); - CheckIlcVersions(testAsset, targetFramework, rid, expectedVersion); + CheckIlcVersions(testAsset, targetFramework, rid, expectedVersion, useRuntimePackLayout); var command = new RunExeCommand(Log, publishedExe) .Execute().Should().Pass() @@ -249,8 +251,10 @@ public void NativeAot_app_builds_with_config_when_PublishAot_is_enabled(string t File.Exists(depsPath).Should().BeTrue(); } + private const string Net7ExplicitPackageVersion = "7.0.0"; + [RequiresMSBuildVersionTheory("17.0.0.32901")] - [InlineData(ToolsetInfo.CurrentTargetFramework)] + [InlineData("net7.0")] public void NativeAot_hw_runs_with_PackageReference_PublishAot_is_enabled(string targetFramework) { if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX)) @@ -266,7 +270,7 @@ public void NativeAot_hw_runs_with_PackageReference_PublishAot_is_enabled(string testProject.AdditionalProperties["PublishAot"] = "true"; // This will add a reference to a package that will also be automatically imported by the SDK - testProject.PackageReferences.Add(new TestPackageReference("Microsoft.DotNet.ILCompiler", ExplicitPackageVersion)); + testProject.PackageReferences.Add(new TestPackageReference("Microsoft.DotNet.ILCompiler", Net7ExplicitPackageVersion)); // Linux symbol files are embedded and require additional steps to be stripped to a separate file // assumes /bin (or /usr/bin) are in the PATH @@ -302,7 +306,7 @@ public void NativeAot_hw_runs_with_PackageReference_PublishAot_is_enabled(string .Execute().Should().Pass() .And.HaveStdOutContaining("Hello World"); - CheckIlcVersions(testAsset, targetFramework, rid, ExplicitPackageVersion); + CheckIlcVersions(testAsset, targetFramework, rid, Net7ExplicitPackageVersion, useRuntimePackLayout: false); } [RequiresMSBuildVersionTheory("17.0.0.32901")] @@ -315,7 +319,7 @@ public void NativeAot_hw_runs_with_PackageReference_PublishAot_is_empty(string t var testProject = CreateHelloWorldTestProject(targetFramework, projectName, true); // This will add a reference to a package that will also be automatically imported by the SDK - testProject.PackageReferences.Add(new TestPackageReference("Microsoft.DotNet.ILCompiler", ExplicitPackageVersion)); + testProject.PackageReferences.Add(new TestPackageReference("Microsoft.DotNet.ILCompiler", NetCurrentExplicitPackageVersion)); // Linux symbol files are embedded and require additional steps to be stripped to a separate file // assumes /bin (or /usr/bin) are in the PATH @@ -343,7 +347,7 @@ public void NativeAot_hw_runs_with_PackageReference_PublishAot_is_empty(string t } [RequiresMSBuildVersionTheory("17.0.0.32901")] - [MemberData(nameof(Net7Plus), MemberType = typeof(PublishTestUtils))] + [InlineData(ToolsetInfo.CurrentTargetFramework)] public void NativeAot_hw_runs_with_cross_target_PublishAot_is_enabled(string targetFramework) { if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows) && (RuntimeInformation.OSArchitecture == Architecture.X64)) @@ -367,13 +371,13 @@ public void NativeAot_hw_runs_with_cross_target_PublishAot_is_enabled(string tar File.Exists(publishedExe).Should().BeTrue(); GetKnownILCompilerPackVersion(testAsset, targetFramework, out string expectedVersion); - CheckIlcVersions(testAsset, targetFramework, rid, expectedVersion); + CheckIlcVersions(testAsset, targetFramework, rid, expectedVersion, useRuntimePackLayout: true); } } [RequiresMSBuildVersionTheory("17.0.0.32901")] - [MemberData(nameof(Net7Plus), MemberType = typeof(PublishTestUtils))] + [InlineData(ToolsetInfo.CurrentTargetFramework)] public void NativeAot_hw_runs_with_cross_PackageReference_PublishAot_is_enabled(string targetFramework) { if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows) && (RuntimeInformation.OSArchitecture == Architecture.X64)) @@ -382,11 +386,16 @@ public void NativeAot_hw_runs_with_cross_PackageReference_PublishAot_is_enabled( var rid = "win-arm64"; var testProject = CreateHelloWorldTestProject(targetFramework, projectName, true); + testProject.RecordProperties("BundledNETCoreAppPackageVersion"); testProject.AdditionalProperties["PublishAot"] = "true"; // This will add a reference to a package that will also be automatically imported by the SDK - testProject.PackageReferences.Add(new TestPackageReference("Microsoft.DotNet.ILCompiler", ExplicitPackageVersion)); - testProject.PackageReferences.Add(new TestPackageReference("runtime.win-x64.Microsoft.DotNet.ILCompiler", ExplicitPackageVersion)); + testProject.PackageReferences.Add(new TestPackageReference("Microsoft.DotNet.ILCompiler", "$(BundledNETCoreAppPackageVersion)")); + testProject.AddItem("PackageDownload", new Dictionary + { + { "Include", "Microsoft.NETCore.App.Runtime.NativeAOT.win-arm64" }, + { "Version", $"[$(BundledNETCoreAppPackageVersion)]" } + }); var testAsset = _testAssetsManager.CreateTestProject(testProject, identifier: targetFramework); @@ -398,13 +407,16 @@ public void NativeAot_hw_runs_with_cross_PackageReference_PublishAot_is_enabled( .And.HaveStdOutContaining("warning") .And.HaveStdOutContaining("Microsoft.DotNet.ILCompiler"); + var buildProperties = testProject.GetPropertyValues(testAsset.TestRoot, targetFramework); + var targetVersion = buildProperties["BundledNETCoreAppPackageVersion"]; + var publishDirectory = publishCommand.GetOutputDirectory(targetFramework: targetFramework, runtimeIdentifier: rid).FullName; var publishedDll = Path.Combine(publishDirectory, $"{projectName}.dll"); var publishedExe = Path.Combine(publishDirectory, $"{testProject.Name}{Constants.ExeSuffix}"); File.Exists(publishedDll).Should().BeFalse(); File.Exists(publishedExe).Should().BeTrue(); - CheckIlcVersions(testAsset, targetFramework, rid, ExplicitPackageVersion); + CheckIlcVersions(testAsset, targetFramework, rid, targetVersion, useRuntimePackLayout: true); } } @@ -420,8 +432,8 @@ public void NativeAot_hw_runs_with_cross_PackageReference_PublishAot_is_empty(st var testProject = CreateHelloWorldTestProject(targetFramework, projectName, true); // This will add a reference to a package that will also be automatically imported by the SDK - testProject.PackageReferences.Add(new TestPackageReference("Microsoft.DotNet.ILCompiler", ExplicitPackageVersion)); - testProject.PackageReferences.Add(new TestPackageReference("runtime.win-x64.Microsoft.DotNet.ILCompiler", ExplicitPackageVersion)); + testProject.PackageReferences.Add(new TestPackageReference("Microsoft.DotNet.ILCompiler", NetCurrentExplicitPackageVersion)); + testProject.PackageReferences.Add(new TestPackageReference("runtime.win-x64.Microsoft.DotNet.ILCompiler", NetCurrentExplicitPackageVersion)); var testAsset = _testAssetsManager.CreateTestProject(testProject, identifier: targetFramework); @@ -469,7 +481,7 @@ public void NativeAot_hw_fails_with_sdk6_PackageReference_PublishAot_is_enabled( var testProject = CreateHelloWorldTestProject("net6.0", projectName, true); testProject.AdditionalProperties["PublishAot"] = "true"; - testProject.PackageReferences.Add(new TestPackageReference("Microsoft.DotNet.ILCompiler", ExplicitPackageVersion)); + testProject.PackageReferences.Add(new TestPackageReference("Microsoft.DotNet.ILCompiler", NetCurrentExplicitPackageVersion)); var testAsset = _testAssetsManager.CreateTestProject(testProject, identifier: targetFramework); @@ -1041,7 +1053,7 @@ private void GetKnownILCompilerPackVersion(TestAsset testAsset, string targetFra .Single(); } - private void CheckIlcVersions(TestAsset testAsset, string targetFramework, string rid, string expectedVersion) + private void CheckIlcVersions(TestAsset testAsset, string targetFramework, string rid, string expectedVersion, bool useRuntimePackLayout) { // Compiler version matches expected version var ilcToolsPathCommand = new GetValuesCommand(testAsset, "IlcToolsPath", targetFramework: targetFramework) @@ -1061,7 +1073,17 @@ private void CheckIlcVersions(TestAsset testAsset, string targetFramework, strin ilcReferenceCommand.Execute($"/p:RuntimeIdentifier={rid}", "/p:SelfContained=true").Should().Pass(); var ilcReference = ilcReferenceCommand.GetValues(); var corelibReference = ilcReference.Where(r => Path.GetFileName(r).Equals("System.Private.CoreLib.dll")).Single(); - var ilcReferenceVersion = Path.GetFileName(Path.GetDirectoryName(Path.GetDirectoryName(corelibReference))); + string ilcReferenceVersion; + if (useRuntimePackLayout) + { + // In the runtime pack layout, System.Private.CoreLib.dll is in the runtimes//native directory + ilcReferenceVersion = Path.GetFileName(Path.GetDirectoryName(Path.GetDirectoryName(Path.GetDirectoryName(Path.GetDirectoryName(corelibReference))))); + } + else + { + // In the old layout, System.Private.CoreLib.dll is in the framework directory + ilcReferenceVersion = Path.GetFileName(Path.GetDirectoryName(Path.GetDirectoryName(corelibReference))); + } ilcReferenceVersion.Should().Be(expectedVersion); }