mirror of
https://salsa.debian.org/srivasta/make-dfsg.git
synced 2024-12-26 14:00:56 +00:00
- Rework secondary expansion so we only defer it if there's a possibility
it might be needed: for most situations we parse prereqs immediately as we used to. Reduces memory usage. - Fixes Savannah bug #18622.
This commit is contained in:
parent
3cc351decd
commit
0afbbf8595
21 changed files with 960 additions and 914 deletions
53
ChangeLog
53
ChangeLog
|
@ -1,3 +1,56 @@
|
|||
2009-09-23 Paul <psmith@gnu.org>
|
||||
|
||||
Rework the way secondary expansion is stored, for efficiency.
|
||||
This changes secondary expansion so that ONLY WHEN we know we have
|
||||
a possibility of needing secondary expansion, do we defer the
|
||||
secondary expansion. This means more parsing the deps but we use
|
||||
a lot less memory (due to the strcache). Also, this fixes
|
||||
Savannah bug #18622.
|
||||
|
||||
* read.c (eval): Don't parse the dep string here anymore.
|
||||
(record_files): Take the dep argument as an unparsed string. If
|
||||
secondary expansion is enabled AND the prereq string has a '$' in
|
||||
it, then set NEED_2ND_EXPANSION and keep the entire string.
|
||||
Otherwise, parse the dep string here to construct the dep list
|
||||
with the names in the strcache.
|
||||
|
||||
* misc.c (copy_dep_chain): For NEED_2ND_EXPANSION, we need to
|
||||
duplicate the name string (others are in the strcache).
|
||||
|
||||
* implicit.c: Remove struct idep and free_idep_chain(): unused.
|
||||
(struct patdeps): New structure to store prereq information.
|
||||
(pattern_search): Use the NEED_2ND_EXPANSION flag to determine
|
||||
which prerequisites need expansion, and expand only those.
|
||||
|
||||
* file.c (split_prereqs): Break parse_prereqs() into two parts: this
|
||||
and enter_prereqs(). split_prereqs() takes a fully-expanded string
|
||||
and splits it into a DEP list, handling order-only prereqs.
|
||||
(enter_prereqs): This function enters a list of DEPs into the file
|
||||
database. If there's a stem defined, expand any pattern chars.
|
||||
(expand_deps): Only try to expand DEPs which have NEED_2ND_EXPANSION
|
||||
set. Use the above functions.
|
||||
(snap_deps): Only perform second expansion on prereqs that need it,
|
||||
as defined by the NEED_2ND_EXPANSION flag.
|
||||
(print_prereqs): New function to print the prereqs
|
||||
(print_file): Call print_prereqs() rather than print inline.
|
||||
|
||||
* hash.h (STRING_COMPARE): Take advantage of strcache() by
|
||||
comparing pointers.
|
||||
(STRING_N_COMPARE): Ditto.
|
||||
(ISTRING_COMPARE): Ditto.
|
||||
|
||||
* dep.h (PARSE_FILE_SEQ): New macro to reduce casts.
|
||||
(parse_file_seq): Return void*
|
||||
* read.c (parse_file_seq): Return void*.
|
||||
(eval): Invoke macroized version of parse_file_seq()
|
||||
* default.c (set_default_suffixes): Ditto.
|
||||
* file.c (split_prereqs): Ditto.
|
||||
* function.c (string_glob): Ditto.
|
||||
* main.c (main): Ditto.
|
||||
* rule.c (install_pattern_rule): Ditto.
|
||||
|
||||
* filedef.h: Add split_prereqs(), enter_prereqs(), etc.
|
||||
|
||||
2009-09-16 Paul Smith <psmith@gnu.org>
|
||||
|
||||
* misc.c (alloc_dep, free_dep): Now that we have xcalloc(),
|
||||
|
|
15
commands.c
15
commands.c
|
@ -116,7 +116,8 @@ set_file_variables (struct file *file)
|
|||
for (d = file->deps; d != 0; d = d->next)
|
||||
if (!d->ignore_mtime)
|
||||
{
|
||||
less = dep_name (d);
|
||||
if (!d->need_2nd_expansion)
|
||||
less = dep_name (d);
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -153,7 +154,7 @@ set_file_variables (struct file *file)
|
|||
|
||||
plus_len = 0;
|
||||
for (d = file->deps; d != 0; d = d->next)
|
||||
if (! d->ignore_mtime)
|
||||
if (! d->ignore_mtime && ! d->need_2nd_expansion)
|
||||
plus_len += strlen (dep_name (d)) + 1;
|
||||
if (plus_len == 0)
|
||||
plus_len++;
|
||||
|
@ -164,7 +165,7 @@ set_file_variables (struct file *file)
|
|||
|
||||
qmark_len = plus_len + 1; /* Will be this or less. */
|
||||
for (d = file->deps; d != 0; d = d->next)
|
||||
if (! d->ignore_mtime)
|
||||
if (! d->ignore_mtime && ! d->need_2nd_expansion)
|
||||
{
|
||||
const char *c = dep_name (d);
|
||||
|
||||
|
@ -198,7 +199,7 @@ set_file_variables (struct file *file)
|
|||
|
||||
bar_len = 0;
|
||||
for (d = file->deps; d != 0; d = d->next)
|
||||
if (d->ignore_mtime)
|
||||
if (d->ignore_mtime && ! d->need_2nd_expansion)
|
||||
bar_len += strlen (dep_name (d)) + 1;
|
||||
if (bar_len == 0)
|
||||
bar_len++;
|
||||
|
@ -217,8 +218,12 @@ set_file_variables (struct file *file)
|
|||
|
||||
for (d = file->deps; d != 0; d = d->next)
|
||||
{
|
||||
const char *c = dep_name (d);
|
||||
const char *c;
|
||||
|
||||
if (d->need_2nd_expansion)
|
||||
continue;
|
||||
|
||||
c = dep_name (d);
|
||||
#ifndef NO_ARCHIVES
|
||||
if (ar_name (c))
|
||||
{
|
||||
|
|
|
@ -542,8 +542,9 @@ set_default_suffixes (void)
|
|||
else
|
||||
{
|
||||
char *p = default_suffixes;
|
||||
suffix_file->deps = (struct dep *)
|
||||
parse_file_seq (&p, sizeof (struct dep), '\0', NULL, 0);
|
||||
suffix_file->deps = enter_prereqs(PARSE_FILE_SEQ (&p, struct dep, '\0',
|
||||
NULL, 0),
|
||||
NULL);
|
||||
define_variable ("SUFFIXES", 8, default_suffixes, o_default, 0);
|
||||
}
|
||||
}
|
||||
|
|
9
dep.h
9
dep.h
|
@ -61,11 +61,14 @@ struct nameseq
|
|||
#define PARSEFS_EXISTS (0x0004)
|
||||
#define PARSEFS_NOCACHE (0x0008)
|
||||
|
||||
#define PARSE_FILE_SEQ(_s,_t,_c,_p,_f) \
|
||||
(_t *)parse_file_seq ((_s),sizeof (_t),(_c),(_p),(_f))
|
||||
|
||||
#ifdef VMS
|
||||
struct nameseq *parse_file_seq ();
|
||||
void *parse_file_seq ();
|
||||
#else
|
||||
struct nameseq *parse_file_seq (char **stringp, unsigned int size,
|
||||
int stopchar, const char *prefix, int flags);
|
||||
void *parse_file_seq (char **stringp, unsigned int size,
|
||||
int stopchar, const char *prefix, int flags);
|
||||
#endif
|
||||
|
||||
char *tilde_expand (const char *name);
|
||||
|
|
4
expand.c
4
expand.c
|
@ -407,8 +407,8 @@ variable_expand_string (char *line, const char *string, long length)
|
|||
|
||||
if (*p == '\0')
|
||||
break;
|
||||
else
|
||||
++p;
|
||||
|
||||
++p;
|
||||
}
|
||||
|
||||
if (abuf)
|
||||
|
|
385
file.c
385
file.c
|
@ -411,11 +411,13 @@ remove_intermediates (int sig)
|
|||
}
|
||||
}
|
||||
|
||||
/* Given a string containing prerequisites (fully expanded), break it up into
|
||||
a struct dep list. Enter each of these prereqs into the file database.
|
||||
*/
|
||||
struct dep *
|
||||
parse_prereqs (char *p)
|
||||
split_prereqs (char *p)
|
||||
{
|
||||
struct dep *new = (struct dep *)
|
||||
parse_file_seq (&p, sizeof (struct dep), '|', NULL, 0);
|
||||
struct dep *new = PARSE_FILE_SEQ (&p, struct dep, '|', NULL, 0);
|
||||
|
||||
if (*p)
|
||||
{
|
||||
|
@ -424,8 +426,7 @@ parse_prereqs (char *p)
|
|||
struct dep *ood;
|
||||
|
||||
++p;
|
||||
ood = (struct dep *)
|
||||
parse_file_seq (&p, sizeof (struct dep), '\0', NULL, 0);
|
||||
ood = PARSE_FILE_SEQ (&p, struct dep, '\0', NULL, 0);
|
||||
|
||||
if (! new)
|
||||
new = ood;
|
||||
|
@ -444,6 +445,85 @@ parse_prereqs (char *p)
|
|||
return new;
|
||||
}
|
||||
|
||||
/* Given a list of prerequisites, enter them into the file database.
|
||||
If STEM is set then first expand patterns using STEM. */
|
||||
struct dep *
|
||||
enter_prereqs (struct dep *deps, const char *stem)
|
||||
{
|
||||
struct dep *d1;
|
||||
|
||||
if (deps == 0)
|
||||
return 0;
|
||||
|
||||
/* If we have a stem, expand the %'s. We use patsubst_expand to translate
|
||||
the prerequisites' patterns into plain prerequisite names. */
|
||||
if (stem)
|
||||
{
|
||||
const char *pattern = "%";
|
||||
char *buffer = variable_expand ("");
|
||||
struct dep *dp = deps, *dl = 0;
|
||||
|
||||
while (dp != 0)
|
||||
{
|
||||
char *percent;
|
||||
int nl = strlen (dp->name) + 1;
|
||||
char *nm = alloca (nl);
|
||||
memcpy (nm, dp->name, nl);
|
||||
percent = find_percent (nm);
|
||||
if (percent)
|
||||
{
|
||||
char *o;
|
||||
|
||||
/* We have to handle empty stems specially, because that
|
||||
would be equivalent to $(patsubst %,dp->name,) which
|
||||
will always be empty. */
|
||||
if (stem[0] == '\0')
|
||||
{
|
||||
memmove (percent, percent+1, strlen (percent));
|
||||
o = variable_buffer_output (buffer, nm, strlen (nm) + 1);
|
||||
}
|
||||
else
|
||||
o = patsubst_expand_pat (buffer, stem, pattern, nm,
|
||||
pattern+1, percent+1);
|
||||
|
||||
/* If the name expanded to the empty string, ignore it. */
|
||||
if (buffer[0] == '\0')
|
||||
{
|
||||
struct dep *df = dp;
|
||||
if (dp == deps)
|
||||
dp = deps = deps->next;
|
||||
else
|
||||
dp = dl->next = dp->next;
|
||||
free_dep (df);
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Save the name. */
|
||||
dp->name = strcache_add_len (buffer, o - buffer);
|
||||
}
|
||||
dp->stem = stem;
|
||||
dp->staticpattern = 1;
|
||||
dl = dp;
|
||||
dp = dp->next;
|
||||
}
|
||||
}
|
||||
|
||||
/* Enter them as files, unless they need a 2nd expansion. */
|
||||
for (d1 = deps; d1 != 0; d1 = d1->next)
|
||||
{
|
||||
if (d1->need_2nd_expansion)
|
||||
continue;
|
||||
|
||||
d1->file = lookup_file (d1->name);
|
||||
if (d1->file == 0)
|
||||
d1->file = enter_file (d1->name);
|
||||
d1->staticpattern = 0;
|
||||
d1->name = 0;
|
||||
}
|
||||
|
||||
return deps;
|
||||
}
|
||||
|
||||
/* Set the intermediate flag. */
|
||||
|
||||
static void
|
||||
|
@ -458,166 +538,94 @@ static void
|
|||
expand_deps (struct file *f)
|
||||
{
|
||||
struct dep *d;
|
||||
struct dep *old = f->deps;
|
||||
struct dep **dp;
|
||||
const char *file_stem = f->stem;
|
||||
unsigned int last_dep_has_cmds = f->updating;
|
||||
int initialized = 0;
|
||||
|
||||
f->updating = 0;
|
||||
f->deps = 0;
|
||||
|
||||
for (d = old; d != 0; d = d->next)
|
||||
/* Walk through the dependencies. For any dependency that needs 2nd
|
||||
expansion, expand it then insert the result into the list. */
|
||||
dp = &f->deps;
|
||||
d = f->deps;
|
||||
while (d != 0)
|
||||
{
|
||||
struct dep *new, *d1;
|
||||
char *p;
|
||||
struct dep *new, *next;
|
||||
char *name = (char *)d->name;
|
||||
|
||||
if (! d->name)
|
||||
continue;
|
||||
|
||||
/* Create the dependency list.
|
||||
If we're not doing 2nd expansion, then it's just the name. We will
|
||||
still need to massage it though. */
|
||||
if (! d->need_2nd_expansion)
|
||||
if (! d->name || ! d->need_2nd_expansion)
|
||||
{
|
||||
p = variable_expand ("");
|
||||
variable_buffer_output (p, d->name, strlen (d->name) + 1);
|
||||
p = variable_buffer;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* 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);
|
||||
|
||||
d->name = strcache_add_len (variable_buffer,
|
||||
o - variable_buffer);
|
||||
d->staticpattern = 0; /* Clear staticpattern so that we don't
|
||||
re-expand %s below. */
|
||||
}
|
||||
|
||||
/* We are going to do second expansion so initialize file variables
|
||||
for the file. Since the stem for static pattern rules comes from
|
||||
individual dep lines, we will temporarily set f->stem to d->stem.
|
||||
*/
|
||||
if (!initialized)
|
||||
{
|
||||
initialize_file_variables (f, 0);
|
||||
initialized = 1;
|
||||
}
|
||||
|
||||
if (d->stem != 0)
|
||||
f->stem = d->stem;
|
||||
|
||||
set_file_variables (f);
|
||||
|
||||
p = variable_expand_for_file (d->name, f);
|
||||
|
||||
if (d->stem != 0)
|
||||
f->stem = file_stem;
|
||||
/* This one is all set already. */
|
||||
dp = &d->next;
|
||||
d = d->next;
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Parse the prerequisites. */
|
||||
new = parse_prereqs (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)
|
||||
/* If it's from a static pattern rule, convert the patterns into
|
||||
"$*" so they'll expand properly. */
|
||||
if (d->staticpattern)
|
||||
{
|
||||
const char *pattern = "%";
|
||||
char *buffer = variable_expand ("");
|
||||
struct dep *dp = new, *dl = 0;
|
||||
|
||||
while (dp != 0)
|
||||
{
|
||||
char *percent;
|
||||
int nl = strlen (dp->name) + 1;
|
||||
char *nm = alloca (nl);
|
||||
memcpy (nm, dp->name, nl);
|
||||
percent = find_percent (nm);
|
||||
if (percent)
|
||||
{
|
||||
char *o;
|
||||
|
||||
/* We have to handle empty stems specially, because that
|
||||
would be equivalent to $(patsubst %,dp->name,) which
|
||||
will always be empty. */
|
||||
if (d->stem[0] == '\0')
|
||||
{
|
||||
memmove (percent, percent+1, strlen (percent));
|
||||
o = variable_buffer_output (buffer, nm, strlen (nm) + 1);
|
||||
}
|
||||
else
|
||||
o = patsubst_expand_pat (buffer, d->stem, pattern, nm,
|
||||
pattern+1, percent+1);
|
||||
|
||||
/* If the name expanded to the empty string, ignore it. */
|
||||
if (buffer[0] == '\0')
|
||||
{
|
||||
struct dep *df = dp;
|
||||
if (dp == new)
|
||||
dp = new = new->next;
|
||||
else
|
||||
dp = dl->next = dp->next;
|
||||
free_dep (df);
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Save the name. */
|
||||
dp->name = strcache_add_len (buffer, o - buffer);
|
||||
}
|
||||
dl = dp;
|
||||
dp = dp->next;
|
||||
}
|
||||
char *o;
|
||||
d->name = o = variable_expand ("");
|
||||
o = subst_expand (o, name, "%", "$*", 1, 2, 0);
|
||||
*o = '\0';
|
||||
free (name);
|
||||
d->name = name = xstrdup (d->name);
|
||||
d->staticpattern = 0;
|
||||
}
|
||||
|
||||
/* Enter them as files. */
|
||||
for (d1 = new; d1 != 0; d1 = d1->next)
|
||||
/* We're going to do second expansion so initialize file variables for
|
||||
the file. Since the stem for static pattern rules comes from
|
||||
individual dep lines, we will temporarily set f->stem to d->stem. */
|
||||
if (!initialized)
|
||||
{
|
||||
d1->file = lookup_file (d1->name);
|
||||
if (d1->file == 0)
|
||||
d1->file = enter_file (d1->name);
|
||||
d1->name = 0;
|
||||
d1->staticpattern = 0;
|
||||
d1->need_2nd_expansion = 0;
|
||||
initialize_file_variables (f, 0);
|
||||
initialized = 1;
|
||||
}
|
||||
|
||||
/* 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 (d->stem != 0)
|
||||
f->stem = d->stem;
|
||||
|
||||
if (new != 0)
|
||||
set_file_variables (f);
|
||||
|
||||
p = variable_expand_for_file (d->name, f);
|
||||
|
||||
if (d->stem != 0)
|
||||
f->stem = file_stem;
|
||||
|
||||
/* At this point we don't need the name anymore: free it. */
|
||||
free (name);
|
||||
|
||||
/* Parse the prerequisites and enter them into the file database. */
|
||||
new = enter_prereqs (split_prereqs (p), d->stem);
|
||||
|
||||
/* If there were no prereqs here (blank!) then throw this one out. */
|
||||
if (new == 0)
|
||||
{
|
||||
if (d->next == 0 && last_dep_has_cmds)
|
||||
{
|
||||
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 = new;
|
||||
}
|
||||
*dp = d->next;
|
||||
free_dep (d);
|
||||
d = *dp;
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Add newly parsed prerequisites. */
|
||||
next = d->next;
|
||||
*dp = new;
|
||||
for (dp = &new->next, d = new->next; d != 0; dp = &d->next, d = d->next)
|
||||
;
|
||||
*dp = next;
|
||||
d = *dp;
|
||||
}
|
||||
}
|
||||
|
||||
free_dep_chain (old);
|
||||
/* Reset the updating flag. */
|
||||
|
||||
static void
|
||||
reset_updating (const void *item)
|
||||
{
|
||||
struct file *f = (struct file *) item;
|
||||
f->updating = 0;
|
||||
}
|
||||
|
||||
/* For each dependency of each file, make the `struct dep' point
|
||||
|
@ -632,30 +640,44 @@ snap_deps (void)
|
|||
struct file *f;
|
||||
struct file *f2;
|
||||
struct dep *d;
|
||||
struct file **file_slot_0;
|
||||
struct file **file_slot;
|
||||
struct file **file_end;
|
||||
|
||||
/* Remember that we've done this. Once we start snapping deps we can no
|
||||
longer define new targets. */
|
||||
snapped_deps = 1;
|
||||
|
||||
/* Perform second expansion and enter each dependency name as a file. */
|
||||
/* Perform second expansion and enter each dependency name as a file. We
|
||||
must use hash_dump() here because within these loops we likely add new
|
||||
files to the table, possibly causing an in-situ table expansion.
|
||||
|
||||
/* Expand .SUFFIXES first; it's dependencies are used for $$* calculation. */
|
||||
for (f = lookup_file (".SUFFIXES"); f != 0; f = f->prev)
|
||||
expand_deps (f);
|
||||
We only need to do this if second_expansion has been defined; if it
|
||||
hasn't then all deps were expanded as the makefile was read in. If we
|
||||
ever change make to be able to unset .SECONDARY_EXPANSION this will have
|
||||
to change. */
|
||||
|
||||
/* For every target that's not .SUFFIXES, expand its dependencies.
|
||||
We must use hash_dump (), because within this loop we might add new files
|
||||
to the table, possibly causing an in-situ table expansion. */
|
||||
file_slot_0 = (struct file **) hash_dump (&files, 0, 0);
|
||||
file_end = file_slot_0 + files.ht_fill;
|
||||
for (file_slot = file_slot_0; file_slot < file_end; file_slot++)
|
||||
for (f = *file_slot; f != 0; f = f->prev)
|
||||
if (strcmp (f->name, ".SUFFIXES") != 0)
|
||||
if (second_expansion)
|
||||
{
|
||||
struct file **file_slot_0 = (struct file **) hash_dump (&files, 0, 0);
|
||||
struct file **file_end = file_slot_0 + files.ht_fill;
|
||||
struct file **file_slot;
|
||||
const char *suffixes;
|
||||
|
||||
/* Expand .SUFFIXES: its prerequisites are used for $$* calc. */
|
||||
f = lookup_file (".SUFFIXES");
|
||||
suffixes = f ? f->name : 0;
|
||||
for (; f != 0; f = f->prev)
|
||||
expand_deps (f);
|
||||
free (file_slot_0);
|
||||
|
||||
/* For every target that's not .SUFFIXES, expand its prerequisites. */
|
||||
|
||||
for (file_slot = file_slot_0; file_slot < file_end; file_slot++)
|
||||
for (f = *file_slot; f != 0; f = f->prev)
|
||||
if (f->name != suffixes)
|
||||
expand_deps (f);
|
||||
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. */
|
||||
|
||||
|
@ -859,35 +881,40 @@ file_timestamp_sprintf (char *p, FILE_TIMESTAMP ts)
|
|||
|
||||
/* Print the data base of files. */
|
||||
|
||||
static void
|
||||
print_file (const void *item)
|
||||
void
|
||||
print_prereqs (const struct dep *deps)
|
||||
{
|
||||
const struct file *f = item;
|
||||
struct dep *d;
|
||||
struct dep *ood = 0;
|
||||
|
||||
putchar ('\n');
|
||||
if (!f->is_target)
|
||||
puts (_("# Not a target:"));
|
||||
printf ("%s:%s", f->name, f->double_colon ? ":" : "");
|
||||
const struct dep *ood = 0;
|
||||
|
||||
/* Print all normal dependencies; note any order-only deps. */
|
||||
for (d = f->deps; d != 0; d = d->next)
|
||||
if (! d->ignore_mtime)
|
||||
printf (" %s", dep_name (d));
|
||||
for (; deps != 0; deps = deps->next)
|
||||
if (! deps->ignore_mtime)
|
||||
printf (" %s", dep_name (deps));
|
||||
else if (! ood)
|
||||
ood = d;
|
||||
ood = deps;
|
||||
|
||||
/* Print order-only deps, if we have any. */
|
||||
if (ood)
|
||||
{
|
||||
printf (" | %s", dep_name (ood));
|
||||
for (d = ood->next; d != 0; d = d->next)
|
||||
if (d->ignore_mtime)
|
||||
printf (" %s", dep_name (d));
|
||||
for (ood = ood->next; ood != 0; ood = ood->next)
|
||||
if (ood->ignore_mtime)
|
||||
printf (" %s", dep_name (ood));
|
||||
}
|
||||
|
||||
putchar ('\n');
|
||||
}
|
||||
|
||||
static void
|
||||
print_file (const void *item)
|
||||
{
|
||||
const struct file *f = item;
|
||||
|
||||
putchar ('\n');
|
||||
if (!f->is_target)
|
||||
puts (_("# Not a target:"));
|
||||
printf ("%s:%s", f->name, f->double_colon ? ":" : "");
|
||||
print_prereqs (f->deps);
|
||||
|
||||
if (f->precious)
|
||||
puts (_("# Precious file (prerequisite of .PRECIOUS)."));
|
||||
|
@ -906,6 +933,7 @@ print_file (const void *item)
|
|||
puts (_("# File is an intermediate prerequisite."));
|
||||
if (f->also_make != 0)
|
||||
{
|
||||
const struct dep *d;
|
||||
fputs (_("# Also makes:"), stdout);
|
||||
for (d = f->also_make; d != 0; d = d->next)
|
||||
printf (" %s", dep_name (d));
|
||||
|
@ -989,7 +1017,7 @@ print_file_data_base (void)
|
|||
#define VERIFY_CACHED(_p,_n) \
|
||||
do{\
|
||||
if (_p->_n && _p->_n[0] && !strcache_iscached (_p->_n)) \
|
||||
printf ("%s: Field %s not cached: %s\n", _p->name, # _n, _p->_n); \
|
||||
error (NULL, "%s: Field '%s' not cached: %s\n", _p->name, # _n, _p->_n); \
|
||||
}while(0)
|
||||
|
||||
static void
|
||||
|
@ -1006,7 +1034,8 @@ verify_file (const void *item)
|
|||
/* Check the deps. */
|
||||
for (d = f->deps; d != 0; d = d->next)
|
||||
{
|
||||
VERIFY_CACHED (d, name);
|
||||
if (! d->need_2nd_expansion)
|
||||
VERIFY_CACHED (d, name);
|
||||
VERIFY_CACHED (d, stem);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -102,7 +102,8 @@ extern struct file *suffix_file, *default_file;
|
|||
|
||||
struct file *lookup_file (const char *name);
|
||||
struct file *enter_file (const char *name);
|
||||
struct dep *parse_prereqs (char *prereqs);
|
||||
struct dep *split_prereqs (char *prereqstr);
|
||||
struct dep *enter_prereqs (struct dep *prereqs, const char *stem);
|
||||
void remove_intermediates (int sig);
|
||||
void snap_deps (void);
|
||||
void rename_file (struct file *file, const char *name);
|
||||
|
@ -111,6 +112,8 @@ void set_command_state (struct file *file, enum cmd_state state);
|
|||
void notice_finished_file (struct file *file);
|
||||
void init_hash_files (void);
|
||||
char *build_target_list (char *old_list);
|
||||
void print_prereqs (const struct dep *deps);
|
||||
void print_file_data_base (void);
|
||||
|
||||
#if FILE_TIMESTAMP_HI_RES
|
||||
# define FILE_TIMESTAMP_STAT_MODTIME(fname, st) \
|
||||
|
|
|
@ -355,7 +355,7 @@ string_glob (char *line)
|
|||
struct nameseq *chain;
|
||||
unsigned int idx;
|
||||
|
||||
chain = parse_file_seq (&line, sizeof (struct nameseq), '\0', NULL,
|
||||
chain = PARSE_FILE_SEQ (&line, struct nameseq, '\0', NULL,
|
||||
/* We do not want parse_file_seq to strip `./'s.
|
||||
That would break examples like:
|
||||
$(patsubst ./%.c,obj/%.o,$(wildcard ./?*.c)). */
|
||||
|
|
15
hash.h
15
hash.h
|
@ -79,6 +79,9 @@ extern void *hash_deleted_item;
|
|||
|
||||
/* hash and comparison macros for case-sensitive string keys. */
|
||||
|
||||
/* Due to the strcache, it's not uncommon for the string pointers to
|
||||
be identical. Take advantage of that to short-circuit string compares. */
|
||||
|
||||
#define STRING_HASH_1(KEY, RESULT) do { \
|
||||
unsigned char const *_key_ = (unsigned char const *) (KEY) - 1; \
|
||||
while (*++_key_) \
|
||||
|
@ -102,10 +105,10 @@ extern void *hash_deleted_item;
|
|||
} while (0)
|
||||
|
||||
#define STRING_COMPARE(X, Y, RESULT) do { \
|
||||
RESULT = strcmp ((X), (Y)); \
|
||||
RESULT = (X) == (Y) ? 0 : strcmp ((X), (Y)); \
|
||||
} while (0)
|
||||
#define return_STRING_COMPARE(X, Y) do { \
|
||||
return strcmp ((X), (Y)); \
|
||||
return (X) == (Y) ? 0 : strcmp ((X), (Y)); \
|
||||
} while (0)
|
||||
|
||||
|
||||
|
@ -138,10 +141,10 @@ extern void *hash_deleted_item;
|
|||
} while (0)
|
||||
|
||||
#define STRING_N_COMPARE(X, Y, N, RESULT) do { \
|
||||
RESULT = strncmp ((X), (Y), (N)); \
|
||||
RESULT = (X) == (Y) ? 0 : strncmp ((X), (Y), (N)); \
|
||||
} while (0)
|
||||
#define return_STRING_N_COMPARE(X, Y, N) do { \
|
||||
return strncmp ((X), (Y), (N)); \
|
||||
return (X) == (Y) ? 0 : strncmp ((X), (Y), (N)); \
|
||||
} while (0)
|
||||
|
||||
#ifdef HAVE_CASE_INSENSITIVE_FS
|
||||
|
@ -171,10 +174,10 @@ extern void *hash_deleted_item;
|
|||
} while (0)
|
||||
|
||||
#define ISTRING_COMPARE(X, Y, RESULT) do { \
|
||||
RESULT = strcasecmp ((X), (Y)); \
|
||||
RESULT = (X) == (Y) ? 0 : strcasecmp ((X), (Y)); \
|
||||
} while (0)
|
||||
#define return_ISTRING_COMPARE(X, Y) do { \
|
||||
return strcasecmp ((X), (Y)); \
|
||||
return (X) == (Y) ? 0 : strcasecmp ((X), (Y)); \
|
||||
} while (0)
|
||||
|
||||
#else
|
||||
|
|
724
implicit.c
724
implicit.c
|
@ -63,36 +63,11 @@ try_implicit_rule (struct file *file, unsigned int depth)
|
|||
}
|
||||
|
||||
|
||||
/* Struct idep captures information about implicit prerequisites
|
||||
that come from implicit rules. */
|
||||
struct idep
|
||||
{
|
||||
struct idep *next; /* struct dep -compatible interface */
|
||||
const char *name; /* name of the prerequisite */
|
||||
struct file *intermediate_file; /* intermediate file, 0 otherwise */
|
||||
const char *intermediate_pattern; /* pattern for intermediate file */
|
||||
unsigned char had_stem; /* had % substituted with stem */
|
||||
unsigned char ignore_mtime; /* ignore_mtime flag */
|
||||
};
|
||||
|
||||
static void
|
||||
free_idep_chain (struct idep *p)
|
||||
{
|
||||
struct idep *n;
|
||||
|
||||
for (; p != 0; p = n)
|
||||
{
|
||||
n = p->next;
|
||||
free (p);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Scans the BUFFER for the next word with whitespace as a separator.
|
||||
Returns the pointer to the beginning of the word. LENGTH hold the
|
||||
length of the word. */
|
||||
|
||||
static char *
|
||||
static const char *
|
||||
get_next_word (const char *buffer, unsigned int *length)
|
||||
{
|
||||
const char *p = buffer, *beg;
|
||||
|
@ -166,9 +141,22 @@ get_next_word (const char *buffer, unsigned int *length)
|
|||
if (length)
|
||||
*length = p - beg;
|
||||
|
||||
return (char *)beg;
|
||||
return beg;
|
||||
}
|
||||
|
||||
/* This structure stores information about the expanded prerequisites for a
|
||||
pattern rule. NAME is always set, to the strcache'd name of the prereq.
|
||||
FILE and PATTERN will be set for intermediate files only. IGNORE_MTIME is
|
||||
copied from the prerequisite we expanded.
|
||||
*/
|
||||
struct patdeps
|
||||
{
|
||||
const char *name;
|
||||
const char *pattern;
|
||||
struct file *file;
|
||||
unsigned int ignore_mtime : 1;
|
||||
};
|
||||
|
||||
/* Search the pattern rules for a rule with an existing dependency to make
|
||||
FILE. If a rule is found, the appropriate commands and deps are put in FILE
|
||||
and 1 is returned. If not, 0 is returned.
|
||||
|
@ -199,15 +187,15 @@ pattern_search (struct file *file, int archive,
|
|||
/* This is a file-object used as an argument in
|
||||
recursive calls. It never contains any data
|
||||
except during a recursive call. */
|
||||
struct file *intermediate_file = 0;
|
||||
struct file *int_file = 0;
|
||||
|
||||
/* This linked list records all the prerequisites actually
|
||||
found for a rule along with some other useful information
|
||||
(see struct idep for details). */
|
||||
struct idep* deps = 0;
|
||||
/* List of dependencies found recursively. */
|
||||
struct patdeps *deplist
|
||||
= xmalloc (max_pattern_deps * sizeof (struct patdeps));
|
||||
struct patdeps *pat = deplist;
|
||||
|
||||
/* 1 if we need to remove explicit prerequisites, 0 otherwise. */
|
||||
unsigned int remove_explicit_deps = 0;
|
||||
/* All the prerequisites actually found for a rule, after expansion. */
|
||||
struct dep *deps;
|
||||
|
||||
/* Names of possible dependencies are constructed in this buffer. */
|
||||
char *depname = alloca (namelen + max_pattern_dep_length);
|
||||
|
@ -242,13 +230,13 @@ pattern_search (struct file *file, int archive,
|
|||
that is not just `%'. */
|
||||
int specific_rule_matched = 0;
|
||||
|
||||
struct nameseq ns_simple;
|
||||
|
||||
unsigned int ri; /* uninit checks OK */
|
||||
struct rule *rule;
|
||||
struct dep *dep, *expl_d;
|
||||
|
||||
struct idep *d;
|
||||
struct idep **id_ptr;
|
||||
struct dep **d_ptr;
|
||||
char *pathdir = NULL;
|
||||
unsigned long pathlen;
|
||||
|
||||
PATH_VAR (stem_str); /* @@ Need to get rid of stem, stemlen, etc. */
|
||||
|
||||
|
@ -283,8 +271,12 @@ pattern_search (struct file *file, int archive,
|
|||
lastslash = 0;
|
||||
}
|
||||
|
||||
/* First see which pattern rules match this target
|
||||
and may be considered. Put them in TRYRULES. */
|
||||
pathlen = lastslash - filename + 1;
|
||||
|
||||
ns_simple.next = 0;
|
||||
|
||||
/* First see which pattern rules match this target and may be considered.
|
||||
Put them in TRYRULES. */
|
||||
|
||||
nrules = 0;
|
||||
for (rule = pattern_rules; rule != 0; rule = rule->next)
|
||||
|
@ -349,11 +341,10 @@ pattern_search (struct file *file, int archive,
|
|||
if (check_lastslash)
|
||||
{
|
||||
/* If so, don't include the directory prefix in STEM here. */
|
||||
unsigned int difference = lastslash - filename + 1;
|
||||
if (difference > stemlen)
|
||||
if (pathlen > stemlen)
|
||||
continue;
|
||||
stemlen -= difference;
|
||||
stem += difference;
|
||||
stemlen -= pathlen;
|
||||
stem += pathlen;
|
||||
}
|
||||
|
||||
/* Check that the rule pattern matches the text before the stem. */
|
||||
|
@ -415,46 +406,44 @@ pattern_search (struct file *file, int archive,
|
|||
initialize_file_variables (file, 0);
|
||||
|
||||
/* Try each rule once without intermediate files, then once with them. */
|
||||
for (intermed_ok = 0; intermed_ok == !!intermed_ok; ++intermed_ok)
|
||||
for (intermed_ok = 0; intermed_ok < 2; ++intermed_ok)
|
||||
{
|
||||
/* Try each pattern rule till we find one that applies.
|
||||
If it does, expand its dependencies (as substituted)
|
||||
and chain them in DEPS. */
|
||||
pat = deplist;
|
||||
|
||||
/* Try each pattern rule till we find one that applies. If it does,
|
||||
expand its dependencies (as substituted) and chain them in DEPS. */
|
||||
for (ri = 0; ri < nrules; ri++)
|
||||
{
|
||||
struct dep *dep;
|
||||
unsigned int failed = 0;
|
||||
int check_lastslash;
|
||||
int check_lastslash;
|
||||
int file_variables_set = 0;
|
||||
unsigned int deps_found = 0;
|
||||
/* NPTR points to the part of the prereq we haven't processed. */
|
||||
const char *nptr = 0;
|
||||
|
||||
rule = tryrules[ri];
|
||||
|
||||
remove_explicit_deps = 0;
|
||||
|
||||
/* RULE is nil when we discover that a rule,
|
||||
already placed in TRYRULES, should not be applied. */
|
||||
/* RULE is nil when we discover that a rule, already placed in
|
||||
TRYRULES, should not be applied. */
|
||||
if (rule == 0)
|
||||
continue;
|
||||
|
||||
/* Reject any terminal rules if we're
|
||||
looking to make intermediate files. */
|
||||
/* Reject any terminal rules if we're looking to make intermediate
|
||||
files. */
|
||||
if (intermed_ok && rule->terminal)
|
||||
continue;
|
||||
|
||||
/* Mark this rule as in use so a recursive
|
||||
pattern_search won't try to use it. */
|
||||
rule->in_use = 1;
|
||||
|
||||
/* From the lengths of the filename and the matching pattern parts,
|
||||
find the stem: the part of the filename that matches the %. */
|
||||
stem = filename
|
||||
+ (rule->suffixes[matches[ri]] - rule->targets[matches[ri]]) - 1;
|
||||
stemlen = namelen - rule->lens[matches[ri]] + 1;
|
||||
stem = filename + (rule->suffixes[matches[ri]]
|
||||
- rule->targets[matches[ri]]) - 1;
|
||||
stemlen = (namelen - rule->lens[matches[ri]]) + 1;
|
||||
check_lastslash = checked_lastslash[ri];
|
||||
if (check_lastslash)
|
||||
{
|
||||
stem += lastslash - filename + 1;
|
||||
stemlen -= (lastslash - filename) + 1;
|
||||
stem += pathlen;
|
||||
stemlen -= pathlen;
|
||||
}
|
||||
|
||||
DBS (DB_IMPLICIT, (_("Trying pattern rule with stem `%.*s'.\n"),
|
||||
|
@ -463,350 +452,345 @@ pattern_search (struct file *file, int archive,
|
|||
strncpy (stem_str, stem, stemlen);
|
||||
stem_str[stemlen] = '\0';
|
||||
|
||||
/* If there are no prerequisites, then this rule matches. */
|
||||
if (rule->deps == 0)
|
||||
break;
|
||||
|
||||
/* Temporary assign STEM to file->stem (needed to set file
|
||||
variables below). */
|
||||
file->stem = stem_str;
|
||||
|
||||
/* Try each dependency; see if it "exists". */
|
||||
/* Mark this rule as in use so a recursive pattern_search won't try
|
||||
to use it. */
|
||||
rule->in_use = 1;
|
||||
|
||||
for (dep = rule->deps; dep != 0; dep = dep->next)
|
||||
{
|
||||
unsigned int len;
|
||||
/* Try each prerequisite; see if it exists or can be created. We'll
|
||||
build a list of prereq info in DEPLIST. Due to 2nd expansion we
|
||||
may have to process multiple prereqs for a single dep entry. */
|
||||
|
||||
pat = deplist;
|
||||
dep = rule->deps;
|
||||
nptr = dep_name (dep);
|
||||
while (1)
|
||||
{
|
||||
const char *dir = NULL;
|
||||
struct nameseq *ns, *n;
|
||||
char *p;
|
||||
char *p2;
|
||||
unsigned int order_only = 0; /* Set if '|' was seen. */
|
||||
|
||||
/* In an ideal world we would take the dependency line,
|
||||
substitute the stem, re-expand the whole line and chop it
|
||||
into individual prerequisites. Unfortunately this won't work
|
||||
because of the "check_lastslash" twist. Instead, we will
|
||||
have to go word by word, taking $()'s into account, for each
|
||||
word we will substitute the stem, re-expand, chop it up, and,
|
||||
if check_lastslash != 0, add the directory part to each
|
||||
resulting prerequisite. */
|
||||
|
||||
p = get_next_word (dep->name, &len);
|
||||
|
||||
while (1)
|
||||
/* If we need to add the directory prefix set it up. */
|
||||
if (check_lastslash)
|
||||
{
|
||||
const char *dir = NULL;
|
||||
int add_dir = 0;
|
||||
int had_stem = 0;
|
||||
|
||||
if (p == 0)
|
||||
break; /* No more words */
|
||||
|
||||
/* Is there a pattern in this prerequisite? */
|
||||
|
||||
for (p2 = p; p2 < p + len && *p2 != '%'; ++p2)
|
||||
;
|
||||
|
||||
if (dep->need_2nd_expansion)
|
||||
if (! pathdir)
|
||||
{
|
||||
/* If the dependency name has %, substitute the stem.
|
||||
pathdir = alloca (pathlen + 1);
|
||||
memcpy (pathdir, filename, pathlen);
|
||||
pathdir[pathlen] = '\0';
|
||||
}
|
||||
dir = pathdir;
|
||||
}
|
||||
|
||||
Watch out, we are going to do something tricky
|
||||
here. If 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 stem (like $).
|
||||
/* If we're out of name to parse, start the next prereq. */
|
||||
if (! nptr)
|
||||
{
|
||||
dep = dep->next;
|
||||
if (dep == 0)
|
||||
break;
|
||||
nptr = dep_name (dep);
|
||||
}
|
||||
|
||||
Instead, we will replace % with $* and allow the
|
||||
second expansion to take care of it for us. This way
|
||||
(since $* is a simple variable) there won't be
|
||||
additional re-expansion of the stem. */
|
||||
|
||||
if (p2 < p + len)
|
||||
/* If we don't need a second expansion, just replace the %. */
|
||||
if (! dep->need_2nd_expansion)
|
||||
{
|
||||
p = strchr (nptr, '%');
|
||||
if (p == 0)
|
||||
ns_simple.name = nptr;
|
||||
else
|
||||
{
|
||||
char *o = depname;
|
||||
if (check_lastslash)
|
||||
{
|
||||
unsigned int i = p2 - p;
|
||||
memcpy (depname, p, i);
|
||||
memcpy (depname + i, "$*", 2);
|
||||
memcpy (depname + i + 2, p2 + 1, len - i - 1);
|
||||
depname[len + 2 - 1] = '\0';
|
||||
|
||||
if (check_lastslash)
|
||||
add_dir = 1;
|
||||
|
||||
had_stem = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
memcpy (depname, p, len);
|
||||
depname[len] = '\0';
|
||||
memcpy (o, filename, pathlen);
|
||||
o += pathlen;
|
||||
}
|
||||
memcpy (o, nptr, p - nptr);
|
||||
o += p - nptr;
|
||||
memcpy (o, stem_str, stemlen);
|
||||
o += stemlen;
|
||||
strcpy (o, p + 1);
|
||||
ns_simple.name = strcache_add (depname);
|
||||
}
|
||||
ns = &ns_simple;
|
||||
|
||||
/* Set file variables. Note that we cannot do it once
|
||||
at the beginning of the function because of the stem
|
||||
value. */
|
||||
if (!file_variables_set)
|
||||
{
|
||||
set_file_variables (file);
|
||||
file_variables_set = 1;
|
||||
}
|
||||
/* We've used up this dep, so next time get a new one. */
|
||||
nptr = 0;
|
||||
++deps_found;
|
||||
}
|
||||
|
||||
p2 = variable_expand_for_file (depname, file);
|
||||
/* We have to perform second expansion on this prereq. In an
|
||||
ideal world we would take the dependency line, substitute the
|
||||
stem, re-expand the whole line and chop it into individual
|
||||
prerequisites. Unfortunately this won't work because of the
|
||||
"check_lastslash" twist. Instead, we will have to go word by
|
||||
word, taking $()'s into account. For each word we will
|
||||
substitute the stem, re-expand, chop it up, and, if
|
||||
check_lastslash != 0, add the directory part to each
|
||||
resulting prerequisite. */
|
||||
else
|
||||
{
|
||||
int order_only = 0;
|
||||
int add_dir = 0;
|
||||
unsigned int len;
|
||||
|
||||
nptr = get_next_word (nptr, &len);
|
||||
if (nptr == 0)
|
||||
continue;
|
||||
|
||||
/* If the dependency name has %, substitute the stem. If we
|
||||
just replace % with the stem value then later, when we do
|
||||
the 2nd expansion, we will re-expand this stem value
|
||||
again. This is not good if you have 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 $*
|
||||
is a simple variable) there won't be additional
|
||||
re-expansion of the stem. */
|
||||
|
||||
p = lindex (nptr, nptr + len, '%');
|
||||
if (p == 0)
|
||||
{
|
||||
memcpy (depname, nptr, len);
|
||||
depname[len] = '\0';
|
||||
}
|
||||
else
|
||||
{
|
||||
if (p2 < p + len)
|
||||
{
|
||||
unsigned int i = p2 - p;
|
||||
memcpy (depname, p, i);
|
||||
memcpy (depname + i, stem_str, stemlen);
|
||||
memcpy (depname + i + stemlen, p2 + 1, len - i - 1);
|
||||
depname[len + stemlen - 1] = '\0';
|
||||
unsigned int i = p - nptr;
|
||||
memcpy (depname, nptr, i);
|
||||
memcpy (depname + i, "$*", 2);
|
||||
memcpy (depname + i + 2, p + 1, len - i - 1);
|
||||
depname[len + 2 - 1] = '\0';
|
||||
|
||||
if (check_lastslash)
|
||||
add_dir = 1;
|
||||
|
||||
had_stem = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
memcpy (depname, p, len);
|
||||
depname[len] = '\0';
|
||||
}
|
||||
|
||||
p2 = depname;
|
||||
if (check_lastslash)
|
||||
add_dir = 1;
|
||||
}
|
||||
|
||||
/* If we need to add the directory prefix set it up. */
|
||||
if (add_dir)
|
||||
/* Set file variables. Note that we cannot do it once at the
|
||||
beginning of the function because the stem value changes
|
||||
for each rule. */
|
||||
if (!file_variables_set)
|
||||
{
|
||||
unsigned long l = lastslash - filename + 1;
|
||||
char *n = alloca (l + 1);
|
||||
memcpy (n, filename, l);
|
||||
n[l] = '\0';
|
||||
dir = n;
|
||||
set_file_variables (file);
|
||||
file_variables_set = 1;
|
||||
}
|
||||
|
||||
/* Parse the dependencies. */
|
||||
/* Perform the 2nd expansion. */
|
||||
p = variable_expand_for_file (depname, file);
|
||||
|
||||
while (1)
|
||||
/* Parse the expanded string. */
|
||||
ns = parse_file_seq (&p, sizeof (struct dep),
|
||||
order_only ? '\0' : '|',
|
||||
add_dir ? dir : NULL, 0);
|
||||
|
||||
for (n = ns; n != NULL; n = n->next)
|
||||
++deps_found;
|
||||
|
||||
/* Set up for the next word. */
|
||||
nptr += len;
|
||||
}
|
||||
|
||||
/* If there are more than max_pattern_deps prerequisites (due to
|
||||
2nd expansion), reset it and realloc the arrays. */
|
||||
|
||||
if (deps_found > max_pattern_deps)
|
||||
{
|
||||
unsigned int l = pat - deplist;
|
||||
deplist = xrealloc (deplist,
|
||||
deps_found * sizeof (struct patdeps));
|
||||
pat = deplist + l;
|
||||
max_pattern_deps = deps_found;
|
||||
}
|
||||
|
||||
/* Go through the nameseq and handle each as a prereq name. */
|
||||
for (n = ns; n != 0; n = n->next)
|
||||
{
|
||||
struct dep *expl_d;
|
||||
int is_rule = n->name == dep_name (dep);
|
||||
|
||||
if (file_impossible_p (n->name))
|
||||
{
|
||||
id_ptr = &deps;
|
||||
|
||||
for (; *id_ptr; id_ptr = &(*id_ptr)->next)
|
||||
;
|
||||
|
||||
*id_ptr = (struct idep *)
|
||||
parse_file_seq (&p2, sizeof (struct idep),
|
||||
order_only ? '\0' : '|', dir, 0);
|
||||
|
||||
if (order_only || had_stem)
|
||||
{
|
||||
for (d = *id_ptr; d != 0; d = d->next)
|
||||
{
|
||||
if (order_only)
|
||||
d->ignore_mtime = 1;
|
||||
|
||||
if (had_stem)
|
||||
d->had_stem = 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (!order_only && *p2)
|
||||
{
|
||||
++p2;
|
||||
order_only = 1;
|
||||
continue;
|
||||
}
|
||||
/* If this prereq has already been ruled "impossible",
|
||||
then the rule fails. Don't bother trying it on the
|
||||
second pass either since we know that will fail. */
|
||||
DBS (DB_IMPLICIT,
|
||||
(is_rule
|
||||
? _("Rejecting impossible rule prerequisite `%s'.\n")
|
||||
: _("Rejecting impossible implicit prerequisite `%s'.\n"),
|
||||
n->name));
|
||||
tryrules[ri] = 0;
|
||||
|
||||
failed = 1;
|
||||
break;
|
||||
}
|
||||
|
||||
p += len;
|
||||
p = get_next_word (p, &len);
|
||||
memset (pat, '\0', sizeof (struct patdeps));
|
||||
pat->ignore_mtime = dep->ignore_mtime;
|
||||
|
||||
DBS (DB_IMPLICIT,
|
||||
(is_rule
|
||||
? _("Trying rule prerequisite `%s'.\n")
|
||||
: _("Trying implicit prerequisite `%s'.\n"), n->name));
|
||||
|
||||
/* If this prereq is also explicitly mentioned for FILE,
|
||||
skip all tests below since it must be built no matter
|
||||
which implicit rule we choose. */
|
||||
|
||||
for (expl_d = file->deps; expl_d != 0; expl_d = expl_d->next)
|
||||
if (streq (dep_name (expl_d), n->name))
|
||||
break;
|
||||
if (expl_d != 0)
|
||||
{
|
||||
(pat++)->name = n->name;
|
||||
continue;
|
||||
}
|
||||
|
||||
/* The DEP->changed flag says that this dependency resides
|
||||
in a nonexistent directory. So we normally can skip
|
||||
looking for the file. However, if CHECK_LASTSLASH is
|
||||
set, then the dependency file we are actually looking for
|
||||
is in a different directory (the one gotten by prepending
|
||||
FILENAME's directory), so it might actually exist. */
|
||||
|
||||
/* @@ dep->changed check is disabled. */
|
||||
if (lookup_file (n->name) != 0
|
||||
/*|| ((!dep->changed || check_lastslash) && */
|
||||
|| file_exists_p (n->name))
|
||||
{
|
||||
(pat++)->name = n->name;
|
||||
continue;
|
||||
}
|
||||
|
||||
/* This code, given FILENAME = "lib/foo.o", dependency name
|
||||
"lib/foo.c", and VPATH=src, searches for
|
||||
"src/lib/foo.c". */
|
||||
{
|
||||
const char *vname = vpath_search (n->name, 0);
|
||||
if (vname)
|
||||
{
|
||||
DBS (DB_IMPLICIT,
|
||||
(_("Found prerequisite `%s' as VPATH `%s'\n"),
|
||||
n->name, vname));
|
||||
(pat++)->name = n->name;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
/* We could not find the file in any place we should look.
|
||||
Try to make this dependency as an intermediate file, but
|
||||
only on the second pass. */
|
||||
|
||||
if (intermed_ok)
|
||||
{
|
||||
DBS (DB_IMPLICIT,
|
||||
(_("Looking for a rule with intermediate file `%s'.\n"),
|
||||
n->name));
|
||||
|
||||
if (int_file == 0)
|
||||
int_file = alloca (sizeof (struct file));
|
||||
memset (int_file, '\0', sizeof (struct file));
|
||||
int_file->name = n->name;
|
||||
|
||||
if (pattern_search (int_file,
|
||||
0,
|
||||
depth + 1,
|
||||
recursions + 1))
|
||||
{
|
||||
pat->pattern = int_file->name;
|
||||
int_file->name = n->name;
|
||||
pat->file = int_file;
|
||||
(pat++)->name = n->name;
|
||||
int_file = 0;
|
||||
continue;
|
||||
}
|
||||
|
||||
/* If we have tried to find P as an intermediate file
|
||||
and failed, mark that name as impossible so we won't
|
||||
go through the search again later. */
|
||||
if (int_file->variables)
|
||||
free_variable_set (int_file->variables);
|
||||
file_impossible (n->name);
|
||||
}
|
||||
|
||||
/* A dependency of this rule does not exist. Therefore, this
|
||||
rule fails. */
|
||||
failed = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Free the ns chain. */
|
||||
if (ns != &ns_simple)
|
||||
free_ns_chain (ns);
|
||||
|
||||
if (failed)
|
||||
break;
|
||||
}
|
||||
|
||||
/* Reset the stem in FILE. */
|
||||
|
||||
file->stem = 0;
|
||||
|
||||
/* @@ This loop can be combined with the previous one. I do
|
||||
it separately for now for transparency.*/
|
||||
|
||||
for (d = deps; d != 0; d = d->next)
|
||||
{
|
||||
const char *name = d->name;
|
||||
|
||||
if (file_impossible_p (name))
|
||||
{
|
||||
/* If this dependency has already been ruled "impossible",
|
||||
then the rule fails and don't bother trying it on the
|
||||
second pass either since we know that will fail too. */
|
||||
DBS (DB_IMPLICIT,
|
||||
(d->had_stem
|
||||
? _("Rejecting impossible implicit prerequisite `%s'.\n")
|
||||
: _("Rejecting impossible rule prerequisite `%s'.\n"),
|
||||
name));
|
||||
tryrules[ri] = 0;
|
||||
|
||||
failed = 1;
|
||||
break;
|
||||
}
|
||||
|
||||
DBS (DB_IMPLICIT,
|
||||
(d->had_stem
|
||||
? _("Trying implicit prerequisite `%s'.\n")
|
||||
: _("Trying rule prerequisite `%s'.\n"), name));
|
||||
|
||||
/* If this prerequisite also happened to be explicitly mentioned
|
||||
for FILE skip all the test below since it it has to be built
|
||||
anyway, no matter which implicit rule we choose. */
|
||||
|
||||
for (expl_d = file->deps; expl_d != 0; expl_d = expl_d->next)
|
||||
if (streq (dep_name (expl_d), name))
|
||||
break;
|
||||
if (expl_d != 0)
|
||||
continue;
|
||||
|
||||
/* The DEP->changed flag says that this dependency resides in a
|
||||
nonexistent directory. So we normally can skip looking for
|
||||
the file. However, if CHECK_LASTSLASH is set, then the
|
||||
dependency file we are actually looking for is in a different
|
||||
directory (the one gotten by prepending FILENAME's directory),
|
||||
so it might actually exist. */
|
||||
|
||||
/* @@ dep->changed check is disabled. */
|
||||
if (lookup_file (name) != 0
|
||||
/*|| ((!dep->changed || check_lastslash) && */
|
||||
|| file_exists_p (name))
|
||||
continue;
|
||||
|
||||
/* This code, given FILENAME = "lib/foo.o", dependency name
|
||||
"lib/foo.c", and VPATH=src, searches for "src/lib/foo.c". */
|
||||
{
|
||||
const char *vname = vpath_search (name, 0);
|
||||
if (vname)
|
||||
{
|
||||
DBS (DB_IMPLICIT,
|
||||
(_("Found prerequisite `%s' as VPATH `%s'\n"),
|
||||
name, vname));
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* We could not find the file in any place we should look. Try
|
||||
to make this dependency as an intermediate file, but only on
|
||||
the second pass. */
|
||||
|
||||
if (intermed_ok)
|
||||
{
|
||||
if (intermediate_file == 0)
|
||||
intermediate_file = alloca (sizeof (struct file));
|
||||
|
||||
DBS (DB_IMPLICIT,
|
||||
(_("Looking for a rule with intermediate file `%s'.\n"),
|
||||
name));
|
||||
|
||||
memset (intermediate_file, '\0', sizeof (struct file));
|
||||
intermediate_file->name = name;
|
||||
if (pattern_search (intermediate_file,
|
||||
0,
|
||||
depth + 1,
|
||||
recursions + 1))
|
||||
{
|
||||
d->intermediate_pattern = intermediate_file->name;
|
||||
intermediate_file->name = strcache_add (name);
|
||||
d->intermediate_file = intermediate_file;
|
||||
intermediate_file = 0;
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
/* If we have tried to find P as an intermediate
|
||||
file and failed, mark that name as impossible
|
||||
so we won't go through the search again later. */
|
||||
if (intermediate_file->variables)
|
||||
free_variable_set (intermediate_file->variables);
|
||||
file_impossible (name);
|
||||
}
|
||||
|
||||
/* A dependency of this rule does not exist. Therefore,
|
||||
this rule fails. */
|
||||
failed = 1;
|
||||
break;
|
||||
}
|
||||
|
||||
/* This rule is no longer `in use' for recursive searches. */
|
||||
rule->in_use = 0;
|
||||
|
||||
if (failed)
|
||||
{
|
||||
/* This pattern rule does not apply. If some of its
|
||||
dependencies succeeded, free the data structure
|
||||
describing them. */
|
||||
free_idep_chain (deps);
|
||||
deps = 0;
|
||||
}
|
||||
else
|
||||
if (! failed)
|
||||
/* This pattern rule does apply. Stop looking for one. */
|
||||
break;
|
||||
|
||||
/* This pattern rule does not apply. If some of its dependencies
|
||||
succeeded, free the data structure describing them. */
|
||||
/* free_idep_chain (deps); */
|
||||
deps = 0;
|
||||
}
|
||||
|
||||
/* If we found an applicable rule without
|
||||
intermediate files, don't try with them. */
|
||||
/* If we found an applicable rule without intermediate files, don't try
|
||||
with them. */
|
||||
if (ri < nrules)
|
||||
break;
|
||||
|
||||
rule = 0;
|
||||
}
|
||||
|
||||
/* RULE is nil if the loop went all the way
|
||||
through the list and everything failed. */
|
||||
/* RULE is nil if the loop went through the list but everything failed. */
|
||||
if (rule == 0)
|
||||
goto done;
|
||||
|
||||
foundrule = ri;
|
||||
|
||||
/* If we are recursing, store the pattern that matched
|
||||
FILENAME in FILE->name for use in upper levels. */
|
||||
/* If we are recursing, store the pattern that matched FILENAME in
|
||||
FILE->name for use in upper levels. */
|
||||
|
||||
if (recursions > 0)
|
||||
/* Kludge-o-matic */
|
||||
file->name = rule->targets[matches[foundrule]];
|
||||
|
||||
/* FOUND_FILES lists the dependencies for the rule we found.
|
||||
This includes the intermediate files, if any.
|
||||
Convert them into entries on the deps-chain of FILE. */
|
||||
/* DEPLIST lists the prerequisites for the rule we found. This includes the
|
||||
intermediate files, if any. Convert them into entries on the deps-chain
|
||||
of FILE. */
|
||||
|
||||
if (remove_explicit_deps)
|
||||
{
|
||||
/* Remove all the dependencies that didn't come from
|
||||
this implicit rule. */
|
||||
|
||||
dep = file->deps;
|
||||
while (dep != 0)
|
||||
{
|
||||
struct dep *next = dep->next;
|
||||
free_dep (dep);
|
||||
dep = next;
|
||||
}
|
||||
file->deps = 0;
|
||||
}
|
||||
|
||||
expl_d = file->deps; /* We will add them at the end. */
|
||||
d_ptr = &file->deps;
|
||||
|
||||
for (d = deps; d != 0; d = d->next)
|
||||
while (pat-- > deplist)
|
||||
{
|
||||
struct dep *dep;
|
||||
const char *s;
|
||||
|
||||
if (d->intermediate_file != 0)
|
||||
if (pat->file != 0)
|
||||
{
|
||||
/* If we need to use an intermediate file,
|
||||
make sure it is entered as a target, with the info that was
|
||||
found for it in the recursive pattern_search call.
|
||||
We know that the intermediate file did not already exist as
|
||||
a target; therefore we can assume that the deps and cmds
|
||||
of F below are null before we change them. */
|
||||
/* If we need to use an intermediate file, make sure it is entered
|
||||
as a target, with the info that was found for it in the recursive
|
||||
pattern_search call. We know that the intermediate file did not
|
||||
already exist as a target; therefore we can assume that the deps
|
||||
and cmds of F below are null before we change them. */
|
||||
|
||||
struct file *imf = d->intermediate_file;
|
||||
register struct file *f = lookup_file (imf->name);
|
||||
struct file *imf = pat->file;
|
||||
struct file *f = lookup_file (imf->name);
|
||||
|
||||
/* We don't want to delete an intermediate file that happened
|
||||
to be a prerequisite of some (other) target. Mark it as
|
||||
|
@ -814,23 +798,20 @@ pattern_search (struct file *file, int archive,
|
|||
if (f != 0)
|
||||
f->precious = 1;
|
||||
else
|
||||
f = enter_file (strcache_add (imf->name));
|
||||
f = enter_file (imf->name);
|
||||
|
||||
f->deps = imf->deps;
|
||||
f->cmds = imf->cmds;
|
||||
f->stem = imf->stem;
|
||||
f->also_make = imf->also_make;
|
||||
f->is_target = 1;
|
||||
|
||||
if (!f->precious)
|
||||
{
|
||||
imf = lookup_file (d->intermediate_pattern);
|
||||
if (imf != 0 && imf->precious)
|
||||
f->precious = 1;
|
||||
}
|
||||
|
||||
f->intermediate = 1;
|
||||
f->tried_implicit = 1;
|
||||
|
||||
imf = lookup_file (pat->pattern);
|
||||
if (imf != 0 && imf->precious)
|
||||
f->precious = 1;
|
||||
|
||||
for (dep = f->deps; dep != 0; dep = dep->next)
|
||||
{
|
||||
dep->file = enter_file (dep->name);
|
||||
|
@ -840,41 +821,38 @@ pattern_search (struct file *file, int archive,
|
|||
}
|
||||
|
||||
dep = alloc_dep ();
|
||||
dep->ignore_mtime = d->ignore_mtime;
|
||||
s = d->name; /* Hijacking the name. */
|
||||
d->name = 0;
|
||||
if (recursions == 0)
|
||||
dep->ignore_mtime = pat->ignore_mtime;
|
||||
s = strcache_add (pat->name);
|
||||
if (recursions)
|
||||
dep->name = s;
|
||||
else
|
||||
{
|
||||
dep->file = lookup_file (s);
|
||||
if (dep->file == 0)
|
||||
dep->file = enter_file (s);
|
||||
}
|
||||
else
|
||||
dep->name = s;
|
||||
|
||||
if (d->intermediate_file == 0 && tryrules[foundrule]->terminal)
|
||||
if (pat->file == 0 && tryrules[foundrule]->terminal)
|
||||
{
|
||||
/* If the file actually existed (was not an intermediate file),
|
||||
and the rule that found it was a terminal one, then we want
|
||||
to mark the found file so that it will not have implicit rule
|
||||
search done for it. If we are not entering a `struct file' for
|
||||
it now, we indicate this with the `changed' flag. */
|
||||
/* If the file actually existed (was not an intermediate file), and
|
||||
the rule that found it was a terminal one, then we want to mark
|
||||
the found file so that it will not have implicit rule search done
|
||||
for it. If we are not entering a `struct file' for it now, we
|
||||
indicate this with the `changed' flag. */
|
||||
if (dep->file == 0)
|
||||
dep->changed = 1;
|
||||
else
|
||||
dep->file->tried_implicit = 1;
|
||||
}
|
||||
|
||||
*d_ptr = dep;
|
||||
d_ptr = &dep->next;
|
||||
dep->next = file->deps;
|
||||
file->deps = dep;
|
||||
}
|
||||
|
||||
*d_ptr = expl_d;
|
||||
|
||||
if (!checked_lastslash[foundrule])
|
||||
{
|
||||
/* Always allocate new storage, since STEM might be
|
||||
on the stack for an intermediate file. */
|
||||
/* Always allocate new storage, since STEM might be on the stack for an
|
||||
intermediate file. */
|
||||
file->stem = strcache_add_len (stem, stemlen);
|
||||
fullstemlen = stemlen;
|
||||
}
|
||||
|
@ -932,8 +910,8 @@ pattern_search (struct file *file, int archive,
|
|||
if (f && f->precious)
|
||||
new->file->precious = 1;
|
||||
|
||||
/* Set the is_target flag so that this file is not treated
|
||||
as intermediate by the pattern rule search algorithm and
|
||||
/* Set the is_target flag so that this file is not treated as
|
||||
intermediate by the pattern rule search algorithm and
|
||||
file_exists_p cannot pick it up yet. */
|
||||
new->file->is_target = 1;
|
||||
|
||||
|
@ -941,8 +919,8 @@ pattern_search (struct file *file, int archive,
|
|||
}
|
||||
|
||||
done:
|
||||
free_idep_chain (deps);
|
||||
free (tryrules);
|
||||
free (deplist);
|
||||
|
||||
return rule != 0;
|
||||
}
|
||||
|
|
5
job.c
5
job.c
|
@ -967,8 +967,9 @@ start_job_command (struct child *child)
|
|||
#if !defined(_AMIGA) && !defined(WINDOWS32)
|
||||
static int bad_stdin = -1;
|
||||
#endif
|
||||
register char *p;
|
||||
int flags;
|
||||
char *p;
|
||||
/* Must be volatile to silence bogus GCC warning about longjmp/vfork. */
|
||||
volatile int flags;
|
||||
#ifdef VMS
|
||||
char *argv;
|
||||
#else
|
||||
|
|
3
main.c
3
main.c
|
@ -56,7 +56,6 @@ RETSIGTYPE fatal_error_signal (int sig);
|
|||
void print_variable_data_base (void);
|
||||
void print_dir_data_base (void);
|
||||
void print_rule_data_base (void);
|
||||
void print_file_data_base (void);
|
||||
void print_vpath_data_base (void);
|
||||
|
||||
void verify_file_data_base (void);
|
||||
|
@ -2192,7 +2191,7 @@ main (int argc, char **argv, char **envp)
|
|||
{
|
||||
struct nameseq *ns;
|
||||
|
||||
ns = parse_file_seq (&p, sizeof (struct nameseq), '\0', NULL, 0);
|
||||
ns = PARSE_FILE_SEQ (&p, struct nameseq, '\0', NULL, 0);
|
||||
if (ns)
|
||||
{
|
||||
/* .DEFAULT_GOAL should contain one target. */
|
||||
|
|
9
misc.c
9
misc.c
|
@ -430,7 +430,8 @@ xstrndup (const char *str, unsigned int length)
|
|||
fatal (NILF, _("virtual memory exhausted"));
|
||||
#else
|
||||
result = xmalloc (length + 1);
|
||||
strncpy (result, str, length);
|
||||
if (length > 0)
|
||||
strncpy (result, str, length);
|
||||
result[length] = '\0';
|
||||
#endif
|
||||
|
||||
|
@ -524,8 +525,7 @@ find_next_token (const char **ptr, unsigned int *lengthptr)
|
|||
}
|
||||
|
||||
|
||||
/* Copy a chain of `struct dep', making a new chain
|
||||
with the same contents as the old one. */
|
||||
/* Copy a chain of `struct dep'. For 2nd expansion deps, dup the name. */
|
||||
|
||||
struct dep *
|
||||
copy_dep_chain (const struct dep *d)
|
||||
|
@ -538,6 +538,9 @@ copy_dep_chain (const struct dep *d)
|
|||
struct dep *c = xmalloc (sizeof (struct dep));
|
||||
memcpy (c, d, sizeof (struct dep));
|
||||
|
||||
if (c->need_2nd_expansion)
|
||||
c->name = xstrdup (c->name);
|
||||
|
||||
c->next = 0;
|
||||
if (firstnew == 0)
|
||||
firstnew = lastnew = c;
|
||||
|
|
301
read.c
301
read.c
|
@ -1,6 +1,6 @@
|
|||
/* Reading and parsing of makefiles for GNU Make.
|
||||
Copyright (C) 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997,
|
||||
1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007 Free Software
|
||||
1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2009 Free Software
|
||||
Foundation, Inc.
|
||||
This file is part of GNU Make.
|
||||
|
||||
|
@ -140,7 +140,7 @@ static struct variable *do_define (char *name, enum variable_origin origin,
|
|||
struct ebuffer *ebuf);
|
||||
static int conditional_line (char *line, int len, const struct floc *flocp);
|
||||
static void record_files (struct nameseq *filenames, const char *pattern,
|
||||
const char *pattern_percent, struct dep *deps,
|
||||
const char *pattern_percent, char *depstr,
|
||||
unsigned int cmds_started, char *commands,
|
||||
unsigned int commands_idx, int two_colon,
|
||||
const struct floc *flocp);
|
||||
|
@ -549,7 +549,7 @@ eval (struct ebuffer *ebuf, int set_default)
|
|||
int ignoring = 0, in_ignored_define = 0;
|
||||
int no_targets = 0; /* Set when reading a rule without targets. */
|
||||
struct nameseq *filenames = 0;
|
||||
struct dep *deps = 0;
|
||||
char *depstr = 0;
|
||||
long nlines = 0;
|
||||
int two_colon = 0;
|
||||
const char *pattern = 0;
|
||||
|
@ -563,7 +563,7 @@ eval (struct ebuffer *ebuf, int set_default)
|
|||
if (filenames != 0) \
|
||||
{ \
|
||||
fi.lineno = tgts_started; \
|
||||
record_files (filenames, pattern, pattern_percent, deps, \
|
||||
record_files (filenames, pattern, pattern_percent, depstr, \
|
||||
cmds_started, commands, commands_idx, two_colon, \
|
||||
&fi); \
|
||||
} \
|
||||
|
@ -834,8 +834,7 @@ eval (struct ebuffer *ebuf, int set_default)
|
|||
|
||||
/* Parse the list of file names. */
|
||||
p2 = p;
|
||||
files = parse_file_seq (&p2, sizeof (struct nameseq), '\0',
|
||||
NULL, 0);
|
||||
files = PARSE_FILE_SEQ (&p2, struct nameseq, '\0', NULL, 0);
|
||||
free (p);
|
||||
|
||||
/* Save the state of conditionals and start
|
||||
|
@ -1019,8 +1018,7 @@ eval (struct ebuffer *ebuf, int set_default)
|
|||
/* Make the colon the end-of-string so we know where to stop
|
||||
looking for targets. */
|
||||
*colonp = '\0';
|
||||
filenames = parse_file_seq (&p2, sizeof (struct nameseq), '\0',
|
||||
NULL, 0);
|
||||
filenames = PARSE_FILE_SEQ (&p2, struct nameseq, '\0', NULL, 0);
|
||||
*p2 = ':';
|
||||
|
||||
if (!filenames)
|
||||
|
@ -1099,8 +1097,8 @@ eval (struct ebuffer *ebuf, int set_default)
|
|||
p = strchr (p2, ':');
|
||||
while (p != 0 && p[-1] == '\\')
|
||||
{
|
||||
register char *q = &p[-1];
|
||||
register int backslash = 0;
|
||||
char *q = &p[-1];
|
||||
int backslash = 0;
|
||||
while (*q-- == '\\')
|
||||
backslash = !backslash;
|
||||
if (backslash)
|
||||
|
@ -1143,8 +1141,8 @@ eval (struct ebuffer *ebuf, int set_default)
|
|||
if (p != 0)
|
||||
{
|
||||
struct nameseq *target;
|
||||
target = parse_file_seq (&p2, sizeof (struct nameseq), ':',
|
||||
NULL, PARSEFS_NOGLOB|PARSEFS_NOCACHE);
|
||||
target = PARSE_FILE_SEQ (&p2, struct nameseq, ':', NULL,
|
||||
PARSEFS_NOGLOB|PARSEFS_NOCACHE);
|
||||
++p2;
|
||||
if (target == 0)
|
||||
fatal (fstart, _("missing target pattern"));
|
||||
|
@ -1164,14 +1162,11 @@ eval (struct ebuffer *ebuf, int set_default)
|
|||
end = beg + strlen (beg) - 1;
|
||||
strip_whitespace (&beg, &end);
|
||||
|
||||
/* Put all the prerequisites here; they'll be parsed later. */
|
||||
if (beg <= end && *beg != '\0')
|
||||
{
|
||||
/* Put all the prerequisites here; they'll be parsed later. */
|
||||
deps = alloc_dep ();
|
||||
deps->name = strcache_add_len (beg, end - beg + 1);
|
||||
}
|
||||
depstr = xstrndup (beg, end - beg + 1);
|
||||
else
|
||||
deps = 0;
|
||||
depstr = 0;
|
||||
|
||||
commands_idx = 0;
|
||||
if (cmdleft != 0)
|
||||
|
@ -1870,16 +1865,15 @@ record_target_var (struct nameseq *filenames, char *defn,
|
|||
|
||||
static void
|
||||
record_files (struct nameseq *filenames, const char *pattern,
|
||||
const char *pattern_percent, struct dep *deps,
|
||||
const char *pattern_percent, char *depstr,
|
||||
unsigned int cmds_started, char *commands,
|
||||
unsigned int commands_idx, int two_colon,
|
||||
const struct floc *flocp)
|
||||
{
|
||||
struct nameseq *nextf;
|
||||
int implicit = 0;
|
||||
unsigned int max_targets = 0, target_idx = 0;
|
||||
const char **targets = 0, **target_percents = 0;
|
||||
struct commands *cmds;
|
||||
struct dep *deps;
|
||||
const char *implicit_percent;
|
||||
const char *name;
|
||||
|
||||
/* If we've already snapped deps, that means we're in an eval being
|
||||
resolved after the makefiles have been read in. We can't add more rules
|
||||
|
@ -1888,6 +1882,11 @@ record_files (struct nameseq *filenames, const char *pattern,
|
|||
if (snapped_deps)
|
||||
fatal (flocp, _("prerequisites cannot be defined in recipes"));
|
||||
|
||||
/* Determine if this is a pattern rule or not. */
|
||||
name = filenames->name;
|
||||
implicit_percent = find_percent_cached (&name);
|
||||
|
||||
/* If there's a recipe, set up a struct for it. */
|
||||
if (commands_idx > 0)
|
||||
{
|
||||
cmds = xmalloc (sizeof (struct commands));
|
||||
|
@ -1897,78 +1896,106 @@ record_files (struct nameseq *filenames, const char *pattern,
|
|||
cmds->command_lines = 0;
|
||||
}
|
||||
else
|
||||
cmds = 0;
|
||||
cmds = 0;
|
||||
|
||||
for (; filenames != 0; filenames = nextf)
|
||||
/* If there's a prereq string then parse it--unless it's eligible for 2nd
|
||||
expansion: if so, snap_deps() will do it. */
|
||||
if (depstr == 0)
|
||||
deps = 0;
|
||||
else if (second_expansion && strchr (depstr, '$'))
|
||||
{
|
||||
const char *name = filenames->name;
|
||||
deps = alloc_dep ();
|
||||
deps->name = depstr;
|
||||
deps->need_2nd_expansion = 1;
|
||||
deps->staticpattern = pattern != 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
deps = split_prereqs (depstr);
|
||||
free (depstr);
|
||||
|
||||
/* We'll enter static pattern prereqs later when we have the stem. We
|
||||
don't want to enter pattern rules at all so that we don't think that
|
||||
they ought to exist (make manual "Implicit Rule Search Algorithm",
|
||||
item 5c). */
|
||||
if (! pattern && ! implicit_percent)
|
||||
deps = enter_prereqs (deps, NULL);
|
||||
}
|
||||
|
||||
/* For implicit rules, _all_ the targets must have a pattern. That means we
|
||||
can test the first one to see if we're working with an implicit rule; if
|
||||
so we handle it specially. */
|
||||
|
||||
if (implicit_percent)
|
||||
{
|
||||
struct nameseq *nextf;
|
||||
const char **targets, **target_pats;
|
||||
unsigned int c;
|
||||
|
||||
if (pattern != 0)
|
||||
fatal (flocp, _("mixed implicit and static pattern rules"));
|
||||
|
||||
/* Create an array of target names */
|
||||
for (c = 1, nextf = filenames->next; nextf; ++c, nextf = nextf->next)
|
||||
;
|
||||
targets = xmalloc (c * sizeof (const char *));
|
||||
target_pats = xmalloc (c * sizeof (const char *));
|
||||
|
||||
targets[0] = name;
|
||||
target_pats[0] = implicit_percent;
|
||||
|
||||
for (c = 1, nextf = filenames->next; nextf; ++c, nextf = nextf->next)
|
||||
{
|
||||
name = nextf->name;
|
||||
implicit_percent = find_percent_cached (&name);
|
||||
|
||||
if (implicit_percent == 0)
|
||||
fatal (flocp, _("mixed implicit and normal rules"));
|
||||
|
||||
targets[c] = name;
|
||||
target_pats[c] = implicit_percent;
|
||||
}
|
||||
|
||||
create_pattern_rule (targets, target_pats, c, two_colon, deps, cmds, 1);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
/* Walk through each target and create it in the database.
|
||||
We already set up the first target, above. */
|
||||
while (1)
|
||||
{
|
||||
struct nameseq *nextf = filenames->next;
|
||||
struct file *f;
|
||||
struct dep *this = 0;
|
||||
const char *implicit_percent;
|
||||
|
||||
nextf = filenames->next;
|
||||
free (filenames);
|
||||
|
||||
/* 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_cached (&name);
|
||||
implicit |= implicit_percent != 0;
|
||||
|
||||
if (implicit)
|
||||
{
|
||||
if (pattern != 0)
|
||||
fatal (flocp, _("mixed implicit and static pattern rules"));
|
||||
|
||||
if (implicit_percent == 0)
|
||||
fatal (flocp, _("mixed implicit and normal rules"));
|
||||
|
||||
if (targets == 0)
|
||||
{
|
||||
max_targets = 5;
|
||||
targets = xmalloc (5 * sizeof (char *));
|
||||
target_percents = xmalloc (5 * sizeof (char *));
|
||||
target_idx = 0;
|
||||
}
|
||||
else if (target_idx == max_targets - 1)
|
||||
{
|
||||
max_targets += 5;
|
||||
targets = xrealloc (targets, max_targets * sizeof (char *));
|
||||
target_percents = xrealloc (target_percents,
|
||||
max_targets * sizeof (char *));
|
||||
}
|
||||
targets[target_idx] = name;
|
||||
target_percents[target_idx] = implicit_percent;
|
||||
++target_idx;
|
||||
continue;
|
||||
}
|
||||
|
||||
/* If this is a static pattern rule:
|
||||
`targets: target%pattern: dep%pattern; cmds',
|
||||
`targets: target%pattern: prereq%pattern; recipe',
|
||||
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
|
||||
&& strchr (this->name, '$'));
|
||||
}
|
||||
/* If there are multiple targets, 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;
|
||||
|
||||
/* Find or create an entry in the file database for this target. */
|
||||
if (!two_colon)
|
||||
{
|
||||
/* Single-colon. Combine these dependencies
|
||||
with others in file's existing record, if any. */
|
||||
/* Single-colon. Combine this rule with the file's existing record,
|
||||
if any. */
|
||||
f = enter_file (strcache_add (name));
|
||||
|
||||
if (f->double_colon)
|
||||
fatal (flocp,
|
||||
_("target file `%s' has both : and :: entries"), f->name);
|
||||
|
@ -1993,8 +2020,6 @@ record_files (struct nameseq *filenames, const char *pattern,
|
|||
f->name);
|
||||
}
|
||||
|
||||
f->is_target = 1;
|
||||
|
||||
/* Defining .DEFAULT with no deps or cmds clears it. */
|
||||
if (f == default_file && this == 0 && cmds == 0)
|
||||
f->cmds = 0;
|
||||
|
@ -2008,71 +2033,18 @@ record_files (struct nameseq *filenames, const char *pattern,
|
|||
free_dep_chain (f->deps);
|
||||
f->deps = 0;
|
||||
}
|
||||
else if (this != 0)
|
||||
{
|
||||
/* Add the file's old deps and the new ones in THIS together. */
|
||||
|
||||
if (f->deps != 0)
|
||||
{
|
||||
struct dep **d_ptr = &f->deps;
|
||||
|
||||
while ((*d_ptr)->next != 0)
|
||||
d_ptr = &(*d_ptr)->next;
|
||||
|
||||
if (cmds != 0)
|
||||
{
|
||||
/* This is the rule with commands, so put its deps
|
||||
last. The rationale behind this is that $< expands to
|
||||
the first dep in the chain, and commands use $<
|
||||
expecting to get the dep that rule specifies. However
|
||||
the second expansion algorithm reverses the order thus
|
||||
we need to make it last here. */
|
||||
(*d_ptr)->next = this;
|
||||
/* This is a hack. I need a way to communicate to
|
||||
snap_deps() that the last dependency line in this
|
||||
file came with commands (so that logic in snap_deps()
|
||||
can put it in front and all this $< -logic works). I
|
||||
cannot simply rely on file->cmds being not 0 because
|
||||
of the cases like the following:
|
||||
|
||||
foo: bar
|
||||
foo:
|
||||
...
|
||||
|
||||
I am going to temporarily "borrow" UPDATING member in
|
||||
`struct file' for this. */
|
||||
f->updating = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* This is a rule without commands. If we already have
|
||||
a rule with commands and prerequisites (see "hack"
|
||||
comment above), put these prereqs at the end but
|
||||
before prereqs from the rule with commands. This way
|
||||
everything appears in makefile order. */
|
||||
if (f->updating)
|
||||
{
|
||||
this->next = *d_ptr;
|
||||
*d_ptr = this;
|
||||
}
|
||||
else
|
||||
(*d_ptr)->next = this;
|
||||
}
|
||||
}
|
||||
else
|
||||
f->deps = this;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* 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. */
|
||||
/* 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 (strcache_add (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
|
||||
|
@ -2082,14 +2054,15 @@ record_files (struct nameseq *filenames, const char *pattern,
|
|||
/* 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;
|
||||
}
|
||||
|
||||
f->is_target = 1;
|
||||
|
||||
/* 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. */
|
||||
commands. If we didn't do it before, enter the prereqs now. */
|
||||
if (pattern)
|
||||
{
|
||||
static const char *percent = "%";
|
||||
|
@ -2099,20 +2072,54 @@ record_files (struct nameseq *filenames, const char *pattern,
|
|||
f->stem = strcache_add_len (buffer, o - buffer);
|
||||
if (this)
|
||||
{
|
||||
this->staticpattern = 1;
|
||||
this->stem = f->stem;
|
||||
if (! this->need_2nd_expansion)
|
||||
this = enter_prereqs (this, f->stem);
|
||||
else
|
||||
this->stem = f->stem;
|
||||
}
|
||||
}
|
||||
|
||||
/* Add the dependencies to this file entry. */
|
||||
if (this != 0)
|
||||
{
|
||||
/* Add the file's old deps and the new ones in THIS together. */
|
||||
if (f->deps == 0)
|
||||
f->deps = this;
|
||||
else if (cmds != 0)
|
||||
{
|
||||
struct dep *d = this;
|
||||
|
||||
/* If this rule has commands, put these deps first. */
|
||||
while (d->next != 0)
|
||||
d = d->next;
|
||||
|
||||
d->next = f->deps;
|
||||
f->deps = this;
|
||||
}
|
||||
else
|
||||
{
|
||||
struct dep *d = f->deps;
|
||||
|
||||
/* A rule without commands: put its prereqs at the end. */
|
||||
while (d->next != 0)
|
||||
d = d->next;
|
||||
|
||||
d->next = this;
|
||||
}
|
||||
}
|
||||
|
||||
name = f->name;
|
||||
}
|
||||
|
||||
if (implicit)
|
||||
{
|
||||
if (deps)
|
||||
deps->need_2nd_expansion = second_expansion;
|
||||
create_pattern_rule (targets, target_percents, target_idx,
|
||||
two_colon, deps, cmds, 1);
|
||||
/* All done! Set up for the next one. */
|
||||
if (nextf == 0)
|
||||
break;
|
||||
|
||||
filenames = nextf;
|
||||
|
||||
/* Reduce escaped percents. If there are any unescaped it's an error */
|
||||
name = filenames->name;
|
||||
if (find_percent_cached (&name))
|
||||
fatal (flocp, _("mixed implicit and normal rules"));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2235,7 +2242,7 @@ find_percent_cached (const char **string)
|
|||
{
|
||||
const char *p = *string;
|
||||
char *new = 0;
|
||||
int slen;
|
||||
int slen = 0;
|
||||
|
||||
/* If the first char is a % return now. This lets us avoid extra tests
|
||||
inside the loop. */
|
||||
|
@ -2330,11 +2337,11 @@ readstring (struct ebuffer *ebuf)
|
|||
while (1)
|
||||
{
|
||||
int backslash = 0;
|
||||
char *bol = eol;
|
||||
char *p;
|
||||
const char *bol = eol;
|
||||
const char *p;
|
||||
|
||||
/* Find the next newline. At EOS, stop. */
|
||||
eol = p = strchr (eol , '\n');
|
||||
p = eol = strchr (eol , '\n');
|
||||
if (!eol)
|
||||
{
|
||||
ebuf->bufnext = ebuf->bufstart + ebuf->size + 1;
|
||||
|
@ -2850,7 +2857,7 @@ tilde_expand (const char *name)
|
|||
PARSEFS_NOCACHE - Do not add filenames to the strcache (caller frees)
|
||||
*/
|
||||
|
||||
struct nameseq *
|
||||
void *
|
||||
parse_file_seq (char **stringp, unsigned int size, int stopchar,
|
||||
const char *prefix, int flags)
|
||||
{
|
||||
|
|
33
rule.c
33
rule.c
|
@ -94,19 +94,20 @@ count_implicit_rule_limits (void)
|
|||
|
||||
for (dep = rule->deps; dep != 0; dep = dep->next)
|
||||
{
|
||||
unsigned int len = strlen (dep->name);
|
||||
const char *dname = dep_name (dep);
|
||||
unsigned int len = strlen (dname);
|
||||
|
||||
#ifdef VMS
|
||||
const char *p = strrchr (dep->name, ']');
|
||||
const char *p = strrchr (dname, ']');
|
||||
const char *p2;
|
||||
if (p == 0)
|
||||
p = strrchr (dep->name, ':');
|
||||
p2 = p != 0 ? strchr (dep->name, '%') : 0;
|
||||
p = strrchr (dname, ':');
|
||||
p2 = p != 0 ? strchr (dname, '%') : 0;
|
||||
#else
|
||||
const char *p = strrchr (dep->name, '/');
|
||||
const char *p2 = p != 0 ? strchr (dep->name, '%') : 0;
|
||||
const char *p = strrchr (dname, '/');
|
||||
const char *p2 = p != 0 ? strchr (dname, '%') : 0;
|
||||
#endif
|
||||
ndeps++;
|
||||
ndeps++;
|
||||
|
||||
if (len > max_pattern_dep_length)
|
||||
max_pattern_dep_length = len;
|
||||
|
@ -115,15 +116,15 @@ count_implicit_rule_limits (void)
|
|||
{
|
||||
/* There is a slash before the % in the dep name.
|
||||
Extract the directory name. */
|
||||
if (p == dep->name)
|
||||
if (p == dname)
|
||||
++p;
|
||||
if (p - dep->name > namelen)
|
||||
if (p - dname > namelen)
|
||||
{
|
||||
namelen = p - dep->name;
|
||||
namelen = p - dname;
|
||||
name = xrealloc (name, namelen + 1);
|
||||
}
|
||||
memcpy (name, dep->name, p - dep->name);
|
||||
name[p - dep->name] = '\0';
|
||||
memcpy (name, dname, p - dname);
|
||||
name[p - dname] = '\0';
|
||||
|
||||
/* In the deps of an implicit rule the `changed' flag
|
||||
actually indicates that the dependency is in a
|
||||
|
@ -376,8 +377,7 @@ install_pattern_rule (struct pspec *p, int terminal)
|
|||
++r->suffixes[0];
|
||||
|
||||
ptr = p->dep;
|
||||
r->deps = (struct dep *) parse_file_seq (&ptr, sizeof (struct dep), '\0',
|
||||
NULL, 0);
|
||||
r->deps = PARSE_FILE_SEQ (&ptr, struct dep, '\0', NULL, 0);
|
||||
|
||||
if (new_pattern_rule (r, 0))
|
||||
{
|
||||
|
@ -481,7 +481,6 @@ static void /* Useful to call from gdb. */
|
|||
print_rule (struct rule *r)
|
||||
{
|
||||
unsigned int i;
|
||||
struct dep *d;
|
||||
|
||||
for (i = 0; i < r->num; ++i)
|
||||
{
|
||||
|
@ -491,9 +490,7 @@ print_rule (struct rule *r)
|
|||
if (r->terminal)
|
||||
putchar (':');
|
||||
|
||||
for (d = r->deps; d != 0; d = d->next)
|
||||
printf (" %s", dep_name (d));
|
||||
putchar ('\n');
|
||||
print_prereqs (r->deps);
|
||||
|
||||
if (r->cmds != 0)
|
||||
print_commands (r->cmds);
|
||||
|
|
|
@ -1,3 +1,10 @@
|
|||
2009-09-23 Paul <psmith@gnu.org>
|
||||
|
||||
* scripts/features/patternrules: Test that we can remove pattern
|
||||
rules, both single and multiple prerequisites. Savannah bug #18622.
|
||||
|
||||
* scripts/features/echoing: Rework for run_make_test().
|
||||
|
||||
2009-06-14 Paul Smith <psmith@gnu.org>
|
||||
|
||||
* scripts/features/vpath: Verify we don't get bogus circular
|
||||
|
|
|
@ -1,87 +1,64 @@
|
|||
$description = "The following test creates a makefile to test command \n"
|
||||
."echoing. It tests that when a command line starts with \n"
|
||||
."a '\@', the echoing of that line is suppressed. It also \n"
|
||||
."tests the -n option which tells make to ONLY echo the \n"
|
||||
."commands and no execution happens. In this case, even \n"
|
||||
."the commands with '\@' are printed. Lastly, it tests the \n"
|
||||
."-s flag which tells make to prevent all echoing, as if \n"
|
||||
."all commands started with a '\@'.";
|
||||
# -*-perl-*-
|
||||
$description = "The following test creates a makefile to test command
|
||||
echoing. It tests that when a command line starts with
|
||||
a '\@', the echoing of that line is suppressed. It also
|
||||
tests the -n option which tells make to ONLY echo the
|
||||
commands and no execution happens. In this case, even
|
||||
the commands with '\@' are printed. Lastly, it tests the
|
||||
-s flag which tells make to prevent all echoing, as if
|
||||
all commands started with a '\@'.";
|
||||
|
||||
$details = "This test is similar to the 'clean' test except that a '\@' has\n"
|
||||
."been placed in front of the delete command line. Four tests \n"
|
||||
."are run here. First, make is run normally and the first echo\n"
|
||||
."command should be executed. In this case there is no '\@' so \n"
|
||||
."we should expect make to display the command AND display the \n"
|
||||
."echoed message. Secondly, make is run with the clean target, \n"
|
||||
."but since there is a '\@' at the beginning of the command, we\n"
|
||||
."expect no output; just the deletion of a file which we check \n"
|
||||
."for. Third, we give the clean target again except this time\n"
|
||||
."we give make the -n option. We now expect the command to be \n"
|
||||
."displayed but not to be executed. In this case we need only \n"
|
||||
."to check the output since an error message would be displayed\n"
|
||||
."if it actually tried to run the delete command again and the \n"
|
||||
."file didn't exist. Lastly, we run the first test again with \n"
|
||||
."the -s option and check that make did not echo the echo \n"
|
||||
."command before printing the message.";
|
||||
$details = "This test is similar to the 'clean' test except that a '\@' has
|
||||
been placed in front of the delete command line. Four tests
|
||||
are run here. First, make is run normally and the first echo
|
||||
command should be executed. In this case there is no '\@' so
|
||||
we should expect make to display the command AND display the
|
||||
echoed message. Secondly, make is run with the clean target,
|
||||
but since there is a '\@' at the beginning of the command, we
|
||||
expect no output; just the deletion of a file which we check
|
||||
for. Third, we give the clean target again except this time
|
||||
we give make the -n option. We now expect the command to be
|
||||
displayed but not to be executed. In this case we need only
|
||||
to check the output since an error message would be displayed
|
||||
if it actually tried to run the delete command again and the
|
||||
file didn't exist. Lastly, we run the first test again with
|
||||
the -s option and check that make did not echo the echo
|
||||
command before printing the message.\n";
|
||||
|
||||
$example = "EXAMPLE_FILE";
|
||||
|
||||
open(MAKEFILE,"> $makefile");
|
||||
|
||||
# The Contents of the MAKEFILE ...
|
||||
|
||||
print MAKEFILE "all: \n";
|
||||
print MAKEFILE "\techo This makefile did not clean the dir... good\n";
|
||||
print MAKEFILE "clean: \n";
|
||||
print MAKEFILE "\t\@$delete_command $example\n";
|
||||
|
||||
# END of Contents of MAKEFILE
|
||||
|
||||
close(MAKEFILE);
|
||||
|
||||
&touch($example);
|
||||
touch($example);
|
||||
|
||||
# TEST #1
|
||||
# -------
|
||||
|
||||
&run_make_with_options($makefile,"",&get_logfile,0);
|
||||
$answer = "echo This makefile did not clean the dir... good\n"
|
||||
."This makefile did not clean the dir... good\n";
|
||||
&compare_output($answer,&get_logfile(1));
|
||||
|
||||
run_make_test("
|
||||
all:
|
||||
\techo This makefile did not clean the dir... good
|
||||
clean:
|
||||
\t\@$delete_command $example\n",
|
||||
'', 'echo This makefile did not clean the dir... good
|
||||
This makefile did not clean the dir... good');
|
||||
|
||||
# TEST #2
|
||||
# -------
|
||||
|
||||
&run_make_with_options($makefile,"clean",&get_logfile,0);
|
||||
run_make_test(undef, 'clean', '');
|
||||
if (-f $example) {
|
||||
$test_passed = 0;
|
||||
unlink($example);
|
||||
}
|
||||
&compare_output('',&get_logfile(1));
|
||||
|
||||
# TEST #3
|
||||
# -------
|
||||
|
||||
&run_make_with_options($makefile,"-n clean",&get_logfile,0);
|
||||
$answer = "$delete_command $example\n";
|
||||
&compare_output($answer,&get_logfile(1));
|
||||
run_make_test(undef, '-n clean', "$delete_command $example\n");
|
||||
|
||||
|
||||
# TEST #4
|
||||
# -------
|
||||
|
||||
&run_make_with_options($makefile,"-s",&get_logfile,0);
|
||||
$answer = "This makefile did not clean the dir... good\n";
|
||||
&compare_output($answer,&get_logfile(1));
|
||||
run_make_test(undef, '-s', "This makefile did not clean the dir... good\n");
|
||||
|
||||
|
||||
1;
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -190,5 +190,23 @@ dep: ; @echo $@
|
|||
'', "dep\nx.t1\nx.t2\nx\nfinal\n");
|
||||
|
||||
|
||||
# TEST 8: Verify we can remove pattern rules. Savannah bug #18622.
|
||||
|
||||
my @f = (qw(foo.w foo.ch));
|
||||
touch(@f);
|
||||
|
||||
run_make_test(q!
|
||||
CWEAVE := :
|
||||
|
||||
# Disable builtin rules
|
||||
%.tex : %.w
|
||||
%.tex : %.w %.ch
|
||||
!,
|
||||
'foo.tex',
|
||||
"#MAKE#: *** No rule to make target `foo.tex'. Stop.", 512);
|
||||
|
||||
unlink(@f);
|
||||
|
||||
|
||||
# This tells the test driver that the perl test script executed properly.
|
||||
1;
|
||||
|
|
|
@ -24,9 +24,9 @@ run_make_test(undef, 'SE=1', "three\nfour\nbariz\nfoo\$bar : baraz bariz");
|
|||
|
||||
# TEST #1: automatic variables.
|
||||
#
|
||||
run_make_test('
|
||||
run_make_test(q!
|
||||
.SECONDEXPANSION:
|
||||
.DEFAULT: ; @echo $@
|
||||
.DEFAULT: ; @echo '$@'
|
||||
|
||||
foo: bar baz
|
||||
|
||||
|
@ -39,7 +39,7 @@ foo: $$@.1 \
|
|||
$$|.5 \
|
||||
$$*.6
|
||||
|
||||
',
|
||||
!,
|
||||
'',
|
||||
'bar
|
||||
baz
|
||||
|
@ -60,17 +60,16 @@ buz.5
|
|||
|
||||
# Test #2: target/pattern -specific variables.
|
||||
#
|
||||
run_make_test('
|
||||
run_make_test(q!
|
||||
.SECONDEXPANSION:
|
||||
.DEFAULT: ; @echo $@
|
||||
.DEFAULT: ; @echo '$@'
|
||||
|
||||
foo.x: $$a $$b
|
||||
|
||||
foo.x: a := bar
|
||||
|
||||
%.x: b := baz
|
||||
|
||||
',
|
||||
!,
|
||||
'',
|
||||
'bar
|
||||
baz
|
||||
|
@ -79,9 +78,9 @@ baz
|
|||
|
||||
# Test #3: order of prerequisites.
|
||||
#
|
||||
run_make_test('
|
||||
run_make_test(q!
|
||||
.SECONDEXPANSION:
|
||||
.DEFAULT: ; @echo $@
|
||||
.DEFAULT: ; @echo '$@'
|
||||
|
||||
all: foo bar baz
|
||||
|
||||
|
@ -99,7 +98,7 @@ bar: bar.3
|
|||
baz: baz.1
|
||||
baz: baz.2
|
||||
baz: ; @:
|
||||
',
|
||||
!,
|
||||
'',
|
||||
'foo.1
|
||||
foo.2
|
||||
|
@ -112,22 +111,23 @@ baz.2
|
|||
');
|
||||
|
||||
# TEST #4: eval in a context where there is no reading_file
|
||||
run_make_test('
|
||||
run_make_test(q!
|
||||
.SECONDEXPANSION:
|
||||
all : $$(eval $$(info test))
|
||||
', '', "test\n#MAKE#: Nothing to be done for `all'.\n");
|
||||
!,
|
||||
'', "test\n#MAKE#: Nothing to be done for `all'.\n");
|
||||
|
||||
# TEST #5: (NEGATIVE) catch eval in a prereq list trying to create new
|
||||
# target/prereq relationships.
|
||||
|
||||
run_make_test('
|
||||
run_make_test(q!
|
||||
.SECONDEXPANSION:
|
||||
proj1.exe : proj1.o $$(eval $$(test))
|
||||
define test
|
||||
proj1.o : proj1.c
|
||||
proj1.c: proj1.h
|
||||
endef
|
||||
',
|
||||
!,
|
||||
'', "#MAKE#: *** prerequisites cannot be defined in recipes. Stop.\n", 512);
|
||||
|
||||
# This tells the test driver that the perl test script executed properly.
|
||||
|
|
|
@ -11,9 +11,9 @@ $dir =~ s,.*/([^/]+)$,../$1,;
|
|||
|
||||
# Test #1: automatic variables.
|
||||
#
|
||||
run_make_test('
|
||||
run_make_test(q!
|
||||
.SECONDEXPANSION:
|
||||
.DEFAULT: ; @echo $@
|
||||
.DEFAULT: ; @echo '$@'
|
||||
|
||||
foo.a: bar baz
|
||||
|
||||
|
@ -37,9 +37,9 @@ foo.%: 1.$$@ \
|
|||
4.biz \
|
||||
5.buz \
|
||||
6.a:
|
||||
@echo $@
|
||||
@echo '$@'
|
||||
|
||||
',
|
||||
!,
|
||||
'',
|
||||
'1.foo.a
|
||||
2.bar
|
||||
|
@ -60,7 +60,7 @@ buz
|
|||
|
||||
# Test #2: target/pattern -specific variables.
|
||||
#
|
||||
run_make_test('
|
||||
run_make_test(q!
|
||||
.SECONDEXPANSION:
|
||||
foo.x:
|
||||
|
||||
|
@ -71,20 +71,16 @@ foo.x: x_a := bar
|
|||
|
||||
%.x: x_b := baz
|
||||
|
||||
bar baz: ; @echo $@
|
||||
|
||||
',
|
||||
'',
|
||||
'bar
|
||||
baz
|
||||
');
|
||||
bar baz: ; @echo '$@'
|
||||
!,
|
||||
'', "bar\nbaz\n");
|
||||
|
||||
|
||||
# Test #3: order of prerequisites.
|
||||
#
|
||||
run_make_test('
|
||||
run_make_test(q!
|
||||
.SECONDEXPANSION:
|
||||
.DEFAULT: ; @echo $@
|
||||
.DEFAULT: ; @echo '$@'
|
||||
|
||||
all: foo bar baz
|
||||
|
||||
|
@ -97,7 +93,7 @@ foo: foo.2
|
|||
|
||||
foo: foo.3
|
||||
|
||||
foo.1: ; @echo $@
|
||||
foo.1: ; @echo '$@'
|
||||
|
||||
|
||||
# Subtest #2
|
||||
|
@ -108,7 +104,7 @@ bar: bar.2
|
|||
|
||||
bar: bar.3
|
||||
|
||||
bar.1: ; @echo $@
|
||||
bar.1: ; @echo '$@'
|
||||
|
||||
|
||||
# Subtest #3
|
||||
|
@ -118,9 +114,8 @@ baz: baz.1
|
|||
baz: baz.2
|
||||
|
||||
%az: ; @:
|
||||
|
||||
',
|
||||
'',
|
||||
!,
|
||||
'',
|
||||
'foo.1
|
||||
foo.2
|
||||
foo.3
|
||||
|
@ -134,20 +129,18 @@ baz.2
|
|||
|
||||
# Test #4: stem splitting logic.
|
||||
#
|
||||
run_make_test('
|
||||
run_make_test(q!
|
||||
.SECONDEXPANSION:
|
||||
$(dir)/tmp/bar.o:
|
||||
|
||||
$(dir)/tmp/foo/bar.c: ; @echo $@
|
||||
$(dir)/tmp/bar/bar.c: ; @echo $@
|
||||
foo.h: ; @echo $@
|
||||
$(dir)/tmp/foo/bar.c: ; @echo '$@'
|
||||
$(dir)/tmp/bar/bar.c: ; @echo '$@'
|
||||
foo.h: ; @echo '$@'
|
||||
|
||||
%.o: $$(addsuffix /%.c,foo bar) foo.h
|
||||
@echo $@: {$<} $^
|
||||
|
||||
',
|
||||
"dir=$dir",
|
||||
"$dir/tmp/foo/bar.c
|
||||
@echo '$@: {$<} $^'
|
||||
!,
|
||||
"dir=$dir", "$dir/tmp/foo/bar.c
|
||||
$dir/tmp/bar/bar.c
|
||||
foo.h
|
||||
$dir/tmp/bar.o: {$dir/tmp/foo/bar.c} $dir/tmp/foo/bar.c $dir/tmp/bar/bar.c foo.h
|
||||
|
@ -156,18 +149,17 @@ $dir/tmp/bar.o: {$dir/tmp/foo/bar.c} $dir/tmp/foo/bar.c $dir/tmp/bar/bar.c foo.h
|
|||
|
||||
# Test #5: stem splitting logic and order-only prerequisites.
|
||||
#
|
||||
run_make_test('
|
||||
run_make_test(q!
|
||||
.SECONDEXPANSION:
|
||||
$(dir)/tmp/foo.o: $(dir)/tmp/foo.c
|
||||
$(dir)/tmp/foo.c: ; @echo $@
|
||||
bar.h: ; @echo $@
|
||||
$(dir)/tmp/foo.c: ; @echo '$@'
|
||||
bar.h: ; @echo '$@'
|
||||
|
||||
%.o: %.c|bar.h
|
||||
@echo $@: {$<} {$|} $^
|
||||
@echo '$@: {$<} {$|} $^'
|
||||
|
||||
',
|
||||
"dir=$dir",
|
||||
"$dir/tmp/foo.c
|
||||
!,
|
||||
"dir=$dir", "$dir/tmp/foo.c
|
||||
bar.h
|
||||
$dir/tmp/foo.o: {$dir/tmp/foo.c} {bar.h} $dir/tmp/foo.c
|
||||
");
|
||||
|
@ -175,54 +167,45 @@ $dir/tmp/foo.o: {$dir/tmp/foo.c} {bar.h} $dir/tmp/foo.c
|
|||
|
||||
# Test #6: lack of implicit prerequisites.
|
||||
#
|
||||
run_make_test('
|
||||
run_make_test(q!
|
||||
.SECONDEXPANSION:
|
||||
foo.o: foo.c
|
||||
foo.c: ; @echo $@
|
||||
foo.c: ; @echo '$@'
|
||||
|
||||
%.o:
|
||||
@echo $@: {$<} $^
|
||||
@echo '$@: {$<} $^'
|
||||
!,
|
||||
'', "foo.c\nfoo.o: {foo.c} foo.c\n");
|
||||
|
||||
',
|
||||
'',
|
||||
'foo.c
|
||||
foo.o: {foo.c} foo.c
|
||||
');
|
||||
|
||||
# Test #7: Test stem from the middle of the name.
|
||||
#
|
||||
run_make_test('
|
||||
run_make_test(q!
|
||||
.SECONDEXPANSION:
|
||||
foobarbaz:
|
||||
|
||||
foo%baz: % $$*.1
|
||||
@echo $*
|
||||
@echo '$*'
|
||||
|
||||
bar bar.1:
|
||||
@echo $@
|
||||
@echo '$@'
|
||||
!,
|
||||
'', "bar\nbar.1\nbar\n");
|
||||
|
||||
',
|
||||
'',
|
||||
'bar
|
||||
bar.1
|
||||
bar
|
||||
');
|
||||
|
||||
# Test #8: Make sure stem triple-expansion does not happen.
|
||||
#
|
||||
run_make_test('
|
||||
run_make_test(q!
|
||||
.SECONDEXPANSION:
|
||||
foo$$bar:
|
||||
|
||||
f%r: % $$*.1
|
||||
@echo \'$*\'
|
||||
@echo '$*'
|
||||
|
||||
oo$$ba oo$$ba.1:
|
||||
@echo \'$@\'
|
||||
|
||||
',
|
||||
'',
|
||||
'oo$ba
|
||||
@echo '$@'
|
||||
!,
|
||||
'', 'oo$ba
|
||||
oo$ba.1
|
||||
oo$ba
|
||||
');
|
||||
|
|
|
@ -5,12 +5,11 @@ $details = "";
|
|||
|
||||
# Test #1: automatic variables.
|
||||
#
|
||||
run_make_test('
|
||||
run_make_test(q!
|
||||
.SECONDEXPANSION:
|
||||
.DEFAULT: ; @echo $@
|
||||
.DEFAULT: ; @echo '$@'
|
||||
|
||||
foo.a foo.b: foo.%: bar.% baz.%
|
||||
|
||||
foo.a foo.b: foo.%: biz.% | buz.%
|
||||
|
||||
foo.a foo.b: foo.%: $$@.1 \
|
||||
|
@ -19,10 +18,8 @@ foo.a foo.b: foo.%: $$@.1 \
|
|||
$$(addsuffix .4,$$+) \
|
||||
$$|.5 \
|
||||
$$*.6
|
||||
|
||||
',
|
||||
'',
|
||||
'bar.a
|
||||
!,
|
||||
'', 'bar.a
|
||||
baz.a
|
||||
biz.a
|
||||
buz.a
|
||||
|
@ -41,61 +38,45 @@ a.6
|
|||
|
||||
# Test #2: target/pattern -specific variables.
|
||||
#
|
||||
run_make_test('
|
||||
run_make_test(q!
|
||||
.SECONDEXPANSION:
|
||||
.DEFAULT: ; @echo $@
|
||||
.DEFAULT: ; @echo '$@'
|
||||
|
||||
foo.x foo.y: foo.%: $$(%_a) $$($$*_b)
|
||||
|
||||
foo.x: x_a := bar
|
||||
|
||||
%.x: x_b := baz
|
||||
|
||||
|
||||
',
|
||||
'',
|
||||
'bar
|
||||
baz
|
||||
');
|
||||
!,
|
||||
'', "bar\nbaz\n");
|
||||
|
||||
|
||||
# Test #3: order of prerequisites.
|
||||
#
|
||||
run_make_test('
|
||||
run_make_test(q!
|
||||
.SECONDEXPANSION:
|
||||
.DEFAULT: ; @echo $@
|
||||
.DEFAULT: ; @echo '$@'
|
||||
|
||||
all: foo.a bar.a baz.a
|
||||
|
||||
# Subtest #1
|
||||
#
|
||||
foo.a foo.b: foo.%: foo.%.1; @:
|
||||
|
||||
foo.a foo.b: foo.%: foo.%.2
|
||||
|
||||
foo.a foo.b: foo.%: foo.%.3
|
||||
|
||||
|
||||
# Subtest #2
|
||||
#
|
||||
bar.a bar.b: bar.%: bar.%.2
|
||||
|
||||
bar.a bar.b: bar.%: bar.%.1; @:
|
||||
|
||||
bar.a bar.b: bar.%: bar.%.3
|
||||
|
||||
|
||||
# Subtest #3
|
||||
#
|
||||
baz.a baz.b: baz.%: baz.%.1
|
||||
|
||||
baz.a baz.b: baz.%: baz.%.2
|
||||
|
||||
baz.a baz.b: ; @:
|
||||
|
||||
',
|
||||
'',
|
||||
'foo.a.1
|
||||
!,
|
||||
'', 'foo.a.1
|
||||
foo.a.2
|
||||
foo.a.3
|
||||
bar.a.1
|
||||
|
@ -108,17 +89,15 @@ baz.a.2
|
|||
|
||||
# Test #4: Make sure stem triple-expansion does not happen.
|
||||
#
|
||||
run_make_test('
|
||||
run_make_test(q!
|
||||
.SECONDEXPANSION:
|
||||
foo$$bar: f%r: % $$*.1
|
||||
@echo \'$*\'
|
||||
@echo '$*'
|
||||
|
||||
oo$$ba oo$$ba.1:
|
||||
@echo \'$@\'
|
||||
|
||||
',
|
||||
'',
|
||||
'oo$ba
|
||||
@echo '$@'
|
||||
!,
|
||||
'', 'oo$ba
|
||||
oo$ba.1
|
||||
oo$ba
|
||||
');
|
||||
|
|
Loading…
Reference in a new issue