Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add restore support for C++/CLI .NET Core projects #4076

Merged
merged 13 commits into from
Jun 8, 2021
Original file line number Diff line number Diff line change
Expand Up @@ -160,12 +160,14 @@ internal static NuGetFramework GetTargetFramework(IVsProjectProperties propertie
var targetFrameworkMoniker = GetPropertyValueOrNull(properties, ProjectBuildProperties.TargetFrameworkMoniker);
var targetPlatformMoniker = GetPropertyValueOrNull(properties, ProjectBuildProperties.TargetPlatformMoniker);
var targetPlatformMinVersion = GetPropertyValueOrNull(properties, ProjectBuildProperties.TargetPlatformMinVersion);
var clrSupport = GetPropertyValueOrNull(properties, ProjectBuildProperties.CLRSupport);

return MSBuildProjectFrameworkUtility.GetProjectFramework(
projectFullPath,
targetFrameworkMoniker,
targetPlatformMoniker,
targetPlatformMinVersion);
targetPlatformMinVersion,
clrSupport);
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is nomination code that handles the VS side.

}

internal static ProjectRestoreMetadataFrameworkInfo ToProjectRestoreMetadataFrameworkInfo(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -570,7 +570,8 @@ internal static List<TargetFrameworkInformation> GetTargetFrameworkInfos(IReadOn
projectFilePath: projectInnerNode.Value.FullPath,
targetFrameworkMoniker: msBuildProjectInstance.GetProperty("TargetFrameworkMoniker"),
targetPlatformMoniker: msBuildProjectInstance.GetProperty("TargetPlatformMoniker"),
targetPlatformMinVersion: msBuildProjectInstance.GetProperty("TargetPlatformMinVersion"));
targetPlatformMinVersion: msBuildProjectInstance.GetProperty("TargetPlatformMinVersion"),
clrSupport: msBuildProjectInstance.GetProperty("CLRSupport"));

