Fix Savannah bugs #15110, #25493, #12686, and #17740.
authorBoris Kolpackov <boris@kolpackov.net>
Wed, 30 Sep 2009 09:54:26 +0000 (09:54 +0000)
committerBoris Kolpackov <boris@kolpackov.net>
Wed, 30 Sep 2009 09:54:26 +0000 (09:54 +0000)
ChangeLog
dep.h
filedef.h
read.c
remake.c
tests/ChangeLog
tests/scripts/features/include

index 177a201..3b894ad 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,25 @@
+2009-09-30  Boris Kolpackov  <boris@codesynthesis.com>
+
+       * dep.h (dep): Add the DONTCARE bitfield.
+
+       * filedef.h (file):Add the NO_DIAG bitfield.
+
+        * read.c (eval_makefile): Set the DONTCARE flag in struct dep,
+       not struct file (a file can be a dependency of many targets,
+       some don't care, some do).
+
+       * remake.c (update_goal_chain): Propagate DONTCARE from struct
+       dep to struct file before updating the goal and restore it
+       afterwards.
+       (update_file): Don't prune the dependency graph if this target
+       has failed but the diagnostics hasn't been issued.
+       (complain): Scan the file's dependency graph to find the file
+       that caused the failure.
+       (update_file_1): Use NO_DIAG instead of DONTCARE to decide
+       whether to print diagnostics.
+
+       Fixes Savannah bugs #15110, #25493, #12686, and #17740.
+
 2009-09-28  Paul Smith  <psmith@gnu.org>
 
        * doc/make.texi (Pattern Intro): Move the match algorithm
diff --git a/dep.h b/dep.h
index 305fb89..9696423 100644 (file)
--- a/dep.h
+++ b/dep.h
@@ -43,6 +43,7 @@ struct dep
     unsigned int ignore_mtime : 1;
     unsigned int staticpattern : 1;
     unsigned int need_2nd_expansion : 1;
+    unsigned int dontcare : 1;
   };
 
 
index 0d09e16..2881c0e 100644 (file)
--- a/filedef.h
+++ b/filedef.h
@@ -94,6 +94,8 @@ struct file
                                    pattern-specific variables.  */
     unsigned int considered:1;  /* equal to 'considered' if file has been
                                    considered on current scan of goal chain */
+    unsigned int no_diag:1;     /* True if the file failed to update and no
+                                   diagnostics has been issued (dontcare). */
   };
 
 
diff --git a/read.c b/read.c
index 2eb98fa..7dd5090 100644 (file)
--- a/read.c
+++ b/read.c
@@ -384,7 +384,7 @@ eval_makefile (const char *filename, int flags)
   filename = deps->file->name;
   deps->changed = flags;
   if (flags & RM_DONTCARE)
-    deps->file->dontcare = 1;
+    deps->dontcare = 1;
 
   if (expanded)
     free (expanded);
