summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBoris Kolpackov <boris@kolpackov.net>2005-03-15 15:31:47 +0000
committerBoris Kolpackov <boris@kolpackov.net>2005-03-15 15:31:47 +0000
commit4923580e3a5b3d9e7ff29ef1e5a5339cc7619a4b (patch)
tree308d6c890fafb2555f0388a4abc4f272ea466bd3
parentd584d0c1c6945e0b498365e7d17f0fe3cb449d04 (diff)
downloadgunmake-4923580e3a5b3d9e7ff29ef1e5a5339cc7619a4b.tar.gz
Fixed Savannah bug #12320.
-rw-r--r--ChangeLog9
-rw-r--r--file.c200
-rw-r--r--tests/ChangeLog4
-rw-r--r--tests/scripts/variables/automatic15
4 files changed, 135 insertions, 93 deletions
diff --git a/ChangeLog b/ChangeLog
index d041dca..7747b99 100644
--- 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 45bcaef..1c34ff4 100644
--- 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);
diff --git a/tests/ChangeLog b/tests/ChangeLog
index ae255a2..72575e8 100644
--- a/tests/ChangeLog
+++ b/tests/ChangeLog
@@ -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.
diff --git a/tests/scripts/variables/automatic b/tests/scripts/variables/automatic
index a51ca20..484cd16 100644
--- a/tests/scripts/variables/automatic
+++ b/tests/scripts/variables/automatic
@@ -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;