Esempio n. 1
0
 /// <summary>
 /// Set the requested project configuration.
 /// </summary>
 internal void SetProjectConfiguration(string configurationName, ProjectConfigurationInSolution configuration)
 {
     _projectConfigurations[configurationName] = configuration;
 }
Esempio n. 2
0
        internal void ProcessProjectConfigurationSection(Hashtable rawProjectConfigurationsEntries)
        {
            char[] chArray1 = new char[1];
            int    index1   = 0;
            int    num1     = 124;

            chArray1[index1] = (char)num1;
            char[] chArray2 = chArray1;
            foreach (ProjectInSolution projectInSolution in this.projectsInOrder)
            {
                if (projectInSolution.ProjectType != SolutionProjectType.SolutionFolder)
                {
                    foreach (ConfigurationInSolution configurationInSolution1 in this.solutionConfigurations)
                    {
                        CultureInfo invariantCulture1 = CultureInfo.InvariantCulture;
                        string      format1           = "{0}.{1}.ActiveCfg";
                        object[]    objArray1         = new object[2];
                        int         index2            = 0;
                        string      projectGuid1      = projectInSolution.ProjectGuid;
                        objArray1[index2] = (object)projectGuid1;
                        int    index3    = 1;
                        string fullName1 = configurationInSolution1.FullName;
                        objArray1[index3] = (object)fullName1;
                        string      str1 = string.Format((IFormatProvider)invariantCulture1, format1, objArray1);
                        CultureInfo invariantCulture2 = CultureInfo.InvariantCulture;
                        string      format2           = "{0}.{1}.Build.0";
                        object[]    objArray2         = new object[2];
                        int         index4            = 0;
                        string      projectGuid2      = projectInSolution.ProjectGuid;
                        objArray2[index4] = (object)projectGuid2;
                        int    index5    = 1;
                        string fullName2 = configurationInSolution1.FullName;
                        objArray2[index5] = (object)fullName2;
                        string str2 = string.Format((IFormatProvider)invariantCulture2, format2, objArray2);
                        if (rawProjectConfigurationsEntries.ContainsKey((object)str1))
                        {
                            string[]           strArray = ((string)rawProjectConfigurationsEntries[(object)str1]).Split(chArray2);
                            int                num2     = strArray.Length <= 2 ? 1 : 0;
                            string             errorSubCategoryResourceName = "SubCategoryForSolutionParsingErrors";
                            BuildEventFileInfo projectFile       = new BuildEventFileInfo(this.SolutionFile);
                            string             resourceName      = "SolutionParseInvalidProjectSolutionConfigurationEntry";
                            object[]           objArray3         = new object[1];
                            int                index6            = 0;
                            CultureInfo        invariantCulture3 = CultureInfo.InvariantCulture;
                            string             format3           = "{0} = {1}";
                            object[]           objArray4         = new object[2];
                            int                index7            = 0;
                            string             str3 = str1;
                            objArray4[index7] = (object)str3;
                            int    index8 = 1;
                            object obj    = rawProjectConfigurationsEntries[(object)str1];
                            objArray4[index8] = obj;
                            string str4 = string.Format((IFormatProvider)invariantCulture3, format3, objArray4);
                            objArray3[index6] = (object)str4;
                            ProjectConfigurationInSolution configurationInSolution2 = new ProjectConfigurationInSolution(strArray[0], strArray.Length > 1 ? strArray[1] : string.Empty, rawProjectConfigurationsEntries.ContainsKey((object)str2));
                            projectInSolution.ProjectConfigurations[configurationInSolution1.FullName] = configurationInSolution2;
                        }
                    }
                }
            }
        }
 /// <summary>
 /// The value to be passed to the Properties attribute of the MSBuild task to build a specific project.  Contains reference to project configuration and
 /// platform as well as the solution configuration bits.
 /// </summary>
 private string GetPropertiesAttributeForDirectMSBuildTask(ProjectConfigurationInSolution projectConfiguration)
 {
     string directProjectProperties = OpportunisticIntern.InternStringIfPossible(String.Join(";", GetConfigurationAndPlatformPropertiesString(projectConfiguration), SolutionProperties));
     return directProjectProperties;
 }
        /// <summary>
        /// Returns true if the specified project can be built directly, without using a metaproject.
        /// </summary>
        private bool CanBuildDirectly(ProjectInstance traversalProject, ProjectInSolution projectToAdd, ProjectConfigurationInSolution projectConfiguration)
        {
            // Can we build this project directly, without a metaproject?  We can if it's MSBuild-able and has no references building in this configuration.
            bool canBuildDirectly = false;
            string unknownProjectTypeErrorMessage;
            if ((projectToAdd.ProjectType == SolutionProjectType.KnownToBeMSBuildFormat) ||
                (projectToAdd.CanBeMSBuildProjectFile(out unknownProjectTypeErrorMessage)))
            {
                canBuildDirectly = true;
                foreach (string dependencyProjectGuid in projectToAdd.Dependencies)
                {
                    ProjectInSolution dependencyProject;
                    if (!_solutionFile.ProjectsByGuid.TryGetValue(dependencyProjectGuid, out dependencyProject))
                    {
                        ProjectFileErrorUtilities.VerifyThrowInvalidProjectFile
                            (
                            false,
                            "SubCategoryForSolutionParsingErrors",
                            new BuildEventFileInfo(traversalProject.FullPath),
                            "SolutionParseProjectDepNotFoundError",
                            projectToAdd.ProjectGuid,
                            dependencyProjectGuid
                            );
                    }

                    if (WouldProjectBuild(_solutionFile, _selectedSolutionConfiguration, dependencyProject, projectConfiguration))
                    {
                        // This is a reference we would have to build, so we can't build the project directly.
                        canBuildDirectly = false;
                        break;
                    }
                }
            }

            return canBuildDirectly;
        }
        /// <summary>
        /// This method adds a new ProjectReference item to the specified instance.  The reference will either be to its metaproject (if the project
        /// is a web project or has reference of its own) or to the project itself (if it has no references and is a normal MSBuildable project.)
        /// </summary>
        private void AddProjectReference(ProjectInstance traversalProject, ProjectInstance projectInstance, ProjectInSolution projectToAdd, ProjectConfigurationInSolution projectConfiguration, bool direct)
        {
            ProjectItemInstance item;

            if (direct)
            {
                // We can build this project directly, so add its reference.
                item = projectInstance.AddItem("ProjectReference", EscapingUtilities.Escape(projectToAdd.AbsolutePath), null);
                item.SetMetadata("ToolsVersion", GetToolsVersionMetadataForDirectMSBuildTask(traversalProject));
                item.SetMetadata("SkipNonexistentProjects", "False"); // Skip if it doesn't exist on disk.
                item.SetMetadata("AdditionalProperties", GetPropertiesMetadataForProjectReference(traversalProject, GetConfigurationAndPlatformPropertiesString(projectConfiguration)));
            }
            else
            {
                // We cannot build directly, add the metaproject reference instead.
                item = projectInstance.AddItem("ProjectReference", GetMetaprojectName(projectToAdd), null);
                item.SetMetadata("ToolsVersion", traversalProject.ToolsVersion);
                item.SetMetadata("SkipNonexistentProjects", "Build"); // Instruct the MSBuild task to try to build even though the file doesn't exist on disk.
                item.SetMetadata("AdditionalProperties", GetPropertiesMetadataForProjectReference(traversalProject, SolutionConfigurationAndPlatformProperties));
            }

            // Set raw config and platform for custom build steps to use if they wish
            // Configuration is null for web projects
            if (projectConfiguration != null)
            {
                item.SetMetadata("Configuration", projectConfiguration.ConfigurationName);
                item.SetMetadata("Platform", projectConfiguration.PlatformName);
            }
        }
 /// <summary>
 /// Gets the project configuration and platform values as an attribute string for an MSBuild task used to build the project.
 /// </summary>
 private string GetConfigurationAndPlatformPropertiesString(ProjectConfigurationInSolution projectConfiguration)
 {
     string directProjectProperties = String.Format(CultureInfo.InvariantCulture, "Configuration={0}; Platform={1}", projectConfiguration.ConfigurationName, projectConfiguration.PlatformName);
     return directProjectProperties;
 }
        /// <summary>
        /// Adds a traversal target which invokes a specified target on a single project.  This creates targets called "Project", "Project:Rebuild", "Project:Clean", "Project:Publish" etc.
        /// </summary>
        private void AddTraversalTargetForProject(ProjectInstance traversalProject, ProjectInSolution project, ProjectConfigurationInSolution projectConfiguration, string targetToBuild, string outputItem, bool canBuildDirectly)
        {
            string baseProjectName = ProjectInSolution.DisambiguateProjectTargetName(project.GetUniqueProjectName());
            string actualTargetName = baseProjectName;
            if (targetToBuild != null)
            {
                actualTargetName += ":" + targetToBuild;
            }

            // The output item name is the concatenation of the project name with the specified outputItem.  In the typical case, if the
            // project name is MyProject, the outputItemName will be MyProjectBuildOutput, and the outputItemAsItem will be @(MyProjectBuildOutput).
            // In the case where the project contains characters not allowed as Xml element attribute values, those characters will
            // be replaced with underscores.  In the case where MyProject is actually unrepresentable in Xml, then the
            // outputItemName would be _________BuildOutput.
            string outputItemName = null;
            string outputItemAsItem = null;
            if (!String.IsNullOrEmpty(outputItem))
            {
                outputItemName = MakeIntoSafeItemName(baseProjectName) + outputItem;
                outputItemAsItem = "@(" + outputItemName + ")";
            }

            ProjectTargetInstance targetElement = traversalProject.AddTarget(actualTargetName, null, null, outputItemAsItem, null, null, null, false /* legacy target returns behaviour */);
            if (canBuildDirectly)
            {
                AddProjectBuildTask(traversalProject, project, projectConfiguration, targetElement, targetToBuild, "@(ProjectReference)", "'%(ProjectReference.Identity)' == '" + EscapingUtilities.Escape(project.AbsolutePath) + "'", outputItemName);
            }
            else
            {
                AddMetaprojectBuildTask(traversalProject, project, targetElement, targetToBuild, outputItemName);
            }
        }
        /// <summary>
        /// Returns true if the specified project will build in the currently selected solution configuration.
        /// </summary>
        private static bool WouldProjectBuild(SolutionFile solutionFile, string selectedSolutionConfiguration, ProjectInSolution project, ProjectConfigurationInSolution projectConfiguration)
        {
            if (projectConfiguration == null)
            {
                if (project.ProjectType == SolutionProjectType.WebProject)
                {
                    // Sometimes web projects won't have the configuration we need (Release typically.)  But they should still build if there is
                    // a solution configuration for it
                    foreach (SolutionConfigurationInSolution configuration in solutionFile.SolutionConfigurations)
                    {
                        if (String.Equals(configuration.FullName, selectedSolutionConfiguration, StringComparison.OrdinalIgnoreCase))
                        {
                            return true;
                        }
                    }
                }

                // No configuration, so it can't build.
                return false;
            }

            if (!projectConfiguration.IncludeInBuild)
            {
                // Not included in the build.
                return false;
            }

            return true;
        }
        /// <summary>
        /// Adds an MSBuild task to a real project.
        /// </summary>
        private void AddProjectBuildTask(ProjectInstance traversalProject, ProjectInSolution project, ProjectConfigurationInSolution projectConfiguration, ProjectTargetInstance target, string targetToBuild, string sourceItems, string condition, string outputItem)
        {
            ProjectTaskInstance task = target.AddTask("MSBuild", condition, String.Empty);
            task.SetParameter("Projects", sourceItems);
            if (targetToBuild != null)
            {
                task.SetParameter("Targets", targetToBuild);
            }

            task.SetParameter("BuildInParallel", "True");

            task.SetParameter("ToolsVersion", GetToolsVersionAttributeForDirectMSBuildTask(traversalProject));
            task.SetParameter("Properties", GetPropertiesAttributeForDirectMSBuildTask(projectConfiguration));

            if (outputItem != null)
            {
                task.AddOutputItem("TargetOutputs", outputItem, String.Empty);
            }
        }
        /// <summary>
        /// Adds the targets which build the dependencies and actual project for a metaproject.
        /// </summary>
        private void AddMetaprojectTargetForManagedProject(ProjectInstance traversalProject, ProjectInstance metaprojectInstance, ProjectInSolution project, ProjectConfigurationInSolution projectConfiguration, string targetName, string outputItem)
        {
            string outputItemAsItem = null;
            if (!String.IsNullOrEmpty(outputItem))
            {
                outputItemAsItem = "@(" + outputItem + ")";
            }

            ProjectTargetInstance target = metaprojectInstance.AddTarget(targetName ?? "Build", String.Empty, String.Empty, outputItemAsItem, null, String.Empty, String.Empty, false /* legacy target returns behaviour */);

            AddReferencesBuildTask(metaprojectInstance, target, targetName, outputItem);

            // Add the task to build the actual project.
            AddProjectBuildTask(traversalProject, project, projectConfiguration, target, targetName, EscapingUtilities.Escape(project.AbsolutePath), String.Empty, outputItem);
        }
        /// <summary>
        /// Produces a set of targets which allows the MSBuild scheduler to schedule projects in the order automatically by 
        /// following their dependencies without enforcing build levels.
        /// </summary>
        /// <remarks>
        /// We want MSBuild to be able to parallelize the builds of these projects where possible and still honor references.
        /// Since the project files referenced by the solution do not (necessarily) themselves contain actual project references
        /// to the projects they depend on, we need to synthesize this relationship ourselves.  This is done by creating a target
        /// which first invokes the project's dependencies, then invokes the actual project itself.  However, invoking the 
        /// dependencies must also invoke their dependencies and so on down the line.  
        /// 
        /// Additionally, we do not wish to create a separate MSBuild project to contain this target yet we want to parallelize
        /// calls to these targets.  The way to do this is to pass in different global properties to the same project in the same
        /// MSBuild call.  MSBuild easily allows this using the AdditionalProperties metadata which can be specified on an Item.
        /// 
        /// Assuming the solution project we are generating is called "foo.proj", we can accomplish this parallelism as follows:
        /// <ItemGroup>
        ///     <ProjectReference Include="Project0"/>
        ///     <ProjectReference Include="Project1"/>
        ///     <ProjectReference Include="Project2"/>
        /// </ItemGroup>
        /// 
        /// We now have expressed the top level reference to all projects as @(SolutionReference) and each project's
        /// set of references as @(PROJECTNAMEReference).  We construct our target as:
        /// 
        /// <Target Name="Build">
        ///     <MSBuild Projects="@(ProjectReference)" Targets="Build" />
        ///     <MSBuild Projects="actualProjectName" Targets="Build" />
        /// </Target>
        /// 
        /// The first MSBuild call re-invokes the solution project instructing it to build the reference projects for the
        /// current project.  The second MSBuild call invokes the actual project itself.  Because all reference projects have
        /// the same additional properties, MSBuild will only build the first one it comes across and the rest will be
        /// satisfied from the cache.
        /// </remarks>
        private ProjectInstance CreateMetaproject(ProjectInstance traversalProject, ProjectInSolution project, ProjectConfigurationInSolution projectConfiguration)
        {
            // Create a new project instance with global properties and tools version from the existing project
            ProjectInstance metaprojectInstance = new ProjectInstance(EscapingUtilities.UnescapeAll(GetMetaprojectName(project)), traversalProject, GetMetaprojectGlobalProperties(traversalProject));

            // Add the project references which must build before this one.
            AddMetaprojectReferenceItems(traversalProject, metaprojectInstance, project);

            // This string holds the error message generated when we try to determine if a project is an MSBuild format
            // project but it is not.
            string unknownProjectTypeErrorMessage;

            if (project.ProjectType == SolutionProjectType.WebProject)
            {
                AddMetaprojectTargetForWebProject(traversalProject, metaprojectInstance, project, null);
                AddMetaprojectTargetForWebProject(traversalProject, metaprojectInstance, project, "Clean");
                AddMetaprojectTargetForWebProject(traversalProject, metaprojectInstance, project, "Rebuild");
                AddMetaprojectTargetForWebProject(traversalProject, metaprojectInstance, project, "Publish");
            }
            else if ((project.ProjectType == SolutionProjectType.KnownToBeMSBuildFormat) ||
                     (project.CanBeMSBuildProjectFile(out unknownProjectTypeErrorMessage)))
            {
                string safeItemNameFromProjectName = MakeIntoSafeItemName(project.ProjectName);
                string targetOutputItemName = string.Format(CultureInfo.InvariantCulture, "{0}BuildOutput", safeItemNameFromProjectName);

                AddMetaprojectTargetForManagedProject(traversalProject, metaprojectInstance, project, projectConfiguration, "Clean", null);
                AddMetaprojectTargetForManagedProject(traversalProject, metaprojectInstance, project, projectConfiguration, null, targetOutputItemName);
                AddMetaprojectTargetForManagedProject(traversalProject, metaprojectInstance, project, projectConfiguration, "Rebuild", targetOutputItemName);
                AddMetaprojectTargetForManagedProject(traversalProject, metaprojectInstance, project, projectConfiguration, "Publish", null);
            }
            else
            {
                AddMetaprojectTargetForUnknownProjectType(traversalProject, metaprojectInstance, project, null, unknownProjectTypeErrorMessage);
                AddMetaprojectTargetForUnknownProjectType(traversalProject, metaprojectInstance, project, "Clean", unknownProjectTypeErrorMessage);
                AddMetaprojectTargetForUnknownProjectType(traversalProject, metaprojectInstance, project, "Rebuild", unknownProjectTypeErrorMessage);
                AddMetaprojectTargetForUnknownProjectType(traversalProject, metaprojectInstance, project, "Publish", unknownProjectTypeErrorMessage);
            }

            return metaprojectInstance;
        }
