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.
This commit is contained in:
Paul Smith 2005-10-24 13:01:39 +00:00
parent 66459baee2
commit 11095a90f1
20 changed files with 461 additions and 330 deletions

View File

@ -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

24
NEWS
View File

@ -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

4
dep.h
View File

@ -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));

View File

@ -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:
(@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

154
file.c
View File

@ -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,19 +464,34 @@ expand_deps (struct file *f)
for (d = old; d != 0; d = d->next)
{
if (d->name != 0)
{
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->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
{
/* We are going to do second expansion so initialize file
variables for the file. */
/* If it's from a static pattern rule, convert the patterns into
"$*" so they'll expand properly. */
if (d->staticpattern)
{
char *o;
char *buffer = variable_expand ("");
o = subst_expand (buffer, d->name, "%", "$*", 1, 2, 0);
free (d->name);
d->name = savestring (buffer, o - buffer);
d->staticpattern = 0;
}
/* We are going to do second expansion so initialize file variables
for the file. */
if (!initialized)
{
initialize_file_variables (f, 0);
@ -453,30 +503,58 @@ expand_deps (struct file *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));
/* Parse the prerequisites. */
new = parse_prereqs (p);
if (*p)
/* 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)
{
/* 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;
char *pattern = "%";
char *buffer = variable_expand ("");
struct dep *dp = new, *dl = 0;
for (d_ptr = &new; *d_ptr; d_ptr = &(*d_ptr)->next)
;
++p;
while (dp != 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);
}
}
*d_ptr = (struct dep *)
multi_glob (
parse_file_seq (&p, '\0', sizeof (struct dep), 1),
sizeof (struct dep));
for (d1 = *d_ptr; d1 != 0; d1 = d1->next)
d1->ignore_mtime = 1;
/* 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. */
@ -488,18 +566,17 @@ expand_deps (struct file *f)
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)
{
@ -522,7 +599,6 @@ expand_deps (struct file *f)
}
}
}
}
free_ns_chain ((struct nameseq *) old);
}

View File

@ -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));

View File

@ -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,

9
main.c
View File

@ -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;
{

2
make.h
View File

@ -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;

17
misc.c
View File

@ -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.*/

124
read.c
View File

@ -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,39 +1958,18 @@ 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:
/* If this is a static pattern 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))
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)
{
/* 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 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;

5
rule.c
View File

@ -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;

View File

@ -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

View File

@ -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`;

View File

@ -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
# TEST #3 -- Make sure the order-only prereq was promoted to normal.
$makefile2 = &get_tmpfile;
open(MAKEFILE,"> $makefile2");
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;
# TEST #5 -- make sure the parser was correct.
open(MAKEFILE,"> $makefile3");
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;
# TEST #7 -- make sure the parser was correct.
open(MAKEFILE,"> $makefile4");
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;

View File

@ -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

View File

@ -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 \'$*\'

View File

@ -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';
&touch('bar.c', 'lose.c');
# TEST #0
# -------
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 $<
EOF
close(MAKEFILE);
&touch('bar.c', 'lose.c');
',
'',
'CC -c bar.c -o bar.o');
# TEST #1
# -------
&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(undef, 'lose.o', 'CC -c lose.c -o lose.o');
# TEST #2
# -------
&run_make_with_options($makefile, 'lose.o', &get_logfile);
$answer = "CC -c lose.c -o lose.o\n";
&compare_output($answer, &get_logfile(1));
# TEST #3
# -------
&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;

View File

@ -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;

View File

@ -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