in src/Tasks/ResolveSDKReference.cs [357:570]
public override bool Execute()
{
ResolvedSDKReferences = new TaskItem[0];
if (InstalledSDKs.Length == 0)
{
Log.LogMessageFromResources("ResolveSDKReference.NoSDKLocationsSpecified");
return true;
}
_runtimeReferenceOnlyDependenciesByName = new Dictionary<string, string>(StringComparer.InvariantCultureIgnoreCase);
if (RuntimeReferenceOnlySDKDependencies != null)
{
foreach (ITaskItem runtimeDependencyOnlyItem in RuntimeReferenceOnlySDKDependencies)
{
string dependencyName;
string dependencyVersion;
if (ParseSDKReference(runtimeDependencyOnlyItem.ItemSpec, out dependencyName, out dependencyVersion))
{
_runtimeReferenceOnlyDependenciesByName[dependencyName] = dependencyVersion;
}
}
}
// Convert the list of installed SDK's to a dictionary for faster lookup
Dictionary<string, ITaskItem> sdkItems = new Dictionary<string, ITaskItem>(StringComparer.OrdinalIgnoreCase);
foreach (ITaskItem installedsdk in InstalledSDKs)
{
string installLocation = installedsdk.ItemSpec;
string sdkName = installedsdk.GetMetadata(SDKName);
string sdkPlatformVersion = installedsdk.GetMetadata(SDKPlatformVersion);
if (installLocation.Length > 0 && sdkName.Length > 0)
{
if (!sdkItems.ContainsKey(sdkName))
{
sdkItems.Add(sdkName, installedsdk);
}
else
{
sdkItems[sdkName] = installedsdk;
}
}
}
// We need to check to see if there are any SDKNames on any of the reference items in the project. If there are
// then we do not want those SDKs to expand their reference assemblies by default because we are going to use RAR to look inside of them for certain reference assemblies only.
HashSet<string> sdkNamesOnReferenceItems = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
if (References != null)
{
foreach (ITaskItem referenceItem in References)
{
string sdkName = referenceItem.GetMetadata(SDKName);
if (sdkName.Length > 0)
{
sdkNamesOnReferenceItems.Add(sdkName);
}
}
}
// The set of reference items declared in the project file, without duplicate entries.
HashSet<SDKReference> sdkReferenceItems = new HashSet<SDKReference>();
// Maps a product family name to a set of SDKs with that product family name
Dictionary<string, HashSet<SDKReference>> productFamilyNameToSDK = new Dictionary<string, HashSet<SDKReference>>(StringComparer.OrdinalIgnoreCase);
// Maps a sdk name (no version) to a set of SDKReferences with the same name
Dictionary<string, HashSet<SDKReference>> sdkNameToSDK = new Dictionary<string, HashSet<SDKReference>>(StringComparer.OrdinalIgnoreCase);
// Set of sdks which are not compatible with other sdks of the same product famuily or with the same sdk name
HashSet<SDKReference> sdksNotCompatibleWithOtherSDKs = new HashSet<SDKReference>();
// Go through each reference passed in and determine if it is in the set of installed SDKs.
// Also create new output items if the item is in an installed SDK and set the metadata correctly.
foreach (ITaskItem referenceItem in SDKReferences)
{
// Parse the SDK reference item include. The name could have been added by a user and may have extra spaces or be not well formatted.
SDKReference reference = ParseSDKReference(referenceItem);
// Could not parse the reference, lets skip over this reference item. An error would have been logged in the ParseSDKReference method to tell the
// user why the parsing did not happen.
if (reference == null)
{
continue;
}
// Make sure we do not include a duplicate reference item if one has already been seen in the project file.
if (!sdkReferenceItems.Contains(reference) /* filter out duplicate sdk reference entries*/)
{
sdkReferenceItems.Add(reference);
reference.Resolve(sdkItems, TargetedSDKConfiguration, TargetedSDKArchitecture, sdkNamesOnReferenceItems, _logResolutionErrorsAsWarnings, _prefer32Bit, TargetPlatformIdentifier, TargetPlatformAsVersion, ProjectName, _enableMaxPlatformVersionEmptyWarning);
if (reference.Resolved)
{
if (!String.IsNullOrEmpty(reference.ProductFamilyName))
{
HashSet<SDKReference> sdksWithProductFamilyName = null;
if (!productFamilyNameToSDK.TryGetValue(reference.ProductFamilyName, out sdksWithProductFamilyName))
{
productFamilyNameToSDK.Add(reference.ProductFamilyName, new HashSet<SDKReference> { reference });
}
else
{
sdksWithProductFamilyName.Add(reference);
}
}
if (reference.SupportsMultipleVersions != MultipleVersionSupport.Allow && !reference.SimpleName.Equals("Microsoft.VCLibs", StringComparison.InvariantCultureIgnoreCase))
{
sdksNotCompatibleWithOtherSDKs.Add(reference);
}
HashSet<SDKReference> sdksWithSimpleName = null;
if (!sdkNameToSDK.TryGetValue(reference.SimpleName, out sdksWithSimpleName))
{
sdkNameToSDK.Add(reference.SimpleName, new HashSet<SDKReference> { reference });
}
else
{
sdksWithSimpleName.Add(reference);
}
}
}
}
// Go through each of the items which have been processed and log the results.
foreach (SDKReference reference in sdkReferenceItems)
{
LogResolution(reference);
}
// Go through each of the incompatible references and log the ones that are not compatible with it
// starting with being incompatible with the product family then with the sdk name.
foreach (SDKReference notCompatibleReference in sdksNotCompatibleWithOtherSDKs)
{
// If we have already error or warned about an sdk not being compatible with one of the notCompatibleReferences then do not log it again
// an sdk could be incompatible because the productfamily is the same but also be incompatible at the same time due to the sdk name
// we only want to log one of those cases so we do not get 2 warings or errors for the same sdks.
HashSet<SDKReference> sdksAlreadyErrorOrWarnedFor = new HashSet<SDKReference>();
// Check to see if a productfamily was set, we want to emit this warning or error first.
if (!String.IsNullOrEmpty(notCompatibleReference.ProductFamilyName))
{
HashSet<SDKReference> referenceInProductFamily = null;
if (productFamilyNameToSDK.TryGetValue(notCompatibleReference.ProductFamilyName, out referenceInProductFamily))
{
// We want to build a list of incompatible reference names so we can emit them in the error or warnings.
List<string> listOfIncompatibleReferences = new List<string>();
foreach (SDKReference incompatibleReference in referenceInProductFamily)
{
if (!sdksAlreadyErrorOrWarnedFor.Contains(incompatibleReference) && incompatibleReference != notCompatibleReference /*cannot be incompatible with self*/)
{
listOfIncompatibleReferences.Add(String.Format(CultureInfo.CurrentCulture, "\"{0}\"", incompatibleReference.SDKName));
sdksAlreadyErrorOrWarnedFor.Add(incompatibleReference);
}
}
// Only log a warning or error if there were incompatible references
if (listOfIncompatibleReferences.Count > 0)
{
string incompatibleReferencesDelimited = String.Join(", ", listOfIncompatibleReferences.ToArray());
if (notCompatibleReference.SupportsMultipleVersions == MultipleVersionSupport.Error)
{
Log.LogErrorWithCodeFromResources("ResolveSDKReference.CannotReferenceTwoSDKsSameFamily", notCompatibleReference.SDKName, incompatibleReferencesDelimited, notCompatibleReference.ProductFamilyName);
}
else
{
Log.LogWarningWithCodeFromResources("ResolveSDKReference.CannotReferenceTwoSDKsSameFamily", notCompatibleReference.SDKName, incompatibleReferencesDelimited, notCompatibleReference.ProductFamilyName);
}
}
}
}
HashSet<SDKReference> referenceWithSameName = null;
if (sdkNameToSDK.TryGetValue(notCompatibleReference.SimpleName, out referenceWithSameName))
{
// We want to build a list of incompatible reference names so we can emit them in the error or warnings.
List<string> listOfIncompatibleReferences = new List<string>();
foreach (SDKReference incompatibleReference in referenceWithSameName)
{
if (!sdksAlreadyErrorOrWarnedFor.Contains(incompatibleReference) && incompatibleReference != notCompatibleReference /*cannot be incompatible with self*/)
{
listOfIncompatibleReferences.Add(String.Format(CultureInfo.CurrentCulture, "\"{0}\"", incompatibleReference.SDKName));
sdksAlreadyErrorOrWarnedFor.Add(incompatibleReference);
}
}
// Only log a warning or error if there were incompatible references
if (listOfIncompatibleReferences.Count > 0)
{
string incompatibleReferencesDelimited = String.Join(", ", listOfIncompatibleReferences.ToArray());
if (notCompatibleReference.SupportsMultipleVersions == MultipleVersionSupport.Error)
{
Log.LogErrorWithCodeFromResources("ResolveSDKReference.CannotReferenceTwoSDKsSameName", notCompatibleReference.SDKName, incompatibleReferencesDelimited);
}
else
{
Log.LogWarningWithCodeFromResources("ResolveSDKReference.CannotReferenceTwoSDKsSameName", notCompatibleReference.SDKName, incompatibleReferencesDelimited);
}
}
}
}
AddMetadataToReferences(Log, sdkReferenceItems, _runtimeReferenceOnlyDependenciesByName, "RuntimeReferenceOnly", "true");
// Gather the ResolvedItems from the SDKReference where the reference was resolved.
ResolvedSDKReferences = sdkReferenceItems.Where(x => x.Resolved).Select(x => x.ResolvedItem).ToArray<ITaskItem>();
VerifySDKDependsOn(Log, sdkReferenceItems);
return !Log.HasLoggedErrors;
}