index a70cbee..67cde00 100644 (file)
--- a/remake.c
+++ b/remake.c
@@ -133,6 +133,9 @@ update_goal_chain (struct dep *goals)
            {
              unsigned int ocommands_started;
              int x;
+
+              file->dontcare = g->dontcare;
+
              check_renamed (file);
              if (rebuilding_makefiles)
                {
@@ -206,6 +209,8 @@ update_goal_chain (struct dep *goals)
                  When they are all finished, the goal is finished.  */
              any_not_updated |= !file->updated;
 
+              file->dontcare = 0;
+
              if (stop)
                break;
            }
@@ -293,8 +298,14 @@ update_file (struct file *file, unsigned int depth)
      change is possible below here until then.  */
   if (f->considered == considered)
     {
-      DBF (DB_VERBOSE, _("Pruning file `%s'.\n"));
-      return f->command_state == cs_finished ? f->update_status : 0;
+      /* Check for the case where a target has been tried and failed but
+         the diagnostics hasn't been issued. If we need the diagnostics
+         then we will have to continue. */
+      if (!(f->updated && f->update_status > 0 && !f->dontcare && f->no_diag))
+        {
+          DBF (DB_VERBOSE, _("Pruning file `%s'.\n"));
+          return f->command_state == cs_finished ? f->update_status : 0;
+        }
     }
 
   /* This loop runs until we start commands for a double colon rule, or until
@@ -311,7 +322,7 @@ update_file (struct file *file, unsigned int depth)
 
       /* If we got an error, don't bother with double_colon etc.  */
       if (status != 0 && !keep_going_flag)
-       return status;
+        return status;
 
       if (f->command_state == cs_running
           || f->command_state == cs_deps_running)
@@ -342,25 +353,48 @@ update_file (struct file *file, unsigned int depth)
 /* Show a message stating the target failed to build.  */
 
 static void
-complain (const struct file *file)
+complain (struct file *file)
 {
   const char *msg_noparent
     = _("%sNo rule to make target `%s'%s");
   const char *msg_parent
     = _("%sNo rule to make target `%s', needed by `%s'%s");
 
-  if (!keep_going_flag)
+  /* If this file has no_diag set then it means we tried to update it
+     before in the dontcare mode and failed. The target that actually
+     failed is not necessarily this file but could be one of its direct
+     or indirect dependencies. So traverse this file's dependencies and
+     find the one that actually caused the failure. */
+
+  struct dep *d;
+
+  for (d = file->deps; d != 0; d = d->next)
     {
+      if (d->file->updated && d->file->update_status > 0 && file->no_diag)
+        {
+          complain (d->file);
+          break;
+        }
+    }
+
+  if (d == 0)
+    {
+      /* Didn't find any dependencies to complain about. */
+      if (!keep_going_flag)
+        {
+          if (file->parent == 0)
+            fatal (NILF, msg_noparent, "", file->name, "");
+
+          fatal (NILF, msg_parent, "", file->name, file->parent->name, "");
+        }
+
       if (file->parent == 0)
-        fatal (NILF, msg_noparent, "", file->name, "");
+        error (NILF, msg_noparent, "*** ", file->name, ".");
+      else
+        error (NILF, msg_parent, "*** ", file->name, file->parent->name, ".");
 
-      fatal (NILF, msg_parent, "", file->name, file->parent->name, "");
+      file->no_diag = 0;
     }
-
-  if (file->parent == 0)
-    error (NILF, msg_noparent, "*** ", file->name, ".");
-  else
-    error (NILF, msg_parent, "*** ", file->name, file->parent->name, ".");
 }
 
 /* Consider a single `struct file' and update it as appropriate.  */
@@ -385,15 +419,12 @@ update_file_1 (struct file *file, unsigned int depth)
          DBF (DB_VERBOSE,
                _("Recently tried and failed to update file `%s'.\n"));
 
-          /* If the file we tried to make is marked dontcare then no message
+          /* If the file we tried to make is marked no_diag then no message
              was printed about it when it failed during the makefile rebuild.
              If we're trying to build it again in the normal rebuild, print a
              message now.  */
-          if (file->dontcare && !rebuilding_makefiles)
-            {
-              file->dontcare = 0;
+          if (file->no_diag && !file->dontcare)
               complain (file);
-            }
 
          return file->update_status;
        }
@@ -417,6 +448,10 @@ update_file_1 (struct file *file, unsigned int depth)
       abort ();
     }
 
+  /* Determine whether the diagnostics will be issued should this update
+     fail. */
+  file->no_diag = file->dontcare;
+
   ++depth;
 
   /* Notice recursive update of the same file.  */
index 5800d66..77b37e3 100644 (file)
@@ -1,3 +1,9 @@
+2009-09-30  Boris Kolpackov  <boris@codesynthesis.com>
+
+       * scripts/features/include: Add diagnostics issuing tests for
+       cases where targets have been updated and failed with the
+       dontcare flag. Savannah bugs #15110, #25493, #12686, #17740.
+
 2009-09-28  Paul Smith  <psmith@gnu.org>
 
        * scripts/functions/shell: Add regression test for Savannah bug
index 196a987..7ad4112 100644 (file)
@@ -90,8 +90,6 @@ all: ; @:
 foo: bar; @:
 ', '', '');
 
-1;
-
 
 # Make sure that we don't die when the command fails but we dontcare.
 # (Savannah bug #13216).
@@ -117,4 +115,54 @@ include
 -include
 sinclude', '', '');
 
+
+# Test that the diagnostics is issued even if the target has been
+# tried before with the dontcare flag (direct dependency case).
+#
+run_make_test('
+-include foo
+
+all: bar
+
+foo: baz
+bar: baz
+',
+'',
+"#MAKE#: *** No rule to make target `baz', needed by `bar'.  Stop.\n",
+512);
+
+# Test that the diagnostics is issued even if the target has been
+# tried before with the dontcare flag (indirect dependency case).
+#
+run_make_test('
+-include foo
+
+all: bar
+
+foo: baz
+bar: baz
+baz: end
+',
+'',
+"#MAKE#: *** No rule to make target `end', needed by `baz'.  Stop.\n",
+512);
+
+# Test that the diagnostics is issued even if the target has been
+# tried before with the dontcare flag (include/-include case).
+#
+run_make_test('
+include bar
+-include foo
+
+all:
+
+foo: baz
+bar: baz
+baz: end
+',
+'',
+"#MAKEFILE#:2: bar: No such file or directory
+#MAKE#: *** No rule to make target `end', needed by `baz'.  Stop.\n",
+512);
+
 1;