Browse Source

Trying to reimplement building (now building using a separate ProjectCollection)

git-svn-id: svn://svn.sharpdevelop.net/sharpdevelop/branches/dotnet4@4287 1ccf3a8d-04fe-1044-b7c0-cef0b8235c61
shortcuts
Daniel Grunwald 16 years ago
parent
commit
8910f68d47
  1. 9
      src/AddIns/BackendBindings/CSharpBinding/Project/Src/Project/CSharpProject.cs
  2. 5
      src/AddIns/BackendBindings/VBNetBinding/Project/Src/Project/VBNetProject.cs
  3. 1
      src/Main/Base/Project/ICSharpCode.SharpDevelop.csproj
  4. 2
      src/Main/Base/Project/Src/Project/AbstractProject.cs
  5. 4
      src/Main/Base/Project/Src/Project/BuildEngine.cs
  6. 2
      src/Main/Base/Project/Src/Project/IProject.cs
  7. 23
      src/Main/Base/Project/Src/Project/MSBuildBasedProject.cs
  8. 21
      src/Main/Base/Project/Src/Project/MSBuildEngine/MSBuildEngine.cs
  9. 177
      src/Main/Base/Project/Src/Project/MSBuildEngine/ParallelMSBuildManager.cs
  10. 4
      src/Main/Base/Project/Src/Project/MSBuildFileProject.cs
  11. 31
      src/Main/Base/Project/Src/Project/MSBuildInternals.cs
  12. 2
      src/Main/Base/Project/Src/Project/Solution/Solution.cs
  13. 24
      src/Main/Base/Project/Src/Services/ParserService/ParserService.cs
  14. 8
      src/Main/Base/Project/Src/Services/ProjectService/CompileModifiedProjectsOnly.cs
  15. 61
      src/Main/Base/Project/Src/Util/ThreadSafeServiceProvider.cs

9
src/AddIns/BackendBindings/CSharpBinding/Project/Src/Project/CSharpProject.cs

@ -5,11 +5,11 @@ @@ -5,11 +5,11 @@
// <version>$Revision$</version>
// </file>
using ICSharpCode.SharpDevelop;
using System;
using System.ComponentModel;
using System.Linq;
using System.IO;
using System.Linq;
using ICSharpCode.SharpDevelop.Dom;
using ICSharpCode.SharpDevelop.Dom.CSharp;
using ICSharpCode.SharpDevelop.Internal.Templates;
@ -76,16 +76,17 @@ namespace CSharpBinding @@ -76,16 +76,17 @@ namespace CSharpBinding
return base.GetDefaultItemType(fileName);
}
public override void StartBuild(ProjectBuildOptions options, IBuildFeedbackSink feedbackSink)
public override void StartBuild(ThreadSafeServiceContainer buildServices, ProjectBuildOptions options, IBuildFeedbackSink feedbackSink)
{
if (this.MinimumSolutionVersion == Solution.SolutionVersionVS2005) {
MSBuildEngine.StartBuild(this,
buildServices,
options,
feedbackSink,
MSBuildEngine.AdditionalTargetFiles.Concat(
new [] { "$(SharpDevelopBinPath)/SharpDevelop.CheckMSBuild35Features.targets" }));
} else {
base.StartBuild(options, feedbackSink);
base.StartBuild(buildServices, options, feedbackSink);
}
}

5
src/AddIns/BackendBindings/VBNetBinding/Project/Src/Project/VBNetProject.cs

@ -101,16 +101,17 @@ namespace VBNetBinding @@ -101,16 +101,17 @@ namespace VBNetBinding
return base.GetDefaultItemType(fileName);
}
public override void StartBuild(ProjectBuildOptions options, IBuildFeedbackSink feedbackSink)
public override void StartBuild(ThreadSafeServiceContainer buildServices, ProjectBuildOptions options, IBuildFeedbackSink feedbackSink)
{
if (this.MinimumSolutionVersion == Solution.SolutionVersionVS2005) {
MSBuildEngine.StartBuild(this,
buildServices,
options,
feedbackSink,
MSBuildEngine.AdditionalTargetFiles.Concat(
new [] { "$(SharpDevelopBinPath)/SharpDevelop.CheckMSBuild35Features.targets" }));
} else {
base.StartBuild(options, feedbackSink);
base.StartBuild(buildServices, options, feedbackSink);
}
}

1
src/Main/Base/Project/ICSharpCode.SharpDevelop.csproj

