[xbuild] Add new reserved properties $(MSBuildThisFile*).
[mono.git] / mcs / class / Microsoft.Build.Engine / Microsoft.Build.BuildEngine / Target.cs
index e76394e7abf2fd104440c14c41f45f4ed2dac582..439c56fd94b14b4887d57ace200ec0d5f5e82e71 100644 (file)
@@ -110,21 +110,48 @@ namespace Microsoft.Build.BuildEngine {
                        buildTasks.Remove (buildTask);
                }
 
-               internal bool Build ()
+               bool Build ()
+               {
+                       return Build (null);
+               }
+
+               internal bool Build (string built_targets_key)
                {
                        bool executeOnErrors;
-                       return Build (out executeOnErrors);
+                       return Build (built_targets_key, out executeOnErrors);
+               }
+
+               bool Build (string built_targets_key, out bool executeOnErrors)
+               {
+                       project.PushThisFileProperty (TargetFile);
+                       try {
+                               return BuildActual (built_targets_key, out executeOnErrors);
+                       } finally {
+                               project.PopThisFileProperty ();
+                       }
                }
 
-               internal bool Build (out bool executeOnErrors)
+               bool BuildActual (string built_targets_key, out bool executeOnErrors)
                {
                        bool result = false;
                        executeOnErrors = false;
 
+                       // built targets are keyed by the particular set of global
+                       // properties. So, a different set could allow a target
+                       // to run again
+                       built_targets_key = project.GetKeyForTarget (Name);
+                       if (project.ParentEngine.BuiltTargetsOutputByName.ContainsKey (built_targets_key)) {
+                               LogTargetSkipped ();
+                               return true;
+                       }
+
+                       // Push a null/empty batch, effectively clearing it
+                       project.PushBatch (null, null);
                        if (!ConditionParser.ParseAndEvaluate (Condition, Project)) {
                                LogMessage (MessageImportance.Low,
                                                "Target {0} skipped due to false condition: {1}",
                                                Name, Condition);
+                               project.PopBatch ();
                                return true;
                        }
 
@@ -143,8 +170,12 @@ namespace Microsoft.Build.BuildEngine {
                        } catch (Exception e) {
                                LogError ("Error building target {0}: {1}", Name, e.ToString ());
                                return false;
+                       } finally {
+                               project.PopBatch ();
                        }
 
+                       project.ParentEngine.BuiltTargetsOutputByName [built_targets_key] = (ITaskItem[]) Outputs.Clone ();
+
                        return result;
                }
 
@@ -157,7 +188,7 @@ namespace Microsoft.Build.BuildEngine {
 
                        if (DependsOnTargets != String.Empty) {
                                deps = new Expression ();
-                               deps.Parse (DependsOnTargets, true);
+                               deps.Parse (DependsOnTargets, ParseOptions.AllowItemsNoMetadataAndSplit);
                                targetNames = (string []) deps.ConvertTo (Project, typeof (string []));
                                foreach (string dep_name in targetNames) {
                                        t = project.Targets [dep_name.Trim ()];
@@ -176,7 +207,7 @@ namespace Microsoft.Build.BuildEngine {
                        executeOnErrors = false;
                        foreach (Target t in deps) {
                                if (t.BuildState == BuildState.NotStarted)
-                                       if (!t.Build (out executeOnErrors))
+                                       if (!t.Build (null, out executeOnErrors))
                                                return false;
                                if (t.BuildState == BuildState.Started)
                                        throw new InvalidProjectFileException ("Cycle in target dependencies detected");
@@ -228,6 +259,16 @@ namespace Microsoft.Build.BuildEngine {
                        }
                }
 
+               void LogTargetSkipped ()
+               {
+                       BuildMessageEventArgs bmea;
+                       bmea = new BuildMessageEventArgs (String.Format (
+                                               "Target {0} skipped, as it has already been built.", Name),
+                                       null, null, MessageImportance.Low);
+
+                       project.ParentEngine.EventSource.FireMessageRaised (this, bmea);
+               }
+
                void LogError (string message, params object [] messageArgs)
                {
                        if (message == null)
@@ -272,6 +313,14 @@ namespace Microsoft.Build.BuildEngine {
                        get { return project; }
                }
 
+               internal string TargetFile {
+                       get {
+                               if (importedProject != null)
+                                       return importedProject.FullFileName;
+                               return project != null ? project.FullFileName : String.Empty;
+                       }
+               }
+
                internal List<BuildTask> BuildTasks {
                        get { return buildTasks; }
                }
@@ -291,7 +340,7 @@ namespace Microsoft.Build.BuildEngine {
                                        return new ITaskItem [0];
 
                                Expression e = new Expression ();
-                               e.Parse (outputs, true);
+                               e.Parse (outputs, ParseOptions.AllowItemsNoMetadataAndSplit);
 
                                return (ITaskItem []) e.ConvertTo (project, typeof (ITaskItem []));
                        }