Esempio n. 12
0
 /// <summary>
 /// Set the requested project configuration. 
 /// </summary>
 internal void SetProjectConfiguration(string configurationName, ProjectConfigurationInSolution configuration)
 {
     _projectConfigurations[configurationName] = configuration;
 }
Esempio n. 13
0
        /// <summary>
        /// Read the project configuration information for every project in the solution, using pre-cached 
        /// solution section data. 
        /// </summary>
        /// <param name="rawProjectConfigurationsEntries">Cached data from the project configuration section</param>
        internal void ProcessProjectConfigurationSection(Hashtable rawProjectConfigurationsEntries)
        {
            // Instead of parsing the data line by line, we parse it project by project, constructing the 
            // entry name (e.g. "{A6F99D27-47B9-4EA4-BFC9-25157CBDC281}.Release|Any CPU.ActiveCfg") and retrieving its 
            // value from the raw data. The reason for this is that the IDE does it this way, and as the result
            // the '.' character is allowed in configuration names although it technically separates different
            // parts of the entry name string. This could lead to ambiguous results if we tried to parse 
            // the entry name instead of constructing it and looking it up. Although it's pretty unlikely that
            // this would ever be a problem, it's safer to do it the same way VS IDE does it.
            char[] configPlatformSeparators = new char[] { SolutionConfigurationInSolution.ConfigurationPlatformSeparator };

            foreach (ProjectInSolution project in _projectsInOrder)
            {
                // Solution folders don't have configurations
                if (project.ProjectType != SolutionProjectType.SolutionFolder)
                {
                    foreach (SolutionConfigurationInSolution solutionConfiguration in _solutionConfigurations)
                    {
                        // The "ActiveCfg" entry defines the active project configuration in the given solution configuration
                        // This entry must be present for every possible solution configuration/project combination.
                        string entryNameActiveConfig = string.Format(CultureInfo.InvariantCulture, "{0}.{1}.ActiveCfg",
                            project.ProjectGuid, solutionConfiguration.FullName);

                        // The "Build.0" entry tells us whether to build the project configuration in the given solution configuration.
                        // Technically, it specifies a configuration name of its own which seems to be a remnant of an initial, 
                        // more flexible design of solution configurations (as well as the '.0' suffix - no higher values are ever used). 
                        // The configuration name is not used, and the whole entry means "build the project configuration" 
                        // if it's present in the solution file, and "don't build" if it's not.
                        string entryNameBuild = string.Format(CultureInfo.InvariantCulture, "{0}.{1}.Build.0",
                            project.ProjectGuid, solutionConfiguration.FullName);

                        if (rawProjectConfigurationsEntries.ContainsKey(entryNameActiveConfig))
                        {
                            string[] configurationPlatformParts = ((string)(rawProjectConfigurationsEntries[entryNameActiveConfig])).Split(configPlatformSeparators);

                            // Project configuration may not necessarily contain the platform part. Some project support only the configuration part.
                            ProjectFileErrorUtilities.VerifyThrowInvalidProjectFile(configurationPlatformParts.Length <= 2, "SubCategoryForSolutionParsingErrors",
                                new BuildEventFileInfo(FullPath), "SolutionParseInvalidProjectSolutionConfigurationEntry",
                                string.Format(CultureInfo.InvariantCulture, "{0} = {1}", entryNameActiveConfig, rawProjectConfigurationsEntries[entryNameActiveConfig]));

                            ProjectConfigurationInSolution projectConfiguration = new ProjectConfigurationInSolution(
                                configurationPlatformParts[0],
                                (configurationPlatformParts.Length > 1) ? configurationPlatformParts[1] : string.Empty,
                                rawProjectConfigurationsEntries.ContainsKey(entryNameBuild)
                            );

                            project.SetProjectConfiguration(solutionConfiguration.FullName, projectConfiguration);
                        }
                    }
                }
            }
        }