diff options
-rw-r--r-- | ChangeLog | 36 | ||||
-rw-r--r-- | NEWS | 24 | ||||
-rw-r--r-- | dep.h | 4 | ||||
-rw-r--r-- | doc/make.texi | 62 | ||||
-rw-r--r-- | file.c | 228 | ||||
-rw-r--r-- | filedef.h | 10 | ||||
-rw-r--r-- | implicit.c | 14 | ||||
-rw-r--r-- | main.c | 9 | ||||
-rw-r--r-- | make.h | 2 | ||||
-rw-r--r-- | misc.c | 17 | ||||
-rw-r--r-- | read.c | 130 | ||||
-rw-r--r-- | rule.c | 5 | ||||
-rw-r--r-- | tests/ChangeLog | 12 | ||||
-rwxr-xr-x | tests/run_make_tests.pl | 7 | ||||
-rw-r--r-- | tests/scripts/features/order_only | 104 | ||||
-rw-r--r-- | tests/scripts/features/se_explicit | 24 | ||||
-rw-r--r-- | tests/scripts/features/se_statpat | 4 | ||||
-rw-r--r-- | tests/scripts/features/statipattrules | 65 | ||||
-rw-r--r-- | tests/scripts/misc/general4 | 25 | ||||
-rw-r--r-- | tests/scripts/variables/automatic | 7 |
20 files changed, 460 insertions, 329 deletions
@@ -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 @@ -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 @@ -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 @@ -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; } } } @@ -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)); @@ -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; } @@ -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; { @@ -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; @@ -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.*/ @@ -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; @@ -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 |