Fixed Savannah bug #12320.
authorBoris Kolpackov <boris@kolpackov.net>
Tue, 15 Mar 2005 15:31:47 +0000 (15:31 +0000)
committerBoris Kolpackov <boris@kolpackov.net>
Tue, 15 Mar 2005 15:31:47 +0000 (15:31 +0000)
ChangeLog
file.c
tests/ChangeLog
tests/scripts/variables/automatic

index d041dca655ffa3ff44af4e0de229ebb5dbf98588..7747b993e767c779d5c9f496b547627c004d0534 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,12 @@
+2005-03-15  Boris Kolpackov  <boris@kolpackov.net>
+
+       * file.c (expand_deps): Factor out the second expansion and
+       prerequisite line parsing logic from snap_deps().
+
+       * file.c (snap_deps): Use expand_deps(). Expand and parse
+       prerequisites of the .SUFFIXES special target first. Fixes
+       Savannah bug #12320.
+
 2005-03-10  Boris Kolpackov  <boris@kolpackov.net>
 
        * implicit.c (pattern_search): Mark an intermediate target as
diff --git a/file.c b/file.c
index 45bcaef28f765d5f38ab1f5c5c9f60c503041b6c..1c34ff4cb183cccffe99d5863add42a01df2e668 100644 (file)
--- a/file.c
+++ b/file.c
@@ -414,6 +414,104 @@ set_intermediate (const void *item)
   f->intermediate = 1;
 }
 
+/* Expand and parse each dependency line. */
+static void
+expand_deps (struct file *f)
+{
+  register struct dep *d, *d1;
+  struct dep *new = 0;
+  struct dep *old = f->deps;
+  unsigned int last_dep_has_cmds = f->updating;
+
+  f->updating = 0;
+  f->deps = 0;
+
+  /* We are going to do second expansion so initialize file
+     variables for the file. */
+  initialize_file_variables (f, 0);
+
+  for (d = old; d != 0; d = d->next)
+    {
+      if (d->name != 0)
+        {
+          char *p;
+          struct dep **d_ptr;
+
+          set_file_variables (f);
+
+          p = variable_expand_for_file (d->name, f);
+
+          /* Parse the dependencies.  */
+          new = (struct dep *)
+            multi_glob (
+              parse_file_seq (&p, '|', sizeof (struct dep), 1),
+              sizeof (struct dep));
+
+          if (*p)
+            {
+              /* Files that follow '|' are special prerequisites that
+                 need only exist in order to satisfy the dependency.
+                 Their modification times are irrelevant.  */
+
+              struct dep *d;
+              for (d_ptr = &new; *d_ptr; d_ptr = &(*d_ptr)->next)
+                ;
+              ++p;
+
+              *d_ptr = (struct dep *)
+                multi_glob (
+                  parse_file_seq (&p, '\0', sizeof (struct dep), 1),
+                  sizeof (struct dep));
+
+              for (d = *d_ptr; d != 0; d = d->next)
+                d->ignore_mtime = 1;
+            }
+
+          /* Enter them as files. */
+          for (d1 = new; d1 != 0; d1 = d1->next)
+            {
+              d1->file = lookup_file (d1->name);
+              if (d1->file == 0)
+                d1->file = enter_file (d1->name);
+              else
+                free (d1->name);
+              d1->name = 0;
+            }
+
+          /* Add newly parsed deps to f->deps. If this is the last
+             dependency line and this target has commands then put
+             it in front so the last dependency line (the one with
+             commands) ends up being the first. This is important
+             because people expect $< to hold first prerequisite
+             from the rule with commands. If it is not the last
+             dependency line or the rule does not have commands
+             then link it at the end so it appears in makefile
+             order.  */
+
+          if (new != 0)
+            {
+              if (d->next == 0 && last_dep_has_cmds)
+                {
+                  for (d_ptr = &new; *d_ptr; d_ptr = &(*d_ptr)->next)
+                        ;
+
+                  *d_ptr = f->deps;
+                  f->deps = new;
+                }
+              else
+                {
+                  for (d_ptr = &(f->deps); *d_ptr; d_ptr = &(*d_ptr)->next)
+                    ;
+
+                  *d_ptr = new;
+                }
+            }
+        }
+    }
+
+  free_ns_chain ((struct nameseq*)old);
+}
+
 /* For each dependency of each file, make the `struct dep' point
    at the appropriate `struct file' (which may have to be created).
 
@@ -425,7 +523,7 @@ snap_deps (void)
 {
   register struct file *f;
   register struct file *f2;
-  register struct dep *d, *d1;
+  register struct dep *d;
   register struct file **file_slot_0;
   register struct file **file_slot;
   register struct file **file_end;
@@ -433,105 +531,21 @@ snap_deps (void)
   /* Perform second expansion and enter each dependency
      name as a file. */
 
