in src/Tasks/ResolveSDKReference.cs [1410:1767]
private void CreateResolvedReferenceItem(string targetConfiguration, string targetArchitecture, HashSet<string> sdkNamesOnReferenceItems, string targetPlatformIdentifier, Version targetPlatformVersion, Version targetPlatformVersionFromItem, string projectName, bool enableMaxPlatformVersionEmptyWarning)
{
// Make output item to send to the project file which represents a resolve SDKReference
ResolvedItem = new TaskItem(ResolvedPath);
ResolvedItem.SetMetadata("SDKName", SDKName);
if (!String.IsNullOrEmpty(ProductFamilyName))
{
ResolvedItem.SetMetadata(SDKManifest.Attributes.ProductFamilyName, ProductFamilyName);
}
// Copy existing metadata onto the output item
ReferenceItem.CopyMetadataTo(ResolvedItem);
ResolvedItem.SetMetadata("SupportsMultipleVersions", _supportsMultipleVersions.ToString());
// If no architecture and configuration is passed in then default to retail neutral
targetArchitecture = String.IsNullOrEmpty(targetArchitecture) ? NeutralArch : targetArchitecture;
targetConfiguration = String.IsNullOrEmpty(targetConfiguration) ? Retail : targetConfiguration;
// Check to see if there was metadata on the original reference item, if there is then that wins.
string sdkConfiguration = ReferenceItem.GetMetadata(TargetedSDKConfiguration);
sdkConfiguration = sdkConfiguration.Length > 0 ? sdkConfiguration : targetConfiguration;
string sdkArchitecture = ReferenceItem.GetMetadata(TargetedSDKArchitecture).Length > 0 ? ReferenceItem.GetMetadata(TargetedSDKArchitecture) : targetArchitecture;
sdkArchitecture = sdkArchitecture.Length > 0 ? sdkArchitecture : targetArchitecture;
// Configuration is somewhat special, if Release is passed in me want to convert it to Retail and set that on the resulting output item.
sdkConfiguration = sdkConfiguration.Equals("Release", StringComparison.OrdinalIgnoreCase) ? Retail : sdkConfiguration;
sdkArchitecture = sdkArchitecture.Equals("msil", StringComparison.OrdinalIgnoreCase) ? NeutralArch : sdkArchitecture;
sdkArchitecture = sdkArchitecture.Equals("AnyCPU", StringComparison.OrdinalIgnoreCase) ? NeutralArch : sdkArchitecture;
sdkArchitecture = sdkArchitecture.Equals("Any CPU", StringComparison.OrdinalIgnoreCase) ? NeutralArch : sdkArchitecture;
sdkArchitecture = sdkArchitecture.Equals("amd64", StringComparison.OrdinalIgnoreCase) ? X64Arch : sdkArchitecture;
ResolvedItem.SetMetadata(TargetedSDKConfiguration, sdkConfiguration);
ResolvedItem.SetMetadata(TargetedSDKArchitecture, sdkArchitecture);
// Print out a message indicating what our targeted sdk configuration and architecture is so users know what the reference is targeting.
AddStatusMessage("ResolveSDKReference.TargetedConfigAndArchitecture", sdkConfiguration, sdkArchitecture);
string[] supportedArchitectures = null;
if (SupportedArchitectures != null && SupportedArchitectures.Length > 0)
{
supportedArchitectures = SupportedArchitectures.Split(s_supportedArchitecturesSplitChars, StringSplitOptions.RemoveEmptyEntries);
}
if (supportedArchitectures != null)
{
bool foundTargetArchitecture = false;
// SupportedArchitectures will usually only contain a handful of elements therefore putting this into a hashtable or dictionary would not likely give us much performance improvement.
foreach (string architecture in supportedArchitectures)
{
if (architecture.Equals(sdkArchitecture, StringComparison.OrdinalIgnoreCase))
{
foundTargetArchitecture = true;
break;
}
}
if (!foundTargetArchitecture)
{
string remappedArchitecture = sdkArchitecture.Equals(NeutralArch, StringComparison.OrdinalIgnoreCase) ? AnyCPUArch : sdkArchitecture;
string supportedArchList = String.Empty;
for (int i = 0; i < supportedArchitectures.Length; i++)
{
supportedArchList += supportedArchitectures[i].Equals(NeutralArch, StringComparison.OrdinalIgnoreCase) ? AnyCPUArch : supportedArchitectures[i];
// only put a comma after the first if there is more that one and do not put one after the end
if (supportedArchitectures.Length > 1 && i != supportedArchitectures.Length - 1)
{
supportedArchList += SupportedArchitectureJoinDelimiter;
}
}
AddResolutionErrorOrWarning("ResolveSDKReference.TargetArchitectureNotSupported", remappedArchitecture, SDKName, supportedArchList);
}
}
if (!String.IsNullOrEmpty(MaxPlatformVersion))
{
Version maxPlatformVersionAsVersion;
if (System.Version.TryParse(MaxPlatformVersion, out maxPlatformVersionAsVersion) && (maxPlatformVersionAsVersion < targetPlatformVersion))
{
AddResolutionWarning("ResolveSDKReference.MaxPlatformVersionLessThanTargetPlatformVersion", projectName, DisplayName, Version, targetPlatformIdentifier, MaxPlatformVersion, targetPlatformIdentifier, targetPlatformVersion.ToString());
}
}
else if (enableMaxPlatformVersionEmptyWarning && targetPlatformVersionFromItem != null && targetPlatformVersionFromItem < targetPlatformVersion)
{
AddResolutionWarning("ResolveSDKReference.MaxPlatformVersionNotSpecified", projectName, DisplayName, Version, targetPlatformIdentifier, targetPlatformVersionFromItem.ToString(), targetPlatformIdentifier, targetPlatformVersion.ToString());
}
if (!String.IsNullOrEmpty(TargetPlatform) && !String.Equals(targetPlatformIdentifier, TargetPlatform))
{
AddResolutionErrorOrWarning("ResolveSDKReference.TargetPlatformIdentifierDoesNotMatch", projectName, DisplayName, Version, targetPlatformIdentifier, TargetPlatform);
}
if (!String.IsNullOrEmpty(TargetPlatformMinVersion))
{
Version targetPlatformMinVersionAsVersion;
if (System.Version.TryParse(TargetPlatformMinVersion, out targetPlatformMinVersionAsVersion) && (targetPlatformVersion < targetPlatformMinVersionAsVersion))
{
AddResolutionErrorOrWarning("ResolveSDKReference.PlatformVersionIsLessThanMinVersion", projectName, DisplayName, Version, targetPlatformVersion.ToString(), targetPlatformMinVersionAsVersion.ToString());
}
}
if (String.Equals(NeutralArch, sdkArchitecture, StringComparison.OrdinalIgnoreCase) && !String.IsNullOrEmpty(SupportPrefer32Bit) && _prefer32BitFromProject)
{
bool supportPrefer32Bit = true;
bool.TryParse(SupportPrefer32Bit, out supportPrefer32Bit);
if (!supportPrefer32Bit)
{
AddResolutionErrorOrWarning("ResolveSDKReference.Prefer32BitNotSupportedWithNeutralProject", SDKName);
}
}
// The SDKManifest may have had a number of frameworkidentity entries inside of it. We want to match the one
// which has the correct configuration and architecture. If a perfect match cannot be found
// then we will look for ones that declare only the configuration. If that cannot be found we just try and find an element that only is "FrameworkIdentity".
if (String.IsNullOrEmpty(FrameworkIdentity))
{
if (FrameworkIdentitiesFromManifest.Count > 0)
{
// Try and find a framework identity that matches on both the configuration and architecture "FrameworkIdentity-<Config>-<Arch>"
FrameworkIdentity = null;
string frameworkIdentityKey = String.Format(CultureInfo.InvariantCulture, "{0}-{1}-{2}", SDKManifest.Attributes.FrameworkIdentity, sdkConfiguration, sdkArchitecture);
FrameworkIdentity = FindFrameworkIdentity(frameworkIdentityKey);
// Try and find a framework identity that matches on the configuration , Element must be named "FrameworkIdentity-<Config>" only.
if (FrameworkIdentity == null)
{
frameworkIdentityKey = String.Format(CultureInfo.InvariantCulture, "{0}-{1}", SDKManifest.Attributes.FrameworkIdentity, sdkConfiguration);
FrameworkIdentity = FindFrameworkIdentity(frameworkIdentityKey);
}
// See if there is an element just called "FrameworkIdentity"
if (FrameworkIdentity == null)
{
frameworkIdentityKey = SDKManifest.Attributes.FrameworkIdentity;
FrameworkIdentity = FindFrameworkIdentity(frameworkIdentityKey);
}
if (FrameworkIdentity == null)
{
AddResolutionErrorOrWarning("ResolveSDKReference.NoMatchingFrameworkIdentity", _sdkManifestPath, sdkConfiguration, sdkArchitecture);
}
else
{
ResolvedItem.SetMetadata(SDKManifest.Attributes.FrameworkIdentity, FrameworkIdentity);
}
}
else
{
AddStatusMessage("ResolveSDKReference.NoFrameworkIdentitiesFound");
}
}
else
{
AddStatusMessage("ResolveSDKReference.FoundFrameworkIdentity", FrameworkIdentity);
}
// Print out if we are a platform SDK
if (!String.IsNullOrEmpty(PlatformIdentity))
{
AddStatusMessage("ResolveSDKReference.PlatformSDK", PlatformIdentity);
ResolvedItem.SetMetadata(SDKManifest.Attributes.PlatformIdentity, PlatformIdentity);
}
// The SDKManifest may have had a number of AppxLocation entries inside of it. We want to return the set of unique architectures for a selected configuration.
if (String.IsNullOrEmpty(AppxLocation))
{
if (AppxLocationsFromManifest.Count > 0)
{
AppxLocation = null;
// For testing especially it's nice to have a set order of what the generated appxlocation string will be at the end
SortedDictionary<string, string> architectureLocations = new SortedDictionary<string, string>(StringComparer.InvariantCultureIgnoreCase);
List<string> appxLocationComponents = new List<string>();
foreach (var appxLocation in AppxLocationsFromManifest)
{
if (!String.IsNullOrEmpty(appxLocation.Key))
{
string[] appxComponents = appxLocation.Key.Split(s_appxSplitChar, StringSplitOptions.RemoveEmptyEntries).Select(x => x.Trim()).ToArray();
// The first component needs to be appx
if (!String.Equals("Appx", appxComponents[0], StringComparison.OrdinalIgnoreCase))
{
continue;
}
string configurationComponent = null;
string architectureComponent = null;
switch (appxComponents.Length)
{
case 1:
architectureComponent = NeutralArch;
break;
case 2:
configurationComponent = appxComponents[1];
architectureComponent = NeutralArch;
// If the configuration is not debug or retail then we will assume it is an architecture
if (!(configurationComponent.Equals(Debug, StringComparison.OrdinalIgnoreCase) || configurationComponent.Equals(Retail, StringComparison.OrdinalIgnoreCase)))
{
configurationComponent = null;
architectureComponent = appxComponents[1];
}
break;
case 3:
configurationComponent = appxComponents[1];
architectureComponent = appxComponents[2];
break;
default:
// Not one of the cases we expect, just skip it
continue;
}
bool containsKey = architectureLocations.ContainsKey(architectureComponent);
// If we have not seen this architecture before (and it has a compatible configuration with what we are targeting) then add it.
// Also, replace the entry if we have already added an entry for a non configuration specific entry and we now have a configuration specific entry that matches what we are targeting.
if ((configurationComponent == null && !containsKey) || (configurationComponent != null && configurationComponent.Equals(sdkConfiguration, StringComparison.OrdinalIgnoreCase)))
{
AddStatusMessage("ResolveSDKReference.FoundAppxLocation", appxLocation.Key + "=" + appxLocation.Value);
if (containsKey)
{
AddStatusMessage("ResolveSDKReference.ReplaceAppxLocation", architectureComponent, architectureLocations[architectureComponent], appxLocation.Value);
}
architectureLocations[architectureComponent] = appxLocation.Value;
}
}
}
foreach (var location in architectureLocations)
{
appxLocationComponents.Add(location.Key);
appxLocationComponents.Add(location.Value);
}
if (appxLocationComponents.Count > 0)
{
AppxLocation = String.Join("|", appxLocationComponents.ToArray());
}
if (AppxLocation == null)
{
AddResolutionErrorOrWarning("ResolveSDKReference.NoMatchingAppxLocation", _sdkManifestPath, sdkConfiguration, sdkArchitecture);
}
else
{
ResolvedItem.SetMetadata(SDKManifest.Attributes.AppxLocation, AppxLocation);
}
}
else
{
AddStatusMessage("ResolveSDKReference.NoAppxLocationsFound");
}
}
else
{
AddStatusMessage("ResolveSDKReference.FoundAppxLocation", AppxLocation);
}
ResolvedItem.SetMetadata("SimpleName", SimpleName);
ResolvedItem.SetMetadata("Version", Version);
// Check to see if the copy local metadata has been set in the project file.
bool result;
bool hasExpandReferenceAssemblies = bool.TryParse(ReferenceItem.GetMetadata(SDKManifest.Attributes.ExpandReferenceAssemblies), out result);
bool hasCopyRedist = bool.TryParse(ReferenceItem.GetMetadata(SDKManifest.Attributes.CopyRedist), out result);
bool hasCopyLocalExpandedReferenceAssemblies = bool.TryParse(ReferenceItem.GetMetadata(SDKManifest.Attributes.CopyLocalExpandedReferenceAssemblies), out result);
bool referenceItemHasSDKName = sdkNamesOnReferenceItems.Contains(SDKName);
if (SDKType != SDKType.Unspecified)
{
ResolvedItem.SetMetadata(SDKManifest.Attributes.SDKType, SDKType.ToString());
}
if (!String.IsNullOrEmpty(DisplayName))
{
ResolvedItem.SetMetadata(SDKManifest.Attributes.DisplayName, DisplayName);
}
// Could be null or empty depending if blank metadata was set or not.
bool frameworkSDK = SDKType == SDKType.Framework || !String.IsNullOrEmpty(FrameworkIdentity);
bool hasPlatformIdentity = SDKType == SDKType.Platform || !String.IsNullOrEmpty(PlatformIdentity);
if (!hasExpandReferenceAssemblies)
{
if (referenceItemHasSDKName)
{
ResolvedItem.SetMetadata(SDKManifest.Attributes.ExpandReferenceAssemblies, "false");
}
else
{
ResolvedItem.SetMetadata(SDKManifest.Attributes.ExpandReferenceAssemblies, "true");
}
}
if (!hasCopyRedist)
{
if (frameworkSDK || hasPlatformIdentity)
{
ResolvedItem.SetMetadata(SDKManifest.Attributes.CopyRedist, "false");
}
else
{
ResolvedItem.SetMetadata(SDKManifest.Attributes.CopyRedist, "true");
}
}
if (!hasCopyLocalExpandedReferenceAssemblies)
{
if (frameworkSDK || referenceItemHasSDKName || hasPlatformIdentity)
{
ResolvedItem.SetMetadata(SDKManifest.Attributes.CopyLocalExpandedReferenceAssemblies, "false");
}
else
{
ResolvedItem.SetMetadata(SDKManifest.Attributes.CopyLocalExpandedReferenceAssemblies, "true");
}
}
if (!String.IsNullOrEmpty(CopyRedistToSubDirectory))
{
ResolvedItem.SetMetadata(SDKManifest.Attributes.CopyRedistToSubDirectory, CopyRedistToSubDirectory);
}
if (!String.IsNullOrEmpty(MaxPlatformVersion))
{
ResolvedItem.SetMetadata(SDKManifest.Attributes.MaxPlatformVersion, MaxPlatformVersion);
}
if (!String.IsNullOrEmpty(MinOSVersion))
{
ResolvedItem.SetMetadata(SDKManifest.Attributes.MinOSVersion, MinOSVersion);
}
if (!String.IsNullOrEmpty(MaxOSVersionTested))
{
ResolvedItem.SetMetadata(SDKManifest.Attributes.MaxOSVersionTested, MaxOSVersionTested);
}
if (!String.IsNullOrEmpty(MoreInfo))
{
ResolvedItem.SetMetadata(SDKManifest.Attributes.MoreInfo, MoreInfo);
}
}