summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPaul Smith <psmith@gnu.org>2005-10-24 13:01:39 +0000
committerPaul Smith <psmith@gnu.org>2005-10-24 13:01:39 +0000
commit11095a90f120545c915c92b8ebf48f04723d1837 (patch)
tree73dba88903ea90cdac930057fe8619a8a04fb869
parent66459baee27374577d32a78564604ad64228f71d (diff)
downloadgunmake-11095a90f120545c915c92b8ebf48f04723d1837.tar.gz
Make second expansion optional (partial implementation).
I decided this feature was too impacting to make the permanent default behavior. This set of changes makes the default behavior of make the old behavior (no second expansion). If you want second expansion, you must define the .SECONDEXPANSION: special target before the first target that needs it. This set of changes ONLY fixes explicit and static pattern rules to work like this. Implicit rules still have second expansion enabled all the time: I'll work on that next. Note that there is still a backward-incompatibility: now to get the old SysV behavior using $$@ etc. in the prerequisites list you need to set .SECONDEXPANSION: as well.
-rw-r--r--ChangeLog36
-rw-r--r--NEWS24
-rw-r--r--dep.h4
-rw-r--r--doc/make.texi62
-rw-r--r--file.c228
-rw-r--r--filedef.h10
-rw-r--r--implicit.c14
-rw-r--r--main.c9
-rw-r--r--make.h2
-rw-r--r--misc.c17
-rw-r--r--read.c130
-rw-r--r--rule.c5
-rw-r--r--tests/ChangeLog12
-rwxr-xr-xtests/run_make_tests.pl7
-rw-r--r--tests/scripts/features/order_only104
-rw-r--r--tests/scripts/features/se_explicit24
-rw-r--r--tests/scripts/features/se_statpat4
-rw-r--r--tests/scripts/features/statipattrules65
-rw-r--r--tests/scripts/misc/general425
-rw-r--r--tests/scripts/variables/automatic7
20 files changed, 460 insertions, 329 deletions
diff --git a/ChangeLog b/ChangeLog
index 83e1fa8..1aadcd6 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,39 @@
+2005-10-24 Paul D. Smith <psmith@gnu.org>
+
+ Make secondary expansion optional: its enabled by declaring the
+ special target .SECONDEXPANSION.
+
+ * NEWS: Update information on second expansion capabilities.
+ * doc/make.texi (Secondary Expansion): Document the
+ .SECONDEXPANSION special target and its behavior.
+ * dep.h (struct dep): Add a flag STATICPATTERN, set to true if the
+ prerequisite list was found in a static pattern rule.
+ (free_dep_chain): Declare a prototype.
+ * file.c (parse_prereqs): New function: break out some complexity
+ from expand_deps().
+ (expand_deps): If we aren't doing second expansion, replace % with
+ the stem for static pattern rules. Call the new function.
+ * filedef.h (parse_prereqs): Declare a prototype.
+ * implicit.c (pattern_search): Initialize the new staticpattern
+ field.
+ * main.c (second_expansion): Declare a global variable to remember
+ if the special target has been seen. Initialize the new
+ staticpattern field for prerequisites.
+ * make.h: Extern for second_expansion.
+ * misc.c (free_dep_chain): New function: frees a struct dep list.
+ * read.c (read_all_makefiles): Initialize the staticpattern field.
+ (eval_makefile): Ditto.
+ (record_files): Check for the .SECONDEXPANSION target and set
+ second_expansion global if it's found.
+ Use the new free_dep_chain() instead of doing it by hand.
+ Set the staticpattern field for prereqs of static pattern targets.
+
+2005-10-16 Paul D. Smith <psmith@gnu.org>
+
+ * main.c (main): Set CURDIR to be a file variable instead of a
+ default, so that values of CURDIR inherited from the environment
+ won't override the make value.
+
2005-09-26 Paul D. Smith <psmith@gnu.org>
* job.c (construct_command_argv_internal): If the line is empty
diff --git a/NEWS b/NEWS
index 5adb7a9..e6b3322 100644
--- a/NEWS
+++ b/NEWS
@@ -18,15 +18,21 @@ Version 3.81beta3
* WARNING: Backward-incompatibility!
GNU make now implements a generic "second expansion" feature on the
- prerequisites of both explicit and implicit (pattern) rules. After
- all rules have been parsed the prerequisites are expanded again, this
- time with all the automatic variables in scope. This means that in
- addition to using standard SysV $$@ in prerequisites lists, you can
- also use complex functions such as $$(notdir $$@) etc. This behavior
- applies to implicit rules, as well, where the second expansion occurs
- after the rule is matched. However, this means that you need to
- double-quote any "$" in your filenames; instead of "foo: boo$$bar" you
- now must write "foo: foo$$$$bar".
+ prerequisites of both explicit and implicit (pattern) rules. In order
+ to enable this feature, the special target '.SECONDEXPANSION' must be
+ defined before the first target which takes advantage of it. If this
+ feature is enabled then after all rules have been parsed the
+ prerequisites are expanded again, this time with all the automatic
+ variables in scope. This means that in addition to using standard
+ SysV $$@ in prerequisites lists, you can also use complex functions
+ such as $$(notdir $$@) etc. This behavior applies to implicit rules,
+ as well, where the second expansion occurs when the rule is matched.
+ However, this means that you need to double-quote any "$" in your
+ filenames; instead of "foo: boo$$bar" you now must write "foo:
+ foo$$$$bar". Note that the SysV $$@ etc. feature, which used to be
+ available by default, is now ONLY available when the .SECONDEXPANSION
+ target is defined. If your makefiles take advantage of this SysV
+ feature you will need to update them.
* WARNING: Backward-incompatibility!
In order to comply with POSIX, the way in which GNU make processes
diff --git a/dep.h b/dep.h
index 7e6a853..1be8db6 100644
--- a/dep.h
+++ b/dep.h
@@ -40,6 +40,7 @@ struct dep
struct file *file;
unsigned int changed : 8;
unsigned int ignore_mtime : 1;
+ unsigned int staticpattern : 1;
unsigned int need_2nd_expansion : 1;
};
@@ -72,7 +73,8 @@ extern struct nameseq *ar_glob PARAMS ((char *arname, char *member_pattern, unsi
extern char *dep_name ();
#endif
-extern struct dep *copy_dep_chain PARAMS ((struct dep *d));
+extern struct dep *copy_dep_chain PARAMS ((const struct dep *d));
+extern void free_dep_chain PARAMS ((struct dep *d));
extern void free_ns_chain PARAMS ((struct nameseq *n));
extern struct dep *read_all_makefiles PARAMS ((char **makefiles));
extern int eval_buffer PARAMS ((char *buffer));
diff --git a/doc/make.texi b/doc/make.texi
index 526aec6..cc5f061 100644
--- a/doc/make.texi
+++ b/doc/make.texi
@@ -1612,22 +1612,31 @@ static pattern rules, and simple prerequisite definitions.
@cindex secondary expansion
@cindex expansion, secondary
+@findex .SECONDEXPANSION
In the previous section we learned that GNU @code{make} works in two
distinct phases: a read-in phase and a target-update phase
-(@pxref{Reading Makefiles, , How @code{make} Reads a Makefile}).
-There is an extra wrinkle that comes in between those two phases,
-right at the end of the read-in phase: at that time, all the
-prerequisites of all of the targets are expanded a @emph{second time}.
-In most circumstances this secondary expansion will have no effect,
-since all variable and function references will have been expanded
-during the initial parsing of the makefiles. In order to take
-advantage of the secondary expansion phase of the parser, then, it's
-necessary to @emph{escape} the variable or function reference in the
-makefile. In this case the first expansion merely un-escapes the
-reference but doesn't expand it, and expansion is left to the
-secondary expansion phase. For example, consider this makefile:
-
-@example
+(@pxref{Reading Makefiles, , How @code{make} Reads a Makefile}). GNU
+make also has the ability to enable a @emph{second expansion} of the
+prerequisites (only) for some or all targets defined in the makefile.
+In order for this second expansion to occur, the special target
+@code{.SECONDEXPANSION} must be defined before the first prerequisite
+list that makes use of this feature.
+
+If that special target is defined then in between the two phases
+mentioned above, right at the end of the read-in phase, all the
+prerequisites of the targets defined after the special target are
+expanded a @emph{second time}. In most circumstances this secondary
+expansion will have no effect, since all variable and function
+references will have been expanded during the initial parsing of the
+makefiles. In order to take advantage of the secondary expansion
+phase of the parser, then, it's necessary to @emph{escape} the
+variable or function reference in the makefile. In this case the
+first expansion merely un-escapes the reference but doesn't expand it,
+and expansion is left to the secondary expansion phase. For example,
+consider this makefile:
+
+@example
+.SECONDEXPANSION:
ONEVAR = onefile
TWOVAR = twofile
myfile: $(ONEVAR) $$(TWOVAR)
@@ -1651,6 +1660,7 @@ appear, unescaped, in the prerequisites list. One difference becomes
apparent if the variables are reset; consider this example:
@example
+.SECONDEXPANSION:
AVAR = top
onefile: $(AVAR)
twofile: $$(AVAR)
@@ -1670,10 +1680,11 @@ target. This means that you can use variables such as @code{$@@},
expected values, just as in the command script. All you have to do is
defer the expansion by escaping the @code{$}. Also, secondary
expansion occurs for both explicit and implicit (pattern) rules.
-Knowing this, the possible uses for this feature are almost endless.
-For example:
+Knowing this, the possible uses for this feature increase
+dramatically. For example:
@example
+.SECONDEXPANSION:
main_OBJS := main.o try.o test.o
lib_OBJS := lib.o api.o
@@ -1694,6 +1705,7 @@ You can also mix functions here, as long as they are properly escaped:
main_SRCS := main.c try.c test.c
lib_SRCS := lib.c api.c
+.SECONDEXPANSION:
main lib: $$(patsubst %.c,%.o,$$($$@@_SRCS))
@end example
@@ -1723,6 +1735,8 @@ the same target (@code{$$+} with repetitions and @code{$$^}
without). The following example will help illustrate these behaviors:
@example
+.SECONDEXPANSION:
+
foo: foo.1 bar.1 $$< $$^ $$+ # line #1
foo: foo.2 bar.2 $$< $$^ $$+ # line #2
@@ -1763,6 +1777,8 @@ target pattern. The value of the automatic variables is derived in
the same fashion as for static pattern rules. As an example:
@example
+.SECONDEXPANSION:
+
foo: bar
foo foz: fo%: bo%
@@ -1781,6 +1797,8 @@ expansion) to all the patterns in the prerequisites list. As an
example:
@example
+.SECONDEXPANSION:
+
/tmp/foo.o:
%.o: $$(addsuffix /%.c,foo bar) foo.h
@@ -2880,6 +2898,18 @@ intermediate files, except that they are never automatically deleted.
as secondary (i.e., no target is removed because it is considered
intermediate).
+@findex .SECONDEXPANSION
+@item .SECONDEXPANSION
+
+If @code{.SECONDEXPANSION} is mentioned as a target anwyeren in the
+makefile, then all prerequisite lists defined @emph{after} it appears
+will be expanded a second time after all makefiles have been read in.
+@xref{Secondary Expansion, ,Secondary Expansion}.
+
+The prerequisites of the special target @code{.SUFFIXES} are the list
+of suffixes to be used in checking for suffix rules.
+@xref{Suffix Rules, , Old-Fashioned Suffix Rules}.
+
@findex .DELETE_ON_ERROR
@item .DELETE_ON_ERROR
@cindex removing targets on failure
diff --git a/file.c b/file.c
index 9f9ddb5..ddec34d 100644
--- a/file.c
+++ b/file.c
@@ -405,6 +405,42 @@ remove_intermediates (int sig)
}
}
+struct dep *
+parse_prereqs (char *p)
+{
+ struct dep *new = (struct dep *)
+ multi_glob (parse_file_seq (&p, '|', sizeof (struct dep), 1),
+ sizeof (struct dep));
+
+ if (*p)
+ {
+ /* Files that follow '|' are "order-only" prerequisites that satisfy the
+ dependency by existing: their modification times are irrelevant. */
+ struct dep *ood;
+
+ ++p;
+ ood = (struct dep *)
+ multi_glob (parse_file_seq (&p, '\0', sizeof (struct dep), 1),
+ sizeof (struct dep));
+
+ if (! new)
+ new = ood;
+ else
+ {
+ struct dep *dp;
+ for (dp = new; dp->next != NULL; dp = dp->next)
+ ;
+ dp->next = ood;
+ }
+
+ for (; ood != NULL; ood = ood->next)
+ ood->ignore_mtime = 1;
+ }
+
+ return new;
+}
+
+
/* Set the intermediate flag. */
static void
@@ -418,8 +454,7 @@ set_intermediate (const void *item)
static void
expand_deps (struct file *f)
{
- struct dep *d, *d1;
- struct dep *new = 0;
+ struct dep *d;
struct dep *old = f->deps;
unsigned int last_dep_has_cmds = f->updating;
int initialized = 0;
@@ -429,97 +464,138 @@ expand_deps (struct file *f)
for (d = old; d != 0; d = d->next)
{
- if (d->name != 0)
- {
- char *p;
+ struct dep *new, *d1;
+ char *p;
- /* If we need a second expansion on these, set up the file
- variables, etc. It takes a lot of extra memory and processing
- to do this, so only do it if it's needed. */
- if (! d->need_2nd_expansion)
- p = d->name;
- else
+ if (! d->name)
+ continue;
+
+ /* Create the dependency list.
+ If we're not doing 2nd expansion, then it's just the name. */
+ if (! d->need_2nd_expansion)
+ p = d->name;
+ else
+ {
+ /* If it's from a static pattern rule, convert the patterns into
+ "$*" so they'll expand properly. */
+ if (d->staticpattern)
{
- /* We are going to do second expansion so initialize file
- variables for the file. */
- if (!initialized)
- {
- initialize_file_variables (f, 0);
- initialized = 1;
- }
+ char *o;
+ char *buffer = variable_expand ("");
- set_file_variables (f);
+ o = subst_expand (buffer, d->name, "%", "$*", 1, 2, 0);
- p = variable_expand_for_file (d->name, f);
+ free (d->name);
+ d->name = savestring (buffer, o - buffer);
+ d->staticpattern = 0;
}
- /* Parse the dependencies. */
- new = (struct dep *)
- multi_glob (
- parse_file_seq (&p, '|', sizeof (struct dep), 1),
- sizeof (struct dep));
-
- if (*p)
+ /* We are going to do second expansion so initialize file variables
+ for the file. */
+ if (!initialized)
{
- /* Files that follow '|' are special prerequisites that
- need only exist in order to satisfy the dependency.
- Their modification times are irrelevant. */
- struct dep **d_ptr;
+ initialize_file_variables (f, 0);
+ initialized = 1;
+ }
- for (d_ptr = &new; *d_ptr; d_ptr = &(*d_ptr)->next)
- ;
- ++p;
+ set_file_variables (f);
- *d_ptr = (struct dep *)
- multi_glob (
- parse_file_seq (&p, '\0', sizeof (struct dep), 1),
- sizeof (struct dep));
+ p = variable_expand_for_file (d->name, f);
+ }
- for (d1 = *d_ptr; d1 != 0; d1 = d1->next)
- d1->ignore_mtime = 1;
- }
+ /* Parse the prerequisites. */
+ new = parse_prereqs (p);
- /* Enter them as files. */
- for (d1 = new; d1 != 0; d1 = d1->next)
+ /* If this dep list was from a static pattern rule, expand the %s. We
+ use patsubst_expand to translate the prerequisites' patterns into
+ plain prerequisite names. */
+ if (new && d->staticpattern)
+ {
+ char *pattern = "%";
+ char *buffer = variable_expand ("");
+ struct dep *dp = new, *dl = 0;
+
+ while (dp != 0)
{
- d1->file = lookup_file (d1->name);
- if (d1->file == 0)
- d1->file = enter_file (d1->name);
- else
- free (d1->name);
- d1->name = 0;
- d1->need_2nd_expansion = 0;
+ char *percent = find_percent (dp->name);
+ if (percent)
+ {
+ /* We have to handle empty stems specially, because that
+ would be equivalent to $(patsubst %,dp->name,) which
+ will always be empty. */
+ if (f->stem[0] == '\0')
+ /* This needs memmove() in ISO C. */
+ bcopy (percent+1, percent, strlen (percent));
+ else
+ {
+ char *o = patsubst_expand (buffer, f->stem, pattern,
+ dp->name, pattern+1,
+ percent+1);
+ if (o == buffer)
+ dp->name[0] = '\0';
+ else
+ {
+ free (dp->name);
+ dp->name = savestring (buffer, o - buffer);
+ }
+ }
+
+ /* If the name expanded to the empty string, ignore it. */
+ if (dp->name[0] == '\0')
+ {
+ struct dep *df = dp;
+ if (dp == new)
+ dp = new = new->next;
+ else
+ dp = dl->next = dp->next;
+ free ((char *)df);
+ continue;
+ }
+ }
+ dl = dp;
+ dp = dp->next;
}
+ }
+
+ /* 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;
+ d1->staticpattern = 0;
+ d1->need_2nd_expansion = 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. */
- /* 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 (new != 0)
+ {
+ if (d->next == 0 && last_dep_has_cmds)
{
- if (d->next == 0 && last_dep_has_cmds)
- {
- struct dep **d_ptr;
- for (d_ptr = &new; *d_ptr; d_ptr = &(*d_ptr)->next)
- ;
+ struct dep **d_ptr;
+ for (d_ptr = &new; *d_ptr; d_ptr = &(*d_ptr)->next)
+ ;
- *d_ptr = f->deps;
- f->deps = new;
- }
- else
- {
- struct dep **d_ptr;
- for (d_ptr = &f->deps; *d_ptr; d_ptr = &(*d_ptr)->next)
- ;
+ *d_ptr = f->deps;
+ f->deps = new;
+ }
+ else
+ {
+ struct dep **d_ptr;
+ for (d_ptr = &f->deps; *d_ptr; d_ptr = &(*d_ptr)->next)
+ ;
- *d_ptr = new;
- }
+ *d_ptr = new;
}
}
}
diff --git a/filedef.h b/filedef.h
index ea5c5bd..ae71110 100644
--- a/filedef.h
+++ b/filedef.h
@@ -84,17 +84,16 @@ struct file
unsigned int is_target:1; /* Nonzero if file is described as target. */
unsigned int cmd_target:1; /* Nonzero if file was given on cmd line. */
unsigned int phony:1; /* Nonzero if this is a phony file
- i.e., a dependency of .PHONY. */
+ i.e., a prerequisite of .PHONY. */
unsigned int intermediate:1;/* Nonzero if this is an intermediate file. */
- /* Nonzero, for an intermediate file,
- means remove_intermediates should not delete it. */
- unsigned int secondary:1;
+ unsigned int secondary:1; /* Nonzero means remove_intermediates should
+ not delete it. */
unsigned int dontcare:1; /* Nonzero if no complaint is to be made if
this target cannot be remade. */
unsigned int ignore_vpath:1;/* Nonzero if we threw out VPATH name. */
unsigned int pat_searched:1;/* Nonzero if we already searched for
pattern-specific variables. */
- unsigned int considered:1; /* equal to `considered' if file has been
+ unsigned int considered:1; /* equal to 'considered' if file has been
considered on current scan of goal chain */
};
@@ -105,6 +104,7 @@ extern char **default_goal_name;
extern struct file *lookup_file PARAMS ((char *name));
extern struct file *enter_file PARAMS ((char *name));
+extern struct dep *parse_prereqs PARAMS ((char *prereqs));
extern void remove_intermediates PARAMS ((int sig));
extern void snap_deps PARAMS ((void));
extern void rename_file PARAMS ((struct file *file, char *name));
diff --git a/implicit.c b/implicit.c
index cae4c40..57510d7 100644
--- a/implicit.c
+++ b/implicit.c
@@ -477,12 +477,6 @@ pattern_search (struct file *file, int archive,
/* Try each dependency; see if it "exists". */
- /* @@ There is always only one dep line for any given implicit
- rule. So the loop is not necessary. Can rule->deps be 0?
-
- Watch out for conversion of suffix rules to implicit rules.
- */
-
for (dep = rule->deps; dep != 0; dep = dep->next)
{
unsigned int len;
@@ -513,7 +507,7 @@ pattern_search (struct file *file, int archive,
we just replace % with the stem value, later, when we do
the second expansion, we will re-expand this stem value
once again. This is not good especially if you have
- certain characters in your setm (like $).
+ certain characters in your stem (like $).
Instead, we will replace % with $* and allow the second
expansion to take care of it for us. This way (since $*
@@ -836,6 +830,7 @@ pattern_search (struct file *file, int archive,
dep = (struct dep *) xmalloc (sizeof (struct dep));
dep->ignore_mtime = d->ignore_mtime;
+ dep->staticpattern = 0;
dep->need_2nd_expansion = 0;
s = d->name; /* Hijacking the name. */
d->name = 0;
@@ -917,6 +912,7 @@ pattern_search (struct file *file, int archive,
struct dep *new = (struct dep *) xmalloc (sizeof (struct dep));
/* GKM FIMXE: handle '|' here too */
new->ignore_mtime = 0;
+ new->staticpattern = 0;
new->need_2nd_expansion = 0;
new->name = p = (char *) xmalloc (rule->lens[i] + fullstemlen + 1);
bcopy (rule->targets[i], p,
@@ -928,12 +924,12 @@ pattern_search (struct file *file, int archive,
rule->lens[i] - (rule->suffixes[i] - rule->targets[i]) + 1);
new->file = enter_file (new->name);
new->next = file->also_make;
-
+
/* Set precious flag. */
f = lookup_file (rule->targets[i]);
if (f && f->precious)
new->file->precious = 1;
-
+
file->also_make = new;
}
diff --git a/main.c b/main.c
index 37c6ef6..8c52724 100644
--- a/main.c
+++ b/main.c
@@ -486,6 +486,11 @@ struct file *default_file;
int posix_pedantic;
+/* Nonzero if we have seen the '.SECONDEXPANSION' target.
+ This turns on secondary expansion of prerequisites. */
+
+int second_expansion;
+
/* Nonzero if we have seen the `.NOTPARALLEL' target.
This turns off parallel builds for this invocation of make. */
@@ -1437,7 +1442,7 @@ main (int argc, char **argv, char **envp)
starting_directory = current_directory;
}
- (void) define_variable ("CURDIR", 6, current_directory, o_default, 0);
+ (void) define_variable ("CURDIR", 6, current_directory, o_file, 0);
/* Read any stdin makefiles into temporary files. */
@@ -2174,6 +2179,7 @@ main (int argc, char **argv, char **envp)
goals->next = 0;
goals->name = 0;
goals->ignore_mtime = 0;
+ goals->staticpattern = 0;
goals->need_2nd_expansion = 0;
goals->file = default_goal_file;
}
@@ -2341,6 +2347,7 @@ handle_non_switch_argument (char *arg, int env)
lastgoal->name = 0;
lastgoal->file = f;
lastgoal->ignore_mtime = 0;
+ lastgoal->staticpattern = 0;
lastgoal->need_2nd_expansion = 0;
{
diff --git a/make.h b/make.h
index 8636928..9724780 100644
--- a/make.h
+++ b/make.h
@@ -500,7 +500,7 @@ extern int print_data_base_flag, question_flag, touch_flag, always_make_flag;
extern int env_overrides, no_builtin_rules_flag, no_builtin_variables_flag;
extern int print_version_flag, print_directory_flag, check_symlink_flag;
extern int warn_undefined_variables_flag, posix_pedantic, not_parallel;
-extern int clock_skew_detected, rebuilding_makefiles;
+extern int second_expansion, clock_skew_detected, rebuilding_makefiles;
/* can we run commands via 'sh -c xxx' or must we use batch files? */
extern int batch_mode_shell;
diff --git a/misc.c b/misc.c
index ac50270..6f12683 100644
--- a/misc.c
+++ b/misc.c
@@ -485,7 +485,7 @@ find_next_token (char **ptr, unsigned int *lengthptr)
with the same contents as the old one. */
struct dep *
-copy_dep_chain (struct dep *d)
+copy_dep_chain (const struct dep *d)
{
register struct dep *c;
struct dep *firstnew = 0;
@@ -508,6 +508,21 @@ copy_dep_chain (struct dep *d)
return firstnew;
}
+
+/* Free a chain of 'struct dep'. */
+
+void
+free_dep_chain (struct dep *d)
+{
+ while (d != 0)
+ {
+ struct dep *df = d;
+ d = d->next;
+
+ free (df->name);
+ free ((char *)df);
+ }
+}
/* Free a chain of `struct nameseq'. Each nameseq->name is freed
as well. Can be used on `struct dep' chains.*/
diff --git a/read.c b/read.c
index 0f07ee9..bad07eb 100644
--- a/read.c
+++ b/read.c
@@ -258,6 +258,7 @@ read_all_makefiles (char **makefiles)
d->file = enter_file (*p);
d->file->dontcare = 1;
d->ignore_mtime = 0;
+ d->staticpattern = 0;
d->need_2nd_expansion = 0;
/* Tell update_goal_chain to bail out as soon as this file is
made, and main not to die if we can't make this file. */
@@ -378,6 +379,7 @@ eval_makefile (char *filename, int flags)
filename = deps->file->name;
deps->changed = flags;
deps->ignore_mtime = 0;
+ deps->staticpattern = 0;
deps->need_2nd_expansion = 0;
if (flags & RM_DONTCARE)
deps->file->dontcare = 1;
@@ -1160,7 +1162,7 @@ eval (struct ebuffer *ebuf, int set_default)
pattern_percent = find_percent (pattern);
if (pattern_percent == 0)
fatal (fstart, _("target pattern contains no `%%'"));
- free((char *)target);
+ free ((char *)target);
}
else
pattern = 0;
@@ -1172,21 +1174,12 @@ eval (struct ebuffer *ebuf, int set_default)
if (beg <= end && *beg != '\0')
{
- char *top;
- const char *fromp = beg;
-
- /* Make a copy of the dependency string. Note if we find '$'. */
- deps = (struct dep*) xmalloc (sizeof (struct dep));
+ /* Put all the prerequisites here; they'll be parsed later. */
+ deps = (struct dep *) xmalloc (sizeof (struct dep));
deps->next = 0;
- deps->name = top = (char *) xmalloc (end - beg + 2);
+ deps->name = xstrdup (beg);
+ deps->staticpattern = 0;
deps->need_2nd_expansion = 0;
- while (fromp <= end)
- {
- if (*fromp == '$')
- deps->need_2nd_expansion = 1;
- *(top++) = *(fromp++);
- }
- *top = '\0';
deps->file = 0;
}
else
@@ -1918,19 +1911,19 @@ record_files (struct nameseq *filenames, char *pattern, char *pattern_percent,
{
char *name = filenames->name;
struct file *f;
- struct dep *d;
- struct dep *this;
+ struct dep *this = 0;
char *implicit_percent;
nextf = filenames->next;
free (filenames);
- /* Check for .POSIX. We used to do this in snap_deps() but that's not
- good enough: it doesn't happen until after the makefile is read,
- which means we cannot use its value during parsing. */
+ /* Check for special targets. Do it here instead of, say, snap_deps()
+ so that we can immediately use the value. */
if (streq (name, ".POSIX"))
posix_pedantic = 1;
+ else if (streq (name, ".SECONDEXPANSION"))
+ second_expansion = 1;
implicit_percent = find_percent (name);
implicit |= implicit_percent != 0;
@@ -1965,40 +1958,19 @@ record_files (struct nameseq *filenames, char *pattern, char *pattern_percent,
continue;
}
- /* If there are multiple filenames, copy the chain DEPS
- for all but the last one. It is not safe for the same deps
- to go in more than one place in the database. */
- this = nextf != 0 ? copy_dep_chain (deps) : deps;
-
- if (pattern != 0)
- {
- /* If this is an extended static rule:
- `targets: target%pattern: dep%pattern; cmds',
- translate each dependency pattern into a plain filename
- using the target pattern and this target's name. */
- if (!pattern_matches (pattern, pattern_percent, name))
- {
- /* Give a warning if the rule is meaningless. */
- error (flocp,
- _("target `%s' doesn't match the target pattern"), name);
- this = 0;
- }
- else
- /* We use subst_expand to do the work of translating % to $* in
- the dependency line. */
-
- if (this != 0 && find_percent (this->name) != 0)
- {
- char *o;
- char *buffer = variable_expand ("");
-
- o = subst_expand (buffer, this->name, "%", "$*", 1, 2, 0);
-
- free (this->name);
- this->name = savestring (buffer, o - buffer);
- this->need_2nd_expansion = 1;
- }
- }
+ /* If this is a static pattern rule:
+ `targets: target%pattern: dep%pattern; cmds',
+ make sure the pattern matches this target name. */
+ if (pattern && !pattern_matches (pattern, pattern_percent, name))
+ error (flocp, _("target `%s' doesn't match the target pattern"), name);
+ else if (deps)
+ {
+ /* If there are multiple filenames, copy the chain DEPS for all but
+ the last one. It is not safe for the same deps to go in more
+ than one place in the database. */
+ this = nextf != 0 ? copy_dep_chain (deps) : deps;
+ this->need_2nd_expansion = second_expansion;
+ }
if (!two_colon)
{
@@ -2038,18 +2010,11 @@ record_files (struct nameseq *filenames, char *pattern, char *pattern_percent,
if (cmds != 0)
f->cmds = cmds;
- /* Defining .SUFFIXES with no dependencies
- clears out the list of suffixes. */
+ /* Defining .SUFFIXES with no dependencies clears out the list of
+ suffixes. */
if (f == suffix_file && this == 0)
{
- d = f->deps;
- while (d != 0)
- {
- struct dep *nextd = d->next;
- free (d->name);
- free ((char *)d);
- d = nextd;
- }
+ free_dep_chain (f->deps);
f->deps = 0;
}
else if (this != 0)
@@ -2109,38 +2074,40 @@ record_files (struct nameseq *filenames, char *pattern, char *pattern_percent,
}
else
{
- /* Double-colon. Make a new record
- even if the file already has one. */
+ /* Double-colon. Make a new record even if there already is one. */
f = lookup_file (name);
+
/* Check for both : and :: rules. Check is_target so
we don't lose on default suffix rules or makefiles. */
if (f != 0 && f->is_target && !f->double_colon)
fatal (flocp,
_("target file `%s' has both : and :: entries"), f->name);
f = enter_file (name);
- /* If there was an existing entry and it was a double-colon
- entry, enter_file will have returned a new one, making it the
- prev pointer of the old one, and setting its double_colon
- pointer to the first one. */
+ /* If there was an existing entry and it was a double-colon entry,
+ enter_file will have returned a new one, making it the prev
+ pointer of the old one, and setting its double_colon pointer to
+ the first one. */
if (f->double_colon == 0)
- /* This is the first entry for this name, so we must
- set its double_colon pointer to itself. */
+ /* This is the first entry for this name, so we must set its
+ double_colon pointer to itself. */
f->double_colon = f;
f->is_target = 1;
f->deps = this;
f->cmds = cmds;
}
- /* If this is a static pattern rule, set the file's stem to
- the part of its name that matched the `%' in the pattern,
- so you can use $* in the commands. */
- if (pattern != 0)
+ /* If this is a static pattern rule, set the stem to the part of its
+ name that matched the `%' in the pattern, so you can use $* in the
+ commands. */
+ if (pattern)
{
static char *percent = "%";
char *buffer = variable_expand ("");
char *o = patsubst_expand (buffer, name, pattern, percent,
pattern_percent+1, percent+1);
f->stem = savestring (buffer, o - buffer);
+ if (this)
+ this->staticpattern = 1;
}
/* Free name if not needed further. */
@@ -2152,9 +2119,9 @@ record_files (struct nameseq *filenames, char *pattern, char *pattern_percent,
}
/* If this target is a default target, update DEFAULT_GOAL_FILE. */
- if (strcmp (*default_goal_name, name) == 0
+ if (streq (*default_goal_name, name)
&& (default_goal_file == 0
- || strcmp (default_goal_file->name, name) != 0))
+ || ! streq (default_goal_file->name, name)))
default_goal_file = f;
}
@@ -2162,6 +2129,9 @@ record_files (struct nameseq *filenames, char *pattern, char *pattern_percent,
{
targets[target_idx] = 0;
target_percents[target_idx] = 0;
+ deps->need_2nd_expansion = second_expansion;
+ /* We set this to indicate we've not yet parsed the prereq string. */
+ deps->staticpattern = 1;
create_pattern_rule (targets, target_percents, two_colon, deps, cmds, 1);
free ((char *) target_percents);
}
@@ -2291,9 +2261,9 @@ find_percent (char *pattern)
struct nameseq *
parse_file_seq (char **stringp, int stopchar, unsigned int size, int strip)
{
- register struct nameseq *new = 0;
- register struct nameseq *new1, *lastnew1;
- register char *p = *stringp;
+ struct nameseq *new = 0;
+ struct nameseq *new1, *lastnew1;
+ char *p = *stringp;
char *q;
char *name;
diff --git a/rule.c b/rule.c
index 152e7e6..235e470 100644
--- a/rule.c
+++ b/rule.c
@@ -206,6 +206,7 @@ convert_suffix_rule (char *target, char *source, struct commands *cmds)
deps->next = 0;
deps->name = depname;
deps->ignore_mtime = 0;
+ deps->staticpattern = 0;
deps->need_2nd_expansion = 0;
}
@@ -476,8 +477,8 @@ create_pattern_rule (char **targets, char **target_percents,
int terminal, struct dep *deps,
struct commands *commands, int override)
{
- register struct rule *r = (struct rule *) xmalloc (sizeof (struct rule));
- register unsigned int max_targets, i;
+ unsigned int max_targets, i;
+ struct rule *r = (struct rule *) xmalloc (sizeof (struct rule));
r->cmds = commands;
r->deps = deps;
diff --git a/tests/ChangeLog b/tests/ChangeLog
index 594361f..c936301 100644
--- a/tests/ChangeLog
+++ b/tests/ChangeLog
@@ -1,3 +1,15 @@
+2005-10-24 Paul D. Smith <psmith@gnu.org>
+
+ * scripts/misc/general4: Test '$$' in prerequisites list.
+ * scripts/features/statipattrules: Rewrite to use run_make_test().
+ Add various static pattern info.
+ * scripts/features/se_statpat: Enable .SECONDEXPANSION target.
+ * scripts/features/se_explicit: Add tests for handling '$$' in
+ prerequisite lists with and without setting .SECONDEXPANSION.
+ * scripts/features/order_only: Convert to run_make_test().
+ * run_make_tests.pl (set_more_defaults): If we can't get the value
+ of $(MAKE) from make, then fatal immediately.
+
2005-08-31 Paul D. Smith <psmith@gnu.org>
* run_make_tests.pl (get_this_pwd): Require the POSIX module (in
diff --git a/tests/run_make_tests.pl b/tests/run_make_tests.pl
index 66be520..d51b72a 100755
--- a/tests/run_make_tests.pl
+++ b/tests/run_make_tests.pl
@@ -253,8 +253,11 @@ sub set_more_defaults
# Find the full pathname of Make. For DOS systems this is more
# complicated, so we ask make itself.
- $make_path = `sh -c 'echo "all:;\@echo \\\$(MAKE)" | $make_path -f-'`;
- chop $make_path;
+ my $mk = `sh -c 'echo "all:;\@echo \\\$(MAKE)" | $make_path -f-'`;
+ chop $mk;
+ $mk or die "FATAL ERROR: Cannot determine the value of \$(MAKE):\n
+'echo \"all:;\@echo \\\$(MAKE)\" | $make_path -f-' failed!\n";
+ $make_path = $mk;
print "Make\t= `$make_path'\n" if $debug;
$string = `$make_path -v -f /dev/null 2> /dev/null`;
diff --git a/tests/scripts/features/order_only b/tests/scripts/features/order_only
index 82a7253..4ebdc2b 100644
--- a/tests/scripts/features/order_only
+++ b/tests/scripts/features/order_only
@@ -5,9 +5,18 @@ $details = "\
Create makefiles with various combinations of normal and order-only
prerequisites and ensure they behave properly. Test the \$| variable.";
-open(MAKEFILE,"> $makefile");
+# TEST #0 -- Basics
-print MAKEFILE <<'EOF';
+run_make_test('
+%r: | baz ; @echo $< $^ $|
+bar: foo
+foo:;@:
+baz:;@:',
+ '', "foo foo baz\n");
+
+# TEST #1 -- First try: the order-only prereqs need to be built.
+
+run_make_test(q!
foo: bar | baz
@echo '$$^ = $^'
@echo '$$| = $|'
@@ -16,34 +25,19 @@ foo: bar | baz
.PHONY: baz
bar baz:
- touch $@
-EOF
-
-close(MAKEFILE);
-
-
-# TEST #1 -- just the syntax
-
-&run_make_with_options($makefile, "", &get_logfile);
-$answer = "touch bar\ntouch baz\n\$^ = bar\n\$| = baz\ntouch foo\n";
-&compare_output($answer,&get_logfile(1));
+ touch $@!,
+ '', "touch bar\ntouch baz\n\$^ = bar\n\$| = baz\ntouch foo\n");
# TEST #2 -- now we do it again: baz is PHONY but foo should _NOT_ be updated
-&run_make_with_options($makefile, "", &get_logfile);
-$answer = "touch baz\n";
-&compare_output($answer,&get_logfile(1));
+run_make_test(undef, '', "touch baz\n");
unlink(qw(foo bar baz));
-# Test prereqs that are both order and non-order
-
-$makefile2 = &get_tmpfile;
-
-open(MAKEFILE,"> $makefile2");
+# TEST #3 -- Make sure the order-only prereq was promoted to normal.
-print MAKEFILE <<'EOF';
+run_make_test(q!
foo: bar | baz
@echo '$$^ = $^'
@echo '$$| = $|'
@@ -54,33 +48,21 @@ foo: baz
.PHONY: baz
bar baz:
- touch $@
-EOF
-
-close(MAKEFILE);
-
-# TEST #3 -- Make sure the order-only prereq was promoted to normal.
-
-&run_make_with_options($makefile2, "", &get_logfile);
-$answer = "touch bar\ntouch baz\n\$^ = bar baz\n\$| = \ntouch foo\n";
-&compare_output($answer,&get_logfile(1));
+ touch $@!,
+ '', "touch bar\ntouch baz\n\$^ = bar baz\n\$| = \ntouch foo\n");
# TEST #4 -- now we do it again
-&run_make_with_options($makefile2, "", &get_logfile);
-$answer = "touch baz\n\$^ = bar baz\n\$| = \ntouch foo\n";
-&compare_output($answer,&get_logfile(1));
+run_make_test(undef, '', "touch baz\n\$^ = bar baz\n\$| = \ntouch foo\n");
unlink(qw(foo bar baz));
# Test empty normal prereqs
-$makefile3 = &get_tmpfile;
-
-open(MAKEFILE,"> $makefile3");
+# TEST #5 -- make sure the parser was correct.
-print MAKEFILE <<'EOF';
+run_make_test(q!
foo:| baz
@echo '$$^ = $^'
@echo '$$| = $|'
@@ -89,33 +71,20 @@ foo:| baz
.PHONY: baz
baz:
- touch $@
-EOF
-
-close(MAKEFILE);
-
-# TEST #5 -- make sure the parser was correct.
-
-&run_make_with_options($makefile3, "", &get_logfile);
-$answer = "touch baz\n\$^ = \n\$| = baz\ntouch foo\n";
-&compare_output($answer,&get_logfile(1));
-
+ touch $@!,
+ '', "touch baz\n\$^ = \n\$| = baz\ntouch foo\n");
# TEST #6 -- now we do it again: this time foo won't be built
-&run_make_with_options($makefile3, "", &get_logfile);
-$answer = "touch baz\n";
-&compare_output($answer,&get_logfile(1));
+run_make_test(undef, '', "touch baz\n");
unlink(qw(foo baz));
# Test order-only in pattern rules
-$makefile4 = &get_tmpfile;
-
-open(MAKEFILE,"> $makefile4");
+# TEST #7 -- make sure the parser was correct.
-print MAKEFILE <<'EOF';
+run_make_test(q!
%.w : %.x | baz
@echo '$$^ = $^'
@echo '$$| = $|'
@@ -125,22 +94,13 @@ all: foo.w
.PHONY: baz
foo.x baz:
- touch $@
-EOF
-
-close(MAKEFILE);
-
-# TEST #7 -- make sure the parser was correct.
-
-&run_make_with_options($makefile4, "", &get_logfile);
-$answer = "touch foo.x\ntouch baz\n\$^ = foo.x\n\$| = baz\ntouch foo.w\n";
-&compare_output($answer,&get_logfile(1));
+ touch $@!,
+ '',
+ "touch foo.x\ntouch baz\n\$^ = foo.x\n\$| = baz\ntouch foo.w\n");
# TEST #8 -- now we do it again: this time foo.w won't be built
-&run_make_with_options($makefile4, "", &get_logfile);
-$answer = "touch baz\n";
-&compare_output($answer,&get_logfile(1));
+run_make_test(undef, '', "touch baz\n");
unlink(qw(foo.w foo.x baz));
@@ -151,8 +111,8 @@ run_make_test('
%r: | baz ; @echo $< $^ $|
bar: foo
foo:;@:
-baz:;@:
-', '', "foo foo baz\n");
+baz:;@:',
+ '', "foo foo baz\n");
1;
diff --git a/tests/scripts/features/se_explicit b/tests/scripts/features/se_explicit
index 0e696be..01860a9 100644
--- a/tests/scripts/features/se_explicit
+++ b/tests/scripts/features/se_explicit
@@ -3,9 +3,29 @@ $description = "Test second expansion in ordinary rules.";
$details = "";
-# Test #1: automatic variables.
+# TEST #0: Test handing of '$' in prerequisites with and without second
+# expansion.
+
+run_make_test(q!
+ifdef SE
+ .SECONDEXPANSION:
+endif
+foo$$bar: bar$$baz bar$$biz ; @echo '$@ : $^'
+PRE = one two
+bar$$baz: $$(PRE)
+baraz: $$(PRE)
+PRE = three four
+.DEFAULT: ; @echo '$@'
+!,
+ '',
+ "\$\nbar\$biz\nfoo\$bar : bar\$baz bar\$biz");
+
+run_make_test(undef, 'SE=1', "three\nfour\nbariz\nfoo\$bar : baraz bariz");
+
+# TEST #1: automatic variables.
#
run_make_test('
+.SECONDEXPANSION:
.DEFAULT: ; @echo $@
foo: bar baz
@@ -41,6 +61,7 @@ buz.5
# Test #2: target/pattern -specific variables.
#
run_make_test('
+.SECONDEXPANSION:
.DEFAULT: ; @echo $@
foo.x: $$a $$b
@@ -59,6 +80,7 @@ baz
# Test #3: order of prerequisites.
#
run_make_test('
+.SECONDEXPANSION:
.DEFAULT: ; @echo $@
all: foo bar baz
diff --git a/tests/scripts/features/se_statpat b/tests/scripts/features/se_statpat
index 3c54622..096b240 100644
--- a/tests/scripts/features/se_statpat
+++ b/tests/scripts/features/se_statpat
@@ -6,6 +6,7 @@ $details = "";
# Test #1: automatic variables.
#
run_make_test('
+.SECONDEXPANSION:
.DEFAULT: ; @echo $@
foo.a foo.b: foo.%: bar.% baz.%
@@ -41,6 +42,7 @@ a.6
# Test #2: target/pattern -specific variables.
#
run_make_test('
+.SECONDEXPANSION:
.DEFAULT: ; @echo $@
foo.x foo.y: foo.%: $$(%_a) $$($$*_b)
@@ -60,6 +62,7 @@ baz
# Test #3: order of prerequisites.
#
run_make_test('
+.SECONDEXPANSION:
.DEFAULT: ; @echo $@
all: foo.a bar.a baz.a
@@ -106,6 +109,7 @@ baz.a.2
# Test #4: Make sure stem triple-expansion does not happen.
#
run_make_test('
+.SECONDEXPANSION:
foo$$bar: f%r: % $$*.1
@echo \'$*\'
diff --git a/tests/scripts/features/statipattrules b/tests/scripts/features/statipattrules
index 0ca2bb7..429b56a 100644
--- a/tests/scripts/features/statipattrules
+++ b/tests/scripts/features/statipattrules
@@ -9,79 +9,62 @@ name and the target name with .c. It also does the same thing
for another target filtered with .elc and creates a command
to emacs a .el file";
-open(MAKEFILE,"> $makefile");
-print MAKEFILE <<'EOF';
-files = foo.elc bar.o lose.o
-
-$(filter %.o,$(files)): %.o: %.c ; @echo CC -c $(CFLAGS) $< -o $@
-
-$(filter %.elc,$(files)): %.elc: %.el ; @echo emacs $<
-EOF
-close(MAKEFILE);
-
-
&touch('bar.c', 'lose.c');
-# TEST #1
+# TEST #0
# -------
-&run_make_with_options($makefile, '', &get_logfile);
-$answer = "CC -c bar.c -o bar.o\n";
-&compare_output($answer, &get_logfile(1));
+run_make_test('
+files = foo.elc bar.o lose.o
+
+$(filter %.o,$(files)): %.o: %.c ; @echo CC -c $(CFLAGS) $< -o $@
+$(filter %.elc,$(files)): %.elc: %.el ; @echo emacs $<
+',
+ '',
+ 'CC -c bar.c -o bar.o');
-# TEST #2
+# TEST #1
# -------
-&run_make_with_options($makefile, 'lose.o', &get_logfile);
-$answer = "CC -c lose.c -o lose.o\n";
-&compare_output($answer, &get_logfile(1));
+run_make_test(undef, 'lose.o', 'CC -c lose.c -o lose.o');
-# TEST #3
+# TEST #2
# -------
&touch("foo.el");
-&run_make_with_options($makefile, 'foo.elc', &get_logfile);
-$answer = "emacs foo.el\n";
-&compare_output($answer, &get_logfile(1));
-
+run_make_test(undef, 'foo.elc', 'emacs foo.el');
+# Clean up after the first tests.
unlink('foo.el', 'bar.c', 'lose.c');
-# TEST #4 -- PR/1670: don't core dump on invalid static pattern rules
+# TEST #3 -- PR/1670: don't core dump on invalid static pattern rules
# -------
-$makefile2 = &get_tmpfile;
-open(MAKEFILE, "> $makefile2");
-print MAKEFILE "foo: foo%: % ; \@echo \$@\n";
-close(MAKEFILE);
+run_make_test('
+.DEFAULT: ; @echo $@
+foo: foo%: % %.x % % % y.% % ; @echo $@
+',
+ '', ".x\ny.\nfoo");
-&run_make_with_options($makefile2, '', &get_logfile);
-$answer = "foo\n";
-&compare_output($answer, &get_logfile(1));
-# TEST #5 -- bug #12180: core dump on a stat pattern rule with an empty
+# TEST #4 -- bug #12180: core dump on a stat pattern rule with an empty
# prerequisite list.
-#
run_make_test('
foo.x bar.x: %.x : ; @echo $@
',
-'',
-'foo.x
-');
+ '', 'foo.x');
-# TEST #6 -- bug #13881: double colon static pattern rule does not
+# TEST #5 -- bug #13881: double colon static pattern rule does not
# substitute %.
-#
run_make_test('
foo.bar:: %.bar: %.baz
foo.baz: ;@:
',
-'',
-'');
+ '', '');
1;
diff --git a/tests/scripts/misc/general4 b/tests/scripts/misc/general4
index 63320e2..0b5c94a 100644
--- a/tests/scripts/misc/general4
+++ b/tests/scripts/misc/general4
@@ -5,8 +5,7 @@ This tests random features of make's algorithms, often somewhat obscure,
which have either broken at some point in the past or seem likely to
break.";
-open(MAKEFILE,"> $makefile");
-print MAKEFILE <<'EOF';
+run_make_test('
# Make sure that subdirectories built as prerequisites are actually handled
# properly.
@@ -16,13 +15,8 @@ dir/subdir: ; @echo mkdir -p dir/subdir
dir/subdir/file.b: dir/subdir ; @echo touch dir/subdir/file.b
-dir/subdir/%.a: dir/subdir/%.b ; @echo cp $< $@
-EOF
-close(MAKEFILE);
-
-&run_make_with_options($makefile,"",&get_logfile);
-$answer = "mkdir -p dir/subdir\ntouch dir/subdir/file.b\ncp dir/subdir/file.b dir/subdir/file.a\n";
-&compare_output($answer,&get_logfile(1));
+dir/subdir/%.a: dir/subdir/%.b ; @echo cp $< $@',
+ '', "mkdir -p dir/subdir\ntouch dir/subdir/file.b\ncp dir/subdir/file.b dir/subdir/file.a\n");
# Test implicit rules
@@ -47,4 +41,17 @@ fox: baz
'done bar');
unlink('bar');
+
+# Test implicit rules with '$' in the name (see se_implicit)
+
+run_make_test(q!
+%.foo : baz$$bar ; @echo 'done $<'
+%.foo : bar$$baz ; @echo 'done $<'
+test.foo:
+fox: baz
+.DEFAULT baz$$bar bar$$baz: ; @echo '$@'
+!,
+ '',
+ 'done bar');
+
1;
diff --git a/tests/scripts/variables/automatic b/tests/scripts/variables/automatic
index 484cd16..dc08bd7 100644
--- a/tests/scripts/variables/automatic
+++ b/tests/scripts/variables/automatic
@@ -27,7 +27,7 @@ $(dir)/bar.y baz.z : ; touch $@
EOF
close(MAKEFILE);
-# TEST #1 -- simple test
+# TEST #0 -- simple test
# -------
# Touch these into the past
@@ -46,7 +46,7 @@ touch $dir/foo.x\n";
unlink(qw(foo.x bar.y baz.z));
-# TEST #2 -- test the SysV emulation of $$@ etc.
+# TEST #1 -- test the SysV emulation of $$@ etc.
# -------
$makefile2 = &get_tmpfile;
@@ -54,6 +54,7 @@ $makefile2 = &get_tmpfile;
open(MAKEFILE, "> $makefile2");
print MAKEFILE "dir = $dir\n";
print MAKEFILE <<'EOF';
+.SECONDEXPANSION:
.SUFFIXES:
.DEFAULT: ; @echo '$@'
@@ -78,7 +79,7 @@ $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.
+# TEST #2 -- test for Savannah bug #12320.
#
run_make_test('
.SUFFIXES: .b .src