Fix bug #559990.
[mcs.git] / class / Microsoft.Build.Engine / Microsoft.Build.BuildEngine / Engine.cs
bloba8f6a067a2c9526c00d0f65409dfd6efcb33c315
1 //
2 // Engine.cs: Main engine of XBuild.
3 //
4 // Author:
5 // Marek Sieradzki (marek.sieradzki@gmail.com)
6 //
7 // (C) 2005 Marek Sieradzki
8 //
9 // Permission is hereby granted, free of charge, to any person obtaining
10 // a copy of this software and associated documentation files (the
11 // "Software"), to deal in the Software without restriction, including
12 // without limitation the rights to use, copy, modify, merge, publish,
13 // distribute, sublicense, and/or sell copies of the Software, and to
14 // permit persons to whom the Software is furnished to do so, subject to
15 // the following conditions:
17 // The above copyright notice and this permission notice shall be
18 // included in all copies or substantial portions of the Software.
20 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
21 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
22 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
23 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
24 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
25 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
26 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
28 #if NET_2_0
30 using System;
31 using System.Collections;
32 using System.Collections.Generic;
33 using System.IO;
34 using Microsoft.Build.Framework;
35 using Microsoft.Build.Utilities;
36 using Mono.XBuild.Utilities;
38 namespace Microsoft.Build.BuildEngine {
39 public class Engine {
41 string binPath;
42 bool buildEnabled;
43 TaskDatabase defaultTasks;
44 bool defaultTasksRegistered;
45 const string defaultTasksProjectName = "Microsoft.Common.tasks";
46 EventSource eventSource;
47 bool buildStarted;
48 BuildPropertyGroup global_properties;
49 //IDictionary importedProjects;
50 List <ILogger> loggers;
51 //bool onlyLogCriticalEvents;
52 Dictionary <string, Project> projects;
54 // the key here represents the project+target+global_properties set
55 Dictionary <string, ITaskItem[]> builtTargetsOutputByName;
56 Stack<Project> currentlyBuildingProjectsStack;
58 static Engine globalEngine;
59 static Version version;
61 static Engine ()
63 version = new Version ("0.1");
66 public Engine ()
67 : this (ToolLocationHelper.GetPathToDotNetFramework (TargetDotNetFrameworkVersion.Version20))
71 // engine should be invoked with path where binary files are
72 // to find microsoft.build.tasks
73 public Engine (string binPath)
75 this.binPath = binPath;
76 this.buildEnabled = true;
77 this.projects = new Dictionary <string, Project> ();
78 this.eventSource = new EventSource ();
79 this.loggers = new List <ILogger> ();
80 this.buildStarted = false;
81 this.global_properties = new BuildPropertyGroup ();
82 this.builtTargetsOutputByName = new Dictionary<string, ITaskItem[]> ();
83 this.currentlyBuildingProjectsStack = new Stack<Project> ();
85 RegisterDefaultTasks ();
88 [MonoTODO]
89 public bool BuildProject (Project project)
91 if (project == null)
92 throw new ArgumentException ("project");
93 return project.Build ();
96 [MonoTODO]
97 public bool BuildProject (Project project, string targetName)
99 if (project == null)
100 throw new ArgumentException ("project");
101 if (targetName == null)
102 return false;
104 return BuildProject (project, new string[] { targetName}, null, BuildSettings.None);
107 [MonoTODO]
108 public bool BuildProject (Project project, string[] targetNames)
110 return BuildProject (project, targetNames, null, BuildSettings.None);
113 [MonoTODO]
114 public bool BuildProject (Project project,
115 string[] targetNames,
116 IDictionary targetOutputs)
118 return BuildProject (project, targetNames, targetOutputs, BuildSettings.None);
121 public bool BuildProject (Project project,
122 string[] targetNames,
123 IDictionary targetOutputs,
124 BuildSettings buildFlags)
126 if (project == null)
127 throw new ArgumentException ("project");
128 if (targetNames == null)
129 return false;
131 return project.Build (targetNames, targetOutputs, buildFlags);
134 [MonoTODO]
135 public bool BuildProjectFile (string projectFile)
137 throw new NotImplementedException ();
140 [MonoTODO]
141 public bool BuildProjectFile (string projectFile,
142 string targetName)
144 throw new NotImplementedException ();
147 [MonoTODO]
148 public bool BuildProjectFile (string projectFile,
149 string[] targetNames)
151 throw new NotImplementedException ();
154 [MonoTODO]
155 public bool BuildProjectFile (string projectFile,
156 string[] targetNames,
157 BuildPropertyGroup globalProperties)
159 return BuildProjectFile (projectFile, targetNames, globalProperties, null, BuildSettings.None);
162 [MonoTODO]
163 public bool BuildProjectFile (string projectFile,
164 string[] targetNames,
165 BuildPropertyGroup globalProperties,
166 IDictionary targetOutputs)
168 return BuildProjectFile (projectFile, targetNames, globalProperties, targetOutputs, BuildSettings.None);
171 public bool BuildProjectFile (string projectFile,
172 string[] targetNames,
173 BuildPropertyGroup globalProperties,
174 IDictionary targetOutputs,
175 BuildSettings buildFlags)
177 Project project;
179 if (projects.ContainsKey (projectFile)) {
180 project = (Project) projects [projectFile];
181 } else {
182 project = CreateNewProject ();
183 project.Load (projectFile);
186 BuildPropertyGroup engine_old_grp = null;
187 BuildPropertyGroup project_old_grp = null;
188 if (globalProperties != null) {
189 engine_old_grp = GlobalProperties.Clone (true);
190 project_old_grp = project.GlobalProperties.Clone (true);
192 // Override project's global properties with the
193 // ones explicitlcur_y specified here
194 foreach (BuildProperty bp in globalProperties)
195 project.GlobalProperties.AddProperty (bp);
196 project.NeedToReevaluate ();
199 try {
200 return project.Build (targetNames, targetOutputs, buildFlags);
201 } finally {
202 if (globalProperties != null) {
203 GlobalProperties = engine_old_grp;
204 project.GlobalProperties = project_old_grp;
209 void CheckBinPath ()
211 if (BinPath == null) {
212 throw new InvalidOperationException ("Before a project can be instantiated, " +
213 "Engine.BinPath must be set to the location on disk where MSBuild " +
214 "is installed. This is used to evaluate $(MSBuildBinPath).");
218 public Project CreateNewProject ()
220 if (defaultTasksRegistered)
221 CheckBinPath ();
222 return new Project (this);
225 public Project GetLoadedProject (string projectFullFileName)
227 if (projectFullFileName == null)
228 throw new ArgumentNullException ("projectFullFileName");
230 // FIXME: test it
231 return projects [projectFullFileName];
234 internal void RemoveLoadedProject (Project p)
236 if (p.FullFileName != String.Empty)
237 projects.Remove (p.FullFileName);
240 internal void AddLoadedProject (Project p)
242 if (p.FullFileName != String.Empty)
243 projects.Add (p.FullFileName, p);
246 public void UnloadProject (Project project)
248 if (project == null)
249 throw new ArgumentNullException ("project");
251 if (project.ParentEngine != this)
252 throw new InvalidOperationException ("The \"Project\" object specified does not belong to the correct \"Engine\" object.");
254 project.CheckUnloaded ();
256 if (project.FullFileName != String.Empty)
257 projects.Remove (project.FullFileName);
259 project.Unload ();
262 public void UnloadAllProjects ()
264 IList<Project> values = new List<Project> (projects.Values);
265 foreach (Project p in values)
266 UnloadProject (p);
269 [MonoTODO]
270 public void RegisterLogger (ILogger logger)
272 if (logger == null)
273 throw new ArgumentNullException ("logger");
275 logger.Initialize (eventSource);
276 loggers.Add (logger);
279 [MonoTODO]
280 public void UnregisterAllLoggers ()
282 // FIXME: check if build succeeded
283 // FIXME: it shouldn't be here
284 if (buildStarted)
285 LogBuildFinished (true);
286 foreach (ILogger i in loggers) {
287 i.Shutdown ();
289 loggers.Clear ();
292 internal void StartProjectBuild (Project project, string [] target_names)
294 if (!buildStarted) {
295 LogBuildStarted ();
296 buildStarted = true;
299 if (currentlyBuildingProjectsStack.Count == 0 ||
300 String.Compare (currentlyBuildingProjectsStack.Peek ().FullFileName, project.FullFileName) != 0)
301 LogProjectStarted (project, target_names);
303 currentlyBuildingProjectsStack.Push (project);
306 internal void EndProjectBuild (Project project, bool succeeded)
308 if (!buildStarted)
309 throw new Exception ("build isnt started currently");
311 Project top_project = currentlyBuildingProjectsStack.Pop ();
313 if (String.Compare (project.FullFileName, top_project.FullFileName) != 0)
314 throw new Exception (String.Format (
315 "INTERNAL ERROR: Project finishing is not the same as the one on top " +
316 "of the stack. Project: {0} Top of stack: {1}",
317 project.FullFileName, top_project.FullFileName));
319 if (currentlyBuildingProjectsStack.Count == 0 ||
320 String.Compare (top_project.FullFileName, currentlyBuildingProjectsStack.Peek ().FullFileName) != 0)
321 LogProjectFinished (top_project, succeeded);
323 if (currentlyBuildingProjectsStack.Count == 0) {
324 LogBuildFinished (succeeded);
325 buildStarted = false;
329 void LogProjectStarted (Project project, string [] target_names)
331 ProjectStartedEventArgs psea;
332 if (target_names == null || target_names.Length == 0)
333 psea = new ProjectStartedEventArgs ("Project started.", null, project.FullFileName,
334 String.Empty, null, null);
335 else
336 psea = new ProjectStartedEventArgs ("Project started.", null, project.FullFileName,
337 String.Join (";", target_names), null, null);
338 eventSource.FireProjectStarted (this, psea);
341 void LogProjectFinished (Project project, bool succeeded)
343 ProjectFinishedEventArgs pfea;
344 pfea = new ProjectFinishedEventArgs ("Project started.", null, project.FullFileName, succeeded);
345 eventSource.FireProjectFinished (this, pfea);
348 void LogBuildStarted ()
350 BuildStartedEventArgs bsea;
351 bsea = new BuildStartedEventArgs ("Build started.", null);
352 eventSource.FireBuildStarted (this, bsea);
355 void LogBuildFinished (bool succeeded)
357 BuildFinishedEventArgs bfea;
358 bfea = new BuildFinishedEventArgs ("Build finished.", null, succeeded);
359 eventSource.FireBuildFinished (this, bfea);
362 void RegisterDefaultTasks ()
364 this.defaultTasksRegistered = false;
366 Project defaultTasksProject = CreateNewProject ();
368 if (binPath != null) {
369 if (File.Exists (Path.Combine (binPath, defaultTasksProjectName))) {
370 defaultTasksProject.Load (Path.Combine (binPath, defaultTasksProjectName));
371 defaultTasks = defaultTasksProject.TaskDatabase;
372 } else
373 defaultTasks = new TaskDatabase ();
374 } else
375 defaultTasks = new TaskDatabase ();
377 this.defaultTasksRegistered = true;
380 public string BinPath {
381 get { return binPath; }
382 set { binPath = value; }
385 public bool BuildEnabled {
386 get { return buildEnabled; }
387 set { buildEnabled = value; }
390 public static Version Version {
391 get { return version; }
394 public static Engine GlobalEngine {
395 get {
396 if (globalEngine == null)
397 globalEngine = new Engine ();
398 return globalEngine;
402 public BuildPropertyGroup GlobalProperties {
403 get { return global_properties; }
404 set { global_properties = value; }
407 public bool OnlyLogCriticalEvents {
408 get { return eventSource.OnlyLogCriticalEvents; }
409 set { eventSource.OnlyLogCriticalEvents = value; }
412 internal EventSource EventSource {
413 get { return eventSource; }
416 internal bool DefaultTasksRegistered {
417 get { return defaultTasksRegistered; }
420 internal TaskDatabase DefaultTasks {
421 get { return defaultTasks; }
424 internal Dictionary<string, ITaskItem[]> BuiltTargetsOutputByName {
425 get { return builtTargetsOutputByName; }
430 #endif