diff --git a/src/Layout/redist/PortableRuntimeIdentifierGraph.json b/src/Layout/redist/PortableRuntimeIdentifierGraph.json new file mode 100644 index 000000000000..15eaa941d8d6 --- /dev/null +++ b/src/Layout/redist/PortableRuntimeIdentifierGraph.json @@ -0,0 +1,464 @@ +{ + "runtimes": { + "android": { + "#import": [ + "linux-bionic" + ] + }, + "android-arm": { + "#import": [ + "android", + "linux-bionic-arm" + ] + }, + "android-arm64": { + "#import": [ + "android", + "linux-bionic-arm64" + ] + }, + "android-x64": { + "#import": [ + "android", + "linux-bionic-x64" + ] + }, + "android-x86": { + "#import": [ + "android", + "linux-bionic-x86" + ] + }, + "any": { + "#import": [ + "base" + ] + }, + "base": { + "#import": [] + }, + "browser": { + "#import": [ + "any" + ] + }, + "browser-wasm": { + "#import": [ + "browser" + ] + }, + "freebsd": { + "#import": [ + "unix" + ] + }, + "freebsd-arm64": { + "#import": [ + "freebsd", + "unix-arm64" + ] + }, + "freebsd-x64": { + "#import": [ + "freebsd", + "unix-x64" + ] + }, + "illumos": { + "#import": [ + "unix" + ] + }, + "illumos-x64": { + "#import": [ + "illumos", + "unix-x64" + ] + }, + "ios": { + "#import": [ + "unix" + ] + }, + "ios-arm": { + "#import": [ + "ios", + "unix-arm" + ] + }, + "ios-arm64": { + "#import": [ + "ios", + "unix-arm64" + ] + }, + "ios-x64": { + "#import": [ + "ios", + "unix-x64" + ] + }, + "ios-x86": { + "#import": [ + "ios", + "unix-x86" + ] + }, + "iossimulator": { + "#import": [ + "ios" + ] + }, + "iossimulator-arm64": { + "#import": [ + "iossimulator", + "ios-arm64" + ] + }, + "iossimulator-x64": { + "#import": [ + "iossimulator", + "ios-x64" + ] + }, + "iossimulator-x86": { + "#import": [ + "iossimulator", + "ios-x86" + ] + }, + "linux": { + "#import": [ + "unix" + ] + }, + "linux-arm": { + "#import": [ + "linux", + "unix-arm" + ] + }, + "linux-arm64": { + "#import": [ + "linux", + "unix-arm64" + ] + }, + "linux-armel": { + "#import": [ + "linux", + "unix-armel" + ] + }, + "linux-armv6": { + "#import": [ + "linux", + "unix-armv6" + ] + }, + "linux-bionic": { + "#import": [ + "linux" + ] + }, + "linux-bionic-arm": { + "#import": [ + "linux-bionic", + "linux-arm" + ] + }, + "linux-bionic-arm64": { + "#import": [ + "linux-bionic", + "linux-arm64" + ] + }, + "linux-bionic-x64": { + "#import": [ + "linux-bionic", + "linux-x64" + ] + }, + "linux-bionic-x86": { + "#import": [ + "linux-bionic", + "linux-x86" + ] + }, + "linux-loongarch64": { + "#import": [ + "linux", + "unix-loongarch64" + ] + }, + "linux-mips64": { + "#import": [ + "linux", + "unix-mips64" + ] + }, + "linux-musl": { + "#import": [ + "linux" + ] + }, + "linux-musl-arm": { + "#import": [ + "linux-musl", + "linux-arm" + ] + }, + "linux-musl-arm64": { + "#import": [ + "linux-musl", + "linux-arm64" + ] + }, + "linux-musl-armel": { + "#import": [ + "linux-musl", + "linux-armel" + ] + }, + "linux-musl-armv6": { + "#import": [ + "linux-musl", + "linux-armv6" + ] + }, + "linux-musl-ppc64le": { + "#import": [ + "linux-musl", + "linux-ppc64le" + ] + }, + "linux-musl-riscv64": { + "#import": [ + "linux-musl", + "linux-riscv64" + ] + }, + "linux-musl-s390x": { + "#import": [ + "linux-musl", + "linux-s390x" + ] + }, + "linux-musl-x64": { + "#import": [ + "linux-musl", + "linux-x64" + ] + }, + "linux-musl-x86": { + "#import": [ + "linux-musl", + "linux-x86" + ] + }, + "linux-ppc64le": { + "#import": [ + "linux", + "unix-ppc64le" + ] + }, + "linux-riscv64": { + "#import": [ + "linux", + "unix-riscv64" + ] + }, + "linux-s390x": { + "#import": [ + "linux", + "unix-s390x" + ] + }, + "linux-x64": { + "#import": [ + "linux", + "unix-x64" + ] + }, + "linux-x86": { + "#import": [ + "linux", + "unix-x86" + ] + }, + "maccatalyst": { + "#import": [ + "ios" + ] + }, + "maccatalyst-arm64": { + "#import": [ + "maccatalyst", + "ios-arm64" + ] + }, + "maccatalyst-x64": { + "#import": [ + "maccatalyst", + "ios-x64" + ] + }, + "osx": { + "#import": [ + "unix" + ] + }, + "osx-arm64": { + "#import": [ + "osx", + "unix-arm64" + ] + }, + "osx-x64": { + "#import": [ + "osx", + "unix-x64" + ] + }, + "solaris": { + "#import": [ + "unix" + ] + }, + "solaris-x64": { + "#import": [ + "solaris", + "unix-x64" + ] + }, + "tvos": { + "#import": [ + "unix" + ] + }, + "tvos-arm64": { + "#import": [ + "tvos", + "unix-arm64" + ] + }, + "tvos-x64": { + "#import": [ + "tvos", + "unix-x64" + ] + }, + "tvossimulator": { + "#import": [ + "tvos" + ] + }, + "tvossimulator-arm64": { + "#import": [ + "tvossimulator", + "tvos-arm64" + ] + }, + "tvossimulator-x64": { + "#import": [ + "tvossimulator", + "tvos-x64" + ] + }, + "unix": { + "#import": [ + "any" + ] + }, + "unix-arm": { + "#import": [ + "unix" + ] + }, + "unix-arm64": { + "#import": [ + "unix" + ] + }, + "unix-armel": { + "#import": [ + "unix" + ] + }, + "unix-armv6": { + "#import": [ + "unix" + ] + }, + "unix-loongarch64": { + "#import": [ + "unix" + ] + }, + "unix-mips64": { + "#import": [ + "unix" + ] + }, + "unix-ppc64le": { + "#import": [ + "unix" + ] + }, + "unix-riscv64": { + "#import": [ + "unix" + ] + }, + "unix-s390x": { + "#import": [ + "unix" + ] + }, + "unix-x64": { + "#import": [ + "unix" + ] + }, + "unix-x86": { + "#import": [ + "unix" + ] + }, + "wasi": { + "#import": [ + "any" + ] + }, + "wasi-wasm": { + "#import": [ + "wasi" + ] + }, + "win": { + "#import": [ + "any" + ] + }, + "win-arm": { + "#import": [ + "win" + ] + }, + "win-arm64": { + "#import": [ + "win" + ] + }, + "win-x64": { + "#import": [ + "win" + ] + }, + "win-x86": { + "#import": [ + "win" + ] + } + } +} \ No newline at end of file diff --git a/src/Layout/redist/targets/BuildToolsetTasks.targets b/src/Layout/redist/targets/BuildToolsetTasks.targets index cac5531e9410..d797c0c58fe8 100644 --- a/src/Layout/redist/targets/BuildToolsetTasks.targets +++ b/src/Layout/redist/targets/BuildToolsetTasks.targets @@ -27,5 +27,6 @@ + diff --git a/src/Layout/redist/targets/GenerateLayout.targets b/src/Layout/redist/targets/GenerateLayout.targets index 1b52be48c55a..ab3fde10b18b 100644 --- a/src/Layout/redist/targets/GenerateLayout.targets +++ b/src/Layout/redist/targets/GenerateLayout.targets @@ -1,4 +1,16 @@ + + + + + + + diff --git a/src/Layout/toolset-tasks/UpdatePortableRuntimeIdentifierGraph.cs b/src/Layout/toolset-tasks/UpdatePortableRuntimeIdentifierGraph.cs new file mode 100644 index 000000000000..823abf44064f --- /dev/null +++ b/src/Layout/toolset-tasks/UpdatePortableRuntimeIdentifierGraph.cs @@ -0,0 +1,60 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Security.Cryptography; +using System.Text; +using System.Threading.Tasks; +using Microsoft.Build.Framework; +using Microsoft.Build.Utilities; +using Newtonsoft.Json; +using Newtonsoft.Json.Linq; + +namespace Microsoft.DotNet.Cli.Build +{ + public class UpdatePortableRuntimeIdentifierGraph : Task + { + [Required] + public string InputFile { get; set; } + + [Required] + public string OutputFile { get; set; } + + + // ItemSpec should be a RID, and "Imports" metadata should be a semicolon-separated list of RIDs that the ItemSpec RID imports + public ITaskItem[] AdditionalRuntimeIdentifiers { get; set; } + + public override bool Execute() + { + JToken json; + + using (var file = File.OpenText(InputFile)) + using (JsonTextReader reader = new JsonTextReader(file)) + { + json = JObject.ReadFrom(reader); + } + + JObject runtimes = (JObject) json["runtimes"]; + + if (AdditionalRuntimeIdentifiers != null) + { + foreach (var rid in AdditionalRuntimeIdentifiers) + { + var importedRids = rid.GetMetadata("Imports").Split(';'); + runtimes.Add(rid.ItemSpec, new JObject(new JProperty("#import", new JArray(importedRids)))); + } + } + + using (var file = File.CreateText(OutputFile)) + using (var writer = new JsonTextWriter(file) { Formatting = Formatting.Indented }) + { + json.WriteTo(writer); + } + + return true; + } + } +} diff --git a/src/Tasks/Microsoft.NET.Build.Tasks/targets/Microsoft.NET.CrossGen.targets b/src/Tasks/Microsoft.NET.Build.Tasks/targets/Microsoft.NET.CrossGen.targets index ccb1de06d902..baef53365801 100644 --- a/src/Tasks/Microsoft.NET.Build.Tasks/targets/Microsoft.NET.CrossGen.targets +++ b/src/Tasks/Microsoft.NET.Build.Tasks/targets/Microsoft.NET.CrossGen.targets @@ -444,7 +444,7 @@ Copyright (c) .NET Foundation. All rights reserved. diff --git a/src/Tasks/Microsoft.NET.Build.Tasks/targets/Microsoft.NET.Publish.targets b/src/Tasks/Microsoft.NET.Build.Tasks/targets/Microsoft.NET.Publish.targets index 883bbe46a621..782633b9ea5d 100644 --- a/src/Tasks/Microsoft.NET.Build.Tasks/targets/Microsoft.NET.Publish.targets +++ b/src/Tasks/Microsoft.NET.Build.Tasks/targets/Microsoft.NET.Publish.targets @@ -329,7 +329,7 @@ Copyright (c) .NET Foundation. All rights reserved. <_GeneratePublishDependencyFilePropertyInputsCacheToHash Include="$(SelfContained)" /> <_GeneratePublishDependencyFilePropertyInputsCacheToHash Include="$(IncludeFileVersionsInDependencyFile)" /> - <_GeneratePublishDependencyFilePropertyInputsCacheToHash Include="$(BundledRuntimeIdentifierGraphFile)" /> + <_GeneratePublishDependencyFilePropertyInputsCacheToHash Include="$(RuntimeIdentifierGraphPath)" /> <_GeneratePublishDependencyFilePropertyInputsCacheToHash Include="$(IncludeProjectsNotInAssetsFileInDepsFile)" /> @@ -1099,7 +1099,7 @@ Copyright (c) .NET Foundation. All rights reserved. IsSelfContained="$(SelfContained)" IsSingleFile="$(_IsSingleFilePublish)" IncludeRuntimeFileVersions="$(IncludeFileVersionsInDependencyFile)" - RuntimeGraphPath="$(BundledRuntimeIdentifierGraphFile)" + RuntimeGraphPath="$(RuntimeIdentifierGraphPath)" IncludeProjectsNotInAssetsFile="$(IncludeProjectsNotInAssetsFileInDepsFile)"/> diff --git a/src/Tasks/Microsoft.NET.Build.Tasks/targets/Microsoft.NET.Sdk.DefaultItems.props b/src/Tasks/Microsoft.NET.Build.Tasks/targets/Microsoft.NET.Sdk.DefaultItems.props index 9aa86611864e..e928f4d1c607 100644 --- a/src/Tasks/Microsoft.NET.Build.Tasks/targets/Microsoft.NET.Sdk.DefaultItems.props +++ b/src/Tasks/Microsoft.NET.Build.Tasks/targets/Microsoft.NET.Sdk.DefaultItems.props @@ -17,12 +17,6 @@ Copyright (c) .NET Foundation. All rights reserved. - - - $(BundledRuntimeIdentifierGraphFile) - - false diff --git a/src/Tasks/Microsoft.NET.Build.Tasks/targets/Microsoft.NET.Sdk.FrameworkReferenceResolution.targets b/src/Tasks/Microsoft.NET.Build.Tasks/targets/Microsoft.NET.Sdk.FrameworkReferenceResolution.targets index 8b32ba911b3c..9c706d603631 100644 --- a/src/Tasks/Microsoft.NET.Build.Tasks/targets/Microsoft.NET.Sdk.FrameworkReferenceResolution.targets +++ b/src/Tasks/Microsoft.NET.Build.Tasks/targets/Microsoft.NET.Sdk.FrameworkReferenceResolution.targets @@ -95,7 +95,7 @@ Copyright (c) .NET Foundation. All rights reserved. TargetPlatformIdentifier="$(TargetPlatformIdentifier)" TargetPlatformVersion="$(TargetPlatformVersion)" TargetingPackRoot="$(NetCoreTargetingPackRoot)" - RuntimeGraphPath="$(BundledRuntimeIdentifierGraphFile)" + RuntimeGraphPath="$(RuntimeIdentifierGraphPath)" SelfContained="$(SelfContained)" ReadyToRunEnabled="$(PublishReadyToRun)" ReadyToRunUseCrossgen2="$(PublishReadyToRunUseCrossgen2)" @@ -155,7 +155,7 @@ Copyright (c) .NET Foundation. All rights reserved. DotNetSingleFileHostExecutableNameWithoutExtension="$(_DotNetSingleFileHostExecutableNameWithoutExtension)" DotNetComHostLibraryNameWithoutExtension="$(_DotNetComHostLibraryNameWithoutExtension)" DotNetIjwHostLibraryNameWithoutExtension="$(_DotNetIjwHostLibraryNameWithoutExtension)" - RuntimeGraphPath="$(BundledRuntimeIdentifierGraphFile)" + RuntimeGraphPath="$(RuntimeIdentifierGraphPath)" KnownAppHostPacks="@(KnownAppHostPack)" NuGetRestoreSupported="$(_NuGetRestoreSupported)" EnableAppHostPackDownload="$(EnableAppHostPackDownload)" diff --git a/src/Tasks/Microsoft.NET.Build.Tasks/targets/Microsoft.NET.Sdk.targets b/src/Tasks/Microsoft.NET.Build.Tasks/targets/Microsoft.NET.Sdk.targets index 61ba663f2670..ccca676c2db1 100644 --- a/src/Tasks/Microsoft.NET.Build.Tasks/targets/Microsoft.NET.Sdk.targets +++ b/src/Tasks/Microsoft.NET.Build.Tasks/targets/Microsoft.NET.Sdk.targets @@ -48,6 +48,19 @@ Copyright (c) .NET Foundation. All rights reserved. <_GenerateSingleFileBundlePropertyInputsCache>$([MSBuild]::NormalizePath($(MSBuildProjectDirectory), $(_GenerateSingleFileBundlePropertyInputsCache))) + + + false + true + + + + $(BundledRuntimeIdentifierGraphFile) + + + $([System.IO.Path]::GetDirectoryName($(BundledRuntimeIdentifierGraphFile)))/PortableRuntimeIdentifierGraph.json + + @@ -288,7 +301,7 @@ Copyright (c) .NET Foundation. All rights reserved. ResolvedRuntimeTargetsFiles="@(RuntimeTargetsCopyLocalItems)" IsSelfContained="$(SelfContained)" IncludeRuntimeFileVersions="$(IncludeFileVersionsInDependencyFile)" - RuntimeGraphPath="$(BundledRuntimeIdentifierGraphFile)" + RuntimeGraphPath="$(RuntimeIdentifierGraphPath)" IncludeProjectsNotInAssetsFile="$(IncludeProjectsNotInAssetsFileInDepsFile)" ValidRuntimeIdentifierPlatformsForAssets="@(_ValidRuntimeIdentifierPlatformsForAssets)"/> diff --git a/src/Tests/Microsoft.NET.Build.Tests/RuntimeIdentifierGraphTests.cs b/src/Tests/Microsoft.NET.Build.Tests/RuntimeIdentifierGraphTests.cs new file mode 100644 index 000000000000..b5917830c2c6 --- /dev/null +++ b/src/Tests/Microsoft.NET.Build.Tests/RuntimeIdentifierGraphTests.cs @@ -0,0 +1,66 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using FluentAssertions; +using Microsoft.NET.TestFramework; +using Microsoft.NET.TestFramework.Assertions; +using Microsoft.NET.TestFramework.Commands; +using Microsoft.NET.TestFramework.ProjectConstruction; +using Xunit; +using Xunit.Abstractions; + +namespace Microsoft.NET.Build.Tests +{ + public class RuntimeIdentifierGraphTests : SdkTest + { + public RuntimeIdentifierGraphTests(ITestOutputHelper log) : base(log) + { + } + + [Theory] + [InlineData("net7.0", null, true)] + [InlineData("net8.0", null, false)] + [InlineData("net7.0", "false", false)] + [InlineData("net8.0", "true", true)] + public void ItUsesCorrectRuntimeIdentifierGraph(string targetFramework, string useRidGraphValue, bool shouldUseFullRidGraph) + { + var testProject = new TestProject() + { + TargetFrameworks = targetFramework, + IsExe = true + }; + + if (useRidGraphValue != null) + { + testProject.AdditionalProperties["UseRidGraph"] = useRidGraphValue; + } + + testProject.RecordProperties("RuntimeIdentifierGraphPath"); + + var testAsset = _testAssetsManager.CreateTestProject(testProject, identifier: targetFramework + "_" + (useRidGraphValue ?? "null")); + + var buildCommand = new BuildCommand(testAsset); + + buildCommand.Execute() + .Should() + .Pass(); + + var runtimeIdentifierGraphPath = testProject.GetPropertyValues(testAsset.TestRoot)["RuntimeIdentifierGraphPath"]; + + if (shouldUseFullRidGraph) + { + Path.GetFileName(runtimeIdentifierGraphPath).Should().Be("RuntimeIdentifierGraph.json"); + } + else + { + Path.GetFileName(runtimeIdentifierGraphPath).Should().Be("PortableRuntimeIdentifierGraph.json"); + } + } + } +} diff --git a/src/Tests/Microsoft.NET.Publish.Tests/GivenThatWeWantToCrossPublish.cs b/src/Tests/Microsoft.NET.Publish.Tests/GivenThatWeWantToCrossPublish.cs index 0c93c6218d51..18b89a648221 100644 --- a/src/Tests/Microsoft.NET.Publish.Tests/GivenThatWeWantToCrossPublish.cs +++ b/src/Tests/Microsoft.NET.Publish.Tests/GivenThatWeWantToCrossPublish.cs @@ -17,7 +17,7 @@ public void There_should_be_no_unresolved_conflicts() Name = "CrossPublish", TargetFrameworks = ToolsetInfo.CurrentTargetFramework, IsExe = true, - RuntimeIdentifier = "centos.8-x64" + RuntimeIdentifier = RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ? "linux-x64" : "win-x64" }; testProject.PackageReferences.Add(new TestPackageReference("System.Threading", "4.3.0")); diff --git a/src/Tests/Microsoft.NET.Publish.Tests/GivenThatWeWantToPublishAHelloWorldProject.cs b/src/Tests/Microsoft.NET.Publish.Tests/GivenThatWeWantToPublishAHelloWorldProject.cs index 7fad71952e61..b6293147b076 100644 --- a/src/Tests/Microsoft.NET.Publish.Tests/GivenThatWeWantToPublishAHelloWorldProject.cs +++ b/src/Tests/Microsoft.NET.Publish.Tests/GivenThatWeWantToPublishAHelloWorldProject.cs @@ -162,9 +162,6 @@ public static void Main() } [Theory] - [InlineData("win-arm")] - [InlineData("win8-arm")] - [InlineData("win81-arm")] [InlineData($"{ToolsetInfo.LatestWinRuntimeIdentifier}-arm")] [InlineData($"{ToolsetInfo.LatestWinRuntimeIdentifier}-arm64")] public void Publish_standalone_post_netcoreapp2_arm_app(string runtimeIdentifier) diff --git a/src/Tests/Microsoft.NET.Publish.Tests/GivenThatWeWantToPublishASingleFileApp.cs b/src/Tests/Microsoft.NET.Publish.Tests/GivenThatWeWantToPublishASingleFileApp.cs index 404ef26bf3c2..d14b7366b79b 100644 --- a/src/Tests/Microsoft.NET.Publish.Tests/GivenThatWeWantToPublishASingleFileApp.cs +++ b/src/Tests/Microsoft.NET.Publish.Tests/GivenThatWeWantToPublishASingleFileApp.cs @@ -44,11 +44,17 @@ public GivenThatWeWantToPublishASingleFileApp(ITestOutputHelper log) : base(log) { } - private PublishCommand GetPublishCommand(string identifier = null, [CallerMemberName] string callingMethod = "") + private PublishCommand GetPublishCommand(string identifier = null, [CallerMemberName] string callingMethod = "", Action projectChanges = null) { + if (projectChanges == null) + { + projectChanges = d => { }; + } + var testAsset = _testAssetsManager .CopyTestAsset(TestProjectName, callingMethod, identifier) - .WithSource(); + .WithSource() + .WithProjectChanges(projectChanges); // Create the following content: // /SmallNameDir/This is a directory with a really long name for one that only contains a small file/.word @@ -127,7 +133,17 @@ public void It_errors_when_publishing_single_file_without_apphost() public void It_generates_publishing_single_file_with_win7() { const string rid = "win7-x86"; - GetPublishCommand() + + // Retarget project to net7.0, as net8.0 and up by default use portable runtime graph which doesn't have win7-* RIDs + var projectChanges = (XDocument doc) => + { + var ns = doc.Root.Name.Namespace; + doc.Root.Element(ns + "PropertyGroup") + .Element(ns + "TargetFramework") + .Value = "net7.0"; + }; + + GetPublishCommand(projectChanges: projectChanges) .Execute($"/p:RuntimeIdentifier={rid}", PublishSingleFile) .Should() .Pass(); diff --git a/src/Tests/Microsoft.NET.TestFramework/ToolsetInfo.cs b/src/Tests/Microsoft.NET.TestFramework/ToolsetInfo.cs index a571291ac55e..d15a8bab3e29 100644 --- a/src/Tests/Microsoft.NET.TestFramework/ToolsetInfo.cs +++ b/src/Tests/Microsoft.NET.TestFramework/ToolsetInfo.cs @@ -12,10 +12,10 @@ public class ToolsetInfo public const string NextTargetFramework = "net9.0"; public const string NextTargetFrameworkVersion = "9.0"; - public const string LatestWinRuntimeIdentifier = "win10"; - public const string LatestLinuxRuntimeIdentifier = "ubuntu.22.04"; - public const string LatestMacRuntimeIdentifier = "osx.13"; - public const string LatestRuntimeIdentifiers = $"{LatestWinRuntimeIdentifier}-x64;{LatestWinRuntimeIdentifier}-x86;osx.10.10-x64;osx.10.11-x64;osx.10.12-x64;osx.10.14-x64;{LatestMacRuntimeIdentifier}-x64;ubuntu.14.04-x64;ubuntu.16.04-x64;ubuntu.16.10-x64;ubuntu.18.04-x64;ubuntu.20.04-x64;{LatestLinuxRuntimeIdentifier}-x64;centos.9-x64;rhel.9-x64;debian.9-x64;fedora.37-x64;opensuse.42.3-x64;linux-musl-x64"; + public const string LatestWinRuntimeIdentifier = "win"; + public const string LatestLinuxRuntimeIdentifier = "linux"; + public const string LatestMacRuntimeIdentifier = "osx"; + public const string LatestRuntimeIdentifiers = $"{LatestWinRuntimeIdentifier}-x64;{LatestWinRuntimeIdentifier}-x86;osx-x64;{LatestMacRuntimeIdentifier}-x64;{LatestLinuxRuntimeIdentifier}-x64;linux-musl-x64"; public string DotNetRoot { get; } public string DotNetHostPath { get; }