mirror of
https://github.com/mirror/make.git
synced 2025-03-29 13:31:09 +08:00
Support the .EXTRA_PREREQS special variable
Initial implementation by Christof Warlich <cwarlich@gmx.de> * NEWS: Announce the new feature. * doc/make.texi (Other Special Variables): Document .EXTRA_PREREQS. * src/dep.h (struct dep): New flag to note extra prereq deps. * src/filedef.h (expand_extra_prereqs): Declare a function to expand the value of .EXTRA_PREREQS. * src/file.c (expand_extra_prereqs): Given a struct variable lookup of .EXTRA_PREREQS, convert it into a list of deps and for each one make sure it has a struct file and has the new flag set. (snap_file): A new function invoked by hash_map that will perform per-file operations: set up second expansion, intermediate, and also .EXTRA_PREREQS. Manage circular dependencies by ignoring them. (snap_deps): Defer per-file operations until the end. Look up the global .EXTRA_PREREQS and pass it along to snap_file for each file. * src/implicit.c (struct patdeps): Remember the extra prereqs flag. (pattern_search): Transfer extra prereqs flag settings into the matched pattern rule. * src/rule.h (snap_implicit_rules): Rename count_implicit_rules to snap_implicit_rules since we now do more than count. * src/rule.c (snap_implicit_rules): As we walk through all the pattern rules, add in any global .EXTRA_PREREQS to the dep list. Ensure we take them into account for the max number of prereqs and name length. * src/main.c (main): Add extra-prereqs to .FEATURES. Call the renamed snap_implicit_rules. * tests/scripts/variables/EXTRA_PREREQS: Add tests.
This commit is contained in:
parent
e56243fe57
commit
4e12a5fa45
1
AUTHORS
1
AUTHORS
@ -68,6 +68,7 @@ Other contributors:
|
|||||||
David Boyce <dsb@boyski.com>
|
David Boyce <dsb@boyski.com>
|
||||||
Frank Heckenbach <f.heckenbach@fh-soft.de>
|
Frank Heckenbach <f.heckenbach@fh-soft.de>
|
||||||
Kaz Kylheku <kaz@kylheku.com>
|
Kaz Kylheku <kaz@kylheku.com>
|
||||||
|
Christof Warlich <cwarlich@gmx.de>
|
||||||
|
|
||||||
With suggestions/comments/bug reports from a cast of ... well ...
|
With suggestions/comments/bug reports from a cast of ... well ...
|
||||||
hundreds, anyway :)
|
hundreds, anyway :)
|
||||||
|
7
NEWS
7
NEWS
@ -48,6 +48,13 @@ http://sv.gnu.org/bugs/index.php?group=make&report_id=111&fix_release_id=108&set
|
|||||||
search for 'grouped-target' in the .FEATURES special variable.
|
search for 'grouped-target' in the .FEATURES special variable.
|
||||||
Implementation contributed by Kaz Kylheku <kaz@kylheku.com>
|
Implementation contributed by Kaz Kylheku <kaz@kylheku.com>
|
||||||
|
|
||||||
|
* New feature: .EXTRA_PREREQS variable
|
||||||
|
Words in this variable are considered prerequisites of targets but they are
|
||||||
|
not added to any of the automatic variable values when expanding the
|
||||||
|
recipe. This variable can either be global (applies to all targets) or
|
||||||
|
a target-specific variable. To detect this feature search for 'extra-prereqs'
|
||||||
|
in the .FEATURES special variable.
|
||||||
|
|
||||||
* Makefiles can now specify the '-j' option in their MAKEFLAGS variable and
|
* Makefiles can now specify the '-j' option in their MAKEFLAGS variable and
|
||||||
this will cause make to enable that parallelism mode.
|
this will cause make to enable that parallelism mode.
|
||||||
|
|
||||||
|
@ -6631,6 +6631,57 @@ Supports dynamically loadable objects for creating custom extensions.
|
|||||||
Expands to a list of directories that @code{make} searches for
|
Expands to a list of directories that @code{make} searches for
|
||||||
included makefiles (@pxref{Include, , Including Other Makefiles}).
|
included makefiles (@pxref{Include, , Including Other Makefiles}).
|
||||||
|
|
||||||
|
@vindex .EXTRA_PREREQS @r{(prerequisites not added to automatic variables)}
|
||||||
|
@item .EXTRA_PREREQS
|
||||||
|
Each word in this variable is a new prerequisite which is added to
|
||||||
|
targets for which it is set. These prerequisites differ from normal
|
||||||
|
prerequisites in that they do not appear in any of the automatic
|
||||||
|
variables (@pxref{Automatic Variables}). This allows prerequisites to
|
||||||
|
be defined which do not impact the recipe.
|
||||||
|
|
||||||
|
Consider a rule to link a program:
|
||||||
|
|
||||||
|
@example
|
||||||
|
myprog: myprog.o file1.o file2.o
|
||||||
|
$(CC) $(CFLAGS) $(LDFLAGS) -o $@@ $^ $(LDLIBS)
|
||||||
|
@end example
|
||||||
|
|
||||||
|
Now suppose you want to enhance this makefile to ensure that updates
|
||||||
|
to the compiler cause the program to be re-linked. You can add the
|
||||||
|
compiler as a prerequisite, but you must ensure that it's not passed
|
||||||
|
as an argument to link command. You'll need something like this:
|
||||||
|
|
||||||
|
@example
|
||||||
|
myprog: myprog.o file1.o file2.o $(CC)
|
||||||
|
$(CC) $(CFLAGS) $(LDFLAGS) -o $@@ $(filter-out $(CC),$^) $(LDLIBS)
|
||||||
|
@end example
|
||||||
|
|
||||||
|
Then consider having multiple extra prerequisites: they would all have
|
||||||
|
to be filtered out. Using @code{.EXTRA_PREREQS} and target-specific
|
||||||
|
variables provides a simpler solution:
|
||||||
|
|
||||||
|
@example
|
||||||
|
myprog: myprog.o file1.o file2.o
|
||||||
|
$(CC) $(CFLAGS) $(LDFLAGS) -o $@@ $^ $(LDLIBS)
|
||||||
|
myprog: .EXTRA_PREREQS = $(CC)
|
||||||
|
@end example
|
||||||
|
|
||||||
|
This feature can also be useful if you want to add prerequisites to a
|
||||||
|
makefile you cannot easily modify: you can create a new file such as
|
||||||
|
@file{extra.mk}:
|
||||||
|
|
||||||
|
@example
|
||||||
|
myprog: .EXTRA_PREREQS = $(CC)
|
||||||
|
@end example
|
||||||
|
|
||||||
|
then invoke @code{make -f extra.mk -f Makefile}.
|
||||||
|
|
||||||
|
Setting @code{.EXTRA_PREREQS} globally will cause those prerequisites
|
||||||
|
to be added to all targets (which did not themselves override it with
|
||||||
|
a target-specific value). Note @code{make} is smart enough not to add
|
||||||
|
a prerequisite listed in @code{.EXTRA_PREREQS} as a prerequisite to
|
||||||
|
itself.
|
||||||
|
|
||||||
@end table
|
@end table
|
||||||
|
|
||||||
@node Conditionals, Functions, Using Variables, Top
|
@node Conditionals, Functions, Using Variables, Top
|
||||||
|
@ -133,7 +133,7 @@ set_file_variables (struct file *file)
|
|||||||
/* $< is the first not order-only dependency. */
|
/* $< is the first not order-only dependency. */
|
||||||
less = "";
|
less = "";
|
||||||
for (d = file->deps; d != 0; d = d->next)
|
for (d = file->deps; d != 0; d = d->next)
|
||||||
if (!d->ignore_mtime)
|
if (!d->ignore_mtime && !d->ignore_automatic_vars)
|
||||||
{
|
{
|
||||||
if (!d->need_2nd_expansion)
|
if (!d->need_2nd_expansion)
|
||||||
less = dep_name (d);
|
less = dep_name (d);
|
||||||
@ -178,7 +178,7 @@ set_file_variables (struct file *file)
|
|||||||
bar_len = 0;
|
bar_len = 0;
|
||||||
for (d = file->deps; d != 0; d = d->next)
|
for (d = file->deps; d != 0; d = d->next)
|
||||||
{
|
{
|
||||||
if (!d->need_2nd_expansion)
|
if (!d->need_2nd_expansion && !d->ignore_automatic_vars)
|
||||||
{
|
{
|
||||||
if (d->ignore_mtime)
|
if (d->ignore_mtime)
|
||||||
bar_len += strlen (dep_name (d)) + 1;
|
bar_len += strlen (dep_name (d)) + 1;
|
||||||
@ -200,7 +200,7 @@ set_file_variables (struct file *file)
|
|||||||
|
|
||||||
qmark_len = plus_len + 1; /* Will be this or less. */
|
qmark_len = plus_len + 1; /* Will be this or less. */
|
||||||
for (d = file->deps; d != 0; d = d->next)
|
for (d = file->deps; d != 0; d = d->next)
|
||||||
if (! d->ignore_mtime && ! d->need_2nd_expansion)
|
if (! d->ignore_mtime && ! d->need_2nd_expansion && ! d->ignore_automatic_vars)
|
||||||
{
|
{
|
||||||
const char *c = dep_name (d);
|
const char *c = dep_name (d);
|
||||||
|
|
||||||
@ -247,7 +247,7 @@ set_file_variables (struct file *file)
|
|||||||
|
|
||||||
for (d = file->deps; d != 0; d = d->next)
|
for (d = file->deps; d != 0; d = d->next)
|
||||||
{
|
{
|
||||||
if (d->need_2nd_expansion)
|
if (d->need_2nd_expansion || d->ignore_automatic_vars)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
slot = hash_find_slot (&dep_hash, d);
|
slot = hash_find_slot (&dep_hash, d);
|
||||||
@ -269,7 +269,7 @@ set_file_variables (struct file *file)
|
|||||||
{
|
{
|
||||||
const char *c;
|
const char *c;
|
||||||
|
|
||||||
if (d->need_2nd_expansion || hash_find_item (&dep_hash, d) != d)
|
if (d->need_2nd_expansion || d->ignore_automatic_vars || hash_find_item (&dep_hash, d) != d)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
c = dep_name (d);
|
c = dep_name (d);
|
||||||
|
@ -48,7 +48,8 @@ struct nameseq
|
|||||||
unsigned int changed : 1; \
|
unsigned int changed : 1; \
|
||||||
unsigned int ignore_mtime : 1; \
|
unsigned int ignore_mtime : 1; \
|
||||||
unsigned int staticpattern : 1; \
|
unsigned int staticpattern : 1; \
|
||||||
unsigned int need_2nd_expansion : 1
|
unsigned int need_2nd_expansion : 1; \
|
||||||
|
unsigned int ignore_automatic_vars : 1
|
||||||
|
|
||||||
struct dep
|
struct dep
|
||||||
{
|
{
|
||||||
|
90
src/file.c
90
src/file.c
@ -550,15 +550,6 @@ enter_prereqs (struct dep *deps, const char *stem)
|
|||||||
return deps;
|
return deps;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Set the intermediate flag. */
|
|
||||||
|
|
||||||
static void
|
|
||||||
set_intermediate (const void *item)
|
|
||||||
{
|
|
||||||
struct file *f = (struct file *) item;
|
|
||||||
f->intermediate = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Expand and parse each dependency line. */
|
/* Expand and parse each dependency line. */
|
||||||
static void
|
static void
|
||||||
expand_deps (struct file *f)
|
expand_deps (struct file *f)
|
||||||
@ -644,13 +635,69 @@ expand_deps (struct file *f)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Reset the updating flag. */
|
/* Add extra prereqs to the file in question. */
|
||||||
|
|
||||||
|
struct dep *
|
||||||
|
expand_extra_prereqs (const struct variable *extra)
|
||||||
|
{
|
||||||
|
struct dep *prereqs = extra ? split_prereqs (variable_expand (extra->value)) : NULL;
|
||||||
|
|
||||||
|
for (struct dep *d = prereqs; d; d = d->next)
|
||||||
|
{
|
||||||
|
d->file = lookup_file (d->name);
|
||||||
|
if (!d->file)
|
||||||
|
d->file = enter_file (d->name);
|
||||||
|
d->name = NULL;
|
||||||
|
d->ignore_automatic_vars = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return prereqs;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Perform per-file snap operations. */
|
||||||
|
|
||||||
static void
|
static void
|
||||||
reset_updating (const void *item)
|
snap_file (const void *item, void *arg)
|
||||||
{
|
{
|
||||||
struct file *f = (struct file *) item;
|
struct file *f = (struct file*)item;
|
||||||
f->updating = 0;
|
struct dep *prereqs = NULL;
|
||||||
|
|
||||||
|
/* If we're not doing second expansion then reset updating. */
|
||||||
|
if (!second_expansion)
|
||||||
|
f->updating = 0;
|
||||||
|
|
||||||
|
/* If .SECONDARY is set with no deps, mark all targets as intermediate. */
|
||||||
|
if (all_secondary)
|
||||||
|
f->intermediate = 1;
|
||||||
|
|
||||||
|
/* If .EXTRA_PREREQS is set, add them as ignored by automatic variables. */
|
||||||
|
if (f->variables)
|
||||||
|
prereqs = expand_extra_prereqs (lookup_variable_in_set (STRING_SIZE_TUPLE(".EXTRA_PREREQS"), f->variables->set));
|
||||||
|
|
||||||
|
else if (f->is_target)
|
||||||
|
prereqs = copy_dep_chain (arg);
|
||||||
|
|
||||||
|
if (prereqs)
|
||||||
|
{
|
||||||
|
struct dep *d;
|
||||||
|
for (d = prereqs; d; d = d->next)
|
||||||
|
if (streq (f->name, dep_name (d)))
|
||||||
|
/* Skip circular dependencies. */
|
||||||
|
break;
|
||||||
|
|
||||||
|
if (d)
|
||||||
|
/* We broke early: must have found a circular dependency. */
|
||||||
|
free_dep_chain (prereqs);
|
||||||
|
else if (!f->deps)
|
||||||
|
f->deps = prereqs;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
d = f->deps;
|
||||||
|
while (d->next)
|
||||||
|
d = d->next;
|
||||||
|
d->next = prereqs;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* For each dependency of each file, make the 'struct dep' point
|
/* For each dependency of each file, make the 'struct dep' point
|
||||||
@ -700,9 +747,6 @@ snap_deps (void)
|
|||||||
expand_deps (f);
|
expand_deps (f);
|
||||||
free (file_slot_0);
|
free (file_slot_0);
|
||||||
}
|
}
|
||||||
else
|
|
||||||
/* We're not doing second expansion, so reset updating. */
|
|
||||||
hash_map (&files, reset_updating);
|
|
||||||
|
|
||||||
/* Now manage all the special targets. */
|
/* Now manage all the special targets. */
|
||||||
|
|
||||||
@ -744,10 +788,7 @@ snap_deps (void)
|
|||||||
f2->intermediate = f2->secondary = 1;
|
f2->intermediate = f2->secondary = 1;
|
||||||
/* .SECONDARY with no deps listed marks *all* files that way. */
|
/* .SECONDARY with no deps listed marks *all* files that way. */
|
||||||
else
|
else
|
||||||
{
|
all_secondary = 1;
|
||||||
all_secondary = 1;
|
|
||||||
hash_map (&files, set_intermediate);
|
|
||||||
}
|
|
||||||
|
|
||||||
f = lookup_file (".EXPORT_ALL_VARIABLES");
|
f = lookup_file (".EXPORT_ALL_VARIABLES");
|
||||||
if (f != 0 && f->is_target)
|
if (f != 0 && f->is_target)
|
||||||
@ -779,6 +820,15 @@ snap_deps (void)
|
|||||||
if (f != 0 && f->is_target)
|
if (f != 0 && f->is_target)
|
||||||
not_parallel = 1;
|
not_parallel = 1;
|
||||||
|
|
||||||
|
{
|
||||||
|
struct dep *prereqs = expand_extra_prereqs (lookup_variable (STRING_SIZE_TUPLE(".EXTRA_PREREQS")));
|
||||||
|
|
||||||
|
/* Perform per-file snap operations. */
|
||||||
|
hash_map_arg(&files, snap_file, prereqs);
|
||||||
|
|
||||||
|
free_dep_chain (prereqs);
|
||||||
|
}
|
||||||
|
|
||||||
#ifndef NO_MINUS_C_MINUS_O
|
#ifndef NO_MINUS_C_MINUS_O
|
||||||
/* If .POSIX was defined, remove OUTPUT_OPTION to comply. */
|
/* If .POSIX was defined, remove OUTPUT_OPTION to comply. */
|
||||||
/* This needs more work: what if the user sets this in the makefile?
|
/* This needs more work: what if the user sets this in the makefile?
|
||||||
|
@ -21,6 +21,11 @@ this program. If not, see <http://www.gnu.org/licenses/>. */
|
|||||||
|
|
||||||
#include "hash.h"
|
#include "hash.h"
|
||||||
|
|
||||||
|
struct commands;
|
||||||
|
struct dep;
|
||||||
|
struct variable;
|
||||||
|
struct variable_set_list;
|
||||||
|
|
||||||
struct file
|
struct file
|
||||||
{
|
{
|
||||||
const char *name;
|
const char *name;
|
||||||
@ -110,6 +115,7 @@ struct file *lookup_file (const char *name);
|
|||||||
struct file *enter_file (const char *name);
|
struct file *enter_file (const char *name);
|
||||||
struct dep *split_prereqs (char *prereqstr);
|
struct dep *split_prereqs (char *prereqstr);
|
||||||
struct dep *enter_prereqs (struct dep *prereqs, const char *stem);
|
struct dep *enter_prereqs (struct dep *prereqs, const char *stem);
|
||||||
|
struct dep *expand_extra_prereqs (const struct variable *extra);
|
||||||
void remove_intermediates (int sig);
|
void remove_intermediates (int sig);
|
||||||
void snap_deps (void);
|
void snap_deps (void);
|
||||||
void rename_file (struct file *file, const char *name);
|
void rename_file (struct file *file, const char *name);
|
||||||
|
@ -152,6 +152,7 @@ struct patdeps
|
|||||||
const char *pattern;
|
const char *pattern;
|
||||||
struct file *file;
|
struct file *file;
|
||||||
unsigned int ignore_mtime : 1;
|
unsigned int ignore_mtime : 1;
|
||||||
|
unsigned int ignore_automatic_vars : 1;
|
||||||
};
|
};
|
||||||
|
|
||||||
/* This structure stores information about pattern rules that we need
|
/* This structure stores information about pattern rules that we need
|
||||||
@ -564,6 +565,7 @@ pattern_search (struct file *file, int archive,
|
|||||||
{
|
{
|
||||||
++deps_found;
|
++deps_found;
|
||||||
d->ignore_mtime = dep->ignore_mtime;
|
d->ignore_mtime = dep->ignore_mtime;
|
||||||
|
d->ignore_automatic_vars = dep->ignore_automatic_vars;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* We've used up this dep, so next time get a new one. */
|
/* We've used up this dep, so next time get a new one. */
|
||||||
@ -723,6 +725,7 @@ pattern_search (struct file *file, int archive,
|
|||||||
|
|
||||||
memset (pat, '\0', sizeof (struct patdeps));
|
memset (pat, '\0', sizeof (struct patdeps));
|
||||||
pat->ignore_mtime = d->ignore_mtime;
|
pat->ignore_mtime = d->ignore_mtime;
|
||||||
|
pat->ignore_automatic_vars = d->ignore_automatic_vars;
|
||||||
|
|
||||||
DBS (DB_IMPLICIT,
|
DBS (DB_IMPLICIT,
|
||||||
(is_rule
|
(is_rule
|
||||||
@ -913,6 +916,7 @@ pattern_search (struct file *file, int archive,
|
|||||||
|
|
||||||
dep = alloc_dep ();
|
dep = alloc_dep ();
|
||||||
dep->ignore_mtime = pat->ignore_mtime;
|
dep->ignore_mtime = pat->ignore_mtime;
|
||||||
|
dep->ignore_automatic_vars = pat->ignore_automatic_vars;
|
||||||
s = strcache_add (pat->name);
|
s = strcache_add (pat->name);
|
||||||
if (recursions)
|
if (recursions)
|
||||||
dep->name = s;
|
dep->name = s;
|
||||||
|
@ -1313,7 +1313,7 @@ main (int argc, char **argv, char **envp)
|
|||||||
{
|
{
|
||||||
const char *features = "target-specific order-only second-expansion"
|
const char *features = "target-specific order-only second-expansion"
|
||||||
" else-if shortest-stem undefine oneshell nocomment"
|
" else-if shortest-stem undefine oneshell nocomment"
|
||||||
" grouped-target"
|
" grouped-target extra-prereqs"
|
||||||
#ifndef NO_ARCHIVES
|
#ifndef NO_ARCHIVES
|
||||||
" archives"
|
" archives"
|
||||||
#endif
|
#endif
|
||||||
@ -2134,9 +2134,9 @@ main (int argc, char **argv, char **envp)
|
|||||||
|
|
||||||
install_default_implicit_rules ();
|
install_default_implicit_rules ();
|
||||||
|
|
||||||
/* Compute implicit rule limits. */
|
/* Compute implicit rule limits and do magic for pattern rules. */
|
||||||
|
|
||||||
count_implicit_rule_limits ();
|
snap_implicit_rules ();
|
||||||
|
|
||||||
/* Construct the listings of directories in VPATH lists. */
|
/* Construct the listings of directories in VPATH lists. */
|
||||||
|
|
||||||
|
61
src/rule.c
61
src/rule.c
@ -60,36 +60,43 @@ struct file *suffix_file;
|
|||||||
|
|
||||||
static size_t maxsuffix;
|
static size_t maxsuffix;
|
||||||
|
|
||||||
/* Compute the maximum dependency length and maximum number of
|
/* Compute the maximum dependency length and maximum number of dependencies of
|
||||||
dependencies of all implicit rules. Also sets the subdir
|
all implicit rules. Also sets the subdir flag for a rule when appropriate,
|
||||||
flag for a rule when appropriate, possibly removing the rule
|
possibly removing the rule completely when appropriate.
|
||||||
completely when appropriate. */
|
|
||||||
|
Add any global EXTRA_PREREQS here as well. */
|
||||||
|
|
||||||
void
|
void
|
||||||
count_implicit_rule_limits (void)
|
snap_implicit_rules (void)
|
||||||
{
|
{
|
||||||
char *name;
|
char *name = NULL;
|
||||||
size_t namelen;
|
size_t namelen = 0;
|
||||||
struct rule *rule;
|
struct dep *prereqs = expand_extra_prereqs (lookup_variable (STRING_SIZE_TUPLE(".EXTRA_PREREQS")));
|
||||||
|
unsigned int pre_deps = 0;
|
||||||
|
|
||||||
num_pattern_rules = max_pattern_targets = max_pattern_deps = 0;
|
|
||||||
max_pattern_dep_length = 0;
|
max_pattern_dep_length = 0;
|
||||||
|
|
||||||
name = 0;
|
for (struct dep *d = prereqs; d; d = d->next)
|
||||||
namelen = 0;
|
|
||||||
rule = pattern_rules;
|
|
||||||
while (rule != 0)
|
|
||||||
{
|
{
|
||||||
unsigned int ndeps = 0;
|
size_t l = strlen (dep_name (d));
|
||||||
struct dep *dep;
|
if (l > max_pattern_dep_length)
|
||||||
struct rule *next = rule->next;
|
max_pattern_dep_length = l;
|
||||||
|
++pre_deps;
|
||||||
|
}
|
||||||
|
|
||||||
|
num_pattern_rules = max_pattern_targets = max_pattern_deps = 0;
|
||||||
|
|
||||||
|
for (struct rule *rule = pattern_rules; rule; rule = rule->next)
|
||||||
|
{
|
||||||
|
unsigned int ndeps = pre_deps;
|
||||||
|
struct dep *lastdep = NULL;
|
||||||
|
|
||||||
++num_pattern_rules;
|
++num_pattern_rules;
|
||||||
|
|
||||||
if (rule->num > max_pattern_targets)
|
if (rule->num > max_pattern_targets)
|
||||||
max_pattern_targets = rule->num;
|
max_pattern_targets = rule->num;
|
||||||
|
|
||||||
for (dep = rule->deps; dep != 0; dep = dep->next)
|
for (struct dep *dep = rule->deps; dep != 0; dep = dep->next)
|
||||||
{
|
{
|
||||||
const char *dname = dep_name (dep);
|
const char *dname = dep_name (dep);
|
||||||
size_t len = strlen (dname);
|
size_t len = strlen (dname);
|
||||||
@ -99,17 +106,20 @@ count_implicit_rule_limits (void)
|
|||||||
const char *p2;
|
const char *p2;
|
||||||
if (p == 0)
|
if (p == 0)
|
||||||
p = strrchr (dname, ':');
|
p = strrchr (dname, ':');
|
||||||
p2 = p != 0 ? strchr (dname, '%') : 0;
|
p2 = p ? strchr (p, '%') : 0;
|
||||||
#else
|
#else
|
||||||
const char *p = strrchr (dname, '/');
|
const char *p = strrchr (dname, '/');
|
||||||
const char *p2 = p != 0 ? strchr (dname, '%') : 0;
|
const char *p2 = p ? strchr (p, '%') : 0;
|
||||||
#endif
|
#endif
|
||||||
ndeps++;
|
ndeps++;
|
||||||
|
|
||||||
if (len > max_pattern_dep_length)
|
if (len > max_pattern_dep_length)
|
||||||
max_pattern_dep_length = len;
|
max_pattern_dep_length = len;
|
||||||
|
|
||||||
if (p != 0 && p2 > p)
|
if (!dep->next)
|
||||||
|
lastdep = dep;
|
||||||
|
|
||||||
|
if (p2)
|
||||||
{
|
{
|
||||||
/* There is a slash before the % in the dep name.
|
/* There is a slash before the % in the dep name.
|
||||||
Extract the directory name. */
|
Extract the directory name. */
|
||||||
@ -134,13 +144,20 @@ count_implicit_rule_limits (void)
|
|||||||
dep->changed = 0;
|
dep->changed = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (prereqs)
|
||||||
|
{
|
||||||
|
if (lastdep)
|
||||||
|
lastdep->next = copy_dep_chain (prereqs);
|
||||||
|
else
|
||||||
|
rule->deps = copy_dep_chain (prereqs);
|
||||||
|
}
|
||||||
|
|
||||||
if (ndeps > max_pattern_deps)
|
if (ndeps > max_pattern_deps)
|
||||||
max_pattern_deps = ndeps;
|
max_pattern_deps = ndeps;
|
||||||
|
|
||||||
rule = next;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
free (name);
|
free (name);
|
||||||
|
free_dep_chain (prereqs);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Create a pattern rule from a suffix rule.
|
/* Create a pattern rule from a suffix rule.
|
||||||
|
@ -48,7 +48,7 @@ extern size_t max_pattern_dep_length;
|
|||||||
extern struct file *suffix_file;
|
extern struct file *suffix_file;
|
||||||
|
|
||||||
|
|
||||||
void count_implicit_rule_limits (void);
|
void snap_implicit_rules (void);
|
||||||
void convert_to_pattern (void);
|
void convert_to_pattern (void);
|
||||||
void install_pattern_rule (struct pspec *p, int terminal);
|
void install_pattern_rule (struct pspec *p, int terminal);
|
||||||
void create_pattern_rule (const char **targets, const char **target_percents,
|
void create_pattern_rule (const char **targets, const char **target_percents,
|
||||||
|
151
tests/scripts/variables/EXTRA_PREREQS
Normal file
151
tests/scripts/variables/EXTRA_PREREQS
Normal file
@ -0,0 +1,151 @@
|
|||||||
|
# -*-perl-*-
|
||||||
|
|
||||||
|
$description = "Test the .EXTRA_PREREQS special variable.";
|
||||||
|
$details = "";
|
||||||
|
|
||||||
|
# Simple global .EXTRA_PREREQS and automatic variable settings
|
||||||
|
run_make_test('
|
||||||
|
.EXTRA_PREREQS = tick tack
|
||||||
|
.PHONY: all
|
||||||
|
all: ; @echo ${.EXTRA_PREREQS}/$@/$</$^/$?/$+/$|/$*/
|
||||||
|
tick tack: ; @echo $@
|
||||||
|
',
|
||||||
|
'', "tick\ntack\ntick tack/all///////\n");
|
||||||
|
|
||||||
|
# Global .EXTRA_PREREQS and pattern rules
|
||||||
|
run_make_test('
|
||||||
|
.EXTRA_PREREQS = tick tack
|
||||||
|
a%: ; @echo ${.EXTRA_PREREQS}/$@/$</$^/$?/$+/$|/$*/
|
||||||
|
tick tack: ; @echo $@
|
||||||
|
',
|
||||||
|
'all', "tick\ntack\ntick tack/all//////ll/\n");
|
||||||
|
|
||||||
|
# Simple target-specific .EXTRA_PREREQS and automatic variable settings
|
||||||
|
run_make_test('
|
||||||
|
.PHONY: all
|
||||||
|
all: ; @echo ${.EXTRA_PREREQS}/$@/$</$^/$?/$+/$|/$*/
|
||||||
|
all: .EXTRA_PREREQS = tick tack
|
||||||
|
tick tack: ; @echo $@
|
||||||
|
',
|
||||||
|
'', "tick\ntack\ntick tack/all///////\n");
|
||||||
|
|
||||||
|
# Simple pattern-specific .EXTRA_PREREQS and automatic variable settings
|
||||||
|
# This is not currently supported :-/
|
||||||
|
if (0) {
|
||||||
|
run_make_test('
|
||||||
|
.PHONY: all
|
||||||
|
all: ; @echo ${.EXTRA_PREREQS}/$@/$</$^/$?/$+/$|/$*/
|
||||||
|
a%: .EXTRA_PREREQS = tick tack
|
||||||
|
tick tack: ; @echo $@
|
||||||
|
',
|
||||||
|
'', "tick\ntack\ntick tack/all///////\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
touch('hi');
|
||||||
|
|
||||||
|
# Basic test target specific .EXTRA_PREREQS:
|
||||||
|
run_make_test('
|
||||||
|
DEPENDENCY_ONLY_PREREQUISITES = ho hey
|
||||||
|
OTHER_PREREQUISITES := foo bar baz
|
||||||
|
target: .EXTRA_PREREQS := hi ${DEPENDENCY_ONLY_PREREQUISITES}
|
||||||
|
target: ${OTHER_PREREQUISITES} ; @echo ${.EXTRA_PREREQS} $^
|
||||||
|
.PHONY: target ${DEPENDENCY_ONLY_PREREQUISITES} ${OTHER_PREREQUISITES}
|
||||||
|
${DEPENDENCY_ONLY_PREREQUISITES} ${OTHER_PREREQUISITES}: ; @echo $@
|
||||||
|
',
|
||||||
|
'', "foo\nbar\nbaz\nho\nhey\nhi ho hey foo bar baz\n");
|
||||||
|
|
||||||
|
# Test target specific .EXTRA_PREREQS and pattern rules:
|
||||||
|
run_make_test('
|
||||||
|
all: target.dst
|
||||||
|
DEPENDENCY_ONLY_PREREQUISITES = ho hey
|
||||||
|
target.dst: .EXTRA_PREREQS := hi ${DEPENDENCY_ONLY_PREREQUISITES}
|
||||||
|
%.dst: %.src ; @echo ${.EXTRA_PREREQS} $^
|
||||||
|
.PHONY: ${DEPENDENCY_ONLY_PREREQUISITES} target.src
|
||||||
|
${DEPENDENCY_ONLY_PREREQUISITES} target.src: ; @echo $@
|
||||||
|
',
|
||||||
|
'', "target.src\nho\nhey\nhi ho hey target.src\n");
|
||||||
|
|
||||||
|
# Test that global .EXTRA_PREREQS are built first:
|
||||||
|
run_make_test('
|
||||||
|
.EXTRA_PREREQS = hi ho hey
|
||||||
|
OTHER_PREREQUISITES := foo bar baz
|
||||||
|
target: ${OTHER_PREREQUISITES} ; @echo ${.EXTRA_PREREQS} $^
|
||||||
|
.PHONY: target ${.EXTRA_PREREQS} ${OTHER_PREREQUISITES}
|
||||||
|
${.EXTRA_PREREQS} ${OTHER_PREREQUISITES}: ; @echo $@
|
||||||
|
',
|
||||||
|
'', "hi\nho\nhey\nfoo\nbar\nbaz\nhi ho hey foo bar baz\n");
|
||||||
|
|
||||||
|
# Test that target specific .EXTRA_PREREQS override global .EXTRA_PREREQS:
|
||||||
|
run_make_test('
|
||||||
|
.EXTRA_PREREQS = tick tack
|
||||||
|
DEPENDENCY_ONLY_PREREQUISITES = ho hey
|
||||||
|
OTHER_PREREQUISITES := foo bar baz
|
||||||
|
target: .EXTRA_PREREQS := hi ${DEPENDENCY_ONLY_PREREQUISITES}
|
||||||
|
target: ${OTHER_PREREQUISITES} ; @echo ${.EXTRA_PREREQS} $^
|
||||||
|
.PHONY: target ${DEPENDENCY_ONLY_PREREQUISITES} ${OTHER_PREREQUISITES} ${.EXTRA_PREREQS}
|
||||||
|
${DEPENDENCY_ONLY_PREREQUISITES} ${OTHER_PREREQUISITES} ${.EXTRA_PREREQS}: ; @echo $@
|
||||||
|
',
|
||||||
|
'', "tick\ntack\nfoo\nbar\nbaz\nho\nhey\nhi ho hey foo bar baz\n");
|
||||||
|
|
||||||
|
# Cleanup:
|
||||||
|
unlink('hi');
|
||||||
|
|
||||||
|
# Test error reporting of global .EXTRA_PREREQS:
|
||||||
|
run_make_test('
|
||||||
|
.EXTRA_PREREQS = tick tack
|
||||||
|
.PHONY: all
|
||||||
|
all: ; @echo ${.EXTRA_PREREQS} $^
|
||||||
|
',
|
||||||
|
'', "#MAKE#: *** No rule to make target 'tick', needed by 'all'. Stop.", 512);
|
||||||
|
|
||||||
|
# Test error reporting of global .EXTRA_PREREQS and keep-going:
|
||||||
|
run_make_test('
|
||||||
|
.EXTRA_PREREQS = tick tack
|
||||||
|
.PHONY: all
|
||||||
|
all: ; @echo ${.EXTRA_PREREQS} $^
|
||||||
|
',
|
||||||
|
'-k', "#MAKE#: *** No rule to make target 'tick', needed by 'all'.\n#MAKE#: *** No rule to make target 'tack', needed by 'all'.\n#MAKE#: Target 'all' not remade because of errors.", 512);
|
||||||
|
|
||||||
|
# Test error reporting of target specific .EXTRA_PREREQS and keep-going:
|
||||||
|
run_make_test('
|
||||||
|
all: .EXTRA_PREREQS = tick tack
|
||||||
|
.PHONY: all
|
||||||
|
all: ; @echo ${.EXTRA_PREREQS} $^
|
||||||
|
',
|
||||||
|
'-k',
|
||||||
|
"#MAKE#: *** No rule to make target 'tick', needed by 'all'.
|
||||||
|
#MAKE#: *** No rule to make target 'tack', needed by 'all'.
|
||||||
|
#MAKE#: Target 'all' not remade because of errors.\n", 512);
|
||||||
|
|
||||||
|
# Test wildcard
|
||||||
|
|
||||||
|
touch('tick', 'tack');
|
||||||
|
|
||||||
|
run_make_test('
|
||||||
|
.EXTRA_PREREQS = *ck
|
||||||
|
.PHONY: all tick tack
|
||||||
|
all: ; @echo ${.EXTRA_PREREQS} $^
|
||||||
|
tick tack: ; @echo $@
|
||||||
|
',
|
||||||
|
'', "tack\ntick\ntack tick\n");
|
||||||
|
|
||||||
|
run_make_test('
|
||||||
|
.PHONY: all tick tack
|
||||||
|
all: ; @echo ${.EXTRA_PREREQS} $^
|
||||||
|
all: .EXTRA_PREREQS = *ck
|
||||||
|
tick tack: ; @echo $@
|
||||||
|
',
|
||||||
|
'', "tack\ntick\ntack tick\n");
|
||||||
|
|
||||||
|
run_make_test('
|
||||||
|
.PHONY: tick tack
|
||||||
|
a%: ; @echo ${.EXTRA_PREREQS} $^
|
||||||
|
.EXTRA_PREREQS = *ck
|
||||||
|
tick tack: ; @echo $@
|
||||||
|
',
|
||||||
|
'all', "tack\ntick\ntack tick\n");
|
||||||
|
|
||||||
|
unlink('tick', 'tack');
|
||||||
|
|
||||||
|
# This tells the test driver that the perl test script executed properly.
|
||||||
|
1;
|
Loading…
Reference in New Issue
Block a user