/// <summary> /// Creates the traversal project instance. This has all of the properties against which we can perform evaluations for the remainder of the process. /// </summary> private ProjectInstance CreateTraversalInstance(string wrapperProjectToolsVersion, bool explicitToolsVersionSpecified, List<ProjectInSolution> projectsInOrder) { // Create the traversal project's root element. We will later instantiate this, and use it for evaluation of conditions on // the metaprojects. ProjectRootElement traversalProject = ProjectRootElement.Create(); traversalProject.ToolsVersion = wrapperProjectToolsVersion; traversalProject.DefaultTargets = "Build"; traversalProject.InitialTargets = "ValidateSolutionConfiguration;ValidateToolsVersions;ValidateProjects"; traversalProject.FullPath = _solutionFile.FullPath + ".metaproj"; // We don't use dependency levels any more - however this will find circular dependencies and throw for us. Dictionary<int, List<ProjectInSolution>> projectsByDependencyLevel = new Dictionary<int, List<ProjectInSolution>>(); // Add default solution configuration/platform names in case the user doesn't specify them on the command line AddConfigurationPlatformDefaults(traversalProject); // Add default Venus configuration names (for more details, see comments for this method) AddVenusConfigurationDefaults(traversalProject); // Add solution related macros AddGlobalProperties(traversalProject); // Add a property group for each solution configuration, each with one XML property containing the // project configurations in this solution configuration. foreach (SolutionConfigurationInSolution solutionConfiguration in _solutionFile.SolutionConfigurations) { AddPropertyGroupForSolutionConfiguration(traversalProject, solutionConfiguration); } // Add our global extensibility points to the project representing the solution: // Imported at the top: $(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\SolutionFile\ImportBefore\* // Imported at the bottom: $(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\SolutionFile\ImportAfter\* ProjectImportElement importBefore = traversalProject.CreateImportElement(@"$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\SolutionFile\ImportBefore\*"); importBefore.Condition = @"'$(ImportByWildcardBeforeSolution)' != 'false' and exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\SolutionFile\ImportBefore')"; // Avoids wildcard perf problem ProjectImportElement importAfter = traversalProject.CreateImportElement(@"$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\SolutionFile\ImportAfter\*"); importAfter.Condition = @"'$(ImportByWildcardBeforeSolution)' != 'false' and exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\SolutionFile\ImportAfter')"; // Avoids wildcard perf problem // Add our local extensibility points to the project representing the solution // Imported at the top: before.mysolution.sln.targets // Imported at the bottom: after.mysolution.sln.targets string escapedSolutionFile = EscapingUtilities.Escape(Path.GetFileName(_solutionFile.FullPath)); string escapedSolutionDirectory = EscapingUtilities.Escape(_solutionFile.SolutionFileDirectory); string localFile = Path.Combine(escapedSolutionDirectory, "before." + escapedSolutionFile + ".targets"); ProjectImportElement importBeforeLocal = traversalProject.CreateImportElement(localFile); importBeforeLocal.Condition = @"exists('" + localFile + "')"; localFile = Path.Combine(escapedSolutionDirectory, "after." + escapedSolutionFile + ".targets"); ProjectImportElement importAfterLocal = traversalProject.CreateImportElement(localFile); importAfterLocal.Condition = @"exists('" + localFile + "')"; // Put locals second so they can override globals if they want traversalProject.PrependChild(importBeforeLocal); traversalProject.PrependChild(importBefore); traversalProject.AppendChild(importAfter); traversalProject.AppendChild(importAfterLocal); // These are just dummies necessary to make the evaluation into a project instance succeed when // any custom imported targets have declarations like BeforeTargets="Build" // They'll be replaced momentarily with the real ones. traversalProject.AddTarget("Build"); traversalProject.AddTarget("Rebuild"); traversalProject.AddTarget("Clean"); traversalProject.AddTarget("Publish"); // For debugging purposes: some information is lost when evaluating into a project instance, // so make it possible to see what we have at this point. if (Environment.GetEnvironmentVariable("MSBUILDEMITSOLUTION") != null) { string path = traversalProject.FullPath; traversalProject.Save(_solutionFile.FullPath + ".metaproj.tmp"); traversalProject.FullPath = path; } // Create the instance. From this point forward we can evaluate conditions against the traversal project directly. ProjectInstance traversalInstance = new ProjectInstance ( traversalProject, _globalProperties, explicitToolsVersionSpecified ? wrapperProjectToolsVersion : null, _solutionFile.VisualStudioVersion, new ProjectCollection() ); // Make way for the real ones traversalInstance.RemoveTarget("Build"); traversalInstance.RemoveTarget("Rebuild"); traversalInstance.RemoveTarget("Clean"); traversalInstance.RemoveTarget("Publish"); AddStandardTraversalTargets(traversalInstance, projectsInOrder); return traversalInstance; }