var targetFrameworkInformation = new TargetFrameworkInformation()
{
Expand Down
1 change: 1 addition & 0 deletions src/NuGet.Core/NuGet.Build.Tasks/NuGet.targets
Original file line number Diff line number Diff line change
Expand Up @@ -943,6 +943,7 @@ Copyright (c) .NET Foundation. All rights reserved.
<TargetPlatformIdentifier>$(TargetPlatformIdentifier)</TargetPlatformIdentifier>
<TargetPlatformVersion>$(TargetPlatformVersion)</TargetPlatformVersion>
<TargetPlatformMinVersion>$(TargetPlatformMinVersion)</TargetPlatformMinVersion>
<CLRSupport>$(CLRSupport)</CLRSupport>
<RuntimeIdentifierGraphPath>$(RuntimeIdentifierGraphPath)</RuntimeIdentifierGraphPath>
</_RestoreGraphEntry>
</ItemGroup>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
NuGet.Commands.SignArgs.PackagePaths.get -> System.Collections.Generic.IReadOnlyList<string>
NuGet.Commands.SignArgs.PackagePaths.set -> void
static NuGet.Commands.MSBuildProjectFrameworkUtility.GetProjectFramework(string projectFilePath, string targetFrameworkMoniker, string targetPlatformMoniker, string targetPlatformMinVersion, string clrSupport) -> NuGet.Frameworks.NuGetFramework
zivkan marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
NuGet.Commands.SignArgs.PackagePaths.get -> System.Collections.Generic.IReadOnlyList<string>
NuGet.Commands.SignArgs.PackagePaths.set -> void
static NuGet.Commands.MSBuildProjectFrameworkUtility.GetProjectFramework(string projectFilePath, string targetFrameworkMoniker, string targetPlatformMoniker, string targetPlatformMinVersion, string clrSupport) -> NuGet.Frameworks.NuGetFramework
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
NuGet.Commands.SignArgs.PackagePaths.get -> System.Collections.Generic.IReadOnlyList<string>
NuGet.Commands.SignArgs.PackagePaths.set -> void
static NuGet.Commands.MSBuildProjectFrameworkUtility.GetProjectFramework(string projectFilePath, string targetFrameworkMoniker, string targetPlatformMoniker, string targetPlatformMinVersion, string clrSupport) -> NuGet.Frameworks.NuGetFramework
Original file line number Diff line number Diff line change
Expand Up @@ -465,6 +465,11 @@ private IEnumerable<LibraryDependency> GetDependencies(
targetFramework,
item => item.TargetFramework);

if (dependencyGroup == null && DeconstructFallbackFrameworks(targetFramework) is DualCompatibilityFramework dualCompatibilityFramework)
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This handles the dependencies selection with dual compat framework.

{
dependencyGroup = NuGetFrameworkUtility.GetNearest(packageInfo.DependencyGroups, dualCompatibilityFramework.SecondaryFramework, item => item.TargetFramework);
}

if (dependencyGroup != null)
{
return dependencyGroup.Packages.Select(PackagingUtility.GetLibraryDependencyFromNuspec).ToArray();
Expand All @@ -473,6 +478,21 @@ private IEnumerable<LibraryDependency> GetDependencies(
return Enumerable.Empty<LibraryDependency>();
}

private static NuGetFramework DeconstructFallbackFrameworks(NuGetFramework nuGetFramework)
{
if (nuGetFramework is AssetTargetFallbackFramework assetTargetFallbackFramework)
{
return assetTargetFallbackFramework.RootFramework;
}

if (nuGetFramework is FallbackFramework fallbackFramework)
{
return fallbackFramework;
}

return nuGetFramework;
}

private async Task EnsureResource()
{
if (_findPackagesByIdResource == null)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -142,7 +142,7 @@ internal static List<List<SelectionCriteria>> CreateOrderedCriteriaSets(RestoreT
// Create an ordered list of selection criteria. Each will be applied, if the result is empty
// fallback frameworks from "imports" will be tried.
// These are only used for framework/RID combinations where content model handles everything.
// AssetTargetFallback frameworks will provide multiple criteria since all assets need to be
// AssetTargetFallback and DualCompatbiility frameworks will provide multiple criteria since all assets need to be

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Typo, DualCompatbiility

// evaluated before selecting the TFM to use.
var orderedCriteriaSets = new List<List<SelectionCriteria>>(1);

Expand All @@ -152,6 +152,11 @@ internal static List<List<SelectionCriteria>> CreateOrderedCriteriaSets(RestoreT
{
// Add the root project framework first.
orderedCriteriaSets.Add(CreateCriteria(targetGraph, assetTargetFallback.RootFramework));
// Add the secondary framework if dual compatibility framework.
if (assetTargetFallback.RootFramework is DualCompatibilityFramework dualCompatibilityFramework)
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This ensures the package assets are selected with dual compatibility in mind.

{
orderedCriteriaSets.Add(CreateCriteria(targetGraph, dualCompatibilityFramework.SecondaryFramework));
}

// Add all fallbacks in order.
orderedCriteriaSets.AddRange(assetTargetFallback.Fallback.Select(e => CreateCriteria(targetGraph, e)));
Expand All @@ -160,6 +165,11 @@ internal static List<List<SelectionCriteria>> CreateOrderedCriteriaSets(RestoreT
{
// Add the current framework.
orderedCriteriaSets.Add(CreateCriteria(targetGraph, framework));

if (framework is DualCompatibilityFramework dualCompatibilityFramework)
{
orderedCriteriaSets.Add(CreateCriteria(targetGraph, dualCompatibilityFramework.SecondaryFramework));
}
}

return orderedCriteriaSets;
Expand Down Expand Up @@ -458,9 +468,17 @@ private static void AddDependencies(IEnumerable<LibraryDependency> dependencies,
{
if (dependencies == null)
{
// AssetFallbackFramework does not apply to dependencies.
// DualCompatibilityFramework & AssetFallbackFramework does not apply to dependencies.
// Convert it to a fallback framework if needed.
var currentFramework = (framework as AssetTargetFallbackFramework)?.AsFallbackFramework() ?? framework;
NuGetFramework currentFramework = framework;
if (framework is AssetTargetFallbackFramework atf)
{
currentFramework = atf.AsFallbackFramework();
}
else if (framework is DualCompatibilityFramework mcf)
{
currentFramework = mcf.AsFallbackFramework();
}

var dependencySet = nuspec
.GetDependencyGroups()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -425,7 +425,7 @@ private static IEnumerable<TargetFrameworkInformation> GetTargetFrameworkInforma
var targetFrameworkMoniker = item.GetProperty("TargetFrameworkMoniker");
var targetPlatforMoniker = item.GetProperty("TargetPlatformMoniker");
var targetPlatformMinVersion = item.GetProperty("TargetPlatformMinVersion");

var clrSupport = item.GetProperty("CLRSupport");
var targetAlias = string.IsNullOrEmpty(frameworkString) ? string.Empty : frameworkString;
if (uniqueIds.Contains(targetAlias))
{
Expand All @@ -437,7 +437,8 @@ private static IEnumerable<TargetFrameworkInformation> GetTargetFrameworkInforma
projectFilePath: filePath,
targetFrameworkMoniker: targetFrameworkMoniker,
targetPlatformMoniker: targetPlatforMoniker,
targetPlatformMinVersion: targetPlatformMinVersion);
targetPlatformMinVersion: targetPlatformMinVersion,
clrSupport: clrSupport);

var targetFrameworkInfo = new TargetFrameworkInformation()
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,26 @@ public static NuGetFramework GetProjectFramework(
targetPlatformIdentifier: null,
targetPlatformVersion: null,
targetPlatformMinVersion,
clrSupport: null,
isXnaWindowsPhoneProject: false,
isManagementPackProject: false);
}

public static NuGetFramework GetProjectFramework(
string projectFilePath,
string targetFrameworkMoniker,
string targetPlatformMoniker,
string targetPlatformMinVersion,
string clrSupport)
{
return GetProjectFramework(
projectFilePath,
targetFrameworkMoniker,
targetPlatformMoniker,
targetPlatformIdentifier: null,
targetPlatformVersion: null,
targetPlatformMinVersion,
clrSupport,
isXnaWindowsPhoneProject: false,
isManagementPackProject: false);
}
Expand Down Expand Up @@ -89,6 +109,7 @@ public static IEnumerable<string> GetProjectFrameworkStrings(
targetPlatformIdentifier,
targetPlatformVersion,
targetPlatformMinVersion,
clrSupport: null,
isXnaWindowsPhoneProject,
isManagementPackProject);
}
Expand All @@ -102,6 +123,7 @@ internal static IEnumerable<string> GetProjectFrameworks(
string targetPlatformIdentifier,
string targetPlatformVersion,
string targetPlatformMinVersion,
string clrSupport,
bool isXnaWindowsPhoneProject,
bool isManagementPackProject)
{
Expand Down Expand Up @@ -132,6 +154,7 @@ internal static IEnumerable<string> GetProjectFrameworks(
targetPlatformIdentifier,
targetPlatformVersion,
targetPlatformMinVersion,
clrSupport,
isXnaWindowsPhoneProject,
isManagementPackProject).DotNetFrameworkName };
}
Expand All @@ -143,15 +166,22 @@ internal static NuGetFramework GetProjectFramework(
string targetPlatformIdentifier,
string targetPlatformVersion,
string targetPlatformMinVersion,
string clrSupport,
bool isXnaWindowsPhoneProject,
bool isManagementPackProject)
{
bool isCppCliSet = clrSupport?.Equals("NetCore", StringComparison.OrdinalIgnoreCase) == true;
bool isCppCli = false;
// C++ check
if (projectFilePath?.EndsWith(".vcxproj", StringComparison.OrdinalIgnoreCase) == true)
{
// The C++ project does not have a TargetFrameworkMoniker property set.
// We hard-code the return value to Native.
return NuGetFramework.Parse("Native, Version=0.0");
if (!isCppCliSet)
{
// The C++ project does not have a TargetFrameworkMoniker property set.
// We hard-code the return value to Native.
return FrameworkConstants.CommonFrameworks.Native;
}
isCppCli = true;
}

// The MP project does not have a TargetFrameworkMoniker property set.
Expand Down Expand Up @@ -227,6 +257,11 @@ internal static NuGetFramework GetProjectFramework(
}
NuGetFramework framework = NuGetFramework.ParseComponents(currentFrameworkString, platformMoniker);

if (isCppCli)
{
return new DualCompatibilityFramework(framework, FrameworkConstants.CommonFrameworks.Native);
}

return framework;
}

Expand Down
106 changes: 106 additions & 0 deletions src/NuGet.Core/NuGet.Frameworks/DualCompatibilityFramework.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.

using System;
using NuGet.Shared;

namespace NuGet.Frameworks
{
/// <summary>
/// Represents a framework that behaves as 2 potentially independent frameworks.
/// Ex. C++/CLI can support both .NET 5.0 and native.
/// This type is immutable.
/// </summary>
public class DualCompatibilityFramework : NuGetFramework
{
/// <summary>
/// The root framework. Any compatibility checks should be performed against this framework first.
/// </summary>
public NuGetFramework RootFramework { get; }

/// <summary>
/// The secondary framework. If the root framework compatibility checks fail, then the compat checks should be performed against this framework next.
/// </summary>
public NuGetFramework SecondaryFramework { get; }

private int? _hashCode;
private FallbackFramework _fallbackFramework;

/// <summary>
/// Multiple compatbility
/// </summary>
/// <param name="framework">Root framework. Never <see langword="null"/>. </param>
/// <param name="secondaryFramework">Secondary framework. Never <see langword="null"/>. </param>
/// <exception cref="ArgumentNullException">if either <paramref name="framework"/> or <paramref name="secondaryFramework"/> are <see langword="null"/>.</exception>
public DualCompatibilityFramework(NuGetFramework framework, NuGetFramework secondaryFramework)
: base(ValidateFrameworkArgument(framework))
{
if (secondaryFramework == null)
{
throw new ArgumentNullException(nameof(secondaryFramework));
}

SecondaryFramework = secondaryFramework;
nkolev92 marked this conversation as resolved.
Show resolved Hide resolved
RootFramework = framework;
}

/// <summary>
/// Create a FallbackFramework from the current DualCompatibilityFramework.
/// </summary>
public FallbackFramework AsFallbackFramework()
{
if (_fallbackFramework == null)
{
_fallbackFramework = new FallbackFramework(RootFramework, new NuGetFramework[] { SecondaryFramework });
}

return _fallbackFramework;
}

private static NuGetFramework ValidateFrameworkArgument(NuGetFramework framework)
{
if (framework == null)
{
throw new ArgumentNullException(nameof(framework));
}
return framework;
}

public override bool Equals(object obj)
{
return Equals(obj as DualCompatibilityFramework);
}

public bool Equals(DualCompatibilityFramework other)
{
if (other == null)
{
return false;
}

if (ReferenceEquals(this, other))
{
return true;
}

return Comparer.Equals(RootFramework, other.RootFramework)
&& Comparer.Equals(SecondaryFramework, other.SecondaryFramework);
}

public override int GetHashCode()
{
if (_hashCode == null)
{
var combiner = new HashCodeCombiner();
// Ensure that this is different from AssetTargetFallback & FallbackFramework;
combiner.AddStringIgnoreCase(nameof(DualCompatibilityFramework));
combiner.AddObject(Comparer.GetHashCode(RootFramework));
combiner.AddObject(Comparer.GetHashCode(SecondaryFramework));
_hashCode = combiner.CombinedHash;
}

return _hashCode.Value;
}

}
}
5 changes: 5 additions & 0 deletions src/NuGet.Core/NuGet.Frameworks/FrameworkConstants.cs
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,9 @@ public static class CommonFrameworks
public static readonly NuGetFramework Net461 = new NuGetFramework(FrameworkIdentifiers.Net, new Version(4, 6, 1, 0));
public static readonly NuGetFramework Net462 = new NuGetFramework(FrameworkIdentifiers.Net, new Version(4, 6, 2, 0));
public static readonly NuGetFramework Net463 = new NuGetFramework(FrameworkIdentifiers.Net, new Version(4, 6, 3, 0));
public static readonly NuGetFramework Net47 = new NuGetFramework(FrameworkIdentifiers.Net, new Version(4, 7, 0, 0));
public static readonly NuGetFramework Net471 = new NuGetFramework(FrameworkIdentifiers.Net, new Version(4, 7, 1, 0));
public static readonly NuGetFramework Net472 = new NuGetFramework(FrameworkIdentifiers.Net, new Version(4, 7, 2, 0));

public static readonly NuGetFramework NetCore45 = new NuGetFramework(FrameworkIdentifiers.NetCore, new Version(4, 5, 0, 0));
public static readonly NuGetFramework NetCore451 = new NuGetFramework(FrameworkIdentifiers.NetCore, new Version(4, 5, 1, 0));
Expand Down Expand Up @@ -185,6 +188,8 @@ public static readonly NuGetFramework NetCoreApp31

// .NET 5.0 and later has NetCoreApp identifier
public static readonly NuGetFramework Net50 = new NuGetFramework(FrameworkIdentifiers.NetCoreApp, Version5);

public static readonly NuGetFramework Native = new NuGetFramework(FrameworkIdentifiers.Native, new Version(0, 0, 0, 0));
}
}
}
13 changes: 13 additions & 0 deletions src/NuGet.Core/NuGet.Frameworks/NuGetFrameworkFactory.cs
Original file line number Diff line number Diff line change
Expand Up @@ -609,6 +609,15 @@ private static bool TryParseCommonFramework(string frameworkString, out NuGetFra
case "net462":
framework = FrameworkConstants.CommonFrameworks.Net462;
break;
case "net47":
framework = FrameworkConstants.CommonFrameworks.Net47;
break;
case "net471":
framework = FrameworkConstants.CommonFrameworks.Net471;
break;
case "net472":
framework = FrameworkConstants.CommonFrameworks.Net472;
break;
case "win8":
framework = FrameworkConstants.CommonFrameworks.Win8;
break;
Expand Down Expand Up @@ -662,6 +671,10 @@ private static bool TryParseCommonFramework(string frameworkString, out NuGetFra
case "netcoreapp21":
framework = FrameworkConstants.CommonFrameworks.NetCoreApp21;
break;
case "netcoreapp3.0":
case "netcoreapp30":
framework = FrameworkConstants.CommonFrameworks.NetCoreApp30;
break;
case "netcoreapp3.1":
case "netcoreapp31":
framework = FrameworkConstants.CommonFrameworks.NetCoreApp31;
Expand Down
Loading