2 // Project.cs: Project class
5 // Marek Sieradzki (marek.sieradzki@gmail.com)
6 // Ankit Jain (jankit@novell.com)
8 // (C) 2005 Marek Sieradzki
9 // Copyright 2011 Novell, Inc (http://www.novell.com)
11 // Permission is hereby granted, free of charge, to any person obtaining
12 // a copy of this software and associated documentation files (the
13 // "Software"), to deal in the Software without restriction, including
14 // without limitation the rights to use, copy, modify, merge, publish,
15 // distribute, sublicense, and/or sell copies of the Software, and to
16 // permit persons to whom the Software is furnished to do so, subject to
17 // the following conditions:
19 // The above copyright notice and this permission notice shall be
20 // included in all copies or substantial portions of the Software.
22 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
23 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
24 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
25 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
26 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
27 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
28 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
31 using System.Collections;
32 using System.Collections.Generic;
33 using System.Collections.Specialized;
36 using System.Reflection;
39 using System.Xml.Schema;
40 using Microsoft.Build.Framework;
41 using Microsoft.Build.Utilities;
42 using Mono.XBuild.Framework;
43 using Mono.XBuild.CommandLine;
45 namespace Microsoft.Build.BuildEngine {
46 public class Project {
49 Dictionary <string, List <string>> conditionedProperties;
50 string[] defaultTargets;
52 BuildItemGroup evaluatedItems;
53 BuildItemGroup evaluatedItemsIgnoringCondition;
54 Dictionary <string, BuildItemGroup> evaluatedItemsByName;
55 Dictionary <string, BuildItemGroup> evaluatedItemsByNameIgnoringCondition;
56 BuildPropertyGroup evaluatedProperties;
57 string firstTargetName;
59 BuildPropertyGroup globalProperties;
60 GroupingCollection groupingCollection;
63 BuildItemGroupCollection itemGroups;
64 ImportCollection imports;
65 List<string> initialTargets;
66 Dictionary <string, BuildItemGroup> last_item_group_containing;
67 bool needToReevaluate;
69 BuildPropertyGroupCollection propertyGroups;
71 TaskDatabase taskDatabase;
72 TargetCollection targets;
73 DateTime timeOfLastDirty;
74 UsingTaskCollection usingTasks;
75 XmlDocument xmlDocument;
77 bool initialTargetsBuilt;
79 BuildSettings current_settings;
82 // This is used to keep track of "current" file,
83 // which is then used to set the reserved properties
84 // $(MSBuildThisFile*)
85 Stack<string> this_file_property_stack;
86 ProjectLoadSettings project_load_settings;
89 static string extensions_path;
90 static XmlNamespaceManager manager;
91 static string ns = "http://schemas.microsoft.com/developer/msbuild/2003";
94 : this (Engine.GlobalEngine)
98 public Project (Engine engine) : this (engine, null)
102 public Project (Engine engine, string toolsVersion)
104 parentEngine = engine;
105 ToolsVersion = toolsVersion;
107 buildEnabled = ParentEngine.BuildEnabled;
108 xmlDocument = new XmlDocument ();
109 xmlDocument.PreserveWhitespace = false;
110 xmlDocument.AppendChild (xmlDocument.CreateElement ("Project", XmlNamespace));
111 xmlDocument.DocumentElement.SetAttribute ("xmlns", ns);
113 fullFileName = String.Empty;
114 timeOfLastDirty = DateTime.Now;
115 current_settings = BuildSettings.None;
116 project_load_settings = ProjectLoadSettings.None;
120 initialTargets = new List<string> ();
121 defaultTargets = new string [0];
122 batches = new Stack<Batch> ();
123 this_file_property_stack = new Stack<string> ();
125 globalProperties = new BuildPropertyGroup (null, this, null, false);
126 foreach (BuildProperty bp in parentEngine.GlobalProperties)
127 GlobalProperties.AddProperty (bp.Clone (true));
133 [MonoTODO ("Not tested")]
134 public void AddNewImport (string importLocation,
135 string importCondition)
137 if (importLocation == null)
138 throw new ArgumentNullException ("importLocation");
140 XmlElement importElement = xmlDocument.CreateElement ("Import", XmlNamespace);
141 xmlDocument.DocumentElement.AppendChild (importElement);
142 importElement.SetAttribute ("Project", importLocation);
143 if (!String.IsNullOrEmpty (importCondition))
144 importElement.SetAttribute ("Condition", importCondition);
146 AddImport (importElement, null, false);
147 MarkProjectAsDirty ();
151 public BuildItem AddNewItem (string itemName,
154 return AddNewItem (itemName, itemInclude, false);
157 [MonoTODO ("Adds item not in the same place as MS")]
158 public BuildItem AddNewItem (string itemName,
160 bool treatItemIncludeAsLiteral)
164 if (itemGroups.Count == 0)
165 big = AddNewItemGroup ();
167 if (last_item_group_containing.ContainsKey (itemName)) {
168 big = last_item_group_containing [itemName];
171 BuildItemGroup [] groups = new BuildItemGroup [itemGroups.Count];
172 itemGroups.CopyTo (groups, 0);
177 BuildItem item = big.AddNewItem (itemName, itemInclude, treatItemIncludeAsLiteral);
179 MarkProjectAsDirty ();
185 [MonoTODO ("Not tested")]
186 public BuildItemGroup AddNewItemGroup ()
188 XmlElement element = xmlDocument.CreateElement ("ItemGroup", XmlNamespace);
189 xmlDocument.DocumentElement.AppendChild (element);
191 BuildItemGroup big = new BuildItemGroup (element, this, null, false);
192 itemGroups.Add (big);
193 MarkProjectAsDirty ();
199 [MonoTODO ("Ignores insertAtEndOfProject")]
200 public BuildPropertyGroup AddNewPropertyGroup (bool insertAtEndOfProject)
202 XmlElement element = xmlDocument.CreateElement ("PropertyGroup", XmlNamespace);
203 xmlDocument.DocumentElement.AppendChild (element);
205 BuildPropertyGroup bpg = new BuildPropertyGroup (element, this, null, false);
206 propertyGroups.Add (bpg);
207 MarkProjectAsDirty ();
213 [MonoTODO ("Not tested, isn't added to TaskDatabase (no reevaluation)")]
214 public void AddNewUsingTaskFromAssemblyFile (string taskName,
217 if (taskName == null)
218 throw new ArgumentNullException ("taskName");
219 if (assemblyFile == null)
220 throw new ArgumentNullException ("assemblyFile");
222 XmlElement element = xmlDocument.CreateElement ("UsingTask", XmlNamespace);
223 xmlDocument.DocumentElement.AppendChild (element);
224 element.SetAttribute ("TaskName", taskName);
225 element.SetAttribute ("AssemblyFile", assemblyFile);
227 UsingTask ut = new UsingTask (element, this, null);
229 MarkProjectAsDirty ();
232 [MonoTODO ("Not tested, isn't added to TaskDatabase (no reevaluation)")]
233 public void AddNewUsingTaskFromAssemblyName (string taskName,
236 if (taskName == null)
237 throw new ArgumentNullException ("taskName");
238 if (assemblyName == null)
239 throw new ArgumentNullException ("assemblyName");
241 XmlElement element = xmlDocument.CreateElement ("UsingTask", XmlNamespace);
242 xmlDocument.DocumentElement.AppendChild (element);
243 element.SetAttribute ("TaskName", taskName);
244 element.SetAttribute ("AssemblyName", assemblyName);
246 UsingTask ut = new UsingTask (element, this, null);
248 MarkProjectAsDirty ();
251 [MonoTODO ("Not tested")]
254 return Build (new string [0]);
257 [MonoTODO ("Not tested")]
258 public bool Build (string targetName)
260 if (targetName == null)
261 return Build ((string[]) null);
263 return Build (new string [1] { targetName });
266 [MonoTODO ("Not tested")]
267 public bool Build (string [] targetNames)
269 return Build (targetNames, null);
272 [MonoTODO ("Not tested")]
273 public bool Build (string [] targetNames,
274 IDictionary targetOutputs)
276 return Build (targetNames, targetOutputs, BuildSettings.None);
279 [MonoTODO ("Not tested")]
280 public bool Build (string [] targetNames,
281 IDictionary targetOutputs,
282 BuildSettings buildFlags)
286 ParentEngine.StartProjectBuild (this, targetNames);
288 // Invoking this to emit a warning in case of unsupported
290 GetToolsVersionToUse (true);
292 string current_directory = Environment.CurrentDirectory;
294 current_settings = buildFlags;
295 if (!String.IsNullOrEmpty (fullFileName))
296 Directory.SetCurrentDirectory (Path.GetDirectoryName (fullFileName));
298 result = BuildInternal (targetNames, targetOutputs, buildFlags);
299 } catch (InvalidProjectFileException ie) {
300 ParentEngine.LogErrorWithFilename (fullFileName, ie.Message);
301 ParentEngine.LogMessage (MessageImportance.Low, String.Format ("{0}: {1}", fullFileName, ie.ToString ()));
302 } catch (Exception e) {
303 ParentEngine.LogErrorWithFilename (fullFileName, e.Message);
304 ParentEngine.LogMessage (MessageImportance.Low, String.Format ("{0}: {1}", fullFileName, e.ToString ()));
307 ParentEngine.EndProjectBuild (this, result);
308 current_settings = BuildSettings.None;
309 Directory.SetCurrentDirectory (current_directory);
316 bool BuildInternal (string [] targetNames,
317 IDictionary targetOutputs,
318 BuildSettings buildFlags)
321 if (buildFlags == BuildSettings.None) {
322 needToReevaluate = false;
326 ProcessBeforeAndAfterTargets ();
328 if (targetNames == null || targetNames.Length == 0) {
329 if (defaultTargets != null && defaultTargets.Length != 0) {
330 targetNames = defaultTargets;
331 } else if (firstTargetName != null) {
332 targetNames = new string [1] { firstTargetName};
334 if (targets == null || targets.Count == 0) {
335 LogError (fullFileName, "No target found in the project");
343 if (!initialTargetsBuilt) {
344 foreach (string target in initialTargets) {
345 if (!BuildTarget (target.Trim (), targetOutputs))
348 initialTargetsBuilt = true;
351 foreach (string target in targetNames) {
353 throw new ArgumentNullException ("Target name cannot be null");
355 if (!BuildTarget (target.Trim (), targetOutputs))
362 bool BuildTarget (string target_name, IDictionary targetOutputs)
364 if (target_name == null)
365 throw new ArgumentException ("targetNames cannot contain null strings");
367 if (!targets.Exists (target_name)) {
368 LogError (fullFileName, "Target named '{0}' not found in the project.", target_name);
372 string key = GetKeyForTarget (target_name);
373 if (!targets [target_name].Build (key))
377 if (ParentEngine.BuiltTargetsOutputByName.TryGetValue (key, out outputs)) {
378 if (targetOutputs != null)
379 targetOutputs.Add (target_name, outputs);
384 internal string GetKeyForTarget (string target_name)
386 return GetKeyForTarget (target_name, true);
389 internal string GetKeyForTarget (string target_name, bool include_global_properties)
391 // target name is case insensitive
392 return fullFileName + ":" + target_name.ToLowerInvariant () +
393 (include_global_properties ? (":" + GlobalPropertiesToString (GlobalProperties))
397 string GlobalPropertiesToString (BuildPropertyGroup bgp)
399 StringBuilder sb = new StringBuilder ();
400 foreach (BuildProperty bp in bgp)
401 sb.AppendFormat (" {0}:{1}", bp.Name, bp.FinalValue);
402 return sb.ToString ();
405 void ProcessBeforeAndAfterTargets ()
407 var beforeTable = Targets.AsIEnumerable ()
408 .SelectMany (target => GetTargetNamesFromString (target.BeforeTargets),
409 (target, before_target) => new {before_target, name = target.Name})
410 .ToLookup (x => x.before_target, x => x.name)
411 .ToDictionary (x => x.Key, x => x.Distinct ().ToList ());
413 foreach (var pair in beforeTable) {
414 if (targets.Exists (pair.Key))
415 targets [pair.Key].BeforeThisTargets = pair.Value;
417 LogWarning (FullFileName, "Target '{0}', not found in the project", pair.Key);
420 var afterTable = Targets.AsIEnumerable ()
421 .SelectMany (target => GetTargetNamesFromString (target.AfterTargets),
422 (target, after_target) => new {after_target, name = target.Name})
423 .ToLookup (x => x.after_target, x => x.name)
424 .ToDictionary (x => x.Key, x => x.Distinct ().ToList ());
426 foreach (var pair in afterTable) {
427 if (targets.Exists (pair.Key))
428 targets [pair.Key].AfterThisTargets = pair.Value;
430 LogWarning (FullFileName, "Target '{0}', not found in the project", pair.Key);
434 string[] GetTargetNamesFromString (string targets)
436 Expression expr = new Expression ();
437 expr.Parse (targets, ParseOptions.AllowItemsNoMetadataAndSplit);
438 return (string []) expr.ConvertTo (this, typeof (string []));
442 public string [] GetConditionedPropertyValues (string propertyName)
444 if (conditionedProperties.ContainsKey (propertyName))
445 return conditionedProperties [propertyName].ToArray ();
447 return new string [0];
450 public BuildItemGroup GetEvaluatedItemsByName (string itemName)
452 if (needToReevaluate) {
453 needToReevaluate = false;
457 if (evaluatedItemsByName.ContainsKey (itemName))
458 return evaluatedItemsByName [itemName];
460 return new BuildItemGroup (this);
463 public BuildItemGroup GetEvaluatedItemsByNameIgnoringCondition (string itemName)
465 if (needToReevaluate) {
466 needToReevaluate = false;
470 if (evaluatedItemsByNameIgnoringCondition.ContainsKey (itemName))
471 return evaluatedItemsByNameIgnoringCondition [itemName];
473 return new BuildItemGroup (this);
476 public string GetEvaluatedProperty (string propertyName)
478 if (needToReevaluate) {
479 needToReevaluate = false;
483 if (propertyName == null)
484 throw new ArgumentNullException ("propertyName");
486 BuildProperty bp = evaluatedProperties [propertyName];
488 return bp == null ? null : (string) bp;
491 [MonoTODO ("We should remember that node and not use XPath to get it")]
492 public string GetProjectExtensions (string id)
494 if (id == null || id == String.Empty)
497 XmlNode node = xmlDocument.SelectSingleNode (String.Format ("/tns:Project/tns:ProjectExtensions/tns:{0}", id), XmlNamespaceManager);
502 return node.InnerXml;
506 public void Load (string projectFileName)
508 Load (projectFileName, ProjectLoadSettings.None);
511 public void Load (string projectFileName, ProjectLoadSettings settings)
513 project_load_settings = settings;
514 if (String.IsNullOrEmpty (projectFileName))
515 throw new ArgumentNullException ("projectFileName");
517 if (!File.Exists (projectFileName))
518 throw new ArgumentException (String.Format ("Project file {0} not found", projectFileName),
521 this.fullFileName = Utilities.FromMSBuildPath (Path.GetFullPath (projectFileName));
522 PushThisFileProperty (fullFileName);
524 string filename = fullFileName;
525 if (String.Compare (Path.GetExtension (fullFileName), ".sln", true) == 0) {
526 Project tmp_project = ParentEngine.CreateNewProject ();
527 tmp_project.FullFileName = filename;
528 SolutionParser sln_parser = new SolutionParser ();
529 sln_parser.ParseSolution (fullFileName, tmp_project, delegate (int errorNumber, string message) {
530 LogWarning (filename, message);
532 filename = fullFileName + ".proj";
534 tmp_project.Save (filename);
535 ParentEngine.RemoveLoadedProject (tmp_project);
536 DoLoad (new StreamReader (filename));
538 if (Environment.GetEnvironmentVariable ("XBUILD_EMIT_SOLUTION") == null)
539 File.Delete (filename);
542 DoLoad (new StreamReader (filename));
546 [MonoTODO ("Not tested")]
547 public void Load (TextReader textReader)
549 Load (textReader, ProjectLoadSettings.None);
552 public void Load (TextReader textReader, ProjectLoadSettings projectLoadSettings)
554 project_load_settings = projectLoadSettings;
555 if (!string.IsNullOrEmpty (fullFileName))
556 PushThisFileProperty (fullFileName);
560 public void LoadXml (string projectXml)
562 LoadXml (projectXml, ProjectLoadSettings.None);
565 public void LoadXml (string projectXml, ProjectLoadSettings projectLoadSettings)
567 project_load_settings = projectLoadSettings;
568 if (!string.IsNullOrEmpty (fullFileName))
569 PushThisFileProperty (fullFileName);
570 DoLoad (new StringReader (projectXml));
571 MarkProjectAsDirty ();
575 public void MarkProjectAsDirty ()
578 timeOfLastDirty = DateTime.Now;
581 [MonoTODO ("Not tested")]
582 public void RemoveAllItemGroups ()
584 int length = ItemGroups.Count;
585 BuildItemGroup [] groups = new BuildItemGroup [length];
586 ItemGroups.CopyTo (groups, 0);
588 for (int i = 0; i < length; i++)
589 RemoveItemGroup (groups [i]);
591 MarkProjectAsDirty ();
595 [MonoTODO ("Not tested")]
596 public void RemoveAllPropertyGroups ()
598 int length = PropertyGroups.Count;
599 BuildPropertyGroup [] groups = new BuildPropertyGroup [length];
600 PropertyGroups.CopyTo (groups, 0);
602 for (int i = 0; i < length; i++)
603 RemovePropertyGroup (groups [i]);
605 MarkProjectAsDirty ();
610 public void RemoveItem (BuildItem itemToRemove)
612 if (itemToRemove == null)
613 throw new ArgumentNullException ("itemToRemove");
615 if (!itemToRemove.FromXml && !itemToRemove.HasParentItem)
616 throw new InvalidOperationException ("The object passed in is not part of the project.");
618 BuildItemGroup big = itemToRemove.ParentItemGroup;
620 if (big.Count == 1) {
621 // ParentItemGroup for items from xml and that have parent is the same
622 groupingCollection.Remove (big);
624 if (big.ParentProject != this)
625 throw new InvalidOperationException ("The object passed in is not part of the project.");
627 if (itemToRemove.FromXml)
628 big.RemoveItem (itemToRemove);
630 big.RemoveItem (itemToRemove.ParentItem);
633 MarkProjectAsDirty ();
637 [MonoTODO ("Not tested")]
638 public void RemoveItemGroup (BuildItemGroup itemGroupToRemove)
640 if (itemGroupToRemove == null)
641 throw new ArgumentNullException ("itemGroupToRemove");
643 groupingCollection.Remove (itemGroupToRemove);
644 MarkProjectAsDirty ();
648 // NOTE: does not modify imported projects
649 public void RemoveItemGroupsWithMatchingCondition (string matchingCondition)
651 throw new NotImplementedException ();
655 public void RemoveItemsByName (string itemName)
657 if (itemName == null)
658 throw new ArgumentNullException ("itemName");
660 throw new NotImplementedException ();
663 [MonoTODO ("Not tested")]
664 public void RemovePropertyGroup (BuildPropertyGroup propertyGroupToRemove)
666 if (propertyGroupToRemove == null)
667 throw new ArgumentNullException ("propertyGroupToRemove");
669 groupingCollection.Remove (propertyGroupToRemove);
670 MarkProjectAsDirty ();
674 // NOTE: does not modify imported projects
675 public void RemovePropertyGroupsWithMatchingCondition (string matchCondition)
677 throw new NotImplementedException ();
681 public void ResetBuildStatus ()
683 // hack to allow built targets to be removed
689 public void Save (string projectFileName)
691 Save (projectFileName, Encoding.Default);
695 [MonoTODO ("Ignores encoding")]
696 public void Save (string projectFileName, Encoding encoding)
698 xmlDocument.Save (projectFileName);
702 public void Save (TextWriter outTextWriter)
704 xmlDocument.Save (outTextWriter);
708 public void SetImportedProperty (string propertyName,
709 string propertyValue,
711 Project importProject)
713 SetImportedProperty (propertyName, propertyValue, condition, importProject,
714 PropertyPosition.UseExistingOrCreateAfterLastPropertyGroup);
717 public void SetImportedProperty (string propertyName,
718 string propertyValue,
720 Project importedProject,
721 PropertyPosition position)
723 SetImportedProperty (propertyName, propertyValue, condition, importedProject,
724 PropertyPosition.UseExistingOrCreateAfterLastPropertyGroup, false);
728 public void SetImportedProperty (string propertyName,
729 string propertyValue,
731 Project importedProject,
732 PropertyPosition position,
733 bool treatPropertyValueAsLiteral)
735 throw new NotImplementedException ();
738 public void SetProjectExtensions (string id, string xmlText)
741 throw new ArgumentNullException ("id");
743 throw new ArgumentNullException ("xmlText");
745 XmlNode projectExtensions, node;
747 projectExtensions = xmlDocument.SelectSingleNode ("/tns:Project/tns:ProjectExtensions", XmlNamespaceManager);
749 if (projectExtensions == null) {
750 projectExtensions = xmlDocument.CreateElement ("ProjectExtensions", XmlNamespace);
751 xmlDocument.DocumentElement.AppendChild (projectExtensions);
753 node = xmlDocument.CreateElement (id, XmlNamespace);
754 node.InnerXml = xmlText;
755 projectExtensions.AppendChild (node);
757 node = xmlDocument.SelectSingleNode (String.Format ("/tns:Project/tns:ProjectExtensions/tns:{0}", id), XmlNamespaceManager);
760 node = xmlDocument.CreateElement (id, XmlNamespace);
761 projectExtensions.AppendChild (node);
764 node.InnerXml = xmlText;
768 MarkProjectAsDirty ();
771 public void SetProperty (string propertyName,
772 string propertyValue)
774 SetProperty (propertyName, propertyValue, "true",
775 PropertyPosition.UseExistingOrCreateAfterLastPropertyGroup, false);
778 public void SetProperty (string propertyName,
779 string propertyValue,
782 SetProperty (propertyName, propertyValue, condition,
783 PropertyPosition.UseExistingOrCreateAfterLastPropertyGroup);
786 public void SetProperty (string propertyName,
787 string propertyValue,
789 PropertyPosition position)
791 SetProperty (propertyName, propertyValue, condition,
792 PropertyPosition.UseExistingOrCreateAfterLastPropertyGroup, false);
796 public void SetProperty (string propertyName,
797 string propertyValue,
799 PropertyPosition position,
800 bool treatPropertyValueAsLiteral)
802 throw new NotImplementedException ();
805 internal void Unload ()
810 internal void CheckUnloaded ()
813 throw new InvalidOperationException ("This project object has been unloaded from the MSBuild engine and is no longer valid.");
816 internal void NeedToReevaluate ()
818 needToReevaluate = true;
821 // Does the actual loading.
822 void DoLoad (TextReader textReader)
825 ParentEngine.RemoveLoadedProject (this);
827 xmlDocument.Load (textReader);
829 if (xmlDocument.DocumentElement.Name == "VisualStudioProject")
830 throw new InvalidProjectFileException (String.Format (
831 "Project file '{0}' is a VS2003 project, which is not " +
832 "supported by xbuild. You need to convert it to msbuild " +
833 "format to build with xbuild.", fullFileName));
835 if (SchemaFile != null) {
836 xmlDocument.Schemas.Add (XmlSchema.Read (
837 new StreamReader (SchemaFile), ValidationCallBack));
838 xmlDocument.Validate (ValidationCallBack);
841 if (xmlDocument.DocumentElement.Name != "Project") {
842 throw new InvalidProjectFileException (String.Format (
843 "The element <{0}> is unrecognized, or not supported in this context.", xmlDocument.DocumentElement.Name));
846 if (xmlDocument.DocumentElement.GetAttribute ("xmlns") != ns) {
847 throw new InvalidProjectFileException (
848 @"The default XML namespace of the project must be the MSBuild XML namespace." +
849 " If the project is authored in the MSBuild 2003 format, please add " +
850 "xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\" to the <Project> element. " +
851 "If the project has been authored in the old 1.0 or 1.2 format, please convert it to MSBuild 2003 format. ");
854 ParentEngine.AddLoadedProject (this);
855 } catch (Exception e) {
856 throw new InvalidProjectFileException (String.Format ("{0}: {1}",
857 fullFileName, e.Message), e);
859 if (textReader != null)
871 groupingCollection = new GroupingCollection (this);
872 imports = new ImportCollection (groupingCollection);
873 usingTasks = new UsingTaskCollection (this);
874 itemGroups = new BuildItemGroupCollection (groupingCollection);
875 propertyGroups = new BuildPropertyGroupCollection (groupingCollection);
876 targets = new TargetCollection (this);
877 last_item_group_containing = new Dictionary <string, BuildItemGroup> ();
879 string effective_tools_version = GetToolsVersionToUse (false);
880 taskDatabase = new TaskDatabase ();
881 taskDatabase.CopyTasks (ParentEngine.GetDefaultTasks (effective_tools_version));
883 initialTargets = new List<string> ();
884 defaultTargets = new string [0];
885 PrepareForEvaluate (effective_tools_version);
886 ProcessElements (xmlDocument.DocumentElement, null);
892 void ProcessProjectAttributes (XmlAttributeCollection attributes)
894 foreach (XmlAttribute attr in attributes) {
896 case "InitialTargets":
897 initialTargets.AddRange (attr.Value.Split (
898 new char [] {';', ' '},
899 StringSplitOptions.RemoveEmptyEntries));
901 case "DefaultTargets":
902 // first non-empty DefaultTargets found is used
903 if (defaultTargets == null || defaultTargets.Length == 0)
904 defaultTargets = attr.Value.Split (new char [] {';', ' '},
905 StringSplitOptions.RemoveEmptyEntries);
906 EvaluatedProperties.AddProperty (new BuildProperty ("MSBuildProjectDefaultTargets",
907 DefaultTargets, PropertyType.Reserved));
913 internal void ProcessElements (XmlElement rootElement, ImportedProject ip)
915 ProcessProjectAttributes (rootElement.Attributes);
916 foreach (XmlNode xn in rootElement.ChildNodes) {
917 if (xn is XmlElement) {
918 XmlElement xe = (XmlElement) xn;
920 case "ProjectExtensions":
921 AddProjectExtensions (xe);
932 AddUsingTask (xe, ip);
935 AddImport (xe, ip, true);
938 AddImportGroup (xe, ip, true);
941 AddItemGroup (xe, ip);
943 case "PropertyGroup":
944 AddPropertyGroup (xe, ip);
949 case "ItemDefinitionGroup":
950 AddItemDefinitionGroup (xe);
953 var pf = ip == null ? null : string.Format (" '{0}'", ip.FullFileName);
954 throw new InvalidProjectFileException (String.Format ("Invalid element '{0}' in project file{1}.", xe.Name, pf));
960 void PrepareForEvaluate (string effective_tools_version)
962 evaluatedItems = new BuildItemGroup (null, this, null, true);
963 evaluatedItemsIgnoringCondition = new BuildItemGroup (null, this, null, true);
964 evaluatedItemsByName = new Dictionary <string, BuildItemGroup> (StringComparer.OrdinalIgnoreCase);
965 evaluatedItemsByNameIgnoringCondition = new Dictionary <string, BuildItemGroup> (StringComparer.OrdinalIgnoreCase);
966 if (building && current_settings == BuildSettings.None)
967 RemoveBuiltTargets ();
969 InitializeProperties (effective_tools_version);
974 groupingCollection.Evaluate ();
976 //FIXME: UsingTasks aren't really evaluated. (shouldn't use expressions or anything)
977 foreach (UsingTask usingTask in UsingTasks)
978 usingTask.Evaluate ();
981 // Removes entries of all earlier built targets for this project
982 void RemoveBuiltTargets ()
984 ParentEngine.ClearBuiltTargetsForProject (this);
987 void InitializeProperties (string effective_tools_version)
991 evaluatedProperties = new BuildPropertyGroup (null, null, null, true);
992 conditionedProperties = new Dictionary<string, List<string>> ();
994 foreach (BuildProperty gp in GlobalProperties) {
995 bp = new BuildProperty (gp.Name, gp.Value, PropertyType.Global);
996 evaluatedProperties.AddProperty (bp);
999 foreach (BuildProperty gp in GlobalProperties)
1000 ParentEngine.GlobalProperties.AddProperty (gp);
1002 // add properties that we dont have from parent engine's
1003 // global properties
1004 foreach (BuildProperty gp in ParentEngine.GlobalProperties) {
1005 if (evaluatedProperties [gp.Name] == null) {
1006 bp = new BuildProperty (gp.Name, gp.Value, PropertyType.Global);
1007 evaluatedProperties.AddProperty (bp);
1011 foreach (DictionaryEntry de in Environment.GetEnvironmentVariables ()) {
1012 bp = new BuildProperty ((string) de.Key, (string) de.Value, PropertyType.Environment);
1013 evaluatedProperties.AddProperty (bp);
1016 evaluatedProperties.AddProperty (new BuildProperty ("MSBuildProjectFile", Path.GetFileName (fullFileName),
1017 PropertyType.Reserved));
1018 evaluatedProperties.AddProperty (new BuildProperty ("MSBuildProjectFullPath", fullFileName, PropertyType.Reserved));
1019 evaluatedProperties.AddProperty (new BuildProperty ("MSBuildProjectName",
1020 Path.GetFileNameWithoutExtension (fullFileName),
1021 PropertyType.Reserved));
1022 evaluatedProperties.AddProperty (new BuildProperty ("MSBuildProjectExtension",
1023 Path.GetExtension (fullFileName),
1024 PropertyType.Reserved));
1026 string toolsPath = parentEngine.Toolsets [effective_tools_version].ToolsPath;
1027 if (toolsPath == null)
1028 throw new Exception (String.Format ("Invalid tools version '{0}', no tools path set for this.", effective_tools_version));
1029 evaluatedProperties.AddProperty (new BuildProperty ("MSBuildBinPath", toolsPath, PropertyType.Reserved));
1030 evaluatedProperties.AddProperty (new BuildProperty ("MSBuildToolsPath", toolsPath, PropertyType.Reserved));
1031 evaluatedProperties.AddProperty (new BuildProperty ("MSBuildToolsRoot", Path.GetDirectoryName (toolsPath), PropertyType.Reserved));
1032 evaluatedProperties.AddProperty (new BuildProperty ("MSBuildToolsVersion", effective_tools_version, PropertyType.Reserved));
1033 SetExtensionsPathProperties (DefaultExtensionsPath);
1034 evaluatedProperties.AddProperty (new BuildProperty ("MSBuildProjectDefaultTargets", DefaultTargets, PropertyType.Reserved));
1035 evaluatedProperties.AddProperty (new BuildProperty ("OS", OS, PropertyType.Environment));
1037 // see http://msdn.microsoft.com/en-us/library/vstudio/hh162058(v=vs.120).aspx
1038 if (effective_tools_version == "12.0" || effective_tools_version == "14.0") {
1039 evaluatedProperties.AddProperty (new BuildProperty ("MSBuildToolsPath32", toolsPath, PropertyType.Reserved));
1041 var frameworkToolsPath = ToolLocationHelper.GetPathToDotNetFramework (TargetDotNetFrameworkVersion.Version451);
1043 evaluatedProperties.AddProperty (new BuildProperty ("MSBuildFrameworkToolsPath", frameworkToolsPath, PropertyType.Reserved));
1044 evaluatedProperties.AddProperty (new BuildProperty ("MSBuildFrameworkToolsPath32", frameworkToolsPath, PropertyType.Reserved));
1047 // FIXME: make some internal method that will work like GetDirectoryName but output String.Empty on null/String.Empty
1049 if (FullFileName == String.Empty)
1050 projectDir = Environment.CurrentDirectory;
1052 projectDir = Path.GetDirectoryName (FullFileName);
1054 evaluatedProperties.AddProperty (new BuildProperty ("MSBuildProjectDirectory", projectDir, PropertyType.Reserved));
1056 if (this_file_property_stack.Count > 0)
1057 // Just re-inited the properties, but according to the stack,
1058 // we should have a MSBuild*This* property set
1059 SetMSBuildThisFileProperties (this_file_property_stack.Peek ());
1062 internal void SetExtensionsPathProperties (string extn_path)
1064 if (!String.IsNullOrEmpty (extn_path)) {
1065 evaluatedProperties.AddProperty (new BuildProperty ("MSBuildExtensionsPath", extn_path, PropertyType.Reserved));
1066 evaluatedProperties.AddProperty (new BuildProperty ("MSBuildExtensionsPath32", extn_path, PropertyType.Reserved));
1067 evaluatedProperties.AddProperty (new BuildProperty ("MSBuildExtensionsPath64", extn_path, PropertyType.Reserved));
1072 // ToolsVersion property
1073 // ToolsVersion attribute on the project
1074 // parentEngine's DefaultToolsVersion
1075 string GetToolsVersionToUse (bool emitWarning)
1077 if (!String.IsNullOrEmpty (ToolsVersion))
1078 return ToolsVersion;
1085 if (!HasToolsVersionAttribute)
1086 return parentEngine.DefaultToolsVersion;
1088 if (parentEngine.Toolsets [DefaultToolsVersion] == null) {
1090 LogWarning (FullFileName, "Project has unknown ToolsVersion '{0}'. Using the default tools version '{1}' instead.",
1091 DefaultToolsVersion, parentEngine.DefaultToolsVersion);
1092 return parentEngine.DefaultToolsVersion;
1095 return DefaultToolsVersion;
1099 void AddProjectExtensions (XmlElement xmlElement)
1103 void AddMessage (XmlElement xmlElement)
1107 void AddTarget (XmlElement xmlElement, ImportedProject importedProject)
1109 Target target = new Target (xmlElement, this, importedProject);
1110 targets.AddTarget (target);
1112 if (firstTargetName == null)
1113 firstTargetName = target.Name;
1116 void AddUsingTask (XmlElement xmlElement, ImportedProject importedProject)
1118 UsingTask usingTask;
1120 usingTask = new UsingTask (xmlElement, this, importedProject);
1121 UsingTasks.Add (usingTask);
1124 void AddImport (XmlElement xmlElement, ImportedProject importingProject, bool evaluate_properties)
1126 // eval all the properties etc till the import
1127 if (evaluate_properties) {
1128 groupingCollection.Evaluate (EvaluationType.Property | EvaluationType.Choose);
1131 PushThisFileProperty (importingProject != null ? importingProject.FullFileName : FullFileName);
1133 string project_attribute = xmlElement.GetAttribute ("Project");
1134 if (String.IsNullOrEmpty (project_attribute))
1135 throw new InvalidProjectFileException ("The required attribute \"Project\" is missing from element <Import>.");
1137 Import.ForEachExtensionPathTillFound (xmlElement, this, importingProject,
1138 (importPath, from_source_msg) => AddSingleImport (xmlElement, importPath, importingProject, from_source_msg));
1140 PopThisFileProperty ();
1144 void AddImportGroup (XmlElement xmlElement, ImportedProject importedProject, bool evaluate_properties)
1146 // eval all the properties etc till the import group
1147 if (evaluate_properties) {
1148 groupingCollection.Evaluate (EvaluationType.Property | EvaluationType.Choose);
1150 string condition_attribute = xmlElement.GetAttribute ("Condition");
1151 if (!ConditionParser.ParseAndEvaluate (condition_attribute, this))
1153 foreach (XmlNode xn in xmlElement.ChildNodes) {
1154 if (xn is XmlElement) {
1155 XmlElement xe = (XmlElement) xn;
1158 AddImport (xe, importedProject, evaluate_properties);
1161 throw new InvalidProjectFileException(String.Format("Invalid element '{0}' inside ImportGroup in project file '{1}'.", xe.Name, importedProject.FullFileName));
1167 void AddItemDefinitionGroup (XmlElement xmlElement)
1169 string condition_attribute = xmlElement.GetAttribute ("Condition");
1170 if (!ConditionParser.ParseAndEvaluate (condition_attribute, this))
1173 foreach (XmlNode xn in xmlElement.ChildNodes) {
1174 // TODO: Add all nodes to some internal dictionary?
1178 bool AddSingleImport (XmlElement xmlElement, string projectPath, ImportedProject importingProject, string from_source_msg)
1180 Import import = new Import (xmlElement, projectPath, this, importingProject);
1181 if (!ConditionParser.ParseAndEvaluate (import.Condition, this)) {
1182 ParentEngine.LogMessage (MessageImportance.Low,
1183 "Not importing project '{0}' as the condition '{1}' is false",
1184 import.ProjectPath, import.Condition);
1188 Import existingImport;
1189 if (Imports.TryGetImport (import, out existingImport)) {
1190 if (importingProject == null)
1191 LogWarning (fullFileName,
1192 "Cannot import project '{0}' again. It was already imported by " +
1194 projectPath, existingImport.ContainedInProjectFileName);
1196 LogWarning (importingProject != null ? importingProject.FullFileName : fullFileName,
1197 "A circular reference was found involving the import of '{0}'. " +
1198 "It was earlier imported by '{1}'. Only " +
1199 "the first import of this file will be used, ignoring others.",
1200 import.EvaluatedProjectPath, existingImport.ContainedInProjectFileName);
1205 if (String.Compare (fullFileName, import.EvaluatedProjectPath) == 0) {
1206 LogWarning (importingProject != null ? importingProject.FullFileName : fullFileName,
1207 "The main project file was imported here, which creates a circular " +
1208 "reference. Ignoring this import.");
1213 if (project_load_settings != ProjectLoadSettings.IgnoreMissingImports &&
1214 !import.CheckEvaluatedProjectPathExists ())
1217 Imports.Add (import);
1218 string importingFile = importingProject != null ? importingProject.FullFileName : FullFileName;
1219 ParentEngine.LogMessage (MessageImportance.Low,
1220 "{0}: Importing project {1} {2}",
1221 importingFile, import.EvaluatedProjectPath, from_source_msg);
1223 import.Evaluate (project_load_settings == ProjectLoadSettings.IgnoreMissingImports);
1227 void AddItemGroup (XmlElement xmlElement, ImportedProject importedProject)
1229 BuildItemGroup big = new BuildItemGroup (xmlElement, this, importedProject, false);
1230 ItemGroups.Add (big);
1233 void AddPropertyGroup (XmlElement xmlElement, ImportedProject importedProject)
1235 BuildPropertyGroup bpg = new BuildPropertyGroup (xmlElement, this, importedProject, false);
1236 PropertyGroups.Add (bpg);
1239 void AddChoose (XmlElement xmlElement, ImportedProject importedProject)
1241 BuildChoose bc = new BuildChoose (xmlElement, this, importedProject);
1242 groupingCollection.Add (bc);
1245 static void ValidationCallBack (object sender, ValidationEventArgs e)
1247 Console.WriteLine ("Validation Error: {0}", e.Message);
1250 public bool BuildEnabled {
1252 return buildEnabled;
1255 buildEnabled = value;
1260 public Encoding Encoding {
1261 get { return encoding; }
1264 public string DefaultTargets {
1266 return String.Join ("; ", defaultTargets);
1269 xmlDocument.DocumentElement.SetAttribute ("DefaultTargets", value);
1271 defaultTargets = value.Split (new char [] {';', ' '},
1272 StringSplitOptions.RemoveEmptyEntries);
1276 public BuildItemGroup EvaluatedItems {
1278 if (needToReevaluate) {
1279 needToReevaluate = false;
1282 return evaluatedItems;
1286 public BuildItemGroup EvaluatedItemsIgnoringCondition {
1288 if (needToReevaluate) {
1289 needToReevaluate = false;
1292 return evaluatedItemsIgnoringCondition;
1296 internal IDictionary <string, BuildItemGroup> EvaluatedItemsByName {
1298 // FIXME: do we need to do this here?
1299 if (needToReevaluate) {
1300 needToReevaluate = false;
1303 return evaluatedItemsByName;
1307 internal IEnumerable EvaluatedItemsByNameAsDictionaryEntries {
1309 if (EvaluatedItemsByName.Count == 0)
1312 foreach (KeyValuePair<string, BuildItemGroup> pair in EvaluatedItemsByName) {
1313 foreach (BuildItem bi in pair.Value)
1314 yield return new DictionaryEntry (pair.Key, bi.ConvertToITaskItem (null, ExpressionOptions.ExpandItemRefs));
1319 internal IDictionary <string, BuildItemGroup> EvaluatedItemsByNameIgnoringCondition {
1321 // FIXME: do we need to do this here?
1322 if (needToReevaluate) {
1323 needToReevaluate = false;
1326 return evaluatedItemsByNameIgnoringCondition;
1330 // For batching implementation
1331 Dictionary<string, BuildItemGroup> perBatchItemsByName;
1332 Dictionary<string, BuildItemGroup> commonItemsByName;
1335 public Dictionary<string, BuildItemGroup> perBatchItemsByName;
1336 public Dictionary<string, BuildItemGroup> commonItemsByName;
1338 public Batch (Dictionary<string, BuildItemGroup> perBatchItemsByName, Dictionary<string, BuildItemGroup> commonItemsByName)
1340 this.perBatchItemsByName = perBatchItemsByName;
1341 this.commonItemsByName = commonItemsByName;
1345 Stack<Batch> Batches {
1346 get { return batches; }
1349 internal void PushBatch (Dictionary<string, BuildItemGroup> perBatchItemsByName, Dictionary<string, BuildItemGroup> commonItemsByName)
1351 batches.Push (new Batch (perBatchItemsByName, commonItemsByName));
1352 SetBatchedItems (perBatchItemsByName, commonItemsByName);
1355 internal void PopBatch ()
1358 if (batches.Count > 0) {
1359 Batch b = batches.Peek ();
1360 SetBatchedItems (b.perBatchItemsByName, b.commonItemsByName);
1362 SetBatchedItems (null, null);
1366 void SetBatchedItems (Dictionary<string, BuildItemGroup> perBatchItemsByName, Dictionary<string, BuildItemGroup> commonItemsByName)
1368 this.perBatchItemsByName = perBatchItemsByName;
1369 this.commonItemsByName = commonItemsByName;
1373 internal bool TryGetEvaluatedItemByNameBatched (string itemName, out BuildItemGroup group)
1375 if (perBatchItemsByName != null && perBatchItemsByName.TryGetValue (itemName, out group))
1378 if (commonItemsByName != null && commonItemsByName.TryGetValue (itemName, out group))
1382 return EvaluatedItemsByName.TryGetValue (itemName, out group);
1385 internal string GetMetadataBatched (string itemName, string metadataName)
1387 BuildItemGroup group = null;
1388 if (itemName == null) {
1389 //unqualified, all items in a batch(bucket) have the
1390 //same metadata values
1391 group = GetFirst<BuildItemGroup> (perBatchItemsByName.Values);
1393 group = GetFirst<BuildItemGroup> (commonItemsByName.Values);
1396 TryGetEvaluatedItemByNameBatched (itemName, out group);
1399 if (group != null) {
1400 foreach (BuildItem item in group) {
1401 if (item.HasMetadata (metadataName))
1402 return item.GetEvaluatedMetadata (metadataName);
1405 return String.Empty;
1408 internal IEnumerable<BuildItemGroup> GetAllItemGroups ()
1410 if (perBatchItemsByName == null && commonItemsByName == null)
1411 foreach (BuildItemGroup group in EvaluatedItemsByName.Values)
1414 if (perBatchItemsByName != null)
1415 foreach (BuildItemGroup group in perBatchItemsByName.Values)
1418 if (commonItemsByName != null)
1419 foreach (BuildItemGroup group in commonItemsByName.Values)
1423 T GetFirst<T> (ICollection<T> list)
1428 foreach (T t in list)
1434 internal string ThisFileFullPath {
1435 get { return this_file_property_stack.Peek (); }
1438 // Used for MSBuild*This* set of properties
1439 internal void PushThisFileProperty (string full_filename)
1441 string last_file = this_file_property_stack.Count == 0 ? String.Empty : this_file_property_stack.Peek ();
1442 this_file_property_stack.Push (full_filename);
1443 if (last_file != full_filename)
1444 // first time, or different from previous one
1445 SetMSBuildThisFileProperties (full_filename);
1448 internal void PopThisFileProperty ()
1450 string last_file = this_file_property_stack.Pop ();
1451 if (this_file_property_stack.Count > 0 && last_file != this_file_property_stack.Peek ())
1452 SetMSBuildThisFileProperties (this_file_property_stack.Peek ());
1455 void SetMSBuildThisFileProperties (string full_filename)
1457 if (String.IsNullOrEmpty (full_filename))
1460 evaluatedProperties.AddProperty (new BuildProperty ("MSBuildThisFile", Path.GetFileName (full_filename), PropertyType.Reserved));
1461 evaluatedProperties.AddProperty (new BuildProperty ("MSBuildThisFileFullPath", full_filename, PropertyType.Reserved));
1462 evaluatedProperties.AddProperty (new BuildProperty ("MSBuildThisFileName", Path.GetFileNameWithoutExtension (full_filename), PropertyType.Reserved));
1463 evaluatedProperties.AddProperty (new BuildProperty ("MSBuildThisFileExtension", Path.GetExtension (full_filename), PropertyType.Reserved));
1465 string project_dir = Path.GetDirectoryName (full_filename) + Path.DirectorySeparatorChar;
1466 evaluatedProperties.AddProperty (new BuildProperty ("MSBuildThisFileDirectory", project_dir, PropertyType.Reserved));
1467 evaluatedProperties.AddProperty (new BuildProperty ("MSBuildThisFileDirectoryNoRoot",
1468 project_dir.Substring (Path.GetPathRoot (project_dir).Length),
1469 PropertyType.Reserved));
1473 internal void LogWarning (string filename, string message, params object[] messageArgs)
1475 BuildWarningEventArgs bwea = new BuildWarningEventArgs (
1476 null, null, filename, 0, 0, 0, 0, String.Format (message, messageArgs),
1478 ParentEngine.EventSource.FireWarningRaised (this, bwea);
1481 internal void LogError (string filename, string message,
1482 params object[] messageArgs)
1484 BuildErrorEventArgs beea = new BuildErrorEventArgs (
1485 null, null, filename, 0, 0, 0, 0, String.Format (message, messageArgs),
1487 ParentEngine.EventSource.FireErrorRaised (this, beea);
1490 internal static string DefaultExtensionsPath {
1492 if (extensions_path == null) {
1493 // NOTE: code from mcs/tools/gacutil/driver.cs
1494 PropertyInfo gac = typeof (System.Environment).GetProperty (
1495 "GacPath", BindingFlags.Static | BindingFlags.NonPublic);
1498 MethodInfo get_gac = gac.GetGetMethod (true);
1499 string gac_path = (string) get_gac.Invoke (null, null);
1500 extensions_path = Path.GetFullPath (Path.Combine (
1501 gac_path, Path.Combine ("..", "xbuild")));
1504 return extensions_path;
1508 public BuildPropertyGroup EvaluatedProperties {
1510 if (needToReevaluate) {
1511 needToReevaluate = false;
1514 return evaluatedProperties;
1518 internal IEnumerable EvaluatedPropertiesAsDictionaryEntries {
1520 foreach (BuildProperty bp in EvaluatedProperties)
1521 yield return new DictionaryEntry (bp.Name, bp.Value);
1525 public string FullFileName {
1526 get { return fullFileName; }
1527 set { fullFileName = value; }
1530 public BuildPropertyGroup GlobalProperties {
1531 get { return globalProperties; }
1534 throw new ArgumentNullException ("value");
1537 throw new InvalidOperationException ("GlobalProperties can not be set to persisted property group.");
1539 globalProperties = value;
1543 public bool IsDirty {
1544 get { return isDirty; }
1547 public bool IsValidated {
1548 get { return isValidated; }
1549 set { isValidated = value; }
1552 public BuildItemGroupCollection ItemGroups {
1553 get { return itemGroups; }
1556 public ImportCollection Imports {
1557 get { return imports; }
1560 public string InitialTargets {
1562 return String.Join ("; ", initialTargets.ToArray ());
1565 initialTargets.Clear ();
1566 xmlDocument.DocumentElement.SetAttribute ("InitialTargets", value);
1568 initialTargets.AddRange (value.Split (
1569 new char [] {';', ' '}, StringSplitOptions.RemoveEmptyEntries));
1573 public Engine ParentEngine {
1574 get { return parentEngine; }
1577 public BuildPropertyGroupCollection PropertyGroups {
1578 get { return propertyGroups; }
1581 public string SchemaFile {
1582 get { return schemaFile; }
1583 set { schemaFile = value; }
1586 public TargetCollection Targets {
1587 get { return targets; }
1590 public DateTime TimeOfLastDirty {
1591 get { return timeOfLastDirty; }
1594 public UsingTaskCollection UsingTasks {
1595 get { return usingTasks; }
1600 get { return xmlDocument.InnerXml; }
1603 // corresponds to the xml attribute
1604 public string DefaultToolsVersion {
1606 if (xmlDocument != null)
1607 return xmlDocument.DocumentElement.GetAttribute ("ToolsVersion");
1611 if (xmlDocument != null)
1612 xmlDocument.DocumentElement.SetAttribute ("ToolsVersion", value);
1616 public bool HasToolsVersionAttribute {
1618 return xmlDocument != null && xmlDocument.DocumentElement.HasAttribute ("ToolsVersion");
1622 public string ToolsVersion {
1626 internal Dictionary <string, BuildItemGroup> LastItemGroupContaining {
1627 get { return last_item_group_containing; }
1630 internal ProjectLoadSettings ProjectLoadSettings {
1631 get { return project_load_settings; }
1632 set { project_load_settings = value; }
1635 internal static XmlNamespaceManager XmlNamespaceManager {
1637 if (manager == null) {
1638 manager = new XmlNamespaceManager (new NameTable ());
1639 manager.AddNamespace ("tns", ns);
1646 internal TaskDatabase TaskDatabase {
1647 get { return taskDatabase; }
1650 internal XmlDocument XmlDocument {
1651 get { return xmlDocument; }
1654 internal static string XmlNamespace {
1660 PlatformID pid = Environment.OSVersion.Platform;
1668 return "Windows_NT";