@ -763,6 +763,7 @@ @@ -763,6 +763,7 @@
<Compile Include="Src\Project\BuildTarget.cs" />
<Compile Include="Src\Util\GenericConverter.cs" />
<Compile Include="Src\Internal\Templates\TemplateLoadException.cs" />
<Compile Include="Src\Util\ThreadSafeServiceProvider.cs" />
<Compile Include="Src\Util\UnclosableStream.cs" />
<Compile Include="Src\Util\WpfSynchronizeInvoke.cs" />
<Compile Include="Src\Util\WorkerThread.cs" />

2
src/Main/Base/Project/Src/Project/AbstractProject.cs

@ -488,7 +488,7 @@ namespace ICSharpCode.SharpDevelop.Project @@ -488,7 +488,7 @@ namespace ICSharpCode.SharpDevelop.Project
{
}
public virtual void StartBuild(ProjectBuildOptions options, IBuildFeedbackSink feedbackSink)
public virtual void StartBuild(ThreadSafeServiceContainer buildServices, ProjectBuildOptions options, IBuildFeedbackSink feedbackSink)
{
feedbackSink.ReportError(new BuildError { ErrorText = "Building project " + Name + " is not supported.", IsWarning = true });
// we don't know how to build anything, report that we're done.

4
src/Main/Base/Project/Src/Project/BuildEngine.cs

@ -301,7 +301,7 @@ namespace ICSharpCode.SharpDevelop.Project @@ -301,7 +301,7 @@ namespace ICSharpCode.SharpDevelop.Project
public void DoStartBuild(object state)
{
project.StartBuild(options, this);
project.StartBuild(engine.serviceContainer, options, this);
}
public void ReportError(BuildError error)
@ -328,6 +328,7 @@ namespace ICSharpCode.SharpDevelop.Project @@ -328,6 +328,7 @@ namespace ICSharpCode.SharpDevelop.Project
BuildNode rootNode;
readonly IBuildable rootProject;
readonly BuildResults results = new BuildResults();
readonly ThreadSafeServiceContainer serviceContainer = new ThreadSafeServiceContainer();
DateTime buildStart;
readonly List<BuildNode> projectsCurrentlyBuilding = new List<BuildNode>();
@ -551,6 +552,7 @@ namespace ICSharpCode.SharpDevelop.Project @@ -551,6 +552,7 @@ namespace ICSharpCode.SharpDevelop.Project
/// </summary>
void ReportDone()
{
serviceContainer.Dispose();
if (combinedBuildFeedbackSink != null) {
if (combinedBuildFeedbackSink is MessageViewSink) {
// Special case GUI-builds so that they have more information available:

2
src/Main/Base/Project/Src/Project/IProject.cs

@ -272,7 +272,7 @@ namespace ICSharpCode.SharpDevelop.Project @@ -272,7 +272,7 @@ namespace ICSharpCode.SharpDevelop.Project
/// Starts building the project using the specified options.
/// This member must be implemented thread-safe.
/// </summary>
void StartBuild(ProjectBuildOptions buildOptions, IBuildFeedbackSink feedbackSink);
void StartBuild(ThreadSafeServiceContainer buildServices, ProjectBuildOptions buildOptions, IBuildFeedbackSink feedbackSink);
/// <summary>
/// Gets the name of the buildable item.

23
src/Main/Base/Project/Src/Project/MSBuildBasedProject.cs

@ -36,6 +36,10 @@ namespace ICSharpCode.SharpDevelop.Project @@ -36,6 +36,10 @@ namespace ICSharpCode.SharpDevelop.Project
/// </summary>
ProjectCollection projectCollection;
internal ProjectCollection MSBuildProjectCollection {
get { return projectCollection; }
}
/// <summary>
/// The underlying MSBuild project.
/// </summary>
@ -1004,23 +1008,10 @@ namespace ICSharpCode.SharpDevelop.Project @@ -1004,23 +1008,10 @@ namespace ICSharpCode.SharpDevelop.Project
return result;
}
public override void StartBuild(ProjectBuildOptions options, IBuildFeedbackSink feedbackSink)
public override void StartBuild(ThreadSafeServiceContainer buildServices, ProjectBuildOptions options, IBuildFeedbackSink feedbackSink)
{
MSBuildEngine.StartBuild(this, options, feedbackSink, MSBuildEngine.AdditionalTargetFiles);
MSBuildEngine.StartBuild(this, buildServices, options, feedbackSink, MSBuildEngine.AdditionalTargetFiles);
}
/*
internal static void RunMSBuild(Solution solution, IProject project,
string configuration, string platform, BuildOptions options)
{
WorkbenchSingleton.Workbench.GetPad(typeof(CompilerMessageView)).BringPadToFront();
oldMSBuildEngine engine = new oldMSBuildEngine();
engine.Configuration = configuration;
engine.Platform = platform;
engine.MessageView = TaskService.BuildMessageViewCategory;
engine.Run(solution, project, options);
}
*/
#endregion
#region Loading
@ -1140,7 +1131,7 @@ namespace ICSharpCode.SharpDevelop.Project @@ -1140,7 +1131,7 @@ namespace ICSharpCode.SharpDevelop.Project
lock (SyncRoot) {
// we need the global lock - if the file is being renamed,
// MSBuild will update the global project collection
lock (MSBuildInternals.GlobalProjectCollectionLock) {
lock (MSBuildInternals.SolutionProjectCollectionLock) {
projectFile.Save(fileName);
//bool userProjectDirty = userProjectFile.HasUnsavedChanges;
string userFile = fileName + ".user";

21
src/Main/Base/Project/Src/Project/MSBuildEngine/MSBuildEngine.cs

@ -78,10 +78,12 @@ namespace ICSharpCode.SharpDevelop.Project @@ -78,10 +78,12 @@ namespace ICSharpCode.SharpDevelop.Project
}
public static void StartBuild(IProject project, ProjectBuildOptions options, IBuildFeedbackSink feedbackSink, IEnumerable<string> additionalTargetFiles)
public static void StartBuild(IProject project, ThreadSafeServiceContainer serviceContainer, ProjectBuildOptions options, IBuildFeedbackSink feedbackSink, IEnumerable<string> additionalTargetFiles)
{
if (project == null)
throw new ArgumentNullException("project");
if (serviceContainer == null)
throw new ArgumentNullException("serviceContainer");
if (options == null)
throw new ArgumentNullException("options");
if (feedbackSink == null)
@ -91,6 +93,7 @@ namespace ICSharpCode.SharpDevelop.Project @@ -91,6 +93,7 @@ namespace ICSharpCode.SharpDevelop.Project
MSBuildEngine engine = new MSBuildEngine(project, options, feedbackSink);
engine.additionalTargetFiles = additionalTargetFiles;
engine.serviceContainer = serviceContainer;
engine.StartBuild();
}
@ -98,6 +101,7 @@ namespace ICSharpCode.SharpDevelop.Project @@ -98,6 +101,7 @@ namespace ICSharpCode.SharpDevelop.Project
ProjectBuildOptions options;
IBuildFeedbackSink feedbackSink;
IEnumerable<string> additionalTargetFiles;
ThreadSafeServiceContainer serviceContainer;
private MSBuildEngine(IProject project, ProjectBuildOptions options, IBuildFeedbackSink feedbackSink)
{
@ -182,11 +186,18 @@ namespace ICSharpCode.SharpDevelop.Project @@ -182,11 +186,18 @@ namespace ICSharpCode.SharpDevelop.Project
InterestingTasks.AddRange(MSBuildEngine.CompileTaskNames);
/*
// Get ParallelMSBuildManager (or create a new one if one doesn't exist already).
// The serviceContainer will automatically dispose it after the build has completed.
ParallelMSBuildManager manager = (ParallelMSBuildManager)serviceContainer.GetOrCreateService(
typeof(ParallelMSBuildManager),
delegate {
return new ParallelMSBuildManager(new MSBuild.ProjectCollection());
});
// Use a temporary project collection to prevent MSBuild from opening the element from the global collection
// - we don't want to modify the ProjectRootElement opened as project because we don't want to save
// back our changes to disk.
ProjectRootElement projectFile = ProjectRootElement.Open(project.FileName, new MSBuild.ProjectCollection());
ProjectRootElement projectFile = ProjectRootElement.Open(project.FileName, manager.ProjectCollection);
foreach (string import in additionalTargetFiles)
projectFile.AddImport(import);
@ -199,7 +210,7 @@ namespace ICSharpCode.SharpDevelop.Project @@ -199,7 +210,7 @@ namespace ICSharpCode.SharpDevelop.Project
projectFile.AddTarget("_ComputeNonExistentFileProperty");
}
ProjectInstance projectInstance = MSBuildInternals.LoadProjectInstance(projectFile, globalProperties);
ProjectInstance projectInstance = MSBuildInternals.LoadProjectInstance(manager.ProjectCollection, projectFile, globalProperties);
string[] targets = { options.Target.TargetName };
BuildRequestData requestData = new BuildRequestData(projectInstance, targets, new HostServices());
@ -207,7 +218,7 @@ namespace ICSharpCode.SharpDevelop.Project @@ -207,7 +218,7 @@ namespace ICSharpCode.SharpDevelop.Project
new SharpDevelopLogger(this),
new BuildLogFileLogger(projectFile.FullPath + ".log", LoggerVerbosity.Diagnostic)
};
ParallelMSBuildManager.StartBuild(requestData, loggers, OnComplete);*/
manager.StartBuild(requestData, loggers, OnComplete);
}
void OnComplete(BuildSubmission submission)

177
src/Main/Base/Project/Src/Project/MSBuildEngine/ParallelMSBuildManager.cs

@ -7,11 +7,15 @@ @@ -7,11 +7,15 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using ICSharpCode.Core;
using Microsoft.Build.Evaluation;
using Microsoft.Build.Execution;
using Microsoft.Build.Framework;
using Microsoft.Build.Logging;
using System.Linq;
using System.Threading;
namespace ICSharpCode.SharpDevelop.Project
{
@ -23,77 +27,114 @@ namespace ICSharpCode.SharpDevelop.Project @@ -23,77 +27,114 @@ namespace ICSharpCode.SharpDevelop.Project
///
/// This class allows to run multiple indepent builds concurrently. Logging events
/// will be forwarded to the appropriate logger.
///
/// Note: due to MSBuild limitations, all projects being built must be from the same ProjectCollection.
/// SharpDevelop simply uses the predefined ProjectCollection.GlobalProjectCollection.
/// Code accessing that collection (even if indirectly through MSBuild) should lock on
/// MSBuildInternals.GlobalProjectCollectionLock.
/// </summary>
public static class ParallelMSBuildManager
public sealed class ParallelMSBuildManager : IDisposable
{
#region Manage StartBuild/EndBuild of BuildManager.DefaultBuildManager
static readonly object enableDisableLock = new object();
static bool buildIsRunning;
static int enableCount;
/// <summary>
/// MSBuild only allows a single build to run at one time - so if multiple ParallelMSBuildManager
/// are present, we synchronize them using this global lock.
/// </summary>
static readonly object globalBuildEngineLock = new object();
static bool globalBuildEngineLockTaken;
static void EnterGlobalBuildEngineLock()
{
lock (globalBuildEngineLock) {
while (globalBuildEngineLockTaken)
Monitor.Wait(globalBuildEngineLock);
globalBuildEngineLockTaken = true;
}
}
static void LeaveGlobalBuildEngineLock()
{
lock (globalBuildEngineLock) {
Debug.Assert(globalBuildEngineLockTaken);
globalBuildEngineLockTaken = false;
Monitor.Pulse(globalBuildEngineLock);
}
}
public ProjectCollection ProjectCollection { get; private set; }
/// <summary>
/// Enables the underlying build engine.
/// Call this method only if you are requesting multiple builds in a series (e.g. building the solution).
/// A counter is increment to remember how many users of this class need the build engine.
/// For each EnableBuildEngine() call, you need to call DisableBuildEngine() exactly once!
/// Creates a new ParallelMSBuildManager for the project collection.
/// WARNING: only a single ParallelMSBuildManager can build at a time, others will wait.
/// Ensure you dispose the ParallelMSBuildManager when you are done with it, otherwise all future
/// ParallelMSBuildManagers will deadlock!
/// </summary>
/// <param name="beginBuild">Specifies whether the build engine should be started immediately.
/// If false (default), the build engine will start on the first StartBuild() call.</param>
public static void EnableBuildEngine(bool beginBuild)
public ParallelMSBuildManager(ProjectCollection projectCollection)
{
if (projectCollection == null)
throw new ArgumentNullException("projectCollection");
this.ProjectCollection = projectCollection;
}
#region Manage StartBuild/EndBuild
readonly object enableDisableLock = new object();
bool buildIsRunning;
void StartupBuildEngine()
{
lock (enableDisableLock) {
if (!buildIsRunning && beginBuild) {
LoggingService.Info("ParallelMSBuildManager starting...");
buildIsRunning = true;
BuildParameters parameters = new BuildParameters();
parameters.Loggers = new ILogger[] {
new CentralLogger(),
#if DEBUG
new ConsoleLogger(LoggerVerbosity.Normal),
#endif
};
parameters.EnableNodeReuse = false;
// parallel build seems to break in-memory modifications of the project (additionalTargetFiles+_ComputeNonExistentFileProperty),
// so we keep it disabled for the moment.
parameters.MaxNodeCount = 1; //BuildOptions.DefaultParallelProjectCount;
BuildManager.DefaultBuildManager.BeginBuild(parameters);
}
enableCount++;
if (buildIsRunning)
return;
buildIsRunning = true;
LoggingService.Info("ParallelMSBuildManager: waiting for start permission...");
EnterGlobalBuildEngineLock();
LoggingService.Info("ParallelMSBuildManager: got start permisson, starting...");
BuildParameters parameters = new BuildParameters(this.ProjectCollection);
parameters.Loggers = new ILogger[] {
new CentralLogger(this),
#if DEBUG
new ConsoleLogger(LoggerVerbosity.Normal),
#endif
};
parameters.EnableNodeReuse = false;
// parallel build seems to break in-memory modifications of the project (additionalTargetFiles+_ComputeNonExistentFileProperty),
// so we keep it disabled for the moment.
parameters.MaxNodeCount = BuildOptions.DefaultParallelProjectCount;
BuildManager.DefaultBuildManager.BeginBuild(parameters);
}
}
/// <summary>
/// Decrements the counter and disables the underlying build engine if the counter reaches 0.
/// Shuts down the build engine and allows other managers to build.
/// </summary>
public static void DisableBuildEngine()
public void Dispose()
{
lock (enableDisableLock) {
enableCount--;
if (enableCount == 0 && buildIsRunning) {
buildIsRunning = false;
if (!buildIsRunning)
return;
buildIsRunning = false;
try {
LoggingService.Info("ParallelMSBuildManager shutting down...");
BuildManager.DefaultBuildManager.EndBuild();
BuildManager.DefaultBuildManager.ResetCaches();
LoggingService.Info("ParallelMSBuildManager shut down!");
} finally {
LeaveGlobalBuildEngineLock();
}
}
}
#endregion
static readonly Dictionary<int, EventSource> submissionEventSourceMapping = new Dictionary<int, EventSource>();
readonly Dictionary<int, EventSource> submissionEventSourceMapping = new Dictionary<int, EventSource>();
/// <summary>
/// Starts building.
/// This method blocks if another ParallelMSBuildManager is currently building.
/// However, it doe
/// </summary>
/// <param name="requestData">The requested build.</param>
/// <param name="logger">The logger that received build output.</param>
/// <param name="callback">Callback that is run when the build is complete</param>
/// <returns>The build submission that was started.</returns>
public static BuildSubmission StartBuild(BuildRequestData requestData, IEnumerable<ILogger> loggers, BuildSubmissionCompleteCallback callback)
public BuildSubmission StartBuild(BuildRequestData requestData, IEnumerable<ILogger> loggers, BuildSubmissionCompleteCallback callback)
{
if (requestData == null)
throw new ArgumentNullException("requestData");
@ -102,35 +143,32 @@ namespace ICSharpCode.SharpDevelop.Project @@ -102,35 +143,32 @@ namespace ICSharpCode.SharpDevelop.Project
loggersArray = new ILogger[0];
else
loggersArray = loggers.ToArray(); // iterate through logger enumerable once
EnableBuildEngine(true);
try {
BuildSubmission submission = BuildManager.DefaultBuildManager.PendBuildRequest(requestData);
EventSource eventSource = new EventSource();
foreach (ILogger logger in loggersArray) {
if (logger != null)
logger.Initialize(eventSource);
}
lock (submissionEventSourceMapping) {
submissionEventSourceMapping.Add(submission.SubmissionId, eventSource);
}
RunningBuild build = new RunningBuild(eventSource, loggersArray, callback);
submission.ExecuteAsync(build.OnComplete, null);
return submission;
} catch (Exception ex) {
LoggingService.Warn("Got exception starting build (exception will be rethrown)", ex);
DisableBuildEngine();
throw;
StartupBuildEngine();
BuildSubmission submission = BuildManager.DefaultBuildManager.PendBuildRequest(requestData);
EventSource eventSource = new EventSource();
foreach (ILogger logger in loggersArray) {
if (logger != null)
logger.Initialize(eventSource);
}
lock (submissionEventSourceMapping) {
submissionEventSourceMapping.Add(submission.SubmissionId, eventSource);
}
RunningBuild build = new RunningBuild(this, eventSource, loggersArray, callback);
submission.ExecuteAsync(build.OnComplete, null);
return submission;
}
sealed class RunningBuild
{
ParallelMSBuildManager manager;
ILogger[] loggers;
BuildSubmissionCompleteCallback callback;
EventSource eventSource;
public RunningBuild(EventSource eventSource, ILogger[] loggers, BuildSubmissionCompleteCallback callback)
public RunningBuild(ParallelMSBuildManager manager, EventSource eventSource, ILogger[] loggers, BuildSubmissionCompleteCallback callback)
{
this.manager = manager;
this.eventSource = eventSource;
this.loggers = loggers;
this.callback = callback;
@ -138,10 +176,8 @@ namespace ICSharpCode.SharpDevelop.Project @@ -138,10 +176,8 @@ namespace ICSharpCode.SharpDevelop.Project
internal void OnComplete(BuildSubmission submission)
{
DisableBuildEngine();
lock (submissionEventSourceMapping) {
submissionEventSourceMapping.Remove(submission.SubmissionId);
lock (manager.submissionEventSourceMapping) {
manager.submissionEventSourceMapping.Remove(submission.SubmissionId);
}
if (submission.BuildResult.Exception != null) {
LoggingService.Error(submission.BuildResult.Exception);
@ -158,6 +194,13 @@ namespace ICSharpCode.SharpDevelop.Project @@ -158,6 +194,13 @@ namespace ICSharpCode.SharpDevelop.Project
sealed class CentralLogger : INodeLogger, IEventRedirector
{
readonly ParallelMSBuildManager parentManager;
public CentralLogger(ParallelMSBuildManager parentManager)
{
this.parentManager = parentManager;
}
public void Initialize(IEventSource eventSource, int nodeCount)
{
Initialize(eventSource);
@ -188,8 +231,8 @@ namespace ICSharpCode.SharpDevelop.Project @@ -188,8 +231,8 @@ namespace ICSharpCode.SharpDevelop.Project
}
}
EventSource redirector;
lock (submissionEventSourceMapping) {
if (!submissionEventSourceMapping.TryGetValue(e.BuildEventContext.SubmissionId, out redirector)) {
lock (parentManager.submissionEventSourceMapping) {
if (!parentManager.submissionEventSourceMapping.TryGetValue(e.BuildEventContext.SubmissionId, out redirector)) {
LoggingService.Warn("Could not deliver build event: " + e + ":\n" + e.Message);
}
}

4
src/Main/Base/Project/Src/Project/MSBuildFileProject.cs

@ -22,9 +22,9 @@ namespace ICSharpCode.SharpDevelop.Project @@ -22,9 +22,9 @@ namespace ICSharpCode.SharpDevelop.Project
TypeGuid = "{00000000-0000-0000-0000-000000000000}";
}
public override void StartBuild(ProjectBuildOptions options, IBuildFeedbackSink feedbackSink)
public override void StartBuild(ThreadSafeServiceContainer buildServices, ProjectBuildOptions options, IBuildFeedbackSink feedbackSink)
{
MSBuildEngine.StartBuild(this, options, feedbackSink, MSBuildEngine.AdditionalTargetFiles);
MSBuildEngine.StartBuild(this, buildServices, options, feedbackSink, MSBuildEngine.AdditionalTargetFiles);
}
}
}

31
src/Main/Base/Project/Src/Project/MSBuildInternals.cs

@ -25,23 +25,22 @@ namespace ICSharpCode.SharpDevelop.Project @@ -25,23 +25,22 @@ namespace ICSharpCode.SharpDevelop.Project
public static class MSBuildInternals
{
/// <summary>
/// Note: due to MSBuild limitations, all projects being built must be from the same ProjectCollection.
/// SharpDevelop simply uses the predefined ProjectCollection.GlobalProjectCollection.
/// Code accessing that collection (even if indirectly through MSBuild) should lock on
/// MSBuildInternals.GlobalProjectCollectionLock.
/// SharpDevelop uses one project collection per solution.
/// Code accessing one of those collection (even if indirectly through MSBuild) should lock on
/// MSBuildInternals.SolutionProjectCollectionLock.
/// </summary>
public readonly static object GlobalProjectCollectionLock = new object();
public readonly static object SolutionProjectCollectionLock = new object();
internal static void UnloadProject(MSBuild.Evaluation.ProjectCollection projectCollection, MSBuild.Evaluation.Project project)
{
lock (GlobalProjectCollectionLock) {
lock (SolutionProjectCollectionLock) {
projectCollection.UnloadProject(project);
}
}
internal static MSBuild.Evaluation.Project LoadProject(MSBuild.Evaluation.ProjectCollection projectCollection, ProjectRootElement rootElement, IDictionary<string, string> globalProps)
{
lock (GlobalProjectCollectionLock) {
lock (SolutionProjectCollectionLock) {
string toolsVersion = rootElement.ToolsVersion;
if (string.IsNullOrEmpty(toolsVersion))
toolsVersion = projectCollection.DefaultToolsVersion;
@ -51,7 +50,7 @@ namespace ICSharpCode.SharpDevelop.Project @@ -51,7 +50,7 @@ namespace ICSharpCode.SharpDevelop.Project
internal static ProjectInstance LoadProjectInstance(MSBuild.Evaluation.ProjectCollection projectCollection, ProjectRootElement rootElement, IDictionary<string, string> globalProps)
{
lock (GlobalProjectCollectionLock) {
lock (SolutionProjectCollectionLock) {
string toolsVersion = rootElement.ToolsVersion;
if (string.IsNullOrEmpty(toolsVersion))
toolsVersion = projectCollection.DefaultToolsVersion;
@ -166,14 +165,16 @@ namespace ICSharpCode.SharpDevelop.Project @@ -166,14 +165,16 @@ namespace ICSharpCode.SharpDevelop.Project
string[] targets = { "ResolveAssemblyReferences" };
BuildRequestData requestData = new BuildRequestData(project, targets, new HostServices());
ILogger[] loggers = { new SimpleErrorLogger() };
BuildSubmission submission = ParallelMSBuildManager.StartBuild(requestData, loggers, null);
LoggingService.Debug("Started build for ResolveAssemblyReferences");
submission.WaitHandle.WaitOne();
BuildResult result = submission.BuildResult;
if (result == null)
throw new InvalidOperationException("BuildResult is null");
LoggingService.Debug("Build for ResolveAssemblyReferences finished: " + result.OverallResult);
using (ParallelMSBuildManager buildManager = new ParallelMSBuildManager(baseProject.MSBuildProjectCollection)) {
BuildSubmission submission = buildManager.StartBuild(requestData, loggers, null);
LoggingService.Debug("Started build for ResolveAssemblyReferences");
submission.WaitHandle.WaitOne();
BuildResult result = submission.BuildResult;
if (result == null)
throw new InvalidOperationException("BuildResult is null");
LoggingService.Debug("Build for ResolveAssemblyReferences finished: " + result.OverallResult);
}
var referenceDict = new Dictionary<string, ReferenceProjectItem>();
foreach (ReferenceProjectItem item in referenceProjectItems) {

2
src/Main/Base/Project/Src/Project/Solution/Solution.cs

@ -1178,7 +1178,7 @@ namespace ICSharpCode.SharpDevelop.Project @@ -1178,7 +1178,7 @@ namespace ICSharpCode.SharpDevelop.Project
return result;
}
void IBuildable.StartBuild(ProjectBuildOptions buildOptions, IBuildFeedbackSink feedbackSink)
void IBuildable.StartBuild(ThreadSafeServiceContainer buildServices, ProjectBuildOptions buildOptions, IBuildFeedbackSink feedbackSink)
{
// building a solution finishes immediately: we only care for the dependencies
feedbackSink.Done(true);

24
src/Main/Base/Project/Src/Services/ParserService/ParserService.cs

@ -177,22 +177,18 @@ namespace ICSharpCode.SharpDevelop @@ -177,22 +177,18 @@ namespace ICSharpCode.SharpDevelop
// multiply Count with 2 so that the progress bar is only at 50% when references are done
progressMonitor.BeginTask("Loading references...", createdContents.Count * 2, false);
ParallelMSBuildManager.EnableBuildEngine(false);
try {
for (int i = 0; i < createdContents.Count; i++) {
if (abortLoadSolutionProjectsThread) return;
ParseProjectContent newContent = createdContents[i];
progressMonitor.WorkDone = i;
try {
newContent.Initialize1(progressMonitor);
workAmount += newContent.GetInitializationWorkAmount();
} catch (Exception e) {
MessageService.ShowError(e, "Error while initializing project references:" + newContent);
}
for (int i = 0; i < createdContents.Count; i++) {
if (abortLoadSolutionProjectsThread) return;
ParseProjectContent newContent = createdContents[i];
progressMonitor.WorkDone = i;
try {
newContent.Initialize1(progressMonitor);
workAmount += newContent.GetInitializationWorkAmount();
} catch (Exception e) {
MessageService.ShowError(e, "Error while initializing project references:" + newContent);
}
} finally {
ParallelMSBuildManager.DisableBuildEngine();
}
// multiply workamount with two and start at workAmount so that the progress bar continues
// from 50% towards 100%.
progressMonitor.BeginTask("${res:ICSharpCode.SharpDevelop.Internal.ParserService.Parsing}...", workAmount * 2, false);

8
src/Main/Base/Project/Src/Services/ProjectService/CompileModifiedProjectsOnly.cs

@ -151,7 +151,7 @@ namespace ICSharpCode.SharpDevelop.Project @@ -151,7 +151,7 @@ namespace ICSharpCode.SharpDevelop.Project
return new IBuildable[0];
}
public void StartBuild(ProjectBuildOptions buildOptions, IBuildFeedbackSink feedbackSink)
public void StartBuild(ThreadSafeServiceContainer buildServices, ProjectBuildOptions buildOptions, IBuildFeedbackSink feedbackSink)
{
}
}
@ -245,11 +245,11 @@ namespace ICSharpCode.SharpDevelop.Project @@ -245,11 +245,11 @@ namespace ICSharpCode.SharpDevelop.Project
return lastCompilationPass.Index > comparisonPass.Index;
}
public void StartBuild(ProjectBuildOptions buildOptions, IBuildFeedbackSink feedbackSink)
public void StartBuild(ThreadSafeServiceContainer buildServices, ProjectBuildOptions buildOptions, IBuildFeedbackSink feedbackSink)
{
IProject p = wrapped as IProject;
if (p == null) {
wrapped.StartBuild(buildOptions, feedbackSink);
wrapped.StartBuild(buildServices, buildOptions, feedbackSink);
} else {
lock (unmodifiedProjects) {
if (!unmodifiedProjects.TryGetValue(p, out lastCompilationPass)) {
@ -272,7 +272,7 @@ namespace ICSharpCode.SharpDevelop.Project @@ -272,7 +272,7 @@ namespace ICSharpCode.SharpDevelop.Project
feedbackSink.Done(true);
} else {
lastCompilationPass = factory.CurrentPass;
wrapped.StartBuild(buildOptions, new BuildFeedbackSink(p, feedbackSink, factory.CurrentPass));
wrapped.StartBuild(buildServices, buildOptions, new BuildFeedbackSink(p, feedbackSink, factory.CurrentPass));
}
}
}

61
src/Main/Base/Project/Src/Util/ThreadSafeServiceProvider.cs

@ -0,0 +1,61 @@ @@ -0,0 +1,61 @@
/*
* Created by SharpDevelop.
* User: Daniel
* Date: 12.06.2009
* Time: 22:28
*
* To change this template use Tools | Options | Coding | Edit Standard Headers.
*/
using System;
using System.Linq;
using System.Collections.Generic;
namespace ICSharpCode.SharpDevelop
{
/// <summary>
/// A thread-safe service container class.
/// </summary>
public class ThreadSafeServiceContainer : IServiceProvider, IDisposable
{
Dictionary<Type, object> services = new Dictionary<Type, object>();
public ThreadSafeServiceContainer()
{
services.Add(typeof(ThreadSafeServiceContainer), this);
}
public object GetOrCreateService(Type type, Func<object> serviceCreator)
{
lock (services) {
object instance;
if (!services.TryGetValue(type, out instance)) {
instance = serviceCreator();
services.Add(type, instance);
}
return instance;
}
}
public object GetService(Type type)
{
lock (services) {
object instance;
if (services.TryGetValue(type, out instance))
return instance;
else
return null;
}
}
public void Dispose()
{
IDisposable[] disposables;
lock (services) {
disposables = services.Values.OfType<IDisposable>().ToArray();
services.Clear();
}
foreach (IDisposable disposable in disposables)
disposable.Dispose();
}
}
}
Loading…
Cancel
Save