+  /* Expand .SUFFIXES first; it's dependencies are used for
+     $$* calculation. */
+  for (f = lookup_file (".SUFFIXES"); f != 0; f = f->prev)
+    expand_deps (f);
+
   /* We must use hash_dump (), because within this loop
      we might add new files to the table, possibly causing
      an in-situ table expansion.  */
   file_slot_0 = (struct file **) hash_dump (&files, 0, 0);
   file_end = file_slot_0 + files.ht_fill;
   for (file_slot = file_slot_0; file_slot < file_end; file_slot++)
-    for (f2 = *file_slot; f2 != 0; f2 = f2->prev)
+    for (f = *file_slot; f != 0; f = f->prev)
       {
-        struct dep *new = 0;
-        struct dep *old = f2->deps;
-        unsigned int last_dep_has_cmds = f2->updating;
-
-        f2->updating = 0;
-        f2->deps = 0;
-
-        /* We are going to do second expansion so initialize file
-           variables for the file. */
-        initialize_file_variables (f2, 0);
-
-        for (d = old; d != 0; d = d->next)
-          {
-            if (d->name != 0)
-              {
-                char *p;
-                struct dep **d_ptr;
-
-                set_file_variables (f2);
-
-                p = variable_expand_for_file (d->name, f2);
-
-                /* Parse the dependencies.  */
-                new = (struct dep *)
-                  multi_glob (
-                    parse_file_seq (&p, '|', sizeof (struct dep), 1),
-                    sizeof (struct dep));
-
-                if (*p)
-                  {
-                    /* Files that follow '|' are special prerequisites that
-                       need only exist in order to satisfy the dependency.
-                       Their modification times are irrelevant.  */
-
-                    struct dep *d;
-                    for (d_ptr = &new; *d_ptr; d_ptr = &(*d_ptr)->next)
-                      ;
-                    ++p;
-
-                    *d_ptr = (struct dep *)
-                      multi_glob (
-                        parse_file_seq (&p, '\0', sizeof (struct dep), 1),
-                        sizeof (struct dep));
-
-                    for (d = *d_ptr; d != 0; d = d->next)
-                      d->ignore_mtime = 1;
-                  }
-
-                /* Enter them as files. */
-                for (d1 = new; d1 != 0; d1 = d1->next)
-                  {
-                    d1->file = lookup_file (d1->name);
-                    if (d1->file == 0)
-                      d1->file = enter_file (d1->name);
-                    else
-                      free (d1->name);
-                    d1->name = 0;
-                  }
-
-                /* Add newly parsed deps to f2->deps. If this is the last
-                   dependency line and this target has commands then put
-                   it in front so the last dependency line (the one with
-                   commands) ends up being the first. This is important
-                   because people expect $< to hold first prerequisite
-                   from the rule with commands. If it is not the last
-                   dependency line or the rule does not have commands
-                   then link it at the end so it appears in makefile
-                   order.  */
-
-                if (new != 0)
-                  {
-                    if (d->next == 0 && last_dep_has_cmds)
-                    {
-                      for (d_ptr = &new; *d_ptr; d_ptr = &(*d_ptr)->next)
-                        ;
-
-                      *d_ptr = f2->deps;
-                      f2->deps = new;
-                    }
-                    else
-                    {
-                      for (d_ptr = &(f2->deps); *d_ptr; d_ptr = &(*d_ptr)->next)
-                        ;
-
-                      *d_ptr = new;
-                    }
-                  }
-              }
-          }
-
-        free_ns_chain ((struct nameseq*)old);
+        if (strcmp (f->name, ".SUFFIXES") != 0)
+          expand_deps (f);
       }
   free (file_slot_0);
 
index ae255a266e75365805f33f469adb8c0404e612c8..72575e850331c78232630df15762def9f2067d79 100644 (file)
@@ -1,3 +1,7 @@
+2005-03-15  Boris Kolpackov  <boris@kolpackov.net>
+
+       * scripts/variables/automatic: Add a test for Savannah bug #12320.
+
 2005-03-10  Boris Kolpackov  <boris@kolpackov.net>
 
        * scripts/features/patternrules: Add a test for Savannah bug #12267.
index a51ca20cd685e120c86de535ee651ec114480734..484cd1694531605b2c0cd538501086a739582808 100644 (file)
@@ -78,4 +78,19 @@ $answer = ".x\n$dir/x.z.x\nx\n\$@.x\n$dir.x\nx.z.x\n.y\n$dir/y.z.y\n\y\n\$@.y\n$
 $answer = "$dir/biz.x\n$dir.x\nbiz.x\n";
 &compare_output($answer, &get_logfile(1));
 
+# TEST #3 -- test for Savannah bug #12320.
+#
+run_make_test('
+.SUFFIXES: .b .src
+
+mbr.b: mbr.src
+       @echo $*
+
+mbr.src: ; @:
+
+',
+'',
+'mbr
+');
+
 1;