|
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
using Microsoft.Build.Framework;
using Microsoft.Build.Utilities;
using Microsoft.DotNet.Cli;
using Microsoft.DotNet.Configurer;
using Microsoft.NET.Sdk.WorkloadManifestReader;
using Newtonsoft.Json;
using NuGet.Frameworks;
using NuGet.Versioning;
namespace Microsoft.NET.Build.Tasks
{
/// <summary>
/// This class processes the FrameworkReference items. It adds PackageReferences for the
/// targeting packs which provide the reference assemblies, and creates RuntimeFramework
/// items, which are written to the runtimeconfig file
/// </summary>
public class ProcessFrameworkReferences : TaskBase
{
public string? TargetFrameworkIdentifier { get; set; }
[Required]
public string TargetFrameworkVersion { get; set; } = null!;
public string? TargetPlatformIdentifier { get; set; }
public string? TargetPlatformVersion { get; set; }
public string? TargetingPackRoot { get; set; }
[Required]
public string RuntimeGraphPath { get; set; } = null!;
public bool SelfContained { get; set; }
public bool ReadyToRunEnabled { get; set; }
public bool ReadyToRunUseCrossgen2 { get; set; }
public bool PublishAot { get; set; }
public bool RequiresILLinkPack { get; set; }
public bool IsAotCompatible { get; set; }
public bool SilenceIsAotCompatibleUnsupportedWarning { get; set; }
public string? MinNonEolTargetFrameworkForAot { get; set; }
public bool EnableAotAnalyzer { get; set; }
public string? FirstTargetFrameworkVersionToSupportAotAnalyzer { get; set; }
public bool PublishTrimmed { get; set; }
public bool IsTrimmable { get; set; }
public string? FirstTargetFrameworkVersionToSupportTrimAnalyzer { get; set; }
public bool SilenceIsTrimmableUnsupportedWarning { get; set; }
public string? MinNonEolTargetFrameworkForTrimming { get; set; }
public bool EnableTrimAnalyzer { get; set; }
public bool EnableSingleFileAnalyzer { get; set; }
public string? FirstTargetFrameworkVersionToSupportSingleFileAnalyzer { get; set; }
public bool SilenceEnableSingleFileAnalyzerUnsupportedWarning { get; set; }
public string? MinNonEolTargetFrameworkForSingleFile { get; set; }
public bool AotUseKnownRuntimePackForTarget { get; set; }
public string? RuntimeIdentifier { get; set; }
/// <summary>
/// Since this Target is mostly focused on managing RID-specific assets, we massage the 'any' RID (which is platform-agnostic) into a 'null'
/// value to make processing simpler.
/// </summary>
public string? EffectiveRuntimeIdentifier => RuntimeIdentifier == "any" ? null : RuntimeIdentifier;
public string[]? RuntimeIdentifiers { get; set; }
public string? RuntimeFrameworkVersion { get; set; }
public bool TargetLatestRuntimePatch { get; set; }
public bool TargetLatestRuntimePatchIsDefault { get; set; }
public bool EnableTargetingPackDownload { get; set; }
public bool EnableRuntimePackDownload { get; set; }
public bool EnableWindowsTargeting { get; set; }
public bool DisableTransitiveFrameworkReferenceDownloads { get; set; }
public ITaskItem[] FrameworkReferences { get; set; } = Array.Empty<ITaskItem>();
public ITaskItem[] KnownFrameworkReferences { get; set; } = Array.Empty<ITaskItem>();
public ITaskItem[] KnownRuntimePacks { get; set; } = Array.Empty<ITaskItem>();
public ITaskItem[] KnownCrossgen2Packs { get; set; } = Array.Empty<ITaskItem>();
public ITaskItem[] KnownILCompilerPacks { get; set; } = Array.Empty<ITaskItem>();
public ITaskItem[] KnownILLinkPacks { get; set; } = Array.Empty<ITaskItem>();
public ITaskItem[] KnownWebAssemblySdkPacks { get; set; } = Array.Empty<ITaskItem>();
public ITaskItem[] KnownAspNetCorePacks { get; set; } = Array.Empty<ITaskItem>();
public bool UsingMicrosoftNETSdkWebAssembly { get; set; }
public bool RequiresAspNetWebAssets { get; set; }
[Required]
public string NETCoreSdkRuntimeIdentifier { get; set; } = null!;
public string? NETCoreSdkPortableRuntimeIdentifier { get; set; }
[Required]
public string NetCoreRoot { get; set; } = null!;
[Required]
public string NETCoreSdkVersion { get; set; } = null!;
[Output]
public ITaskItem[]? PackagesToDownload { get; set; }
[Output]
public ITaskItem[]? RuntimeFrameworks { get; set; }
[Output]
public ITaskItem[]? TargetingPacks { get; set; }
[Output]
public ITaskItem[]? RuntimePacks { get; set; }
[Output]
public ITaskItem[]? Crossgen2Packs { get; set; }
[Output]
public ITaskItem[]? HostILCompilerPacks { get; set; }
[Output]
public ITaskItem[]? TargetILCompilerPacks { get; set; }
[Output]
public ITaskItem[]? ImplicitPackageReferences { get; set; }
// Runtime packs which aren't available for the specified RuntimeIdentifier
[Output]
public ITaskItem[]? UnavailableRuntimePacks { get; set; }
[Output]
public string[]? KnownRuntimeIdentifierPlatforms { get; set; }
private Version? _normalizedTargetFrameworkVersion;
void AddPacksForFrameworkReferences(
List<ITaskItem> packagesToDownload,
List<ITaskItem> runtimeFrameworks,
List<ITaskItem> targetingPacks,
List<ITaskItem> runtimePacks,
List<ITaskItem> unavailableRuntimePacks,
out List<KnownRuntimePack> knownRuntimePacksForTargetFramework
)
{
var knownFrameworkReferencesForTargetFramework =
KnownFrameworkReferences
.Select(item => new KnownFrameworkReference(item))
.Where(kfr => KnownFrameworkReferenceAppliesToTargetFramework(kfr.TargetFramework))
.ToList();
// Get known runtime packs from known framework references.
// Only use items where the framework reference name matches the RuntimeFrameworkName.
// This will filter out known framework references for "profiles", ie WindowsForms and WPF
knownRuntimePacksForTargetFramework =
knownFrameworkReferencesForTargetFramework
.Where(kfr => kfr.Name.Equals(kfr.RuntimeFrameworkName, StringComparison.OrdinalIgnoreCase))
.Select(kfr => kfr.ToKnownRuntimePack())
.ToList();
// Add additional known runtime packs
knownRuntimePacksForTargetFramework.AddRange(
KnownRuntimePacks.Select(item => new KnownRuntimePack(item))
.Where(krp => KnownFrameworkReferenceAppliesToTargetFramework(krp.TargetFramework)));
var frameworkReferenceMap = FrameworkReferences.ToDictionary(fr => fr.ItemSpec, StringComparer.OrdinalIgnoreCase);
Log.LogMessage(MessageImportance.Low, $"Found {frameworkReferenceMap.Count} known framework references for target framework {TargetFrameworkIdentifier}");
Log.LogMessage(MessageImportance.Low, $"Found {knownRuntimePacksForTargetFramework.Count} known runtime packs for target framework {TargetFrameworkIdentifier}");
HashSet<string> unrecognizedRuntimeIdentifiers = new(StringComparer.OrdinalIgnoreCase);
bool windowsOnlyErrorLogged = false;
foreach (var knownFrameworkReference in knownFrameworkReferencesForTargetFramework)
{
frameworkReferenceMap.TryGetValue(knownFrameworkReference.Name, out ITaskItem? frameworkReference);
// Handle Windows-only frameworks on non-Windows platforms
if (knownFrameworkReference.IsWindowsOnly &&
!RuntimeInformation.IsOSPlatform(OSPlatform.Windows) &&
!EnableWindowsTargeting)
{
// It is an error to reference the framework from non-Windows
if (!windowsOnlyErrorLogged && frameworkReference != null)
{
Log.LogError(Strings.WindowsDesktopFrameworkRequiresWindows);
windowsOnlyErrorLogged = true;
}
Log.LogMessage(MessageImportance.Low, $"Ignoring framework reference to {knownFrameworkReference.Name} as it is Windows-only and the current platform is not Windows.");
// Ignore (and don't download) this known framework reference as it requires Windows
continue;
}
KnownRuntimePack? selectedRuntimePack = SelectRuntimePack(frameworkReference, knownFrameworkReference, knownRuntimePacksForTargetFramework);
// Add targeting pack and all known runtime packs to "preferred packages" list.
// These are packages that will win in conflict resolution for assets that have identical assembly and file versions
var preferredPackages = new HashSet<string>(StringComparer.InvariantCultureIgnoreCase)
{
knownFrameworkReference.TargetingPackName
};
if (selectedRuntimePack is KnownRuntimePack selectedPack)
{
var knownFrameworkReferenceRuntimePackRuntimeIdentifiers = selectedPack.RuntimePackRuntimeIdentifiers.Split(';');
foreach (var runtimeIdentifier in knownFrameworkReferenceRuntimePackRuntimeIdentifiers)
{
foreach (var runtimePackNamePattern in selectedPack.RuntimePackNamePatterns.Split(';'))
{
string runtimePackName = runtimePackNamePattern.Replace("**RID**", runtimeIdentifier);
preferredPackages.Add(runtimePackName);
}
}
Log.LogMessage(MessageImportance.Low, $"Selected {selectedPack.Name} with RIDs '{selectedPack.RuntimePackRuntimeIdentifiers}'");
}
else
{
Log.LogMessage(MessageImportance.Low, $"No runtime pack found for {knownFrameworkReference.Name}.");
}
TaskItem targetingPack = new(knownFrameworkReference.Name);
targetingPack.SetMetadata(MetadataKeys.NuGetPackageId, knownFrameworkReference.TargetingPackName);
targetingPack.SetMetadata(MetadataKeys.PackageConflictPreferredPackages, string.Join(";", preferredPackages));
string? targetingPackVersion = null;
if (frameworkReference != null)
{
// Allow targeting pack version to be overridden via metadata on FrameworkReference
targetingPackVersion = frameworkReference.GetMetadata("TargetingPackVersion");
}
if (string.IsNullOrEmpty(targetingPackVersion))
{
targetingPackVersion = knownFrameworkReference.TargetingPackVersion;
}
// Look up targeting pack version from workload manifests if necessary
targetingPackVersion = GetResolvedPackVersion(knownFrameworkReference.TargetingPackName, targetingPackVersion);
targetingPack.SetMetadata(MetadataKeys.NuGetPackageVersion, targetingPackVersion);
targetingPack.SetMetadata("TargetingPackFormat", knownFrameworkReference.TargetingPackFormat);
targetingPack.SetMetadata("TargetFramework", knownFrameworkReference.TargetFramework.GetShortFolderName());
targetingPack.SetMetadata(MetadataKeys.RuntimeFrameworkName, knownFrameworkReference.RuntimeFrameworkName);
if (selectedRuntimePack != null)
{
targetingPack.SetMetadata(MetadataKeys.RuntimePackRuntimeIdentifiers, selectedRuntimePack?.RuntimePackRuntimeIdentifiers);
}
if (!string.IsNullOrEmpty(knownFrameworkReference.Profile))
{
targetingPack.SetMetadata("Profile", knownFrameworkReference.Profile);
}
// Get the path of the targeting pack in the targeting pack root (e.g. dotnet/packs)
string? targetingPackPath = GetPackPath(knownFrameworkReference.TargetingPackName, targetingPackVersion);
if (targetingPackPath != null)
{
// Use targeting pack from packs folder
targetingPack.SetMetadata(MetadataKeys.PackageDirectory, targetingPackPath);
targetingPack.SetMetadata(MetadataKeys.Path, targetingPackPath);
}
else
{
// If transitive framework reference downloads are disabled, then don't download targeting packs where there isn't
// a direct framework reference
if (EnableTargetingPackDownload &&
!(DisableTransitiveFrameworkReferenceDownloads && frameworkReference == null))
{
// Download targeting pack
TaskItem packageToDownload = new(knownFrameworkReference.TargetingPackName);
packageToDownload.SetMetadata(MetadataKeys.Version, targetingPackVersion);
packagesToDownload.Add(packageToDownload);
}
}
targetingPacks.Add(targetingPack);
Log.LogMessage(MessageImportance.Low, $"Selected targeting pack '{targetingPack.ItemSpec}@{targetingPackVersion}'");
string runtimeFrameworkVersion = GetRuntimeFrameworkVersion(
frameworkReference,
knownFrameworkReference,
selectedRuntimePack,
out string runtimePackVersion);
string? isTrimmable = null;
if (frameworkReference != null)
{
// Allow IsTrimmable to be overridden via metadata on FrameworkReference
isTrimmable = frameworkReference.GetMetadata(MetadataKeys.IsTrimmable);
}
if (string.IsNullOrEmpty(isTrimmable))
{
isTrimmable = selectedRuntimePack?.IsTrimmable;
}
bool useRuntimePackAndDownloadIfNecessary;
KnownRuntimePack runtimePackForRuntimeIDProcessing;
if (knownFrameworkReference.Name.Equals(knownFrameworkReference.RuntimeFrameworkName, StringComparison.OrdinalIgnoreCase) && selectedRuntimePack != null)
{
// Only add runtime packs where the framework reference name matches the RuntimeFrameworkName
// Framework references for "profiles" will use the runtime pack from the corresponding non-profile framework
runtimePackForRuntimeIDProcessing = selectedRuntimePack.Value;
useRuntimePackAndDownloadIfNecessary = true;
}
else if (!knownFrameworkReference.RuntimePackRuntimeIdentifiers.Equals(selectedRuntimePack?.RuntimePackRuntimeIdentifiers))
{
// If the profile has a different set of runtime identifiers than the runtime pack, use the profile.
runtimePackForRuntimeIDProcessing = knownFrameworkReference.ToKnownRuntimePack();
useRuntimePackAndDownloadIfNecessary = true;
}
else
{
// For the remaining profiles, don't include them in package download but add them to unavailable if necessary.
runtimePackForRuntimeIDProcessing = knownFrameworkReference.ToKnownRuntimePack();
useRuntimePackAndDownloadIfNecessary = false;
}
bool processedPrimaryRuntimeIdentifier = false;
var hasRuntimePackAlwaysCopyLocal =
selectedRuntimePack != null && selectedRuntimePack.Value.RuntimePackAlwaysCopyLocal;
var runtimeRequiredByDeployment
= (SelfContained || ReadyToRunEnabled) &&
!string.IsNullOrEmpty(EffectiveRuntimeIdentifier) &&
!string.IsNullOrEmpty(selectedRuntimePack?.RuntimePackNamePatterns);
if (hasRuntimePackAlwaysCopyLocal || runtimeRequiredByDeployment)
{
// Find other KnownFrameworkReferences that map to the same runtime pack, if any
List<string>? additionalFrameworkReferencesForRuntimePack = null;
foreach (var additionalKnownFrameworkReference in knownFrameworkReferencesForTargetFramework)
{
if (additionalKnownFrameworkReference.RuntimeFrameworkName.Equals(knownFrameworkReference.RuntimeFrameworkName, StringComparison.OrdinalIgnoreCase) &&
!additionalKnownFrameworkReference.RuntimeFrameworkName.Equals(additionalKnownFrameworkReference.Name, StringComparison.OrdinalIgnoreCase))
{
additionalFrameworkReferencesForRuntimePack ??= [];
additionalFrameworkReferencesForRuntimePack.Add(additionalKnownFrameworkReference.Name);
}
}
// Process primary runtime identifier
ProcessRuntimeIdentifier(EffectiveRuntimeIdentifier ?? "any", runtimePackForRuntimeIDProcessing, runtimePackVersion, additionalFrameworkReferencesForRuntimePack,
unrecognizedRuntimeIdentifiers, unavailableRuntimePacks, runtimePacks, packagesToDownload, isTrimmable, useRuntimePackAndDownloadIfNecessary,
wasReferencedDirectly: frameworkReference != null);
processedPrimaryRuntimeIdentifier = true;
}
if (RuntimeIdentifiers != null)
{
foreach (var runtimeIdentifier in RuntimeIdentifiers)
{
if (processedPrimaryRuntimeIdentifier && runtimeIdentifier == EffectiveRuntimeIdentifier)
{
// We've already processed this RID
continue;
}
if (runtimeIdentifier == "any")
{
// The `any` RID represents a platform-agnostic target. As such, it has no
// platform-specific runtime pack associated with it.
continue;
}
// Pass in null for the runtimePacks list, as for these runtime identifiers we only want to
// download the runtime packs, but not use the assets from them
ProcessRuntimeIdentifier(runtimeIdentifier, runtimePackForRuntimeIDProcessing, runtimePackVersion, additionalFrameworkReferencesForRuntimePack: null,
unrecognizedRuntimeIdentifiers, unavailableRuntimePacks, runtimePacks: null, packagesToDownload, isTrimmable, useRuntimePackAndDownloadIfNecessary,
wasReferencedDirectly: frameworkReference != null);
}
}
if (!string.IsNullOrEmpty(knownFrameworkReference.RuntimeFrameworkName) && !knownFrameworkReference.RuntimePackAlwaysCopyLocal)
{
TaskItem runtimeFramework = new(knownFrameworkReference.RuntimeFrameworkName);
runtimeFramework.SetMetadata(MetadataKeys.Version, runtimeFrameworkVersion);
runtimeFramework.SetMetadata(MetadataKeys.FrameworkName, knownFrameworkReference.Name);
runtimeFramework.SetMetadata("Profile", knownFrameworkReference.Profile);
runtimeFrameworks.Add(runtimeFramework);
Log.LogMessage(MessageImportance.Low, $"Added runtime framework '{runtimeFramework.ItemSpec}@{runtimeFrameworkVersion}'");
}
}
}
protected override void ExecuteCore()
{
List<ITaskItem>? packagesToDownload = null;
List<ITaskItem>? runtimeFrameworks = null;
List<ITaskItem>? targetingPacks = null;
List<ITaskItem>? runtimePacks = null;
List<ITaskItem>? unavailableRuntimePacks = null;
List<KnownRuntimePack>? knownRuntimePacksForTargetFramework = null;
// Perf optimization: If there are no FrameworkReference items, then don't do anything
// (This means that if you don't have any direct framework references, you won't get any transitive ones either
if (FrameworkReferences != null && FrameworkReferences.Length != 0)
{
_normalizedTargetFrameworkVersion = NormalizeVersion(new Version(TargetFrameworkVersion));
packagesToDownload = new List<ITaskItem>();
runtimeFrameworks = new List<ITaskItem>();
targetingPacks = new List<ITaskItem>();
runtimePacks = new List<ITaskItem>();
unavailableRuntimePacks = new List<ITaskItem>();
AddPacksForFrameworkReferences(
packagesToDownload,
runtimeFrameworks,
targetingPacks,
runtimePacks,
unavailableRuntimePacks,
out knownRuntimePacksForTargetFramework);
}
_normalizedTargetFrameworkVersion ??= NormalizeVersion(new Version(TargetFrameworkVersion));
packagesToDownload ??= new List<ITaskItem>();
List<ITaskItem> implicitPackageReferences = new();
if (ReadyToRunEnabled && ReadyToRunUseCrossgen2)
{
if (AddToolPack(ToolPackType.Crossgen2, _normalizedTargetFrameworkVersion, packagesToDownload, implicitPackageReferences) is not ToolPackSupport.Supported)
{
Log.LogError(Strings.ReadyToRunNoValidRuntimePackageError);
return;
}
}
if (PublishAot)
{
switch (AddToolPack(ToolPackType.ILCompiler, _normalizedTargetFrameworkVersion, packagesToDownload, implicitPackageReferences))
{
case ToolPackSupport.UnsupportedForTargetFramework:
Log.LogError(Strings.AotUnsupportedTargetFramework);
return;
case ToolPackSupport.UnsupportedForHostRuntimeIdentifier:
Log.LogError(Strings.AotUnsupportedHostRuntimeIdentifier, NETCoreSdkRuntimeIdentifier);
return;
case ToolPackSupport.UnsupportedForTargetRuntimeIdentifier when EffectiveRuntimeIdentifier != null:
Log.LogError(Strings.AotUnsupportedTargetRuntimeIdentifier, EffectiveRuntimeIdentifier!);
return;
case ToolPackSupport.Supported:
break;
}
}
if (RequiresILLinkPack)
{
if (AddToolPack(ToolPackType.ILLink, _normalizedTargetFrameworkVersion, packagesToDownload, implicitPackageReferences) is not ToolPackSupport.Supported)
{
// Keep the checked properties in sync with _RequiresILLinkPack in Microsoft.NET.Publish.targets.
if (PublishAot)
{
// If PublishAot is set, this should produce a specific error above already.
// Also produce one here just in case there are custom KnownILCompilerPack/KnownILLinkPack
// items that bypass the error above.
Log.LogError(Strings.AotUnsupportedTargetFramework);
}
else if (IsAotCompatible || EnableAotAnalyzer)
{
if (!SilenceIsAotCompatibleUnsupportedWarning)
Log.LogWarning(Strings.IsAotCompatibleUnsupported, MinNonEolTargetFrameworkForAot!);
}
else if (PublishTrimmed)
{
Log.LogError(Strings.PublishTrimmedRequiresVersion30);
}
else if (IsTrimmable || EnableTrimAnalyzer)
{
if (!SilenceIsTrimmableUnsupportedWarning)
Log.LogWarning(Strings.IsTrimmableUnsupported, MinNonEolTargetFrameworkForTrimming!);
}
else if (EnableSingleFileAnalyzer)
{
// There's no IsSingleFileCompatible setting. EnableSingleFileAnalyzer is the
// recommended way to ensure single-file compatibility for libraries.
if (!SilenceEnableSingleFileAnalyzerUnsupportedWarning)
Log.LogWarning(Strings.EnableSingleFileAnalyzerUnsupported, MinNonEolTargetFrameworkForSingleFile!);
}
else
{
// _RequiresILLinkPack was set. This setting acts as an override for the
// user-visible properties, and should generally only be used by
// other SDKs that can't use the other properties for some reason.
Log.LogError(Strings.ILLinkNoValidRuntimePackageError);
}
}
}
if (UsingMicrosoftNETSdkWebAssembly)
{
// WebAssemblySdk is used for .NET >= 6, it's ok if no pack is added.
AddToolPack(ToolPackType.WebAssemblySdk, _normalizedTargetFrameworkVersion, packagesToDownload, implicitPackageReferences);
}
if (RequiresAspNetWebAssets && _normalizedTargetFrameworkVersion.Major >= 10)
{
if (AddToolPack(ToolPackType.AspNetCore, _normalizedTargetFrameworkVersion, packagesToDownload, implicitPackageReferences) is not ToolPackSupport.Supported)
{
Log.LogWarning(Strings.AspNetCorePackUnsupportedTargetFramework);
}
}
if (packagesToDownload.Any())
{
PackagesToDownload = packagesToDownload.Distinct(new PackageToDownloadComparer<ITaskItem>()).ToArray();
}
if (runtimeFrameworks?.Any() == true)
{
RuntimeFrameworks = runtimeFrameworks.ToArray();
}
if (targetingPacks?.Any() == true)
{
TargetingPacks = targetingPacks.ToArray();
}
if (runtimePacks?.Any() == true)
{
RuntimePacks = runtimePacks.ToArray();
}
if (unavailableRuntimePacks?.Any() == true)
{
UnavailableRuntimePacks = unavailableRuntimePacks.ToArray();
}
if (implicitPackageReferences.Any())
{
ImplicitPackageReferences = implicitPackageReferences.ToArray();
}
if (knownRuntimePacksForTargetFramework?.Any() == true)
{
// Determine the known runtime identifier platforms based on all available Microsoft.NETCore.App packs
HashSet<string> knownRuntimeIdentifierPlatforms = new(StringComparer.OrdinalIgnoreCase);
var netCoreAppPacks = knownRuntimePacksForTargetFramework!.Where(krp => krp.Name.Equals("Microsoft.NETCore.App", StringComparison.OrdinalIgnoreCase));
foreach (KnownRuntimePack netCoreAppPack in netCoreAppPacks)
{
foreach (var runtimeIdentifier in netCoreAppPack.RuntimePackRuntimeIdentifiers.Split(';'))
{
int separator = runtimeIdentifier.LastIndexOf('-');
string platform = separator < 0 ? runtimeIdentifier : runtimeIdentifier.Substring(0, separator);
knownRuntimeIdentifierPlatforms.Add(platform);
}
}
if (knownRuntimeIdentifierPlatforms.Count > 0)
{
KnownRuntimeIdentifierPlatforms = knownRuntimeIdentifierPlatforms.ToArray();
}
}
}
private bool KnownFrameworkReferenceAppliesToTargetFramework(NuGetFramework knownFrameworkReferenceTargetFramework)
{
if (!knownFrameworkReferenceTargetFramework.Framework.Equals(TargetFrameworkIdentifier, StringComparison.OrdinalIgnoreCase)
|| NormalizeVersion(knownFrameworkReferenceTargetFramework.Version) != _normalizedTargetFrameworkVersion)
{
return false;
}
if (!string.IsNullOrEmpty(knownFrameworkReferenceTargetFramework.Platform)
&& knownFrameworkReferenceTargetFramework.PlatformVersion != null)
{
if (!knownFrameworkReferenceTargetFramework.Platform.Equals(TargetPlatformIdentifier, StringComparison.OrdinalIgnoreCase))
{
return false;
}
if (!Version.TryParse(TargetPlatformVersion, out var targetPlatformVersionParsed))
{
return false;
}
if (NormalizeVersion(targetPlatformVersionParsed) != NormalizeVersion(knownFrameworkReferenceTargetFramework.PlatformVersion)
|| NormalizeVersion(knownFrameworkReferenceTargetFramework.Version) != _normalizedTargetFrameworkVersion)
{
return false;
}
}
return true;
}
private KnownRuntimePack? SelectRuntimePack(ITaskItem? frameworkReference, KnownFrameworkReference knownFrameworkReference, List<KnownRuntimePack> knownRuntimePacks)
{
var requiredLabelsMetadata = frameworkReference?.GetMetadata(MetadataKeys.RuntimePackLabels) ?? "";
HashSet<string>? requiredRuntimePackLabels = null;
if (frameworkReference != null)
{
requiredRuntimePackLabels = new HashSet<string>(requiredLabelsMetadata.Split(new[] { ';' }, StringSplitOptions.RemoveEmptyEntries), StringComparer.OrdinalIgnoreCase);
}
// The runtime pack name matches the RuntimeFrameworkName on the KnownFrameworkReference
var matchingRuntimePacks = knownRuntimePacks.Where(krp => krp.Name.Equals(knownFrameworkReference.RuntimeFrameworkName, StringComparison.OrdinalIgnoreCase))
.Where(krp =>
{
if (requiredRuntimePackLabels == null)
{
return krp.RuntimePackLabels.Length == 0;
}
else
{
return requiredRuntimePackLabels.SetEquals(krp.RuntimePackLabels);
}
})
.ToList();
if (matchingRuntimePacks.Count == 0)
{
return null;
}
else if (matchingRuntimePacks.Count == 1)
{
return matchingRuntimePacks[0];
}
else
{
string runtimePackDescriptionForErrorMessage = knownFrameworkReference.RuntimeFrameworkName +
(requiredLabelsMetadata == string.Empty ? string.Empty : ":" + requiredLabelsMetadata);
Log.LogError(Strings.ConflictingRuntimePackInformation, runtimePackDescriptionForErrorMessage,
string.Join(Environment.NewLine, matchingRuntimePacks.Select(rp => rp.RuntimePackNamePatterns)));
return knownFrameworkReference.ToKnownRuntimePack();
}
}
private void ProcessRuntimeIdentifier(
string runtimeIdentifier,
KnownRuntimePack selectedRuntimePack,
string runtimePackVersion,
List<string>? additionalFrameworkReferencesForRuntimePack,
HashSet<string> unrecognizedRuntimeIdentifiers,
List<ITaskItem> unavailableRuntimePacks,
List<ITaskItem>? runtimePacks,
List<ITaskItem> packagesToDownload,
string? isTrimmable,
bool addRuntimePackAndDownloadIfNecessary,
bool wasReferencedDirectly)
{
var runtimeGraph = new RuntimeGraphCache(this).GetRuntimeGraph(RuntimeGraphPath);
var knownFrameworkReferenceRuntimePackRuntimeIdentifiers = selectedRuntimePack.RuntimePackRuntimeIdentifiers.Split(';');
var knownFrameworkReferenceRuntimePackExcludedRuntimeIdentifiers = selectedRuntimePack.RuntimePackExcludedRuntimeIdentifiers.Split(';');
Log.LogMessage(MessageImportance.Low, $"Finding best RID match for pack {selectedRuntimePack.Name}@{runtimePackVersion} for target RID '{runtimeIdentifier}' from '{selectedRuntimePack.RuntimePackRuntimeIdentifiers}' excluding '{selectedRuntimePack.RuntimePackExcludedRuntimeIdentifiers}'");
string? runtimePackRuntimeIdentifier = NuGetUtils.GetBestMatchingRidWithExclusion(
runtimeGraph,
runtimeIdentifier,
knownFrameworkReferenceRuntimePackExcludedRuntimeIdentifiers,
knownFrameworkReferenceRuntimePackRuntimeIdentifiers,
out bool wasInGraph);
if (runtimePackRuntimeIdentifier == null)
{
if (wasInGraph)
{
// Report this as an error later, if necessary. This is because we try to download
// all available runtime packs in case there is a transitive reference to a shared
// framework we don't directly reference. But we don't want to immediately error out
// here if a runtime pack that we might not need to reference isn't available for the
// targeted RID (e.g. Microsoft.WindowsDesktop.App for a linux RID).
var unavailableRuntimePack = new TaskItem(selectedRuntimePack.Name);
unavailableRuntimePack.SetMetadata(MetadataKeys.RuntimeIdentifier, runtimeIdentifier);
unavailableRuntimePacks.Add(unavailableRuntimePack);
}
else if (!unrecognizedRuntimeIdentifiers.Contains(runtimeIdentifier))
{
// NETSDK1083: The specified RuntimeIdentifier '{0}' is not recognized.
Log.LogError(Strings.RuntimeIdentifierNotRecognized, runtimeIdentifier);
unrecognizedRuntimeIdentifiers.Add(runtimeIdentifier);
}
}
else if (addRuntimePackAndDownloadIfNecessary)
{
foreach (var runtimePackNamePattern in selectedRuntimePack.RuntimePackNamePatterns.Split(';'))
{
string runtimePackName = runtimePackNamePattern.Replace("**RID**", runtimePackRuntimeIdentifier);
// Look up runtimePackVersion from workload manifests if necessary
string resolvedRuntimePackVersion = GetResolvedPackVersion(runtimePackName, runtimePackVersion);
string? runtimePackPath = GetPackPath(runtimePackName, resolvedRuntimePackVersion);
if (runtimePacks != null)
{
TaskItem runtimePackItem = new(runtimePackName);
runtimePackItem.SetMetadata(MetadataKeys.NuGetPackageId, runtimePackName);
runtimePackItem.SetMetadata(MetadataKeys.NuGetPackageVersion, resolvedRuntimePackVersion);
runtimePackItem.SetMetadata(MetadataKeys.FrameworkName, selectedRuntimePack.Name);
runtimePackItem.SetMetadata(MetadataKeys.RuntimeIdentifier, runtimePackRuntimeIdentifier);
runtimePackItem.SetMetadata(MetadataKeys.IsTrimmable, isTrimmable);
if (selectedRuntimePack.RuntimePackAlwaysCopyLocal)
{
runtimePackItem.SetMetadata(MetadataKeys.RuntimePackAlwaysCopyLocal, "true");
}
if (additionalFrameworkReferencesForRuntimePack != null)
{
runtimePackItem.SetMetadata(MetadataKeys.AdditionalFrameworkReferences, string.Join(";", additionalFrameworkReferencesForRuntimePack));
}
if (runtimePackPath != null)
{
runtimePackItem.SetMetadata(MetadataKeys.PackageDirectory, runtimePackPath);
}
runtimePacks.Add(runtimePackItem);
}
if (EnableRuntimePackDownload &&
runtimePackPath == null &&
(wasReferencedDirectly || !DisableTransitiveFrameworkReferenceDownloads))
{
TaskItem packageToDownload = new(runtimePackName);
packageToDownload.SetMetadata(MetadataKeys.Version, resolvedRuntimePackVersion);
packagesToDownload.Add(packageToDownload);
}
}
}
}
// Enum values should match the name of the pack: Known<Foo>Pack
private enum ToolPackType
{
Crossgen2,
ILCompiler,
ILLink,
WebAssemblySdk,
AspNetCore,
}
enum ToolPackSupport
{
UnsupportedForTargetFramework,
UnsupportedForHostRuntimeIdentifier,
UnsupportedForTargetRuntimeIdentifier,
Supported
}
private ToolPackSupport AddToolPack(
ToolPackType toolPackType,
Version normalizedTargetFrameworkVersion,
List<ITaskItem> packagesToDownload,
List<ITaskItem> implicitPackageReferences)
{
var knownPacks = toolPackType switch
{
ToolPackType.Crossgen2 => KnownCrossgen2Packs,
ToolPackType.ILCompiler => KnownILCompilerPacks,
ToolPackType.ILLink => KnownILLinkPacks,
ToolPackType.WebAssemblySdk => KnownWebAssemblySdkPacks,
ToolPackType.AspNetCore => KnownAspNetCorePacks,
_ => throw new ArgumentException($"Unknown package type {toolPackType}", nameof(toolPackType))
};
Log.LogMessage(MessageImportance.Low, $"Adding tool pack {toolPackType} for runtime {normalizedTargetFrameworkVersion}");
var knownPack = knownPacks.Where(pack =>
{
var packTargetFramework = NuGetFramework.Parse(pack.GetMetadata("TargetFramework"));
return packTargetFramework.Framework.Equals(TargetFrameworkIdentifier, StringComparison.OrdinalIgnoreCase) &&
NormalizeVersion(packTargetFramework.Version) == normalizedTargetFrameworkVersion;
}).SingleOrDefault();
if (knownPack == null)
{
return ToolPackSupport.UnsupportedForTargetFramework;
}
var packName = toolPackType.ToString();
var packVersion = knownPack.GetMetadata(packName + "PackVersion");
if (!string.IsNullOrEmpty(RuntimeFrameworkVersion))
{
packVersion = RuntimeFrameworkVersion;
}
Log.LogMessage(MessageImportance.Low, $"Found {toolPackType} pack '{knownPack.ItemSpec}@{packVersion}'");
TaskItem? runtimePackToDownload = null;
// Crossgen and ILCompiler have RID-specific bits.
if (toolPackType is ToolPackType.Crossgen2 or ToolPackType.ILCompiler)
{
var packNamePattern = knownPack.GetMetadata(packName + "PackNamePattern");
var packSupportedRuntimeIdentifiers = knownPack.GetMetadata(packName + "RuntimeIdentifiers").Split(';');
// When publishing for the non-portable RID that matches NETCoreSdkRuntimeIdentifier, prefer NETCoreSdkRuntimeIdentifier for the host.
// Otherwise prefer the NETCoreSdkPortableRuntimeIdentifier.
// This makes non-portable SDKs behave the same as portable SDKs except for the specific case of targetting the non-portable RID.
// It also enables the non-portable ILCompiler to be packaged separately from the SDK and
// only required when publishing for the non-portable SDK RID.
string portableSdkRid = !string.IsNullOrEmpty(NETCoreSdkPortableRuntimeIdentifier) ? NETCoreSdkPortableRuntimeIdentifier : NETCoreSdkRuntimeIdentifier;
bool targetsNonPortableSdkRid = EffectiveRuntimeIdentifier == NETCoreSdkRuntimeIdentifier && NETCoreSdkRuntimeIdentifier != portableSdkRid;
string? hostRuntimeIdentifier = targetsNonPortableSdkRid ? NETCoreSdkRuntimeIdentifier : portableSdkRid;
Log.LogMessage(MessageImportance.Low, $"Determining best RID for '{knownPack.ItemSpec}@{packVersion}' for '{hostRuntimeIdentifier}' from among '{knownPack.GetMetadata(packName + "RuntimeIdentifiers")}'");
// Get the best RID for the host machine, which will be used to validate that we can run crossgen for the target platform and architecture
var runtimeGraph = new RuntimeGraphCache(this).GetRuntimeGraph(RuntimeGraphPath);
hostRuntimeIdentifier = NuGetUtils.GetBestMatchingRid(runtimeGraph, hostRuntimeIdentifier, packSupportedRuntimeIdentifiers, out bool wasInGraph);
if (hostRuntimeIdentifier == null)
{
return ToolPackSupport.UnsupportedForHostRuntimeIdentifier;
}
Log.LogMessage(MessageImportance.Low, $"Best RID for '{knownPack.ItemSpec}@{packVersion}' is '{hostRuntimeIdentifier}'");
var runtimePackName = packNamePattern.Replace("**RID**", hostRuntimeIdentifier);
var runtimePackItem = new TaskItem(runtimePackName);
runtimePackItem.SetMetadata(MetadataKeys.NuGetPackageId, runtimePackName);
runtimePackItem.SetMetadata(MetadataKeys.NuGetPackageVersion, packVersion);
string? runtimePackPath = GetPackPath(runtimePackName, packVersion);
if (runtimePackPath != null)
{
runtimePackItem.SetMetadata(MetadataKeys.PackageDirectory, runtimePackPath);
}
else if (EnableRuntimePackDownload)
{
// We need to download the runtime pack
runtimePackToDownload = new TaskItem(runtimePackName);
runtimePackToDownload.SetMetadata(MetadataKeys.Version, packVersion);
}
runtimePackItem.SetMetadata(MetadataKeys.RuntimeIdentifier, hostRuntimeIdentifier);
Log.LogMessage(MessageImportance.Low, $"Added {toolPackType} runtime pack '{runtimePackName}@{packVersion}'");
switch (toolPackType)
{
case ToolPackType.Crossgen2:
Crossgen2Packs = new[] { runtimePackItem };
break;
case ToolPackType.ILCompiler:
// ILCompiler supports cross target compilation. If there is a cross-target request,
// we need to download that package as well unless we use KnownRuntimePack entries for the target.
// We expect RuntimeIdentifier to be defined during publish but can allow during build
if (EffectiveRuntimeIdentifier != null && !AotUseKnownRuntimePackForTarget)
{
Log.LogMessage(MessageImportance.Low, $"Checking for cross-targeting compilation packs");
var targetRuntimeIdentifier = NuGetUtils.GetBestMatchingRid(runtimeGraph, EffectiveRuntimeIdentifier, packSupportedRuntimeIdentifiers, out bool wasInGraph2);
if (targetRuntimeIdentifier == null)
{
return ToolPackSupport.UnsupportedForTargetRuntimeIdentifier;
}
// 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 && runtimePackNamePattern != string.Empty)
{
targetPackNamePattern = runtimePackNamePattern;
useRuntimePackForAllTargets = true;
}
if (useRuntimePackForAllTargets || !hostRuntimeIdentifier.Equals(targetRuntimeIdentifier))
{
var targetIlcPackName = targetPackNamePattern.Replace("**RID**", targetRuntimeIdentifier);
var targetIlcPack = new TaskItem(targetIlcPackName);
targetIlcPack.SetMetadata(MetadataKeys.NuGetPackageId, targetIlcPackName);
targetIlcPack.SetMetadata(MetadataKeys.NuGetPackageVersion, packVersion);
TargetILCompilerPacks = new[] { targetIlcPack };
Log.LogMessage(MessageImportance.Low, $"Added {targetIlcPackName}@{packVersion} for cross-targeting compilation");
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);
}
}
else
{
Log.LogMessage(MessageImportance.Low, $"No cross-targeting compilation packs required.");
}
}
HostILCompilerPacks = new[] { runtimePackItem };
break;
}
}
if (runtimePackToDownload != null)
{
packagesToDownload.Add(runtimePackToDownload);
}
if (toolPackType is ToolPackType.ILLink)
{
// The ILLink tool pack is available for some TargetFrameworks where we nonetheless consider
// IsTrimmable/IsAotCompatible/EnableSingleFile to be unsupported, because the framework
// was not annotated with the attributes.
if (FirstTargetFrameworkVersionToSupportAotAnalyzer != null)
{
var firstTargetFrameworkVersionToSupportAotAnalyzer = NormalizeVersion(new Version(FirstTargetFrameworkVersionToSupportAotAnalyzer));
if ((IsAotCompatible || EnableAotAnalyzer) && normalizedTargetFrameworkVersion < firstTargetFrameworkVersionToSupportAotAnalyzer)
{
return ToolPackSupport.UnsupportedForTargetFramework;
}
}
if (FirstTargetFrameworkVersionToSupportSingleFileAnalyzer != null)
{
var firstTargetFrameworkVersionToSupportSingleFileAnalyzer = NormalizeVersion(new Version(FirstTargetFrameworkVersionToSupportSingleFileAnalyzer));
if (EnableSingleFileAnalyzer && normalizedTargetFrameworkVersion < firstTargetFrameworkVersionToSupportSingleFileAnalyzer)
{
return ToolPackSupport.UnsupportedForTargetFramework;
}
}
if (FirstTargetFrameworkVersionToSupportTrimAnalyzer != null)
{
var firstTargetFrameworkVersionToSupportTrimAnalyzer = NormalizeVersion(new Version(FirstTargetFrameworkVersionToSupportTrimAnalyzer));
if ((IsTrimmable || EnableTrimAnalyzer) && normalizedTargetFrameworkVersion < firstTargetFrameworkVersionToSupportTrimAnalyzer)
{
return ToolPackSupport.UnsupportedForTargetFramework;
}
}
}
// Packs with RID-agnostic build packages that contain MSBuild targets.
if (toolPackType is not ToolPackType.Crossgen2 && EnableRuntimePackDownload)
{
Log.LogMessage(MessageImportance.Low, $"Added {knownPack.ItemSpec}@{packVersion} for build-time targets");
var buildPackageName = knownPack.ItemSpec;
var buildPackage = new TaskItem(buildPackageName);
buildPackage.SetMetadata(MetadataKeys.Version, packVersion);
implicitPackageReferences.Add(buildPackage);
}
// Before net8.0, ILLink analyzers shipped in a separate package.
// Add the analyzer package with version taken from KnownILLinkPack if the version is less than 8.0.0.
// The version comparison doesn't consider prerelease labels, so 8.0.0-foo will be considered equal to 8.0.0 and
// will not get the extra analyzer package reference.
if (toolPackType is ToolPackType.ILLink &&
new VersionComparer(VersionComparison.Version).Compare(NuGetVersion.Parse(packVersion), new NuGetVersion(8, 0, 0)) < 0 &&
EnableRuntimePackDownload)
{
var analyzerPackage = new TaskItem("Microsoft.NET.ILLink.Analyzers");
analyzerPackage.SetMetadata(MetadataKeys.Version, packVersion);
implicitPackageReferences.Add(analyzerPackage);
Log.LogMessage(MessageImportance.Low, $"Added {analyzerPackage.ItemSpec}@{packVersion} for linker analyzers");
}
return ToolPackSupport.Supported;
}
private string GetRuntimeFrameworkVersion(
ITaskItem? frameworkReference,
KnownFrameworkReference knownFrameworkReference,
KnownRuntimePack? knownRuntimePack,
out string runtimePackVersion)
{
// Precedence order for selecting runtime framework version
// - RuntimeFrameworkVersion metadata on FrameworkReference item
// - RuntimeFrameworkVersion MSBuild property
// - Then, use either the LatestRuntimeFrameworkVersion or the DefaultRuntimeFrameworkVersion of the KnownFrameworkReference, based on
// - The value (if set) of TargetLatestRuntimePatch metadata on the FrameworkReference
// - The TargetLatestRuntimePatch MSBuild property (which defaults to True if SelfContained is true, and False otherwise)
// - But, if TargetLatestRuntimePatch was defaulted and not overridden by user, then acquire latest runtime pack for future
// self-contained deployment (or for crossgen of framework-dependent deployment), while targeting the default version.
string? requestedVersion = GetRequestedRuntimeFrameworkVersion(frameworkReference);
if (!string.IsNullOrEmpty(requestedVersion))
{
runtimePackVersion = requestedVersion;
return requestedVersion;
}
switch (GetRuntimePatchRequest(frameworkReference))
{
case RuntimePatchRequest.UseDefaultVersion:
runtimePackVersion = knownFrameworkReference.DefaultRuntimeFrameworkVersion;
return knownFrameworkReference.DefaultRuntimeFrameworkVersion;
case RuntimePatchRequest.UseLatestVersion:
if (knownRuntimePack is KnownRuntimePack knownPack)
{
runtimePackVersion = knownPack.LatestRuntimeFrameworkVersion;
return knownPack.LatestRuntimeFrameworkVersion;
}
else
{
runtimePackVersion = knownFrameworkReference.DefaultRuntimeFrameworkVersion;
return knownFrameworkReference.DefaultRuntimeFrameworkVersion;
}
case RuntimePatchRequest.UseDefaultVersionWithLatestRuntimePack:
if (knownRuntimePack is KnownRuntimePack knownPack2)
{
runtimePackVersion = knownPack2.LatestRuntimeFrameworkVersion;
}
else
{
runtimePackVersion = knownFrameworkReference.DefaultRuntimeFrameworkVersion;
}
return knownFrameworkReference.DefaultRuntimeFrameworkVersion;
default:
// Unreachable
throw new InvalidOperationException();
}
}
private string? GetPackPath(string packName, string packVersion)
{
IEnumerable<string> GetPackFolders()
{
var packRootEnvironmentVariable = Environment.GetEnvironmentVariable(EnvironmentVariableNames.WORKLOAD_PACK_ROOTS);
if (!string.IsNullOrEmpty(packRootEnvironmentVariable))
{
foreach (var packRoot in packRootEnvironmentVariable.Split(Path.PathSeparator))
{
yield return Path.Combine(packRoot, "packs");
}
}
if (!string.IsNullOrEmpty(NetCoreRoot) && !string.IsNullOrEmpty(NETCoreSdkVersion))
{
if (WorkloadFileBasedInstall.IsUserLocal(NetCoreRoot, NETCoreSdkVersion) &&
CliFolderPathCalculatorCore.GetDotnetUserProfileFolderPath() is { } userProfileDir)
{
yield return Path.Combine(userProfileDir, "packs");
}
}
if (!string.IsNullOrEmpty(TargetingPackRoot))
{
yield return TargetingPackRoot;
}
}
foreach (var packFolder in GetPackFolders())
{
string packPath = Path.Combine(packFolder, packName, packVersion);
if (Directory.Exists(packPath))
{
return packPath;
}
}
return null;
}
Lazy<WorkloadResolver> _workloadResolver
{
get
{
field ??= LazyCreateWorkloadResolver();
return field;
}
}
private string GetResolvedPackVersion(string packID, string packVersion)
{
if (!packVersion.Equals("**FromWorkload**", StringComparison.OrdinalIgnoreCase))
{
return packVersion;
}
var packInfo = _workloadResolver.Value.TryGetPackInfo(new WorkloadPackId(packID));
if (packInfo == null)
{
Log.LogError(Strings.CouldNotGetPackVersionFromWorkloadManifests, packID);
return packVersion;
}
return packInfo.Version;
}
private Lazy<WorkloadResolver> LazyCreateWorkloadResolver()
{
return new(() =>
{
string? userProfileDir = CliFolderPathCalculatorCore.GetDotnetUserProfileFolderPath();
// When running MSBuild tasks, the current directory is always the project directory, so we can use that as the
// starting point to search for global.json
string? globalJsonPath = SdkDirectoryWorkloadManifestProvider.GetGlobalJsonPath(Environment.CurrentDirectory);
var manifestProvider = new SdkDirectoryWorkloadManifestProvider(NetCoreRoot, NETCoreSdkVersion, userProfileDir, globalJsonPath);
return WorkloadResolver.Create(manifestProvider, NetCoreRoot, NETCoreSdkVersion, userProfileDir);
});
}
private enum RuntimePatchRequest
{
UseDefaultVersionWithLatestRuntimePack,
UseDefaultVersion,
UseLatestVersion,
}
/// <summary>
/// Compare PackageToDownload by name and version.
/// Used to deduplicate PackageToDownloads
/// </summary>
private class PackageToDownloadComparer<T> : IEqualityComparer<T> where T : ITaskItem
{
public bool Equals(T? x, T? y)
{
if (x is null || y is null)
{
return false;
}
return x.ItemSpec.Equals(y.ItemSpec,
StringComparison.OrdinalIgnoreCase) &&
x.GetMetadata(MetadataKeys.Version).Equals(
y.GetMetadata(MetadataKeys.Version), StringComparison.OrdinalIgnoreCase);
}
public int GetHashCode(T obj)
{
var hashCode = -1923861349;
hashCode = hashCode * -1521134295 + obj.ItemSpec.GetHashCode();
hashCode = hashCode * -1521134295 + obj.GetMetadata(MetadataKeys.Version).GetHashCode();
return hashCode;
}
}
private RuntimePatchRequest GetRuntimePatchRequest(ITaskItem? frameworkReference)
{
string? value = frameworkReference?.GetMetadata("TargetLatestRuntimePatch");
if (!string.IsNullOrEmpty(value))
{
return MSBuildUtilities.ConvertStringToBool(value, defaultValue: false)
? RuntimePatchRequest.UseLatestVersion
: RuntimePatchRequest.UseDefaultVersion;
}
if (TargetLatestRuntimePatch)
{
return RuntimePatchRequest.UseLatestVersion;
}
return TargetLatestRuntimePatchIsDefault
? RuntimePatchRequest.UseDefaultVersionWithLatestRuntimePack
: RuntimePatchRequest.UseDefaultVersion;
}
private string? GetRequestedRuntimeFrameworkVersion(ITaskItem? frameworkReference)
{
string? requestedVersion = frameworkReference?.GetMetadata("RuntimeFrameworkVersion");
if (string.IsNullOrEmpty(requestedVersion))
{
requestedVersion = RuntimeFrameworkVersion;
}
return requestedVersion;
}
internal static Version NormalizeVersion(Version version)
{
if (version.Revision == 0)
{
if (version.Build == 0)
{
return new Version(version.Major, version.Minor);
}
else
{
return new Version(version.Major, version.Minor, version.Build);
}
}
return version;
}
private struct KnownFrameworkReference
{
ITaskItem _item;
public KnownFrameworkReference(ITaskItem item)
{
_item = item;
TargetFramework = NuGetFramework.Parse(item.GetMetadata("TargetFramework"));
}
// The name / itemspec of the FrameworkReference used in the project
public string Name => _item.ItemSpec;
// The framework name to write to the runtimeconfig file (and the name of the folder under dotnet/shared)
public string RuntimeFrameworkName => _item.GetMetadata(MetadataKeys.RuntimeFrameworkName);
public string DefaultRuntimeFrameworkVersion => _item.GetMetadata("DefaultRuntimeFrameworkVersion");
// The ID of the targeting pack NuGet package to reference
public string TargetingPackName => _item.GetMetadata("TargetingPackName");
public string TargetingPackVersion => _item.GetMetadata("TargetingPackVersion");
public string TargetingPackFormat => _item.GetMetadata("TargetingPackFormat");
public string RuntimePackRuntimeIdentifiers => _item.GetMetadata(MetadataKeys.RuntimePackRuntimeIdentifiers);
public bool IsWindowsOnly => _item.HasMetadataValue("IsWindowsOnly", "true");
public bool RuntimePackAlwaysCopyLocal =>
_item.HasMetadataValue(MetadataKeys.RuntimePackAlwaysCopyLocal, "true");
public string Profile => _item.GetMetadata("Profile");
public NuGetFramework TargetFramework { get; }
public KnownRuntimePack ToKnownRuntimePack()
{
return new KnownRuntimePack(_item);
}
}
private struct KnownRuntimePack
{
ITaskItem _item;
public KnownRuntimePack(ITaskItem item)
{
_item = item;
TargetFramework = NuGetFramework.Parse(item.GetMetadata("TargetFramework"));
string runtimePackLabels = item.GetMetadata(MetadataKeys.RuntimePackLabels);
if (string.IsNullOrEmpty(runtimePackLabels))
{
RuntimePackLabels = Array.Empty<string>();
}
else
{
RuntimePackLabels = runtimePackLabels.Split(';');
}
}
// The name / itemspec of the FrameworkReference used in the project
public string Name => _item.ItemSpec;
//// The framework name to write to the runtimeconfig file (and the name of the folder under dotnet/shared)
public string LatestRuntimeFrameworkVersion => _item.GetMetadata("LatestRuntimeFrameworkVersion");
public string RuntimePackNamePatterns => _item.GetMetadata("RuntimePackNamePatterns");
public string RuntimePackRuntimeIdentifiers => _item.GetMetadata(MetadataKeys.RuntimePackRuntimeIdentifiers);
public string RuntimePackExcludedRuntimeIdentifiers => _item.GetMetadata(MetadataKeys.RuntimePackExcludedRuntimeIdentifiers);
public string IsTrimmable => _item.GetMetadata(MetadataKeys.IsTrimmable);
public bool IsWindowsOnly => _item.HasMetadataValue("IsWindowsOnly", "true");
public bool RuntimePackAlwaysCopyLocal =>
_item.HasMetadataValue(MetadataKeys.RuntimePackAlwaysCopyLocal, "true");
public string[] RuntimePackLabels { get; }
public NuGetFramework TargetFramework { get; }
}
}
} |