+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
* 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
struct file *file;
unsigned int changed : 8;
unsigned int ignore_mtime : 1;
+ unsigned int staticpattern : 1;
unsigned int need_2nd_expansion : 1;
};
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));
@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)
apparent if the variables are reset; consider this example:
@example
+.SECONDEXPANSION:
AVAR = top
onefile: $(AVAR)
twofile: $$(AVAR)
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
main_SRCS := main.c try.c test.c
lib_SRCS := lib.c api.c
+.SECONDEXPANSION:
main lib: $$(patsubst %.c,%.o,$$($$@@_SRCS))
@end example
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
the same fashion as for static pattern rules. As an example:
@example
+.SECONDEXPANSION:
+
foo: bar
foo foz: fo%: bo%
example:
@example
+.SECONDEXPANSION:
+
/tmp/foo.o:
%.o: $$(addsuffix /%.c,foo bar) foo.h
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
}
}
\f
+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
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;
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;
}
}
}
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 */
};
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));
/* 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;
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 $*
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;
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,
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;
}
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. */
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. */
goals->next = 0;
goals->name = 0;
goals->ignore_mtime = 0;
+ goals->staticpattern = 0;
goals->need_2nd_expansion = 0;
goals->file = default_goal_file;
}
lastgoal->name = 0;
lastgoal->file = f;
lastgoal->ignore_mtime = 0;
+ lastgoal->staticpattern = 0;
lastgoal->need_2nd_expansion = 0;
{
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;
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;
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);
+ }
+}
\f
/* Free a chain of `struct nameseq'. Each nameseq->name is freed
as well. Can be used on `struct dep' chains.*/
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. */
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;
pattern_percent = find_percent (pattern);
if (pattern_percent == 0)
fatal (fstart, _("target pattern contains no `%%'"));
- free((char *)target);
+ free ((char *)target);
}
else
pattern = 0;
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
{
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;
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)
{
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)
}
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. */
}
/* 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;
}
{
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);
}
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;
deps->next = 0;
deps->name = depname;
deps->ignore_mtime = 0;
+ deps->staticpattern = 0;
deps->need_2nd_expansion = 0;
}
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;
+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
# 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`;
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 '$$| = $|'
.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 '$$| = $|'
.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 '$$| = $|'
.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 '$$| = $|'
.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));
%r: | baz ; @echo $< $^ $|
bar: foo
foo:;@:
-baz:;@:
-', '', "foo foo baz\n");
+baz:;@:',
+ '', "foo foo baz\n");
1;
$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
# Test #2: target/pattern -specific variables.
#
run_make_test('
+.SECONDEXPANSION:
.DEFAULT: ; @echo $@
foo.x: $$a $$b
# Test #3: order of prerequisites.
#
run_make_test('
+.SECONDEXPANSION:
.DEFAULT: ; @echo $@
all: foo bar baz
# Test #1: automatic variables.
#
run_make_test('
+.SECONDEXPANSION:
.DEFAULT: ; @echo $@
foo.a foo.b: foo.%: bar.% baz.%
# Test #2: target/pattern -specific variables.
#
run_make_test('
+.SECONDEXPANSION:
.DEFAULT: ; @echo $@
foo.x foo.y: foo.%: $$(%_a) $$($$*_b)
# Test #3: order of prerequisites.
#
run_make_test('
+.SECONDEXPANSION:
.DEFAULT: ; @echo $@
all: foo.a bar.a baz.a
# Test #4: Make sure stem triple-expansion does not happen.
#
run_make_test('
+.SECONDEXPANSION:
foo$$bar: f%r: % $$*.1
@echo \'$*\'
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;
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.
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
'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;
EOF
close(MAKEFILE);
-# TEST #1 -- simple test
+# TEST #0 -- simple test
# -------
# Touch these into the past
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;
open(MAKEFILE, "> $makefile2");
print MAKEFILE "dir = $dir\n";
print MAKEFILE <<'EOF';
+.SECONDEXPANSION:
.SUFFIXES:
.DEFAULT: ; @echo '$@'
$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