mirror of
https://github.com/mirror/make.git
synced 2025-03-27 20:40:35 +08: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
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>
|
2009-09-16 Paul Smith <psmith@gnu.org>
|
||||||
|
|
||||||
* misc.c (alloc_dep, free_dep): Now that we have xcalloc(),
|
* 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)
|
for (d = file->deps; d != 0; d = d->next)
|
||||||
if (!d->ignore_mtime)
|
if (!d->ignore_mtime)
|
||||||
{
|
{
|
||||||
less = dep_name (d);
|
if (!d->need_2nd_expansion)
|
||||||
|
less = dep_name (d);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -153,7 +154,7 @@ set_file_variables (struct file *file)
|
|||||||
|
|
||||||
plus_len = 0;
|
plus_len = 0;
|
||||||
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->need_2nd_expansion)
|
||||||
plus_len += strlen (dep_name (d)) + 1;
|
plus_len += strlen (dep_name (d)) + 1;
|
||||||
if (plus_len == 0)
|
if (plus_len == 0)
|
||||||
plus_len++;
|
plus_len++;
|
||||||
@ -164,7 +165,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)
|
if (! d->ignore_mtime && ! d->need_2nd_expansion)
|
||||||
{
|
{
|
||||||
const char *c = dep_name (d);
|
const char *c = dep_name (d);
|
||||||
|
|
||||||
@ -198,7 +199,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->ignore_mtime)
|
if (d->ignore_mtime && ! d->need_2nd_expansion)
|
||||||
bar_len += strlen (dep_name (d)) + 1;
|
bar_len += strlen (dep_name (d)) + 1;
|
||||||
if (bar_len == 0)
|
if (bar_len == 0)
|
||||||
bar_len++;
|
bar_len++;
|
||||||
@ -217,8 +218,12 @@ set_file_variables (struct file *file)
|
|||||||
|
|
||||||
for (d = file->deps; d != 0; d = d->next)
|
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
|
#ifndef NO_ARCHIVES
|
||||||
if (ar_name (c))
|
if (ar_name (c))
|
||||||
{
|
{
|
||||||
|
@ -542,8 +542,9 @@ set_default_suffixes (void)
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
char *p = default_suffixes;
|
char *p = default_suffixes;
|
||||||
suffix_file->deps = (struct dep *)
|
suffix_file->deps = enter_prereqs(PARSE_FILE_SEQ (&p, struct dep, '\0',
|
||||||
parse_file_seq (&p, sizeof (struct dep), '\0', NULL, 0);
|
NULL, 0),
|
||||||
|
NULL);
|
||||||
define_variable ("SUFFIXES", 8, default_suffixes, o_default, 0);
|
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_EXISTS (0x0004)
|
||||||
#define PARSEFS_NOCACHE (0x0008)
|
#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
|
#ifdef VMS
|
||||||
struct nameseq *parse_file_seq ();
|
void *parse_file_seq ();
|
||||||
#else
|
#else
|
||||||
struct nameseq *parse_file_seq (char **stringp, unsigned int size,
|
void *parse_file_seq (char **stringp, unsigned int size,
|
||||||
int stopchar, const char *prefix, int flags);
|
int stopchar, const char *prefix, int flags);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
char *tilde_expand (const char *name);
|
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')
|
if (*p == '\0')
|
||||||
break;
|
break;
|
||||||
else
|
|
||||||
++p;
|
++p;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (abuf)
|
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 *
|
struct dep *
|
||||||
parse_prereqs (char *p)
|
split_prereqs (char *p)
|
||||||
{
|
{
|
||||||
struct dep *new = (struct dep *)
|
struct dep *new = PARSE_FILE_SEQ (&p, struct dep, '|', NULL, 0);
|
||||||
parse_file_seq (&p, sizeof (struct dep), '|', NULL, 0);
|
|
||||||
|
|
||||||
if (*p)
|
if (*p)
|
||||||
{
|
{
|
||||||
@ -424,8 +426,7 @@ parse_prereqs (char *p)
|
|||||||
struct dep *ood;
|
struct dep *ood;
|
||||||
|
|
||||||
++p;
|
++p;
|
||||||
ood = (struct dep *)
|
ood = PARSE_FILE_SEQ (&p, struct dep, '\0', NULL, 0);
|
||||||
parse_file_seq (&p, sizeof (struct dep), '\0', NULL, 0);
|
|
||||||
|
|
||||||
if (! new)
|
if (! new)
|
||||||
new = ood;
|
new = ood;
|
||||||
@ -444,6 +445,85 @@ parse_prereqs (char *p)
|
|||||||
return new;
|
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. */
|
/* Set the intermediate flag. */
|
||||||
|
|
||||||
static void
|
static void
|
||||||
@ -458,166 +538,94 @@ static void
|
|||||||
expand_deps (struct file *f)
|
expand_deps (struct file *f)
|
||||||
{
|
{
|
||||||
struct dep *d;
|
struct dep *d;
|
||||||
struct dep *old = f->deps;
|
struct dep **dp;
|
||||||
const char *file_stem = f->stem;
|
const char *file_stem = f->stem;
|
||||||
unsigned int last_dep_has_cmds = f->updating;
|
|
||||||
int initialized = 0;
|
int initialized = 0;
|
||||||
|
|
||||||
f->updating = 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;
|
char *p;
|
||||||
|
struct dep *new, *next;
|
||||||
|
char *name = (char *)d->name;
|
||||||
|
|
||||||
if (! d->name)
|
if (! d->name || ! d->need_2nd_expansion)
|
||||||
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)
|
|
||||||
{
|
{
|
||||||
p = variable_expand ("");
|
/* This one is all set already. */
|
||||||
variable_buffer_output (p, d->name, strlen (d->name) + 1);
|
dp = &d->next;
|
||||||
p = variable_buffer;
|
d = d->next;
|
||||||
}
|
continue;
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Parse the prerequisites. */
|
/* If it's from a static pattern rule, convert the patterns into
|
||||||
new = parse_prereqs (p);
|
"$*" so they'll expand properly. */
|
||||||
|
if (d->staticpattern)
|
||||||
/* 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)
|
|
||||||
{
|
{
|
||||||
const char *pattern = "%";
|
char *o;
|
||||||
char *buffer = variable_expand ("");
|
d->name = o = variable_expand ("");
|
||||||
struct dep *dp = new, *dl = 0;
|
o = subst_expand (o, name, "%", "$*", 1, 2, 0);
|
||||||
|
*o = '\0';
|
||||||
while (dp != 0)
|
free (name);
|
||||||
{
|
d->name = name = xstrdup (d->name);
|
||||||
char *percent;
|
d->staticpattern = 0;
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Enter them as files. */
|
/* We're going to do second expansion so initialize file variables for
|
||||||
for (d1 = new; d1 != 0; d1 = d1->next)
|
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);
|
initialize_file_variables (f, 0);
|
||||||
if (d1->file == 0)
|
initialized = 1;
|
||||||
d1->file = enter_file (d1->name);
|
|
||||||
d1->name = 0;
|
|
||||||
d1->staticpattern = 0;
|
|
||||||
d1->need_2nd_expansion = 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Add newly parsed deps to f->deps. If this is the last dependency
|
if (d->stem != 0)
|
||||||
line and this target has commands then put it in front so the
|
f->stem = d->stem;
|
||||||
last dependency line (the one with commands) ends up being the
|
|
||||||
first. This is important because people expect $< to hold first
|
|
||||||
prerequisite from the rule with commands. If it is not the last
|
|
||||||
dependency line or the rule does not have commands then link it
|
|
||||||
at the end so it appears in makefile order. */
|
|
||||||
|
|
||||||
if (new != 0)
|
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)
|
*dp = d->next;
|
||||||
{
|
free_dep (d);
|
||||||
struct dep **d_ptr;
|
d = *dp;
|
||||||
for (d_ptr = &new; *d_ptr; d_ptr = &(*d_ptr)->next)
|
continue;
|
||||||
;
|
|
||||||
|
|
||||||
*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;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* 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
|
/* For each dependency of each file, make the `struct dep' point
|
||||||
@ -632,30 +640,44 @@ snap_deps (void)
|
|||||||
struct file *f;
|
struct file *f;
|
||||||
struct file *f2;
|
struct file *f2;
|
||||||
struct dep *d;
|
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
|
/* Remember that we've done this. Once we start snapping deps we can no
|
||||||
longer define new targets. */
|
longer define new targets. */
|
||||||
snapped_deps = 1;
|
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. */
|
We only need to do this if second_expansion has been defined; if it
|
||||||
for (f = lookup_file (".SUFFIXES"); f != 0; f = f->prev)
|
hasn't then all deps were expanded as the makefile was read in. If we
|
||||||
expand_deps (f);
|
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.
|
if (second_expansion)
|
||||||
We must use hash_dump (), because within this loop we might add new files
|
{
|
||||||
to the table, possibly causing an in-situ table expansion. */
|
struct file **file_slot_0 = (struct file **) hash_dump (&files, 0, 0);
|
||||||
file_slot_0 = (struct file **) hash_dump (&files, 0, 0);
|
struct file **file_end = file_slot_0 + files.ht_fill;
|
||||||
file_end = file_slot_0 + files.ht_fill;
|
struct file **file_slot;
|
||||||
for (file_slot = file_slot_0; file_slot < file_end; file_slot++)
|
const char *suffixes;
|
||||||
for (f = *file_slot; f != 0; f = f->prev)
|
|
||||||
if (strcmp (f->name, ".SUFFIXES") != 0)
|
/* 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);
|
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. */
|
/* Now manage all the special targets. */
|
||||||
|
|
||||||
@ -859,35 +881,40 @@ file_timestamp_sprintf (char *p, FILE_TIMESTAMP ts)
|
|||||||
|
|
||||||
/* Print the data base of files. */
|
/* Print the data base of files. */
|
||||||
|
|
||||||
static void
|
void
|
||||||
print_file (const void *item)
|
print_prereqs (const struct dep *deps)
|
||||||
{
|
{
|
||||||
const struct file *f = item;
|
const struct dep *ood = 0;
|
||||||
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 ? ":" : "");
|
|
||||||
|
|
||||||
/* Print all normal dependencies; note any order-only deps. */
|
/* Print all normal dependencies; note any order-only deps. */
|
||||||
for (d = f->deps; d != 0; d = d->next)
|
for (; deps != 0; deps = deps->next)
|
||||||
if (! d->ignore_mtime)
|
if (! deps->ignore_mtime)
|
||||||
printf (" %s", dep_name (d));
|
printf (" %s", dep_name (deps));
|
||||||
else if (! ood)
|
else if (! ood)
|
||||||
ood = d;
|
ood = deps;
|
||||||
|
|
||||||
/* Print order-only deps, if we have any. */
|
/* Print order-only deps, if we have any. */
|
||||||
if (ood)
|
if (ood)
|
||||||
{
|
{
|
||||||
printf (" | %s", dep_name (ood));
|
printf (" | %s", dep_name (ood));
|
||||||
for (d = ood->next; d != 0; d = d->next)
|
for (ood = ood->next; ood != 0; ood = ood->next)
|
||||||
if (d->ignore_mtime)
|
if (ood->ignore_mtime)
|
||||||
printf (" %s", dep_name (d));
|
printf (" %s", dep_name (ood));
|
||||||
}
|
}
|
||||||
|
|
||||||
putchar ('\n');
|
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)
|
if (f->precious)
|
||||||
puts (_("# Precious file (prerequisite of .PRECIOUS)."));
|
puts (_("# Precious file (prerequisite of .PRECIOUS)."));
|
||||||
@ -906,6 +933,7 @@ print_file (const void *item)
|
|||||||
puts (_("# File is an intermediate prerequisite."));
|
puts (_("# File is an intermediate prerequisite."));
|
||||||
if (f->also_make != 0)
|
if (f->also_make != 0)
|
||||||
{
|
{
|
||||||
|
const struct dep *d;
|
||||||
fputs (_("# Also makes:"), stdout);
|
fputs (_("# Also makes:"), stdout);
|
||||||
for (d = f->also_make; d != 0; d = d->next)
|
for (d = f->also_make; d != 0; d = d->next)
|
||||||
printf (" %s", dep_name (d));
|
printf (" %s", dep_name (d));
|
||||||
@ -989,7 +1017,7 @@ print_file_data_base (void)
|
|||||||
#define VERIFY_CACHED(_p,_n) \
|
#define VERIFY_CACHED(_p,_n) \
|
||||||
do{\
|
do{\
|
||||||
if (_p->_n && _p->_n[0] && !strcache_iscached (_p->_n)) \
|
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)
|
}while(0)
|
||||||
|
|
||||||
static void
|
static void
|
||||||
@ -1006,7 +1034,8 @@ verify_file (const void *item)
|
|||||||
/* Check the deps. */
|
/* Check the deps. */
|
||||||
for (d = f->deps; d != 0; d = d->next)
|
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);
|
VERIFY_CACHED (d, stem);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -102,7 +102,8 @@ extern struct file *suffix_file, *default_file;
|
|||||||
|
|
||||||
struct file *lookup_file (const char *name);
|
struct file *lookup_file (const char *name);
|
||||||
struct file *enter_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 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);
|
||||||
@ -111,6 +112,8 @@ void set_command_state (struct file *file, enum cmd_state state);
|
|||||||
void notice_finished_file (struct file *file);
|
void notice_finished_file (struct file *file);
|
||||||
void init_hash_files (void);
|
void init_hash_files (void);
|
||||||
char *build_target_list (char *old_list);
|
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
|
#if FILE_TIMESTAMP_HI_RES
|
||||||
# define FILE_TIMESTAMP_STAT_MODTIME(fname, st) \
|
# define FILE_TIMESTAMP_STAT_MODTIME(fname, st) \
|
||||||
|
@ -355,7 +355,7 @@ string_glob (char *line)
|
|||||||
struct nameseq *chain;
|
struct nameseq *chain;
|
||||||
unsigned int idx;
|
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.
|
/* We do not want parse_file_seq to strip `./'s.
|
||||||
That would break examples like:
|
That would break examples like:
|
||||||
$(patsubst ./%.c,obj/%.o,$(wildcard ./?*.c)). */
|
$(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. */
|
/* 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 { \
|
#define STRING_HASH_1(KEY, RESULT) do { \
|
||||||
unsigned char const *_key_ = (unsigned char const *) (KEY) - 1; \
|
unsigned char const *_key_ = (unsigned char const *) (KEY) - 1; \
|
||||||
while (*++_key_) \
|
while (*++_key_) \
|
||||||
@ -102,10 +105,10 @@ extern void *hash_deleted_item;
|
|||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
#define STRING_COMPARE(X, Y, RESULT) do { \
|
#define STRING_COMPARE(X, Y, RESULT) do { \
|
||||||
RESULT = strcmp ((X), (Y)); \
|
RESULT = (X) == (Y) ? 0 : strcmp ((X), (Y)); \
|
||||||
} while (0)
|
} while (0)
|
||||||
#define return_STRING_COMPARE(X, Y) do { \
|
#define return_STRING_COMPARE(X, Y) do { \
|
||||||
return strcmp ((X), (Y)); \
|
return (X) == (Y) ? 0 : strcmp ((X), (Y)); \
|
||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
|
|
||||||
@ -138,10 +141,10 @@ extern void *hash_deleted_item;
|
|||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
#define STRING_N_COMPARE(X, Y, N, RESULT) do { \
|
#define STRING_N_COMPARE(X, Y, N, RESULT) do { \
|
||||||
RESULT = strncmp ((X), (Y), (N)); \
|
RESULT = (X) == (Y) ? 0 : strncmp ((X), (Y), (N)); \
|
||||||
} while (0)
|
} while (0)
|
||||||
#define return_STRING_N_COMPARE(X, Y, N) do { \
|
#define return_STRING_N_COMPARE(X, Y, N) do { \
|
||||||
return strncmp ((X), (Y), (N)); \
|
return (X) == (Y) ? 0 : strncmp ((X), (Y), (N)); \
|
||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
#ifdef HAVE_CASE_INSENSITIVE_FS
|
#ifdef HAVE_CASE_INSENSITIVE_FS
|
||||||
@ -171,10 +174,10 @@ extern void *hash_deleted_item;
|
|||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
#define ISTRING_COMPARE(X, Y, RESULT) do { \
|
#define ISTRING_COMPARE(X, Y, RESULT) do { \
|
||||||
RESULT = strcasecmp ((X), (Y)); \
|
RESULT = (X) == (Y) ? 0 : strcasecmp ((X), (Y)); \
|
||||||
} while (0)
|
} while (0)
|
||||||
#define return_ISTRING_COMPARE(X, Y) do { \
|
#define return_ISTRING_COMPARE(X, Y) do { \
|
||||||
return strcasecmp ((X), (Y)); \
|
return (X) == (Y) ? 0 : strcasecmp ((X), (Y)); \
|
||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
#else
|
#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.
|
/* Scans the BUFFER for the next word with whitespace as a separator.
|
||||||
Returns the pointer to the beginning of the word. LENGTH hold the
|
Returns the pointer to the beginning of the word. LENGTH hold the
|
||||||
length of the word. */
|
length of the word. */
|
||||||
|
|
||||||
static char *
|
static const char *
|
||||||
get_next_word (const char *buffer, unsigned int *length)
|
get_next_word (const char *buffer, unsigned int *length)
|
||||||
{
|
{
|
||||||
const char *p = buffer, *beg;
|
const char *p = buffer, *beg;
|
||||||
@ -166,9 +141,22 @@ get_next_word (const char *buffer, unsigned int *length)
|
|||||||
if (length)
|
if (length)
|
||||||
*length = p - beg;
|
*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
|
/* 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
|
FILE. If a rule is found, the appropriate commands and deps are put in FILE
|
||||||
and 1 is returned. If not, 0 is returned.
|
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
|
/* This is a file-object used as an argument in
|
||||||
recursive calls. It never contains any data
|
recursive calls. It never contains any data
|
||||||
except during a recursive call. */
|
except during a recursive call. */
|
||||||
struct file *intermediate_file = 0;
|
struct file *int_file = 0;
|
||||||
|
|
||||||
/* This linked list records all the prerequisites actually
|
/* List of dependencies found recursively. */
|
||||||
found for a rule along with some other useful information
|
struct patdeps *deplist
|
||||||
(see struct idep for details). */
|
= xmalloc (max_pattern_deps * sizeof (struct patdeps));
|
||||||
struct idep* deps = 0;
|
struct patdeps *pat = deplist;
|
||||||
|
|
||||||
/* 1 if we need to remove explicit prerequisites, 0 otherwise. */
|
/* All the prerequisites actually found for a rule, after expansion. */
|
||||||
unsigned int remove_explicit_deps = 0;
|
struct dep *deps;
|
||||||
|
|
||||||
/* Names of possible dependencies are constructed in this buffer. */
|
/* Names of possible dependencies are constructed in this buffer. */
|
||||||
char *depname = alloca (namelen + max_pattern_dep_length);
|
char *depname = alloca (namelen + max_pattern_dep_length);
|
||||||
@ -242,13 +230,13 @@ pattern_search (struct file *file, int archive,
|
|||||||
that is not just `%'. */
|
that is not just `%'. */
|
||||||
int specific_rule_matched = 0;
|
int specific_rule_matched = 0;
|
||||||
|
|
||||||
|
struct nameseq ns_simple;
|
||||||
|
|
||||||
unsigned int ri; /* uninit checks OK */
|
unsigned int ri; /* uninit checks OK */
|
||||||
struct rule *rule;
|
struct rule *rule;
|
||||||
struct dep *dep, *expl_d;
|
|
||||||
|
|
||||||
struct idep *d;
|
char *pathdir = NULL;
|
||||||
struct idep **id_ptr;
|
unsigned long pathlen;
|
||||||
struct dep **d_ptr;
|
|
||||||
|
|
||||||
PATH_VAR (stem_str); /* @@ Need to get rid of stem, stemlen, etc. */
|
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;
|
lastslash = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* First see which pattern rules match this target
|
pathlen = lastslash - filename + 1;
|
||||||
and may be considered. Put them in TRYRULES. */
|
|
||||||
|
ns_simple.next = 0;
|
||||||
|
|
||||||
|
/* First see which pattern rules match this target and may be considered.
|
||||||
|
Put them in TRYRULES. */
|
||||||
|
|
||||||
nrules = 0;
|
nrules = 0;
|
||||||
for (rule = pattern_rules; rule != 0; rule = rule->next)
|
for (rule = pattern_rules; rule != 0; rule = rule->next)
|
||||||
@ -349,11 +341,10 @@ pattern_search (struct file *file, int archive,
|
|||||||
if (check_lastslash)
|
if (check_lastslash)
|
||||||
{
|
{
|
||||||
/* If so, don't include the directory prefix in STEM here. */
|
/* If so, don't include the directory prefix in STEM here. */
|
||||||
unsigned int difference = lastslash - filename + 1;
|
if (pathlen > stemlen)
|
||||||
if (difference > stemlen)
|
|
||||||
continue;
|
continue;
|
||||||
stemlen -= difference;
|
stemlen -= pathlen;
|
||||||
stem += difference;
|
stem += pathlen;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Check that the rule pattern matches the text before the stem. */
|
/* 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);
|
initialize_file_variables (file, 0);
|
||||||
|
|
||||||
/* Try each rule once without intermediate files, then once with them. */
|
/* 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.
|
pat = deplist;
|
||||||
If it does, expand its dependencies (as substituted)
|
|
||||||
and chain them in DEPS. */
|
|
||||||
|
|
||||||
|
/* 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++)
|
for (ri = 0; ri < nrules; ri++)
|
||||||
{
|
{
|
||||||
|
struct dep *dep;
|
||||||
unsigned int failed = 0;
|
unsigned int failed = 0;
|
||||||
int check_lastslash;
|
int check_lastslash;
|
||||||
int file_variables_set = 0;
|
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];
|
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)
|
if (rule == 0)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
/* Reject any terminal rules if we're
|
/* Reject any terminal rules if we're looking to make intermediate
|
||||||
looking to make intermediate files. */
|
files. */
|
||||||
if (intermed_ok && rule->terminal)
|
if (intermed_ok && rule->terminal)
|
||||||
continue;
|
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,
|
/* From the lengths of the filename and the matching pattern parts,
|
||||||
find the stem: the part of the filename that matches the %. */
|
find the stem: the part of the filename that matches the %. */
|
||||||
stem = filename
|
stem = filename + (rule->suffixes[matches[ri]]
|
||||||
+ (rule->suffixes[matches[ri]] - rule->targets[matches[ri]]) - 1;
|
- rule->targets[matches[ri]]) - 1;
|
||||||
stemlen = namelen - rule->lens[matches[ri]] + 1;
|
stemlen = (namelen - rule->lens[matches[ri]]) + 1;
|
||||||
check_lastslash = checked_lastslash[ri];
|
check_lastslash = checked_lastslash[ri];
|
||||||
if (check_lastslash)
|
if (check_lastslash)
|
||||||
{
|
{
|
||||||
stem += lastslash - filename + 1;
|
stem += pathlen;
|
||||||
stemlen -= (lastslash - filename) + 1;
|
stemlen -= pathlen;
|
||||||
}
|
}
|
||||||
|
|
||||||
DBS (DB_IMPLICIT, (_("Trying pattern rule with stem `%.*s'.\n"),
|
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);
|
strncpy (stem_str, stem, stemlen);
|
||||||
stem_str[stemlen] = '\0';
|
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
|
/* Temporary assign STEM to file->stem (needed to set file
|
||||||
variables below). */
|
variables below). */
|
||||||
file->stem = stem_str;
|
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)
|
/* 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
|
||||||
unsigned int len;
|
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 *p;
|
||||||
char *p2;
|
|
||||||
unsigned int order_only = 0; /* Set if '|' was seen. */
|
|
||||||
|
|
||||||
/* In an ideal world we would take the dependency line,
|
/* If we need to add the directory prefix set it up. */
|
||||||
substitute the stem, re-expand the whole line and chop it
|
if (check_lastslash)
|
||||||
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)
|
|
||||||
{
|
{
|
||||||
const char *dir = NULL;
|
if (! pathdir)
|
||||||
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 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
|
/* If we're out of name to parse, start the next prereq. */
|
||||||
here. If we just replace % with the stem value,
|
if (! nptr)
|
||||||
later, when we do the second expansion, we will
|
{
|
||||||
re-expand this stem value once again. This is not
|
dep = dep->next;
|
||||||
good especially if you have certain characters in
|
if (dep == 0)
|
||||||
your stem (like $).
|
break;
|
||||||
|
nptr = dep_name (dep);
|
||||||
|
}
|
||||||
|
|
||||||
Instead, we will replace % with $* and allow the
|
/* If we don't need a second expansion, just replace the %. */
|
||||||
second expansion to take care of it for us. This way
|
if (! dep->need_2nd_expansion)
|
||||||
(since $* is a simple variable) there won't be
|
{
|
||||||
additional re-expansion of the stem. */
|
p = strchr (nptr, '%');
|
||||||
|
if (p == 0)
|
||||||
if (p2 < p + len)
|
ns_simple.name = nptr;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
char *o = depname;
|
||||||
|
if (check_lastslash)
|
||||||
{
|
{
|
||||||
unsigned int i = p2 - p;
|
memcpy (o, filename, pathlen);
|
||||||
memcpy (depname, p, i);
|
o += pathlen;
|
||||||
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, 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
|
/* We've used up this dep, so next time get a new one. */
|
||||||
at the beginning of the function because of the stem
|
nptr = 0;
|
||||||
value. */
|
++deps_found;
|
||||||
if (!file_variables_set)
|
}
|
||||||
{
|
|
||||||
set_file_variables (file);
|
|
||||||
file_variables_set = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
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
|
else
|
||||||
{
|
{
|
||||||
if (p2 < p + len)
|
unsigned int i = p - nptr;
|
||||||
{
|
memcpy (depname, nptr, i);
|
||||||
unsigned int i = p2 - p;
|
memcpy (depname + i, "$*", 2);
|
||||||
memcpy (depname, p, i);
|
memcpy (depname + i + 2, p + 1, len - i - 1);
|
||||||
memcpy (depname + i, stem_str, stemlen);
|
depname[len + 2 - 1] = '\0';
|
||||||
memcpy (depname + i + stemlen, p2 + 1, len - i - 1);
|
|
||||||
depname[len + stemlen - 1] = '\0';
|
|
||||||
|
|
||||||
if (check_lastslash)
|
if (check_lastslash)
|
||||||
add_dir = 1;
|
add_dir = 1;
|
||||||
|
|
||||||
had_stem = 1;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
memcpy (depname, p, len);
|
|
||||||
depname[len] = '\0';
|
|
||||||
}
|
|
||||||
|
|
||||||
p2 = depname;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* If we need to add the directory prefix set it up. */
|
/* Set file variables. Note that we cannot do it once at the
|
||||||
if (add_dir)
|
beginning of the function because the stem value changes
|
||||||
|
for each rule. */
|
||||||
|
if (!file_variables_set)
|
||||||
{
|
{
|
||||||
unsigned long l = lastslash - filename + 1;
|
set_file_variables (file);
|
||||||
char *n = alloca (l + 1);
|
file_variables_set = 1;
|
||||||
memcpy (n, filename, l);
|
|
||||||
n[l] = '\0';
|
|
||||||
dir = n;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 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;
|
/* If this prereq has already been ruled "impossible",
|
||||||
|
then the rule fails. Don't bother trying it on the
|
||||||
for (; *id_ptr; id_ptr = &(*id_ptr)->next)
|
second pass either since we know that will fail. */
|
||||||
;
|
DBS (DB_IMPLICIT,
|
||||||
|
(is_rule
|
||||||
*id_ptr = (struct idep *)
|
? _("Rejecting impossible rule prerequisite `%s'.\n")
|
||||||
parse_file_seq (&p2, sizeof (struct idep),
|
: _("Rejecting impossible implicit prerequisite `%s'.\n"),
|
||||||
order_only ? '\0' : '|', dir, 0);
|
n->name));
|
||||||
|
tryrules[ri] = 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;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
failed = 1;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
p += len;
|
memset (pat, '\0', sizeof (struct patdeps));
|
||||||
p = get_next_word (p, &len);
|
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. */
|
/* Reset the stem in FILE. */
|
||||||
|
|
||||||
file->stem = 0;
|
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. */
|
/* This rule is no longer `in use' for recursive searches. */
|
||||||
rule->in_use = 0;
|
rule->in_use = 0;
|
||||||
|
|
||||||
if (failed)
|
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
|
|
||||||
/* This pattern rule does apply. Stop looking for one. */
|
/* This pattern rule does apply. Stop looking for one. */
|
||||||
break;
|
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
|
/* If we found an applicable rule without intermediate files, don't try
|
||||||
intermediate files, don't try with them. */
|
with them. */
|
||||||
if (ri < nrules)
|
if (ri < nrules)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
rule = 0;
|
rule = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* RULE is nil if the loop went all the way
|
/* RULE is nil if the loop went through the list but everything failed. */
|
||||||
through the list and everything failed. */
|
|
||||||
if (rule == 0)
|
if (rule == 0)
|
||||||
goto done;
|
goto done;
|
||||||
|
|
||||||
foundrule = ri;
|
foundrule = ri;
|
||||||
|
|
||||||
/* If we are recursing, store the pattern that matched
|
/* If we are recursing, store the pattern that matched FILENAME in
|
||||||
FILENAME in FILE->name for use in upper levels. */
|
FILE->name for use in upper levels. */
|
||||||
|
|
||||||
if (recursions > 0)
|
if (recursions > 0)
|
||||||
/* Kludge-o-matic */
|
/* Kludge-o-matic */
|
||||||
file->name = rule->targets[matches[foundrule]];
|
file->name = rule->targets[matches[foundrule]];
|
||||||
|
|
||||||
/* FOUND_FILES lists the dependencies for the rule we found.
|
/* DEPLIST lists the prerequisites for the rule we found. This includes the
|
||||||
This includes the intermediate files, if any.
|
intermediate files, if any. Convert them into entries on the deps-chain
|
||||||
Convert them into entries on the deps-chain of FILE. */
|
of FILE. */
|
||||||
|
|
||||||
if (remove_explicit_deps)
|
while (pat-- > deplist)
|
||||||
{
|
|
||||||
/* 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)
|
|
||||||
{
|
{
|
||||||
|
struct dep *dep;
|
||||||
const char *s;
|
const char *s;
|
||||||
|
|
||||||
if (d->intermediate_file != 0)
|
if (pat->file != 0)
|
||||||
{
|
{
|
||||||
/* If we need to use an intermediate file,
|
/* If we need to use an intermediate file, make sure it is entered
|
||||||
make sure it is entered as a target, with the info that was
|
as a target, with the info that was found for it in the recursive
|
||||||
found for it in the recursive pattern_search call.
|
pattern_search call. We know that the intermediate file did not
|
||||||
We know that the intermediate file did not already exist as
|
already exist as a target; therefore we can assume that the deps
|
||||||
a target; therefore we can assume that the deps and cmds
|
and cmds of F below are null before we change them. */
|
||||||
of F below are null before we change them. */
|
|
||||||
|
|
||||||
struct file *imf = d->intermediate_file;
|
struct file *imf = pat->file;
|
||||||
register struct file *f = lookup_file (imf->name);
|
struct file *f = lookup_file (imf->name);
|
||||||
|
|
||||||
/* We don't want to delete an intermediate file that happened
|
/* We don't want to delete an intermediate file that happened
|
||||||
to be a prerequisite of some (other) target. Mark it as
|
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)
|
if (f != 0)
|
||||||
f->precious = 1;
|
f->precious = 1;
|
||||||
else
|
else
|
||||||
f = enter_file (strcache_add (imf->name));
|
f = enter_file (imf->name);
|
||||||
|
|
||||||
f->deps = imf->deps;
|
f->deps = imf->deps;
|
||||||
f->cmds = imf->cmds;
|
f->cmds = imf->cmds;
|
||||||
f->stem = imf->stem;
|
f->stem = imf->stem;
|
||||||
f->also_make = imf->also_make;
|
f->also_make = imf->also_make;
|
||||||
f->is_target = 1;
|
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->intermediate = 1;
|
||||||
f->tried_implicit = 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)
|
for (dep = f->deps; dep != 0; dep = dep->next)
|
||||||
{
|
{
|
||||||
dep->file = enter_file (dep->name);
|
dep->file = enter_file (dep->name);
|
||||||
@ -840,41 +821,38 @@ pattern_search (struct file *file, int archive,
|
|||||||
}
|
}
|
||||||
|
|
||||||
dep = alloc_dep ();
|
dep = alloc_dep ();
|
||||||
dep->ignore_mtime = d->ignore_mtime;
|
dep->ignore_mtime = pat->ignore_mtime;
|
||||||
s = d->name; /* Hijacking the name. */
|
s = strcache_add (pat->name);
|
||||||
d->name = 0;
|
if (recursions)
|
||||||
if (recursions == 0)
|
dep->name = s;
|
||||||
|
else
|
||||||
{
|
{
|
||||||
dep->file = lookup_file (s);
|
dep->file = lookup_file (s);
|
||||||
if (dep->file == 0)
|
if (dep->file == 0)
|
||||||
dep->file = enter_file (s);
|
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),
|
/* If the file actually existed (was not an intermediate file), and
|
||||||
and the rule that found it was a terminal one, then we want
|
the rule that found it was a terminal one, then we want to mark
|
||||||
to mark the found file so that it will not have implicit rule
|
the found file so that it will not have implicit rule search done
|
||||||
search done for it. If we are not entering a `struct file' for
|
for it. If we are not entering a `struct file' for it now, we
|
||||||
it now, we indicate this with the `changed' flag. */
|
indicate this with the `changed' flag. */
|
||||||
if (dep->file == 0)
|
if (dep->file == 0)
|
||||||
dep->changed = 1;
|
dep->changed = 1;
|
||||||
else
|
else
|
||||||
dep->file->tried_implicit = 1;
|
dep->file->tried_implicit = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
*d_ptr = dep;
|
dep->next = file->deps;
|
||||||
d_ptr = &dep->next;
|
file->deps = dep;
|
||||||
}
|
}
|
||||||
|
|
||||||
*d_ptr = expl_d;
|
|
||||||
|
|
||||||
if (!checked_lastslash[foundrule])
|
if (!checked_lastslash[foundrule])
|
||||||
{
|
{
|
||||||
/* Always allocate new storage, since STEM might be
|
/* Always allocate new storage, since STEM might be on the stack for an
|
||||||
on the stack for an intermediate file. */
|
intermediate file. */
|
||||||
file->stem = strcache_add_len (stem, stemlen);
|
file->stem = strcache_add_len (stem, stemlen);
|
||||||
fullstemlen = stemlen;
|
fullstemlen = stemlen;
|
||||||
}
|
}
|
||||||
@ -932,8 +910,8 @@ pattern_search (struct file *file, int archive,
|
|||||||
if (f && f->precious)
|
if (f && f->precious)
|
||||||
new->file->precious = 1;
|
new->file->precious = 1;
|
||||||
|
|
||||||
/* Set the is_target flag so that this file is not treated
|
/* Set the is_target flag so that this file is not treated as
|
||||||
as intermediate by the pattern rule search algorithm and
|
intermediate by the pattern rule search algorithm and
|
||||||
file_exists_p cannot pick it up yet. */
|
file_exists_p cannot pick it up yet. */
|
||||||
new->file->is_target = 1;
|
new->file->is_target = 1;
|
||||||
|
|
||||||
@ -941,8 +919,8 @@ pattern_search (struct file *file, int archive,
|
|||||||
}
|
}
|
||||||
|
|
||||||
done:
|
done:
|
||||||
free_idep_chain (deps);
|
|
||||||
free (tryrules);
|
free (tryrules);
|
||||||
|
free (deplist);
|
||||||
|
|
||||||
return rule != 0;
|
return rule != 0;
|
||||||
}
|
}
|
||||||
|
5
job.c
5
job.c
@ -967,8 +967,9 @@ start_job_command (struct child *child)
|
|||||||
#if !defined(_AMIGA) && !defined(WINDOWS32)
|
#if !defined(_AMIGA) && !defined(WINDOWS32)
|
||||||
static int bad_stdin = -1;
|
static int bad_stdin = -1;
|
||||||
#endif
|
#endif
|
||||||
register char *p;
|
char *p;
|
||||||
int flags;
|
/* Must be volatile to silence bogus GCC warning about longjmp/vfork. */
|
||||||
|
volatile int flags;
|
||||||
#ifdef VMS
|
#ifdef VMS
|
||||||
char *argv;
|
char *argv;
|
||||||
#else
|
#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_variable_data_base (void);
|
||||||
void print_dir_data_base (void);
|
void print_dir_data_base (void);
|
||||||
void print_rule_data_base (void);
|
void print_rule_data_base (void);
|
||||||
void print_file_data_base (void);
|
|
||||||
void print_vpath_data_base (void);
|
void print_vpath_data_base (void);
|
||||||
|
|
||||||
void verify_file_data_base (void);
|
void verify_file_data_base (void);
|
||||||
@ -2192,7 +2191,7 @@ main (int argc, char **argv, char **envp)
|
|||||||
{
|
{
|
||||||
struct nameseq *ns;
|
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)
|
if (ns)
|
||||||
{
|
{
|
||||||
/* .DEFAULT_GOAL should contain one target. */
|
/* .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"));
|
fatal (NILF, _("virtual memory exhausted"));
|
||||||
#else
|
#else
|
||||||
result = xmalloc (length + 1);
|
result = xmalloc (length + 1);
|
||||||
strncpy (result, str, length);
|
if (length > 0)
|
||||||
|
strncpy (result, str, length);
|
||||||
result[length] = '\0';
|
result[length] = '\0';
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@ -524,8 +525,7 @@ find_next_token (const char **ptr, unsigned int *lengthptr)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Copy a chain of `struct dep', making a new chain
|
/* Copy a chain of `struct dep'. For 2nd expansion deps, dup the name. */
|
||||||
with the same contents as the old one. */
|
|
||||||
|
|
||||||
struct dep *
|
struct dep *
|
||||||
copy_dep_chain (const struct dep *d)
|
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));
|
struct dep *c = xmalloc (sizeof (struct dep));
|
||||||
memcpy (c, d, sizeof (struct dep));
|
memcpy (c, d, sizeof (struct dep));
|
||||||
|
|
||||||
|
if (c->need_2nd_expansion)
|
||||||
|
c->name = xstrdup (c->name);
|
||||||
|
|
||||||
c->next = 0;
|
c->next = 0;
|
||||||
if (firstnew == 0)
|
if (firstnew == 0)
|
||||||
firstnew = lastnew = c;
|
firstnew = lastnew = c;
|
||||||
|
301
read.c
301
read.c
@ -1,6 +1,6 @@
|
|||||||
/* Reading and parsing of makefiles for GNU Make.
|
/* Reading and parsing of makefiles for GNU Make.
|
||||||
Copyright (C) 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997,
|
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.
|
Foundation, Inc.
|
||||||
This file is part of GNU Make.
|
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);
|
struct ebuffer *ebuf);
|
||||||
static int conditional_line (char *line, int len, const struct floc *flocp);
|
static int conditional_line (char *line, int len, const struct floc *flocp);
|
||||||
static void record_files (struct nameseq *filenames, const char *pattern,
|
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 cmds_started, char *commands,
|
||||||
unsigned int commands_idx, int two_colon,
|
unsigned int commands_idx, int two_colon,
|
||||||
const struct floc *flocp);
|
const struct floc *flocp);
|
||||||
@ -549,7 +549,7 @@ eval (struct ebuffer *ebuf, int set_default)
|
|||||||
int ignoring = 0, in_ignored_define = 0;
|
int ignoring = 0, in_ignored_define = 0;
|
||||||
int no_targets = 0; /* Set when reading a rule without targets. */
|
int no_targets = 0; /* Set when reading a rule without targets. */
|
||||||
struct nameseq *filenames = 0;
|
struct nameseq *filenames = 0;
|
||||||
struct dep *deps = 0;
|
char *depstr = 0;
|
||||||
long nlines = 0;
|
long nlines = 0;
|
||||||
int two_colon = 0;
|
int two_colon = 0;
|
||||||
const char *pattern = 0;
|
const char *pattern = 0;
|
||||||
@ -563,7 +563,7 @@ eval (struct ebuffer *ebuf, int set_default)
|
|||||||
if (filenames != 0) \
|
if (filenames != 0) \
|
||||||
{ \
|
{ \
|
||||||
fi.lineno = tgts_started; \
|
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, \
|
cmds_started, commands, commands_idx, two_colon, \
|
||||||
&fi); \
|
&fi); \
|
||||||
} \
|
} \
|
||||||
@ -834,8 +834,7 @@ eval (struct ebuffer *ebuf, int set_default)
|
|||||||
|
|
||||||
/* Parse the list of file names. */
|
/* Parse the list of file names. */
|
||||||
p2 = p;
|
p2 = p;
|
||||||
files = parse_file_seq (&p2, sizeof (struct nameseq), '\0',
|
files = PARSE_FILE_SEQ (&p2, struct nameseq, '\0', NULL, 0);
|
||||||
NULL, 0);
|
|
||||||
free (p);
|
free (p);
|
||||||
|
|
||||||
/* Save the state of conditionals and start
|
/* 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
|
/* Make the colon the end-of-string so we know where to stop
|
||||||
looking for targets. */
|
looking for targets. */
|
||||||
*colonp = '\0';
|
*colonp = '\0';
|
||||||
filenames = parse_file_seq (&p2, sizeof (struct nameseq), '\0',
|
filenames = PARSE_FILE_SEQ (&p2, struct nameseq, '\0', NULL, 0);
|
||||||
NULL, 0);
|
|
||||||
*p2 = ':';
|
*p2 = ':';
|
||||||
|
|
||||||
if (!filenames)
|
if (!filenames)
|
||||||
@ -1099,8 +1097,8 @@ eval (struct ebuffer *ebuf, int set_default)
|
|||||||
p = strchr (p2, ':');
|
p = strchr (p2, ':');
|
||||||
while (p != 0 && p[-1] == '\\')
|
while (p != 0 && p[-1] == '\\')
|
||||||
{
|
{
|
||||||
register char *q = &p[-1];
|
char *q = &p[-1];
|
||||||
register int backslash = 0;
|
int backslash = 0;
|
||||||
while (*q-- == '\\')
|
while (*q-- == '\\')
|
||||||
backslash = !backslash;
|
backslash = !backslash;
|
||||||
if (backslash)
|
if (backslash)
|
||||||
@ -1143,8 +1141,8 @@ eval (struct ebuffer *ebuf, int set_default)
|
|||||||
if (p != 0)
|
if (p != 0)
|
||||||
{
|
{
|
||||||
struct nameseq *target;
|
struct nameseq *target;
|
||||||
target = parse_file_seq (&p2, sizeof (struct nameseq), ':',
|
target = PARSE_FILE_SEQ (&p2, struct nameseq, ':', NULL,
|
||||||
NULL, PARSEFS_NOGLOB|PARSEFS_NOCACHE);
|
PARSEFS_NOGLOB|PARSEFS_NOCACHE);
|
||||||
++p2;
|
++p2;
|
||||||
if (target == 0)
|
if (target == 0)
|
||||||
fatal (fstart, _("missing target pattern"));
|
fatal (fstart, _("missing target pattern"));
|
||||||
@ -1164,14 +1162,11 @@ eval (struct ebuffer *ebuf, int set_default)
|
|||||||
end = beg + strlen (beg) - 1;
|
end = beg + strlen (beg) - 1;
|
||||||
strip_whitespace (&beg, &end);
|
strip_whitespace (&beg, &end);
|
||||||
|
|
||||||
|
/* Put all the prerequisites here; they'll be parsed later. */
|
||||||
if (beg <= end && *beg != '\0')
|
if (beg <= end && *beg != '\0')
|
||||||
{
|
depstr = xstrndup (beg, end - beg + 1);
|
||||||
/* Put all the prerequisites here; they'll be parsed later. */
|
|
||||||
deps = alloc_dep ();
|
|
||||||
deps->name = strcache_add_len (beg, end - beg + 1);
|
|
||||||
}
|
|
||||||
else
|
else
|
||||||
deps = 0;
|
depstr = 0;
|
||||||
|
|
||||||
commands_idx = 0;
|
commands_idx = 0;
|
||||||
if (cmdleft != 0)
|
if (cmdleft != 0)
|
||||||
@ -1870,16 +1865,15 @@ record_target_var (struct nameseq *filenames, char *defn,
|
|||||||
|
|
||||||
static void
|
static void
|
||||||
record_files (struct nameseq *filenames, const char *pattern,
|
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 cmds_started, char *commands,
|
||||||
unsigned int commands_idx, int two_colon,
|
unsigned int commands_idx, int two_colon,
|
||||||
const struct floc *flocp)
|
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 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
|
/* 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
|
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)
|
if (snapped_deps)
|
||||||
fatal (flocp, _("prerequisites cannot be defined in recipes"));
|
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)
|
if (commands_idx > 0)
|
||||||
{
|
{
|
||||||
cmds = xmalloc (sizeof (struct commands));
|
cmds = xmalloc (sizeof (struct commands));
|
||||||
@ -1897,78 +1896,106 @@ record_files (struct nameseq *filenames, const char *pattern,
|
|||||||
cmds->command_lines = 0;
|
cmds->command_lines = 0;
|
||||||
}
|
}
|
||||||
else
|
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 file *f;
|
||||||
struct dep *this = 0;
|
struct dep *this = 0;
|
||||||
const char *implicit_percent;
|
|
||||||
|
|
||||||
nextf = filenames->next;
|
|
||||||
free (filenames);
|
free (filenames);
|
||||||
|
|
||||||
/* Check for special targets. Do it here instead of, say, snap_deps()
|
/* Check for special targets. Do it here instead of, say, snap_deps()
|
||||||
so that we can immediately use the value. */
|
so that we can immediately use the value. */
|
||||||
|
|
||||||
if (streq (name, ".POSIX"))
|
if (streq (name, ".POSIX"))
|
||||||
posix_pedantic = 1;
|
posix_pedantic = 1;
|
||||||
else if (streq (name, ".SECONDEXPANSION"))
|
else if (streq (name, ".SECONDEXPANSION"))
|
||||||
second_expansion = 1;
|
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:
|
/* 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. */
|
make sure the pattern matches this target name. */
|
||||||
if (pattern && !pattern_matches (pattern, pattern_percent, name))
|
if (pattern && !pattern_matches (pattern, pattern_percent, name))
|
||||||
error (flocp, _("target `%s' doesn't match the target pattern"), name);
|
error (flocp, _("target `%s' doesn't match the target pattern"), name);
|
||||||
else if (deps)
|
else if (deps)
|
||||||
{
|
/* If there are multiple targets, copy the chain DEPS for all but the
|
||||||
/* If there are multiple filenames, copy the chain DEPS for all but
|
last one. It is not safe for the same deps to go in more than one
|
||||||
the last one. It is not safe for the same deps to go in more
|
place in the database. */
|
||||||
than one place in the database. */
|
this = nextf != 0 ? copy_dep_chain (deps) : deps;
|
||||||
this = nextf != 0 ? copy_dep_chain (deps) : deps;
|
|
||||||
this->need_2nd_expansion = (second_expansion
|
|
||||||
&& strchr (this->name, '$'));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
/* Find or create an entry in the file database for this target. */
|
||||||
if (!two_colon)
|
if (!two_colon)
|
||||||
{
|
{
|
||||||
/* Single-colon. Combine these dependencies
|
/* Single-colon. Combine this rule with the file's existing record,
|
||||||
with others in file's existing record, if any. */
|
if any. */
|
||||||
f = enter_file (strcache_add (name));
|
f = enter_file (strcache_add (name));
|
||||||
|
|
||||||
if (f->double_colon)
|
if (f->double_colon)
|
||||||
fatal (flocp,
|
fatal (flocp,
|
||||||
_("target file `%s' has both : and :: entries"), f->name);
|
_("target file `%s' has both : and :: entries"), f->name);
|
||||||
@ -1993,8 +2020,6 @@ record_files (struct nameseq *filenames, const char *pattern,
|
|||||||
f->name);
|
f->name);
|
||||||
}
|
}
|
||||||
|
|
||||||
f->is_target = 1;
|
|
||||||
|
|
||||||
/* Defining .DEFAULT with no deps or cmds clears it. */
|
/* Defining .DEFAULT with no deps or cmds clears it. */
|
||||||
if (f == default_file && this == 0 && cmds == 0)
|
if (f == default_file && this == 0 && cmds == 0)
|
||||||
f->cmds = 0;
|
f->cmds = 0;
|
||||||
@ -2008,71 +2033,18 @@ record_files (struct nameseq *filenames, const char *pattern,
|
|||||||
free_dep_chain (f->deps);
|
free_dep_chain (f->deps);
|
||||||
f->deps = 0;
|
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
|
else
|
||||||
{
|
{
|
||||||
/* Double-colon. Make a new record even if there already is one. */
|
/* Double-colon. Make a new record even if there already is one. */
|
||||||
f = lookup_file (name);
|
f = lookup_file (name);
|
||||||
|
|
||||||
/* Check for both : and :: rules. Check is_target so
|
/* Check for both : and :: rules. Check is_target so we don't lose
|
||||||
we don't lose on default suffix rules or makefiles. */
|
on default suffix rules or makefiles. */
|
||||||
if (f != 0 && f->is_target && !f->double_colon)
|
if (f != 0 && f->is_target && !f->double_colon)
|
||||||
fatal (flocp,
|
fatal (flocp,
|
||||||
_("target file `%s' has both : and :: entries"), f->name);
|
_("target file `%s' has both : and :: entries"), f->name);
|
||||||
|
|
||||||
f = enter_file (strcache_add (name));
|
f = enter_file (strcache_add (name));
|
||||||
/* If there was an existing entry and it was a double-colon entry,
|
/* 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
|
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
|
/* This is the first entry for this name, so we must set its
|
||||||
double_colon pointer to itself. */
|
double_colon pointer to itself. */
|
||||||
f->double_colon = f;
|
f->double_colon = f;
|
||||||
f->is_target = 1;
|
|
||||||
f->deps = this;
|
|
||||||
f->cmds = cmds;
|
f->cmds = cmds;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
f->is_target = 1;
|
||||||
|
|
||||||
/* If this is a static pattern rule, set the stem to the part of its
|
/* 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
|
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)
|
if (pattern)
|
||||||
{
|
{
|
||||||
static const char *percent = "%";
|
static const char *percent = "%";
|
||||||
@ -2099,20 +2072,54 @@ record_files (struct nameseq *filenames, const char *pattern,
|
|||||||
f->stem = strcache_add_len (buffer, o - buffer);
|
f->stem = strcache_add_len (buffer, o - buffer);
|
||||||
if (this)
|
if (this)
|
||||||
{
|
{
|
||||||
this->staticpattern = 1;
|
if (! this->need_2nd_expansion)
|
||||||
this->stem = f->stem;
|
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;
|
name = f->name;
|
||||||
}
|
|
||||||
|
|
||||||
if (implicit)
|
/* All done! Set up for the next one. */
|
||||||
{
|
if (nextf == 0)
|
||||||
if (deps)
|
break;
|
||||||
deps->need_2nd_expansion = second_expansion;
|
|
||||||
create_pattern_rule (targets, target_percents, target_idx,
|
filenames = nextf;
|
||||||
two_colon, deps, cmds, 1);
|
|
||||||
|
/* 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;
|
const char *p = *string;
|
||||||
char *new = 0;
|
char *new = 0;
|
||||||
int slen;
|
int slen = 0;
|
||||||
|
|
||||||
/* If the first char is a % return now. This lets us avoid extra tests
|
/* If the first char is a % return now. This lets us avoid extra tests
|
||||||
inside the loop. */
|
inside the loop. */
|
||||||
@ -2330,11 +2337,11 @@ readstring (struct ebuffer *ebuf)
|
|||||||
while (1)
|
while (1)
|
||||||
{
|
{
|
||||||
int backslash = 0;
|
int backslash = 0;
|
||||||
char *bol = eol;
|
const char *bol = eol;
|
||||||
char *p;
|
const char *p;
|
||||||
|
|
||||||
/* Find the next newline. At EOS, stop. */
|
/* Find the next newline. At EOS, stop. */
|
||||||
eol = p = strchr (eol , '\n');
|
p = eol = strchr (eol , '\n');
|
||||||
if (!eol)
|
if (!eol)
|
||||||
{
|
{
|
||||||
ebuf->bufnext = ebuf->bufstart + ebuf->size + 1;
|
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)
|
PARSEFS_NOCACHE - Do not add filenames to the strcache (caller frees)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
struct nameseq *
|
void *
|
||||||
parse_file_seq (char **stringp, unsigned int size, int stopchar,
|
parse_file_seq (char **stringp, unsigned int size, int stopchar,
|
||||||
const char *prefix, int flags)
|
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)
|
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
|
#ifdef VMS
|
||||||
const char *p = strrchr (dep->name, ']');
|
const char *p = strrchr (dname, ']');
|
||||||
const char *p2;
|
const char *p2;
|
||||||
if (p == 0)
|
if (p == 0)
|
||||||
p = strrchr (dep->name, ':');
|
p = strrchr (dname, ':');
|
||||||
p2 = p != 0 ? strchr (dep->name, '%') : 0;
|
p2 = p != 0 ? strchr (dname, '%') : 0;
|
||||||
#else
|
#else
|
||||||
const char *p = strrchr (dep->name, '/');
|
const char *p = strrchr (dname, '/');
|
||||||
const char *p2 = p != 0 ? strchr (dep->name, '%') : 0;
|
const char *p2 = p != 0 ? strchr (dname, '%') : 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;
|
||||||
@ -115,15 +116,15 @@ count_implicit_rule_limits (void)
|
|||||||
{
|
{
|
||||||
/* 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. */
|
||||||
if (p == dep->name)
|
if (p == dname)
|
||||||
++p;
|
++p;
|
||||||
if (p - dep->name > namelen)
|
if (p - dname > namelen)
|
||||||
{
|
{
|
||||||
namelen = p - dep->name;
|
namelen = p - dname;
|
||||||
name = xrealloc (name, namelen + 1);
|
name = xrealloc (name, namelen + 1);
|
||||||
}
|
}
|
||||||
memcpy (name, dep->name, p - dep->name);
|
memcpy (name, dname, p - dname);
|
||||||
name[p - dep->name] = '\0';
|
name[p - dname] = '\0';
|
||||||
|
|
||||||
/* In the deps of an implicit rule the `changed' flag
|
/* In the deps of an implicit rule the `changed' flag
|
||||||
actually indicates that the dependency is in a
|
actually indicates that the dependency is in a
|
||||||
@ -376,8 +377,7 @@ install_pattern_rule (struct pspec *p, int terminal)
|
|||||||
++r->suffixes[0];
|
++r->suffixes[0];
|
||||||
|
|
||||||
ptr = p->dep;
|
ptr = p->dep;
|
||||||
r->deps = (struct dep *) parse_file_seq (&ptr, sizeof (struct dep), '\0',
|
r->deps = PARSE_FILE_SEQ (&ptr, struct dep, '\0', NULL, 0);
|
||||||
NULL, 0);
|
|
||||||
|
|
||||||
if (new_pattern_rule (r, 0))
|
if (new_pattern_rule (r, 0))
|
||||||
{
|
{
|
||||||
@ -481,7 +481,6 @@ static void /* Useful to call from gdb. */
|
|||||||
print_rule (struct rule *r)
|
print_rule (struct rule *r)
|
||||||
{
|
{
|
||||||
unsigned int i;
|
unsigned int i;
|
||||||
struct dep *d;
|
|
||||||
|
|
||||||
for (i = 0; i < r->num; ++i)
|
for (i = 0; i < r->num; ++i)
|
||||||
{
|
{
|
||||||
@ -491,9 +490,7 @@ print_rule (struct rule *r)
|
|||||||
if (r->terminal)
|
if (r->terminal)
|
||||||
putchar (':');
|
putchar (':');
|
||||||
|
|
||||||
for (d = r->deps; d != 0; d = d->next)
|
print_prereqs (r->deps);
|
||||||
printf (" %s", dep_name (d));
|
|
||||||
putchar ('\n');
|
|
||||||
|
|
||||||
if (r->cmds != 0)
|
if (r->cmds != 0)
|
||||||
print_commands (r->cmds);
|
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>
|
2009-06-14 Paul Smith <psmith@gnu.org>
|
||||||
|
|
||||||
* scripts/features/vpath: Verify we don't get bogus circular
|
* 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"
|
# -*-perl-*-
|
||||||
."echoing. It tests that when a command line starts with \n"
|
$description = "The following test creates a makefile to test command
|
||||||
."a '\@', the echoing of that line is suppressed. It also \n"
|
echoing. It tests that when a command line starts with
|
||||||
."tests the -n option which tells make to ONLY echo the \n"
|
a '\@', the echoing of that line is suppressed. It also
|
||||||
."commands and no execution happens. In this case, even \n"
|
tests the -n option which tells make to ONLY echo the
|
||||||
."the commands with '\@' are printed. Lastly, it tests the \n"
|
commands and no execution happens. In this case, even
|
||||||
."-s flag which tells make to prevent all echoing, as if \n"
|
the commands with '\@' are printed. Lastly, it tests the
|
||||||
."all commands started with a '\@'.";
|
-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"
|
$details = "This test is similar to the 'clean' test except that a '\@' has
|
||||||
."been placed in front of the delete command line. Four tests \n"
|
been placed in front of the delete command line. Four tests
|
||||||
."are run here. First, make is run normally and the first echo\n"
|
are run here. First, make is run normally and the first echo
|
||||||
."command should be executed. In this case there is no '\@' so \n"
|
command should be executed. In this case there is no '\@' so
|
||||||
."we should expect make to display the command AND display the \n"
|
we should expect make to display the command AND display the
|
||||||
."echoed message. Secondly, make is run with the clean target, \n"
|
echoed message. Secondly, make is run with the clean target,
|
||||||
."but since there is a '\@' at the beginning of the command, we\n"
|
but since there is a '\@' at the beginning of the command, we
|
||||||
."expect no output; just the deletion of a file which we check \n"
|
expect no output; just the deletion of a file which we check
|
||||||
."for. Third, we give the clean target again except this time\n"
|
for. Third, we give the clean target again except this time
|
||||||
."we give make the -n option. We now expect the command to be \n"
|
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 \n"
|
displayed but not to be executed. In this case we need only
|
||||||
."to check the output since an error message would be displayed\n"
|
to check the output since an error message would be displayed
|
||||||
."if it actually tried to run the delete command again and the \n"
|
if it actually tried to run the delete command again and the
|
||||||
."file didn't exist. Lastly, we run the first test again with \n"
|
file didn't exist. Lastly, we run the first test again with
|
||||||
."the -s option and check that make did not echo the echo \n"
|
the -s option and check that make did not echo the echo
|
||||||
."command before printing the message.";
|
command before printing the message.\n";
|
||||||
|
|
||||||
$example = "EXAMPLE_FILE";
|
$example = "EXAMPLE_FILE";
|
||||||
|
|
||||||
open(MAKEFILE,"> $makefile");
|
touch($example);
|
||||||
|
|
||||||
# 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);
|
|
||||||
|
|
||||||
# TEST #1
|
# TEST #1
|
||||||
# -------
|
# -------
|
||||||
|
|
||||||
&run_make_with_options($makefile,"",&get_logfile,0);
|
run_make_test("
|
||||||
$answer = "echo This makefile did not clean the dir... good\n"
|
all:
|
||||||
."This makefile did not clean the dir... good\n";
|
\techo This makefile did not clean the dir... good
|
||||||
&compare_output($answer,&get_logfile(1));
|
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
|
# TEST #2
|
||||||
# -------
|
# -------
|
||||||
|
|
||||||
&run_make_with_options($makefile,"clean",&get_logfile,0);
|
run_make_test(undef, 'clean', '');
|
||||||
if (-f $example) {
|
if (-f $example) {
|
||||||
$test_passed = 0;
|
$test_passed = 0;
|
||||||
|
unlink($example);
|
||||||
}
|
}
|
||||||
&compare_output('',&get_logfile(1));
|
|
||||||
|
|
||||||
# TEST #3
|
# TEST #3
|
||||||
# -------
|
# -------
|
||||||
|
|
||||||
&run_make_with_options($makefile,"-n clean",&get_logfile,0);
|
run_make_test(undef, '-n clean', "$delete_command $example\n");
|
||||||
$answer = "$delete_command $example\n";
|
|
||||||
&compare_output($answer,&get_logfile(1));
|
|
||||||
|
|
||||||
|
|
||||||
# TEST #4
|
# TEST #4
|
||||||
# -------
|
# -------
|
||||||
|
|
||||||
&run_make_with_options($makefile,"-s",&get_logfile,0);
|
run_make_test(undef, '-s', "This makefile did not clean the dir... good\n");
|
||||||
$answer = "This makefile did not clean the dir... good\n";
|
|
||||||
&compare_output($answer,&get_logfile(1));
|
|
||||||
|
|
||||||
|
|
||||||
1;
|
1;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -190,5 +190,23 @@ dep: ; @echo $@
|
|||||||
'', "dep\nx.t1\nx.t2\nx\nfinal\n");
|
'', "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.
|
# This tells the test driver that the perl test script executed properly.
|
||||||
1;
|
1;
|
||||||
|
@ -24,9 +24,9 @@ run_make_test(undef, 'SE=1', "three\nfour\nbariz\nfoo\$bar : baraz bariz");
|
|||||||
|
|
||||||
# TEST #1: automatic variables.
|
# TEST #1: automatic variables.
|
||||||
#
|
#
|
||||||
run_make_test('
|
run_make_test(q!
|
||||||
.SECONDEXPANSION:
|
.SECONDEXPANSION:
|
||||||
.DEFAULT: ; @echo $@
|
.DEFAULT: ; @echo '$@'
|
||||||
|
|
||||||
foo: bar baz
|
foo: bar baz
|
||||||
|
|
||||||
@ -39,7 +39,7 @@ foo: $$@.1 \
|
|||||||
$$|.5 \
|
$$|.5 \
|
||||||
$$*.6
|
$$*.6
|
||||||
|
|
||||||
',
|
!,
|
||||||
'',
|
'',
|
||||||
'bar
|
'bar
|
||||||
baz
|
baz
|
||||||
@ -60,17 +60,16 @@ buz.5
|
|||||||
|
|
||||||
# Test #2: target/pattern -specific variables.
|
# Test #2: target/pattern -specific variables.
|
||||||
#
|
#
|
||||||
run_make_test('
|
run_make_test(q!
|
||||||
.SECONDEXPANSION:
|
.SECONDEXPANSION:
|
||||||
.DEFAULT: ; @echo $@
|
.DEFAULT: ; @echo '$@'
|
||||||
|
|
||||||
foo.x: $$a $$b
|
foo.x: $$a $$b
|
||||||
|
|
||||||
foo.x: a := bar
|
foo.x: a := bar
|
||||||
|
|
||||||
%.x: b := baz
|
%.x: b := baz
|
||||||
|
!,
|
||||||
',
|
|
||||||
'',
|
'',
|
||||||
'bar
|
'bar
|
||||||
baz
|
baz
|
||||||
@ -79,9 +78,9 @@ baz
|
|||||||
|
|
||||||
# Test #3: order of prerequisites.
|
# Test #3: order of prerequisites.
|
||||||
#
|
#
|
||||||
run_make_test('
|
run_make_test(q!
|
||||||
.SECONDEXPANSION:
|
.SECONDEXPANSION:
|
||||||
.DEFAULT: ; @echo $@
|
.DEFAULT: ; @echo '$@'
|
||||||
|
|
||||||
all: foo bar baz
|
all: foo bar baz
|
||||||
|
|
||||||
@ -99,7 +98,7 @@ bar: bar.3
|
|||||||
baz: baz.1
|
baz: baz.1
|
||||||
baz: baz.2
|
baz: baz.2
|
||||||
baz: ; @:
|
baz: ; @:
|
||||||
',
|
!,
|
||||||
'',
|
'',
|
||||||
'foo.1
|
'foo.1
|
||||||
foo.2
|
foo.2
|
||||||
@ -112,22 +111,23 @@ baz.2
|
|||||||
');
|
');
|
||||||
|
|
||||||
# TEST #4: eval in a context where there is no reading_file
|
# TEST #4: eval in a context where there is no reading_file
|
||||||
run_make_test('
|
run_make_test(q!
|
||||||
.SECONDEXPANSION:
|
.SECONDEXPANSION:
|
||||||
all : $$(eval $$(info test))
|
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
|
# TEST #5: (NEGATIVE) catch eval in a prereq list trying to create new
|
||||||
# target/prereq relationships.
|
# target/prereq relationships.
|
||||||
|
|
||||||
run_make_test('
|
run_make_test(q!
|
||||||
.SECONDEXPANSION:
|
.SECONDEXPANSION:
|
||||||
proj1.exe : proj1.o $$(eval $$(test))
|
proj1.exe : proj1.o $$(eval $$(test))
|
||||||
define test
|
define test
|
||||||
proj1.o : proj1.c
|
proj1.o : proj1.c
|
||||||
proj1.c: proj1.h
|
proj1.c: proj1.h
|
||||||
endef
|
endef
|
||||||
',
|
!,
|
||||||
'', "#MAKE#: *** prerequisites cannot be defined in recipes. Stop.\n", 512);
|
'', "#MAKE#: *** prerequisites cannot be defined in recipes. Stop.\n", 512);
|
||||||
|
|
||||||
# This tells the test driver that the perl test script executed properly.
|
# This tells the test driver that the perl test script executed properly.
|
||||||
|
@ -11,9 +11,9 @@ $dir =~ s,.*/([^/]+)$,../$1,;
|
|||||||
|
|
||||||
# Test #1: automatic variables.
|
# Test #1: automatic variables.
|
||||||
#
|
#
|
||||||
run_make_test('
|
run_make_test(q!
|
||||||
.SECONDEXPANSION:
|
.SECONDEXPANSION:
|
||||||
.DEFAULT: ; @echo $@
|
.DEFAULT: ; @echo '$@'
|
||||||
|
|
||||||
foo.a: bar baz
|
foo.a: bar baz
|
||||||
|
|
||||||
@ -37,9 +37,9 @@ foo.%: 1.$$@ \
|
|||||||
4.biz \
|
4.biz \
|
||||||
5.buz \
|
5.buz \
|
||||||
6.a:
|
6.a:
|
||||||
@echo $@
|
@echo '$@'
|
||||||
|
|
||||||
',
|
!,
|
||||||
'',
|
'',
|
||||||
'1.foo.a
|
'1.foo.a
|
||||||
2.bar
|
2.bar
|
||||||
@ -60,7 +60,7 @@ buz
|
|||||||
|
|
||||||
# Test #2: target/pattern -specific variables.
|
# Test #2: target/pattern -specific variables.
|
||||||
#
|
#
|
||||||
run_make_test('
|
run_make_test(q!
|
||||||
.SECONDEXPANSION:
|
.SECONDEXPANSION:
|
||||||
foo.x:
|
foo.x:
|
||||||
|
|
||||||
@ -71,20 +71,16 @@ foo.x: x_a := bar
|
|||||||
|
|
||||||
%.x: x_b := baz
|
%.x: x_b := baz
|
||||||
|
|
||||||
bar baz: ; @echo $@
|
bar baz: ; @echo '$@'
|
||||||
|
!,
|
||||||
',
|
'', "bar\nbaz\n");
|
||||||
'',
|
|
||||||
'bar
|
|
||||||
baz
|
|
||||||
');
|
|
||||||
|
|
||||||
|
|
||||||
# Test #3: order of prerequisites.
|
# Test #3: order of prerequisites.
|
||||||
#
|
#
|
||||||
run_make_test('
|
run_make_test(q!
|
||||||
.SECONDEXPANSION:
|
.SECONDEXPANSION:
|
||||||
.DEFAULT: ; @echo $@
|
.DEFAULT: ; @echo '$@'
|
||||||
|
|
||||||
all: foo bar baz
|
all: foo bar baz
|
||||||
|
|
||||||
@ -97,7 +93,7 @@ foo: foo.2
|
|||||||
|
|
||||||
foo: foo.3
|
foo: foo.3
|
||||||
|
|
||||||
foo.1: ; @echo $@
|
foo.1: ; @echo '$@'
|
||||||
|
|
||||||
|
|
||||||
# Subtest #2
|
# Subtest #2
|
||||||
@ -108,7 +104,7 @@ bar: bar.2
|
|||||||
|
|
||||||
bar: bar.3
|
bar: bar.3
|
||||||
|
|
||||||
bar.1: ; @echo $@
|
bar.1: ; @echo '$@'
|
||||||
|
|
||||||
|
|
||||||
# Subtest #3
|
# Subtest #3
|
||||||
@ -118,9 +114,8 @@ baz: baz.1
|
|||||||
baz: baz.2
|
baz: baz.2
|
||||||
|
|
||||||
%az: ; @:
|
%az: ; @:
|
||||||
|
!,
|
||||||
',
|
'',
|
||||||
'',
|
|
||||||
'foo.1
|
'foo.1
|
||||||
foo.2
|
foo.2
|
||||||
foo.3
|
foo.3
|
||||||
@ -134,20 +129,18 @@ baz.2
|
|||||||
|
|
||||||
# Test #4: stem splitting logic.
|
# Test #4: stem splitting logic.
|
||||||
#
|
#
|
||||||
run_make_test('
|
run_make_test(q!
|
||||||
.SECONDEXPANSION:
|
.SECONDEXPANSION:
|
||||||
$(dir)/tmp/bar.o:
|
$(dir)/tmp/bar.o:
|
||||||
|
|
||||||
$(dir)/tmp/foo/bar.c: ; @echo $@
|
$(dir)/tmp/foo/bar.c: ; @echo '$@'
|
||||||
$(dir)/tmp/bar/bar.c: ; @echo $@
|
$(dir)/tmp/bar/bar.c: ; @echo '$@'
|
||||||
foo.h: ; @echo $@
|
foo.h: ; @echo '$@'
|
||||||
|
|
||||||
%.o: $$(addsuffix /%.c,foo bar) foo.h
|
%.o: $$(addsuffix /%.c,foo bar) foo.h
|
||||||
@echo $@: {$<} $^
|
@echo '$@: {$<} $^'
|
||||||
|
!,
|
||||||
',
|
"dir=$dir", "$dir/tmp/foo/bar.c
|
||||||
"dir=$dir",
|
|
||||||
"$dir/tmp/foo/bar.c
|
|
||||||
$dir/tmp/bar/bar.c
|
$dir/tmp/bar/bar.c
|
||||||
foo.h
|
foo.h
|
||||||
$dir/tmp/bar.o: {$dir/tmp/foo/bar.c} $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.
|
# Test #5: stem splitting logic and order-only prerequisites.
|
||||||
#
|
#
|
||||||
run_make_test('
|
run_make_test(q!
|
||||||
.SECONDEXPANSION:
|
.SECONDEXPANSION:
|
||||||
$(dir)/tmp/foo.o: $(dir)/tmp/foo.c
|
$(dir)/tmp/foo.o: $(dir)/tmp/foo.c
|
||||||
$(dir)/tmp/foo.c: ; @echo $@
|
$(dir)/tmp/foo.c: ; @echo '$@'
|
||||||
bar.h: ; @echo $@
|
bar.h: ; @echo '$@'
|
||||||
|
|
||||||
%.o: %.c|bar.h
|
%.o: %.c|bar.h
|
||||||
@echo $@: {$<} {$|} $^
|
@echo '$@: {$<} {$|} $^'
|
||||||
|
|
||||||
',
|
!,
|
||||||
"dir=$dir",
|
"dir=$dir", "$dir/tmp/foo.c
|
||||||
"$dir/tmp/foo.c
|
|
||||||
bar.h
|
bar.h
|
||||||
$dir/tmp/foo.o: {$dir/tmp/foo.c} {bar.h} $dir/tmp/foo.c
|
$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.
|
# Test #6: lack of implicit prerequisites.
|
||||||
#
|
#
|
||||||
run_make_test('
|
run_make_test(q!
|
||||||
.SECONDEXPANSION:
|
.SECONDEXPANSION:
|
||||||
foo.o: foo.c
|
foo.o: foo.c
|
||||||
foo.c: ; @echo $@
|
foo.c: ; @echo '$@'
|
||||||
|
|
||||||
%.o:
|
%.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.
|
# Test #7: Test stem from the middle of the name.
|
||||||
#
|
#
|
||||||
run_make_test('
|
run_make_test(q!
|
||||||
.SECONDEXPANSION:
|
.SECONDEXPANSION:
|
||||||
foobarbaz:
|
foobarbaz:
|
||||||
|
|
||||||
foo%baz: % $$*.1
|
foo%baz: % $$*.1
|
||||||
@echo $*
|
@echo '$*'
|
||||||
|
|
||||||
bar bar.1:
|
bar bar.1:
|
||||||
@echo $@
|
@echo '$@'
|
||||||
|
!,
|
||||||
|
'', "bar\nbar.1\nbar\n");
|
||||||
|
|
||||||
',
|
|
||||||
'',
|
|
||||||
'bar
|
|
||||||
bar.1
|
|
||||||
bar
|
|
||||||
');
|
|
||||||
|
|
||||||
# Test #8: Make sure stem triple-expansion does not happen.
|
# Test #8: Make sure stem triple-expansion does not happen.
|
||||||
#
|
#
|
||||||
run_make_test('
|
run_make_test(q!
|
||||||
.SECONDEXPANSION:
|
.SECONDEXPANSION:
|
||||||
foo$$bar:
|
foo$$bar:
|
||||||
|
|
||||||
f%r: % $$*.1
|
f%r: % $$*.1
|
||||||
@echo \'$*\'
|
@echo '$*'
|
||||||
|
|
||||||
oo$$ba oo$$ba.1:
|
oo$$ba oo$$ba.1:
|
||||||
@echo \'$@\'
|
@echo '$@'
|
||||||
|
!,
|
||||||
',
|
'', 'oo$ba
|
||||||
'',
|
|
||||||
'oo$ba
|
|
||||||
oo$ba.1
|
oo$ba.1
|
||||||
oo$ba
|
oo$ba
|
||||||
');
|
');
|
||||||
|
@ -5,12 +5,11 @@ $details = "";
|
|||||||
|
|
||||||
# Test #1: automatic variables.
|
# Test #1: automatic variables.
|
||||||
#
|
#
|
||||||
run_make_test('
|
run_make_test(q!
|
||||||
.SECONDEXPANSION:
|
.SECONDEXPANSION:
|
||||||
.DEFAULT: ; @echo $@
|
.DEFAULT: ; @echo '$@'
|
||||||
|
|
||||||
foo.a foo.b: foo.%: bar.% baz.%
|
foo.a foo.b: foo.%: bar.% baz.%
|
||||||
|
|
||||||
foo.a foo.b: foo.%: biz.% | buz.%
|
foo.a foo.b: foo.%: biz.% | buz.%
|
||||||
|
|
||||||
foo.a foo.b: foo.%: $$@.1 \
|
foo.a foo.b: foo.%: $$@.1 \
|
||||||
@ -19,10 +18,8 @@ foo.a foo.b: foo.%: $$@.1 \
|
|||||||
$$(addsuffix .4,$$+) \
|
$$(addsuffix .4,$$+) \
|
||||||
$$|.5 \
|
$$|.5 \
|
||||||
$$*.6
|
$$*.6
|
||||||
|
!,
|
||||||
',
|
'', 'bar.a
|
||||||
'',
|
|
||||||
'bar.a
|
|
||||||
baz.a
|
baz.a
|
||||||
biz.a
|
biz.a
|
||||||
buz.a
|
buz.a
|
||||||
@ -41,61 +38,45 @@ a.6
|
|||||||
|
|
||||||
# Test #2: target/pattern -specific variables.
|
# Test #2: target/pattern -specific variables.
|
||||||
#
|
#
|
||||||
run_make_test('
|
run_make_test(q!
|
||||||
.SECONDEXPANSION:
|
.SECONDEXPANSION:
|
||||||
.DEFAULT: ; @echo $@
|
.DEFAULT: ; @echo '$@'
|
||||||
|
|
||||||
foo.x foo.y: foo.%: $$(%_a) $$($$*_b)
|
foo.x foo.y: foo.%: $$(%_a) $$($$*_b)
|
||||||
|
|
||||||
foo.x: x_a := bar
|
foo.x: x_a := bar
|
||||||
|
|
||||||
%.x: x_b := baz
|
%.x: x_b := baz
|
||||||
|
!,
|
||||||
|
'', "bar\nbaz\n");
|
||||||
',
|
|
||||||
'',
|
|
||||||
'bar
|
|
||||||
baz
|
|
||||||
');
|
|
||||||
|
|
||||||
|
|
||||||
# Test #3: order of prerequisites.
|
# Test #3: order of prerequisites.
|
||||||
#
|
#
|
||||||
run_make_test('
|
run_make_test(q!
|
||||||
.SECONDEXPANSION:
|
.SECONDEXPANSION:
|
||||||
.DEFAULT: ; @echo $@
|
.DEFAULT: ; @echo '$@'
|
||||||
|
|
||||||
all: foo.a bar.a baz.a
|
all: foo.a bar.a baz.a
|
||||||
|
|
||||||
# Subtest #1
|
# Subtest #1
|
||||||
#
|
|
||||||
foo.a foo.b: foo.%: foo.%.1; @:
|
foo.a foo.b: foo.%: foo.%.1; @:
|
||||||
|
|
||||||
foo.a foo.b: foo.%: foo.%.2
|
foo.a foo.b: foo.%: foo.%.2
|
||||||
|
|
||||||
foo.a foo.b: foo.%: foo.%.3
|
foo.a foo.b: foo.%: foo.%.3
|
||||||
|
|
||||||
|
|
||||||
# Subtest #2
|
# Subtest #2
|
||||||
#
|
|
||||||
bar.a bar.b: bar.%: bar.%.2
|
bar.a bar.b: bar.%: bar.%.2
|
||||||
|
|
||||||
bar.a bar.b: bar.%: bar.%.1; @:
|
bar.a bar.b: bar.%: bar.%.1; @:
|
||||||
|
|
||||||
bar.a bar.b: bar.%: bar.%.3
|
bar.a bar.b: bar.%: bar.%.3
|
||||||
|
|
||||||
|
|
||||||
# Subtest #3
|
# Subtest #3
|
||||||
#
|
|
||||||
baz.a baz.b: baz.%: baz.%.1
|
baz.a baz.b: baz.%: baz.%.1
|
||||||
|
|
||||||
baz.a baz.b: baz.%: baz.%.2
|
baz.a baz.b: baz.%: baz.%.2
|
||||||
|
|
||||||
baz.a baz.b: ; @:
|
baz.a baz.b: ; @:
|
||||||
|
!,
|
||||||
',
|
'', 'foo.a.1
|
||||||
'',
|
|
||||||
'foo.a.1
|
|
||||||
foo.a.2
|
foo.a.2
|
||||||
foo.a.3
|
foo.a.3
|
||||||
bar.a.1
|
bar.a.1
|
||||||
@ -108,17 +89,15 @@ baz.a.2
|
|||||||
|
|
||||||
# Test #4: Make sure stem triple-expansion does not happen.
|
# Test #4: Make sure stem triple-expansion does not happen.
|
||||||
#
|
#
|
||||||
run_make_test('
|
run_make_test(q!
|
||||||
.SECONDEXPANSION:
|
.SECONDEXPANSION:
|
||||||
foo$$bar: f%r: % $$*.1
|
foo$$bar: f%r: % $$*.1
|
||||||
@echo \'$*\'
|
@echo '$*'
|
||||||
|
|
||||||
oo$$ba oo$$ba.1:
|
oo$$ba oo$$ba.1:
|
||||||
@echo \'$@\'
|
@echo '$@'
|
||||||
|
!,
|
||||||
',
|
'', 'oo$ba
|
||||||
'',
|
|
||||||
'oo$ba
|
|
||||||
oo$ba.1
|
oo$ba.1
|
||||||
oo$ba
|
oo$ba
|
||||||
');
|
');
|
||||||
|
Loading…
Reference in New Issue
Block a user