in src/Build/Evaluation/Evaluator.cs [724:941]
private IDictionary<string, object> Evaluate()
{
#if FEATURE_MSBUILD_DEBUGGER
InitializeForDebugging();
#endif
// Pass0: load initial properties
// Follow the order of precedence so that Global properties overwrite Environment properties
ICollection<P> builtInProperties = AddBuiltInProperties();
ICollection<P> environmentProperties = AddEnvironmentProperties();
ICollection<P> toolsetProperties = AddToolsetProperties();
ICollection<P> subToolsetProperties = AddSubToolsetProperties();
ICollection<P> globalProperties = AddGlobalProperties();
#if FEATURE_MSBUILD_DEBUGGER
// Create a state for the root project node to show initial properties
if (DebuggerManager.DebuggingEnabled)
{
_initialLocals = new Dictionary<string, object>();
_initialLocals.Add(new KeyValuePair<string, object>(s_initialLocalsTypes[(int)LocalsTypes.Project].Name, _projectInstanceIfAnyForDebuggerOnly));
_initialLocals.Add(new KeyValuePair<string, object>(s_initialLocalsTypes[(int)LocalsTypes.BuiltIn].Name, builtInProperties));
_initialLocals.Add(new KeyValuePair<string, object>(s_initialLocalsTypes[(int)LocalsTypes.Environment].Name, environmentProperties));
_initialLocals.Add(new KeyValuePair<string, object>(s_initialLocalsTypes[(int)LocalsTypes.Toolset].Name, toolsetProperties));
_initialLocals.Add(new KeyValuePair<string, object>(s_initialLocalsTypes[(int)LocalsTypes.SubToolset].Name, subToolsetProperties));
_initialLocals.Add(new KeyValuePair<string, object>(s_initialLocalsTypes[(int)LocalsTypes.Global].Name, globalProperties));
DebuggerManager.DefineState(_projectRootElement.Location, _projectRootElement.ElementName, s_initialLocalsTypes);
DebuggerManager.BakeStates(Path.GetFileNameWithoutExtension(_projectRootElement.FullPath));
DebuggerManager.PulseState(_projectRootElement.Location, _initialLocals);
_propertyPassLocals = new Dictionary<string, object>(_initialLocals);
_propertyPassLocals.Add(new KeyValuePair<string, object>(s_propertyPassLocalsTypes[(int)LocalsTypes.EvaluateExpression].Name, (ExpandExpression)_data.ExpandString));
_propertyPassLocals.Add(new KeyValuePair<string, object>(s_propertyPassLocalsTypes[(int)LocalsTypes.EvaluateCondition].Name, (EvaluateConditionalExpression)_data.EvaluateCondition));
_propertyPassLocals.Add(new KeyValuePair<string, object>(s_propertyPassLocalsTypes[(int)LocalsTypes.ToolsVersion].Name, _data.Toolset.ToolsVersion));
_propertyPassLocals.Add(new KeyValuePair<string, object>(s_propertyPassLocalsTypes[(int)LocalsTypes.Properties].Name, _data.Properties));
_itemDefinitionPassLocals = new Dictionary<string, object>(_propertyPassLocals);
_itemDefinitionPassLocals.Add(new KeyValuePair<string, object>(s_itemDefinitionPassLocalsTypes[(int)LocalsTypes.ItemDefinitions].Name, _data.ItemDefinitionsEnumerable));
_itemPassLocals = new Dictionary<string, object>(_itemDefinitionPassLocals);
_itemPassLocals.Add(new KeyValuePair<string, object>(s_itemPassLocalsTypes[(int)LocalsTypes.Items].Name, _data.Items));
// This is currently only needed when debugging
_importRelationships = new Dictionary<ProjectRootElement, ProjectRootElement>();
// This is passed back to the build, so locals are visible during the build
_projectLevelLocalsForBuild = _itemPassLocals;
}
#endif
#if (!STANDALONEBUILD)
CodeMarkers.Instance.CodeMarker(CodeMarkerEvent.perfMSBuildProjectEvaluatePass0End);
#endif
string projectFile = String.IsNullOrEmpty(_projectRootElement.ProjectFileLocation.File) ? "(null)" : _projectRootElement.ProjectFileLocation.File;
_loggingService.LogComment(_buildEventContext, MessageImportance.Low, "EvaluationStarted", projectFile);
#if MSBUILDENABLEVSPROFILING
string endPass0 = String.Format(CultureInfo.CurrentCulture, "Evaluate Project {0} - End Pass 0 (Initial properties)", projectFile);
DataCollection.CommentMarkProfile(8816, endPass0);
#endif
// Pass1: evaluate properties, load imports, and gather everything else
PerformDepthFirstPass(_projectRootElement);
List<string> initialTargets = new List<string>(_initialTargetsList.Count);
for (int i = 0; i < _initialTargetsList.Count; i++)
{
initialTargets.Add(EscapingUtilities.UnescapeAll(_initialTargetsList[i].Trim()));
}
_data.InitialTargets = initialTargets;
#if (!STANDALONEBUILD)
CodeMarkers.Instance.CodeMarker(CodeMarkerEvent.perfMSBuildProjectEvaluatePass1End);
#endif
#if MSBUILDENABLEVSPROFILING
string endPass1 = String.Format(CultureInfo.CurrentCulture, "Evaluate Project {0} - End Pass 1 (Properties and Imports)", projectFile);
DataCollection.CommentMarkProfile(8817, endPass1);
#endif
// Pass2: evaluate item definitions
foreach (ProjectItemDefinitionGroupElement itemDefinitionGroupElement in _itemDefinitionGroupElements)
{
EvaluateItemDefinitionGroupElement(itemDefinitionGroupElement);
}
#if (!STANDALONEBUILD)
CodeMarkers.Instance.CodeMarker(CodeMarkerEvent.perfMSBuildProjectEvaluatePass2End);
#endif
#if MSBUILDENABLEVSPROFILING
string endPass2 = String.Format(CultureInfo.CurrentCulture, "Evaluate Project {0} - End Pass 2 (Item Definitions)", projectFile);
DataCollection.CommentMarkProfile(8818, endPass2);
#endif
LazyItemEvaluator<P, I, M, D> lazyEvaluator = null;
// comment next line to turn off lazy Evaluation
lazyEvaluator = new LazyItemEvaluator<P, I, M, D>(_data, _itemFactory, _buildEventContext, _loggingService);
// Pass3: evaluate project items
foreach (ProjectItemGroupElement itemGroupElement in _itemGroupElements)
{
EvaluateItemGroupElement(itemGroupElement, lazyEvaluator);
}
if (lazyEvaluator != null)
{
// Tell the lazy evaluator to compute the items and add them to _data
IList<LazyItemEvaluator<P, I, M, D>.ItemData> items = lazyEvaluator.GetAllItems();
foreach (var itemData in items)
{
if (itemData.ConditionResult)
{
_data.AddItem(itemData.Item);
if (_data.ShouldEvaluateForDesignTime)
{
_data.AddToAllEvaluatedItemsList(itemData.Item);
}
}
if (_data.ShouldEvaluateForDesignTime)
{
_data.AddItemIgnoringCondition(itemData.Item);
}
}
// lazy evaluator can be collected now, the rest of evaluation does not need it anymore
lazyEvaluator = null;
}
#if (!STANDALONEBUILD)
CodeMarkers.Instance.CodeMarker(CodeMarkerEvent.perfMSBuildProjectEvaluatePass3End);
#endif
#if MSBUILDENABLEVSPROFILING
string endPass3 = String.Format(CultureInfo.CurrentCulture, "Evaluate Project {0} - End Pass 3 (Items)", projectFile);
DataCollection.CommentMarkProfile(8819, endPass3);
#endif
// Pass4: evaluate using-tasks
foreach (Pair<string, ProjectUsingTaskElement> entry in _usingTaskElements)
{
EvaluateUsingTaskElement(entry.Key, entry.Value);
}
// If there was no DefaultTargets attribute found in the depth first pass,
// use the name of the first target. If there isn't any target, don't error until build time.
if (_data.DefaultTargets == null || _data.DefaultTargets.Count == 0)
{
List<string> defaultTargets = new List<string>(_targetElements.Count);
if (_targetElements.Count > 0)
{
defaultTargets.Add(_targetElements[0].Name);
}
_data.DefaultTargets = defaultTargets;
}
Dictionary<string, List<TargetSpecification>> targetsWhichRunBeforeByTarget = new Dictionary<string, List<TargetSpecification>>(StringComparer.OrdinalIgnoreCase);
Dictionary<string, List<TargetSpecification>> targetsWhichRunAfterByTarget = new Dictionary<string, List<TargetSpecification>>(StringComparer.OrdinalIgnoreCase);
LinkedList<ProjectTargetElement> activeTargetsByEvaluationOrder = new LinkedList<ProjectTargetElement>();
Dictionary<string, LinkedListNode<ProjectTargetElement>> activeTargets = new Dictionary<string, LinkedListNode<ProjectTargetElement>>(StringComparer.OrdinalIgnoreCase);
#if (!STANDALONEBUILD)
CodeMarkers.Instance.CodeMarker(CodeMarkerEvent.perfMSBuildProjectEvaluatePass4End);
#endif
#if MSBUILDENABLEVSPROFILING
string endPass4 = String.Format(CultureInfo.CurrentCulture, "Evaluate Project {0} - End Pass 4 (UsingTasks)", projectFile);
DataCollection.CommentMarkProfile(8820, endPass4);
#endif
// Pass5: read targets (but don't evaluate them: that happens during build)
foreach (ProjectTargetElement targetElement in _targetElements)
{
ReadTargetElement(targetElement, activeTargetsByEvaluationOrder, activeTargets);
}
foreach (ProjectTargetElement target in activeTargetsByEvaluationOrder)
{
AddBeforeAndAfterTargetMappings(target, activeTargets, targetsWhichRunBeforeByTarget, targetsWhichRunAfterByTarget);
}
_data.BeforeTargets = targetsWhichRunBeforeByTarget;
_data.AfterTargets = targetsWhichRunAfterByTarget;
if (s_debugEvaluation)
{
// This is so important for VS performance it's worth always tracing; accidentally having
// inconsistent sets of global properties will cause reevaluations, which are wasteful and incorrect
if (_projectRootElement.Count > 0) // VB/C# will new up empty projects; they aren't worth recording
{
ProjectPropertyInstance configurationData = _data.GlobalPropertiesDictionary["currentsolutionconfigurationcontents"];
int hash = (configurationData != null) ? configurationData.EvaluatedValue.GetHashCode() : 0;
string propertyDump = null;
foreach (var entry in _data.GlobalPropertiesDictionary)
{
if (!String.Equals(entry.Name, "currentsolutionconfigurationcontents", StringComparison.OrdinalIgnoreCase))
{
propertyDump += entry.Name + "=" + entry.EvaluatedValue + "\n";
}
}
string line = new string('#', 100) + "\n";
string output = String.Format(CultureInfo.CurrentUICulture, "###: MSBUILD: Evaluating or reevaluating project {0} with {1} global properties and {2} tools version, child count {3}, CurrentSolutionConfigurationContents hash {4} other properties:\n{5}", _projectRootElement.FullPath, globalProperties.Count, _data.Toolset.ToolsVersion, _projectRootElement.Count, hash, propertyDump);
Trace.WriteLine(line + output + line);
}
}
_data.FinishEvaluation();
_loggingService.LogComment(_buildEventContext, MessageImportance.Low, "EvaluationFinished", projectFile);
#if FEATURE_MSBUILD_DEBUGGER
return _projectLevelLocalsForBuild;
#else
return null;
#endif
}