/// <summary> /// Adds a ProjectToBuild item for the project and it's project references. /// Returns the added item, or null if an error occured. /// </summary> ProjectToBuild ParseMSBuildProject(IProject project) { ProjectToBuild ptb; if (parseMSBuildProjectProjectsToBuildDict.TryGetValue(project, out ptb)) { // only add each project once, reuse existing ProjectToBuild return(ptb); } ptb = new ProjectToBuild(project.FileName, options.Target.TargetName); ptb.configuration = parentEngine.Configuration; ptb.platform = parentEngine.Platform; projectsToBuild.Add(ptb); parseMSBuildProjectProjectsToBuildDict[project] = ptb; foreach (ProjectItem item in project.GetItemsOfType(ItemType.ProjectReference)) { ProjectReferenceProjectItem prpi = item as ProjectReferenceProjectItem; if (prpi != null && prpi.ReferencedProject != null) { ProjectToBuild referencedProject = ParseMSBuildProject(prpi.ReferencedProject); if (referencedProject == null) { return(null); } ptb.dependencies.Add(referencedProject); } } return(ptb); }
/// <summary> /// Find available work and run it on the specified worker. /// </summary> bool RunWorkerInternal(MSBuildEngineWorker worker) { ProjectToBuild nextFreeProject = null; lock (projectsToBuild) { foreach (ProjectToBuild ptb in projectsToBuild) { if (ptb.buildStarted == false && ptb.DependenciesSatisfied()) { if (nextFreeProject == null) { nextFreeProject = ptb; // all workers busy, don't look if there is more work available if (workerCount == maxWorkerCount) { break; } } else { // free workers available + additional work available: // start a new worker LoggingService.Debug("Starting a new worker"); workerCount++; Thread thread = new Thread(RunWorkerBuild); thread.Name = "MSBuildEngine worker " + (++lastUniqueWorkerID); thread.SetApartmentState(ApartmentState.STA); thread.Start(); // start at most one additional worker, the new worker can // start more threads if desired break; } } } if (nextFreeProject == null) { // nothing to do for this worker thread return(false); } // now build nextFreeProject nextFreeProject.buildStarted = true; } // end lock StatusBarService.SetMessage("${res:MainWindow.CompilerMessages.BuildVerb} " + Path.GetFileNameWithoutExtension(nextFreeProject.file) + "..."); // run the build: if (worker.Build(nextFreeProject)) { // build successful: mark it as finished lock (projectsToBuild) { nextFreeProject.buildFinished = true; } } return(true); }
/// <summary> /// Recursively increment requiredByCount on ptb and all its dependencies /// </summary> static void IncrementRequiredByCount(ProjectToBuild ptb) { if (ptb.visitFlag == 1) { return; } if (ptb.visitFlag == -1) { throw new DependencyCycleException(); } ptb.visitFlag = -1; ptb.requiredByCount++; ptb.dependencies.ForEach(IncrementRequiredByCount); ptb.visitFlag = 1; }
bool ParseSolution(Project solution) { // get the build target to call Target mainBuildTarget = solution.Targets[options.Target.TargetName]; if (mainBuildTarget == null) { currentResults.Result = BuildResultCode.BuildFileError; currentResults.Add(new BuildError(this.solution.FileName, "Target '" + options.Target + "' not supported by solution.")); return(false); } // example of mainBuildTarget: // <Target Name="Build" Condition="'$(CurrentSolutionConfigurationContents)' != ''"> // <CallTarget Targets="Main\ICSharpCode_SharpDevelop;Main\ICSharpCode_Core;Main\StartUp;Tools" RunEachTargetSeparately="true" /> // </Target> List <BuildTask> mainBuildTargetTasks = Linq.ToList(Linq.CastTo <BuildTask>(mainBuildTarget)); if (mainBuildTargetTasks.Count != 1 || mainBuildTargetTasks[0].Name != "CallTarget") { return(InvalidTarget(mainBuildTarget)); } List <Target> solutionTargets = new List <Target>(); foreach (string solutionTargetName in mainBuildTargetTasks[0].GetParameterValue("Targets").Split(';')) { Target target = solution.Targets[solutionTargetName]; if (target != null) { solutionTargets.Add(target); } } // dictionary for fast lookup of ProjectToBuild elements Dictionary <string, ProjectToBuild> projectsToBuildDict = new Dictionary <string, ProjectToBuild>(); // now look through targets that took like this: // <Target Name="Main\ICSharpCode_Core" Condition="'$(CurrentSolutionConfigurationContents)' != ''"> // <MSBuild Projects="Main\Core\Project\ICSharpCode.Core.csproj" Properties="Configuration=Debug; Platform=AnyCPU; BuildingSolutionFile=true; CurrentSolutionConfigurationContents=$(CurrentSolutionConfigurationContents); SolutionDir=$(SolutionDir); SolutionExt=$(SolutionExt); SolutionFileName=$(SolutionFileName); SolutionName=$(SolutionName); SolutionPath=$(SolutionPath)" Condition=" ('$(Configuration)' == 'Debug') and ('$(Platform)' == 'Any CPU') " /> // <MSBuild Projects="Main\Core\Project\ICSharpCode.Core.csproj" Properties="Configuration=Release; Platform=AnyCPU; BuildingSolutionFile=true; CurrentSolutionConfigurationContents=$(CurrentSolutionConfigurationContents); SolutionDir=$(SolutionDir); SolutionExt=$(SolutionExt); SolutionFileName=$(SolutionFileName); SolutionName=$(SolutionName); SolutionPath=$(SolutionPath)" Condition=" ('$(Configuration)' == 'Release') and ('$(Platform)' == 'Any CPU') " /> // </Target> // and add those targets to the "projectsToBuild" list. foreach (Target target in solutionTargets) { List <BuildTask> tasks = Linq.ToList(Linq.CastTo <BuildTask>(target)); if (tasks.Count == 0) { return(InvalidTarget(target)); } // find task to run when this target is executed BuildTask bestTask = null; foreach (BuildTask task in tasks) { if (task.Name != "MSBuild") { return(InvalidTarget(target)); } if (MSBuildInternals.EvaluateCondition(solution, task.Condition)) { bestTask = task; } } if (bestTask == null) { LoggingService.Warn("No matching condition for solution target " + target.Name); bestTask = tasks[0]; } // create projectToBuild entry and add it to list and dictionary string projectFileName = Path.Combine(this.solution.Directory, bestTask.GetParameterValue("Projects")); ProjectToBuild projectToBuild = new ProjectToBuild(Path.GetFullPath(projectFileName), bestTask.GetParameterValue("Targets")); // get project configuration and platform from properties section string propertiesString = bestTask.GetParameterValue("Properties"); Match match = Regex.Match(propertiesString, @"\bConfiguration=([^;]+);"); if (match.Success) { projectToBuild.configuration = match.Groups[1].Value; } else { projectToBuild.configuration = parentEngine.Configuration; } match = Regex.Match(propertiesString, @"\bPlatform=([^;]+);"); if (match.Success) { projectToBuild.platform = match.Groups[1].Value; } else { projectToBuild.platform = parentEngine.Platform; if (projectToBuild.platform == "Any CPU") { projectToBuild.platform = "AnyCPU"; } } projectsToBuild.Add(projectToBuild); projectsToBuildDict[target.Name] = projectToBuild; } // now create dependencies between projectsToBuild foreach (Target target in solutionTargets) { ProjectToBuild p1; if (!projectsToBuildDict.TryGetValue(target.Name, out p1)) { continue; } foreach (string dependency in target.DependsOnTargets.Split(';')) { ProjectToBuild p2; if (!projectsToBuildDict.TryGetValue(dependency, out p2)) { continue; } p1.dependencies.Add(p2); } } return(true); }
/// <summary> /// Adds a ProjectToBuild item for the project and it's project references. /// Returns the added item, or null if an error occured. /// </summary> ProjectToBuild ParseMSBuildProject(IProject project) { ProjectToBuild ptb; if (parseMSBuildProjectProjectsToBuildDict.TryGetValue(project, out ptb)) { // only add each project once, reuse existing ProjectToBuild return ptb; } ptb = new ProjectToBuild(project.FileName, options.Target.TargetName); ptb.configuration = parentEngine.Configuration; ptb.platform = parentEngine.Platform; projectsToBuild.Add(ptb); parseMSBuildProjectProjectsToBuildDict[project] = ptb; foreach (ProjectItem item in project.GetItemsOfType(ItemType.ProjectReference)) { ProjectReferenceProjectItem prpi = item as ProjectReferenceProjectItem; if (prpi != null && prpi.ReferencedProject != null) { ProjectToBuild referencedProject = ParseMSBuildProject(prpi.ReferencedProject); if (referencedProject == null) return null; ptb.dependencies.Add(referencedProject); } } return ptb; }
bool ParseSolution(Project solution) { // get the build target to call Target mainBuildTarget = solution.Targets[options.Target.TargetName]; if (mainBuildTarget == null) { currentResults.Result = BuildResultCode.BuildFileError; currentResults.Add(new BuildError(this.solution.FileName, "Target '" + options.Target + "' not supported by solution.")); return false; } // example of mainBuildTarget: // <Target Name="Build" Condition="'$(CurrentSolutionConfigurationContents)' != ''"> // <CallTarget Targets="Main\ICSharpCode_SharpDevelop;Main\ICSharpCode_Core;Main\StartUp;Tools" RunEachTargetSeparately="true" /> // </Target> List<BuildTask> mainBuildTargetTasks = Linq.ToList(Linq.CastTo<BuildTask>(mainBuildTarget)); if (mainBuildTargetTasks.Count != 1 || mainBuildTargetTasks[0].Name != "CallTarget") { return InvalidTarget(mainBuildTarget); } List<Target> solutionTargets = new List<Target>(); foreach (string solutionTargetName in mainBuildTargetTasks[0].GetParameterValue("Targets").Split(';')) { Target target = solution.Targets[solutionTargetName]; if (target != null) { solutionTargets.Add(target); } } // dictionary for fast lookup of ProjectToBuild elements Dictionary<string, ProjectToBuild> projectsToBuildDict = new Dictionary<string, ProjectToBuild>(); // now look through targets that took like this: // <Target Name="Main\ICSharpCode_Core" Condition="'$(CurrentSolutionConfigurationContents)' != ''"> // <MSBuild Projects="Main\Core\Project\ICSharpCode.Core.csproj" Properties="Configuration=Debug; Platform=AnyCPU; BuildingSolutionFile=true; CurrentSolutionConfigurationContents=$(CurrentSolutionConfigurationContents); SolutionDir=$(SolutionDir); SolutionExt=$(SolutionExt); SolutionFileName=$(SolutionFileName); SolutionName=$(SolutionName); SolutionPath=$(SolutionPath)" Condition=" ('$(Configuration)' == 'Debug') and ('$(Platform)' == 'Any CPU') " /> // <MSBuild Projects="Main\Core\Project\ICSharpCode.Core.csproj" Properties="Configuration=Release; Platform=AnyCPU; BuildingSolutionFile=true; CurrentSolutionConfigurationContents=$(CurrentSolutionConfigurationContents); SolutionDir=$(SolutionDir); SolutionExt=$(SolutionExt); SolutionFileName=$(SolutionFileName); SolutionName=$(SolutionName); SolutionPath=$(SolutionPath)" Condition=" ('$(Configuration)' == 'Release') and ('$(Platform)' == 'Any CPU') " /> // </Target> // and add those targets to the "projectsToBuild" list. foreach (Target target in solutionTargets) { List<BuildTask> tasks = Linq.ToList(Linq.CastTo<BuildTask>(target)); if (tasks.Count == 0) { return InvalidTarget(target); } // find task to run when this target is executed BuildTask bestTask = null; foreach (BuildTask task in tasks) { if (task.Name != "MSBuild") { return InvalidTarget(target); } if (MSBuildInternals.EvaluateCondition(solution, task.Condition)) { bestTask = task; } } if (bestTask == null) { LoggingService.Warn("No matching condition for solution target " + target.Name); bestTask = tasks[0]; } // create projectToBuild entry and add it to list and dictionary string projectFileName = Path.Combine(this.solution.Directory, bestTask.GetParameterValue("Projects")); ProjectToBuild projectToBuild = new ProjectToBuild(Path.GetFullPath(projectFileName), bestTask.GetParameterValue("Targets")); // get project configuration and platform from properties section string propertiesString = bestTask.GetParameterValue("Properties"); Match match = Regex.Match(propertiesString, @"\bConfiguration=([^;]+);"); if (match.Success) { projectToBuild.configuration = match.Groups[1].Value; } else { projectToBuild.configuration = parentEngine.Configuration; } match = Regex.Match(propertiesString, @"\bPlatform=([^;]+);"); if (match.Success) { projectToBuild.platform = match.Groups[1].Value; } else { projectToBuild.platform = parentEngine.Platform; if (projectToBuild.platform == "Any CPU") { projectToBuild.platform = "AnyCPU"; } } projectsToBuild.Add(projectToBuild); projectsToBuildDict[target.Name] = projectToBuild; } // now create dependencies between projectsToBuild foreach (Target target in solutionTargets) { ProjectToBuild p1; if (!projectsToBuildDict.TryGetValue(target.Name, out p1)) continue; foreach (string dependency in target.DependsOnTargets.Split(';')) { ProjectToBuild p2; if (!projectsToBuildDict.TryGetValue(dependency, out p2)) continue; p1.dependencies.Add(p2); } } return true; }