mirror of
https://github.com/mirror/make.git
synced 2025-01-27 12:51:07 +08:00
[SV 61042] Enhance logging of implicit rule search
Logging of implicit rule search gives limited information as to why a given implicit rule was rejected, and if no implicit rule is found we get the confusing "No rule to make target" result when the real issue is that some prerequisite of some implicit rule could not be built. Enhance logging around implicit rule search as follows: 1. The messages which refer to a rule print a description (the targets and prerequisites) of the rule. 2. A new message tells when a rule is rejected, along with the reason. 3. The 'Looking for an implicit rule...' message is printed for every prerequisite, not just the top-level target. 4. "Trying harder" message is printed, when intermediate prerequisites are going to be searched. 5. The 'No rule found...' and 'Found implicit rule...' messages are printed for every prerequisite, not just the top-level target. 6. "Ought to exist...", "Found..." or "Not found..." message is printed for each prerequisite. * src/rule.h (struct rule): Remember the definition of the rule. * src/rule.c (get_rule_defn): Compute the definition of a rule. (install_pattern_rule): Initialize the definition to empty. (create_pattern_rule): Ditto. (freerule): Free the definition. (print_rule): Use the definition when printing rules. * src/remake.c (update_file_1): Push debug output down into try_implicit_rule(). * src/implicit.c (try_implicit_rule): Add debugging (pattern_search): Show the rule definition in various debug output. Add new debug messages for implicit rule search. Additional changes by Paul Smith <psmith@gnu.org>: Since we usually don't need the rule definition, defer computing it until we do. * bootstrap.conf: Include the mempcpy Gnulib module. * src/makeint.h (mempcpy): Declare mempcpy if not available. * src/misc.c (mempcpy): Define mempcpy if not available. * src/config.h-vms.template: Don't set HAVE_MEMPCPY. * src/config.h.W32.template: Ditto. * src/rule.h (get_rule_defn): Return the definition of a rule. * src/rule.c (get_rule_defn): If we don't have a definition compute it; either way return it. * src/implicit.c (pattern_search): Rework the handling of explicit prerequisites to pattern rules to be more clear. There is no change in behavior.
This commit is contained in:
parent
f5af979357
commit
f8f9d371ff
@ -49,5 +49,6 @@ fdl
|
||||
findprog-in
|
||||
getloadavg
|
||||
host-cpu-c-abi
|
||||
mempcpy
|
||||
strerror
|
||||
make-glob"
|
||||
|
@ -324,6 +324,9 @@ this program. If not, see <http://www.gnu.org/licenses/>. */
|
||||
/* Define to 1 if you have the <memory.h> header file. */
|
||||
/* #undef HAVE_MEMORY_H */
|
||||
|
||||
/* Define to 1 if you have the `mempcpy' function. */
|
||||
/* #undef HAVE_MEMPCPY */
|
||||
|
||||
/* Define to 1 if you have the <ndir.h> header file. */
|
||||
/* #undef HAVE_NDIR_H */
|
||||
|
||||
|
@ -177,6 +177,9 @@ this program. If not, see <http://www.gnu.org/licenses/>. */
|
||||
/* Define to 1 if you have the <memory.h> header file. */
|
||||
#define HAVE_MEMORY_H 1
|
||||
|
||||
/* Define to 1 if you have the `mempcpy' function. */
|
||||
/* #undef HAVE_MEMPCPY */
|
||||
|
||||
/* Define to 1 if you have the 'mkstemp' function. */
|
||||
/* #undef HAVE_MKSTEMP */
|
||||
|
||||
|
106
src/implicit.c
106
src/implicit.c
@ -54,6 +54,9 @@ try_implicit_rule (struct file *file, unsigned int depth)
|
||||
_("Looking for archive-member implicit rule for '%s'.\n"));
|
||||
if (pattern_search (file, 1, depth, 0))
|
||||
return 1;
|
||||
DBS (DB_IMPLICIT,
|
||||
(_("No archive-member implicit rule found for '%s'.\n"),
|
||||
file->name));
|
||||
}
|
||||
#endif
|
||||
|
||||
@ -309,7 +312,9 @@ pattern_search (struct file *file, int archive,
|
||||
don't use it here. */
|
||||
if (rule->in_use)
|
||||
{
|
||||
DBS (DB_IMPLICIT, (_("Avoiding implicit rule recursion.\n")));
|
||||
DBS (DB_IMPLICIT,
|
||||
(_("Avoiding implicit rule recursion for rule '%s'.\n"),
|
||||
get_rule_defn (rule)));
|
||||
continue;
|
||||
}
|
||||
|
||||
@ -432,6 +437,8 @@ pattern_search (struct file *file, int archive,
|
||||
for (intermed_ok = 0; intermed_ok < 2; ++intermed_ok)
|
||||
{
|
||||
pat = deplist;
|
||||
if (intermed_ok)
|
||||
DBS (DB_IMPLICIT, (_("Trying harder.\n")));
|
||||
|
||||
/* Try each pattern rule till we find one that applies. If it does,
|
||||
expand its dependencies (as substituted) and chain them in DEPS. */
|
||||
@ -480,6 +487,10 @@ pattern_search (struct file *file, int archive,
|
||||
}
|
||||
}
|
||||
|
||||
DBS (DB_IMPLICIT,
|
||||
(_("Trying pattern rule '%s' with stem '%.*s'.\n"),
|
||||
get_rule_defn (rule), (int) stemlen, stem));
|
||||
|
||||
if (stemlen + (check_lastslash ? pathlen : 0) > GET_PATH_MAX)
|
||||
{
|
||||
DBS (DB_IMPLICIT, (_("Stem too long: '%s%.*s'.\n"),
|
||||
@ -488,9 +499,6 @@ pattern_search (struct file *file, int archive,
|
||||
continue;
|
||||
}
|
||||
|
||||
DBS (DB_IMPLICIT, (_("Trying pattern rule with stem '%.*s'.\n"),
|
||||
(int) stemlen, stem));
|
||||
|
||||
if (!check_lastslash)
|
||||
{
|
||||
memcpy (stem_str, stem, stemlen);
|
||||
@ -712,9 +720,10 @@ pattern_search (struct file *file, int archive,
|
||||
/* Go through the nameseq and handle each as a prereq name. */
|
||||
for (d = dl; d != 0; d = d->next)
|
||||
{
|
||||
struct dep *expl_d;
|
||||
struct file *f;
|
||||
struct file *df;
|
||||
int is_rule = d->name == dep_name (dep);
|
||||
int explicit;
|
||||
int exists = -1;
|
||||
|
||||
if (file_impossible_p (d->name))
|
||||
{
|
||||
@ -723,9 +732,11 @@ pattern_search (struct file *file, int archive,
|
||||
second pass either since we know that will fail. */
|
||||
DBS (DB_IMPLICIT,
|
||||
(is_rule
|
||||
? _("Rejecting impossible rule prerequisite '%s'.\n")
|
||||
: _("Rejecting impossible implicit prerequisite '%s'.\n"),
|
||||
d->name));
|
||||
? _("Rejecting rule '%s' due to impossible rule"
|
||||
" prerequisite '%s'.\n")
|
||||
: _("Rejecting rule '%s' due to impossible implicit"
|
||||
" prerequisite '%s'.\n"),
|
||||
get_rule_defn (rule), d->name));
|
||||
tryrules[ri].rule = 0;
|
||||
|
||||
failed = 1;
|
||||
@ -742,38 +753,41 @@ pattern_search (struct file *file, int archive,
|
||||
? _("Trying rule prerequisite '%s'.\n")
|
||||
: _("Trying implicit prerequisite '%s'.\n"), d->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. */
|
||||
df = lookup_file (d->name);
|
||||
|
||||
for (expl_d = file->deps; expl_d != 0; expl_d = expl_d->next)
|
||||
if (streq (dep_name (expl_d), d->name))
|
||||
break;
|
||||
if (expl_d != 0)
|
||||
{
|
||||
(pat++)->name = d->name;
|
||||
continue;
|
||||
}
|
||||
|
||||
/* f->is_explicit is set when this file is mentioned
|
||||
explicitly on some other rule. d->is_explicit is set when
|
||||
this file is mentioned explicitly on this rule. */
|
||||
f = lookup_file (d->name);
|
||||
if (f && !f->is_explicit && !d->is_explicit)
|
||||
f->intermediate = 1;
|
||||
|
||||
/* 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 (f /* || ((!dep->changed || check_lastslash) */
|
||||
|| file_exists_p (d->name))
|
||||
/* If we found a file for the dep, set its intermediate flag.
|
||||
df->is_explicit is set when the dep file is mentioned
|
||||
explicitly on some other rule. d->is_explicit is set when
|
||||
the dep file is mentioned explicitly on this rule. E.g.:
|
||||
%.x : %.y ; ...
|
||||
then:
|
||||
one.x:
|
||||
one.y: # df->is_explicit
|
||||
vs.
|
||||
one.x: one.y # d->is_explicit
|
||||
*/
|
||||
if (df && !df->is_explicit && !d->is_explicit)
|
||||
df->intermediate = 1;
|
||||
|
||||
/* If the pattern prereq is also explicitly mentioned for
|
||||
FILE, skip all tests below since it must be built no
|
||||
matter which implicit rule we choose. */
|
||||
explicit = df || (exists = file_exists_p (d->name)) != 0;
|
||||
if (!explicit)
|
||||
for (struct dep *dp = file->deps; dp != 0; dp = dp->next)
|
||||
if (streq (d->name, dep_name (dp)))
|
||||
{
|
||||
explicit = 1;
|
||||
break;
|
||||
}
|
||||
|
||||
if (explicit)
|
||||
{
|
||||
(pat++)->name = d->name;
|
||||
if (exists > 0)
|
||||
DBS (DB_IMPLICIT, (_("Found '%s'.\n"), d->name));
|
||||
else
|
||||
DBS (DB_IMPLICIT, (_("'%s' ought to exist.\n"), d->name));
|
||||
continue;
|
||||
}
|
||||
|
||||
@ -785,7 +799,7 @@ pattern_search (struct file *file, int archive,
|
||||
if (vname)
|
||||
{
|
||||
DBS (DB_IMPLICIT,
|
||||
(_("Found prerequisite '%s' as VPATH '%s'\n"),
|
||||
(_("Found prerequisite '%s' as VPATH '%s'.\n"),
|
||||
d->name, vname));
|
||||
(pat++)->name = d->name;
|
||||
continue;
|
||||
@ -833,6 +847,14 @@ pattern_search (struct file *file, int archive,
|
||||
|
||||
/* A dependency of this rule does not exist. Therefore, this
|
||||
rule fails. */
|
||||
if (intermed_ok)
|
||||
DBS (DB_IMPLICIT,
|
||||
(_("Rejecting rule '%s' "
|
||||
"due to impossible prerequisite '%s'.\n"),
|
||||
get_rule_defn (rule), d->name));
|
||||
else
|
||||
DBS (DB_IMPLICIT, (_("Not found '%s'.\n"), d->name));
|
||||
|
||||
failed = 1;
|
||||
break;
|
||||
}
|
||||
@ -1042,5 +1064,11 @@ pattern_search (struct file *file, int archive,
|
||||
free (tryrules);
|
||||
free (deplist);
|
||||
|
||||
if (rule)
|
||||
DBS (DB_IMPLICIT, (_("Found implicit rule '%s' for '%s'.\n"),
|
||||
get_rule_defn (rule), filename));
|
||||
else
|
||||
DBS (DB_IMPLICIT, (_("No implicit rule found for '%s'.\n"), filename));
|
||||
|
||||
return rule != 0;
|
||||
}
|
||||
|
@ -922,7 +922,7 @@ reap_children (int block, int err)
|
||||
to fork/exec but I don't want to bother with that. Just do the
|
||||
best we can. */
|
||||
|
||||
EINTRLOOP(r, stat(c->cmd_name, &st));
|
||||
EINTRLOOP(r, stat (c->cmd_name, &st));
|
||||
if (r < 0)
|
||||
e = strerror (errno);
|
||||
else if (S_ISDIR(st.st_mode) || !(st.st_mode & S_IXUSR))
|
||||
|
@ -671,6 +671,11 @@ int strncasecmp (const char *s1, const char *s2, int n);
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#if !HAVE_MEMPCPY
|
||||
/* Create our own, in misc.c */
|
||||
void *mempcpy (void *dest, const void *src, size_t n);
|
||||
#endif
|
||||
|
||||
#define OUTPUT_SYNC_NONE 0
|
||||
#define OUTPUT_SYNC_LINE 1
|
||||
#define OUTPUT_SYNC_TARGET 2
|
||||
|
@ -846,3 +846,11 @@ get_path_max (void)
|
||||
return value;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if !HAVE_MEMPCPY
|
||||
void *
|
||||
mempcpy (void *dest, const void *src, size_t n)
|
||||
{
|
||||
return (char *) memcpy (dest, src, n) + n;
|
||||
}
|
||||
#endif
|
||||
|
10
src/remake.c
10
src/remake.c
@ -509,10 +509,7 @@ update_file_1 (struct file *file, unsigned int depth)
|
||||
|
||||
if (!file->phony && file->cmds == 0 && !file->tried_implicit)
|
||||
{
|
||||
if (try_implicit_rule (file, depth))
|
||||
DBF (DB_IMPLICIT, _("Found an implicit rule for '%s'.\n"));
|
||||
else
|
||||
DBF (DB_IMPLICIT, _("No implicit rule found for '%s'.\n"));
|
||||
try_implicit_rule (file, depth);
|
||||
file->tried_implicit = 1;
|
||||
}
|
||||
if (file->cmds == 0 && !file->is_target
|
||||
@ -1045,10 +1042,7 @@ check_dep (struct file *file, unsigned int depth,
|
||||
|
||||
if (!file->phony && file->cmds == 0 && !file->tried_implicit)
|
||||
{
|
||||
if (try_implicit_rule (file, depth))
|
||||
DBF (DB_IMPLICIT, _("Found an implicit rule for '%s'.\n"));
|
||||
else
|
||||
DBF (DB_IMPLICIT, _("No implicit rule found for '%s'.\n"));
|
||||
try_implicit_rule (file, depth);
|
||||
file->tried_implicit = 1;
|
||||
}
|
||||
if (file->cmds == 0 && !file->is_target
|
||||
|
65
src/rule.c
65
src/rule.c
@ -59,6 +59,55 @@ struct file *suffix_file;
|
||||
/* Maximum length of a suffix. */
|
||||
|
||||
static size_t maxsuffix;
|
||||
|
||||
/* Return the rule definition: space separated rule targets, followed by
|
||||
either a colon or two colons in the case of a terminal rule, followed by
|
||||
space separated rule prerequisites, followed by a pipe, followed by
|
||||
order-only prerequisites, if present. */
|
||||
|
||||
const char *get_rule_defn (struct rule *r)
|
||||
{
|
||||
if (r->_defn == NULL)
|
||||
{
|
||||
unsigned int k;
|
||||
ptrdiff_t len = 8; // Reserve for ":: ", " | " and the null terminator.
|
||||
char *p;
|
||||
const char *sep = "";
|
||||
const struct dep *dep, *ood = 0;
|
||||
|
||||
for (k = 0; k < r->num; ++k)
|
||||
len += r->lens[k] + 1; // Add one for a space.
|
||||
|
||||
for (dep = r->deps; dep; dep = dep->next)
|
||||
len += strlen (dep_name (dep)) + 1; // Add one for a space.
|
||||
|
||||
p = r->_defn = xmalloc (len);
|
||||
for (k = 0; k < r->num; ++k, sep = " ")
|
||||
p = mempcpy (mempcpy (p, sep, strlen (sep)), r->targets[k], r->lens[k]);
|
||||
*p++ = ':';
|
||||
if (r->terminal)
|
||||
*p++ = ':';
|
||||
|
||||
/* Copy all normal dependencies; note any order-only deps. */
|
||||
for (dep = r->deps; dep; dep = dep->next)
|
||||
if (dep->ignore_mtime == 0)
|
||||
p = mempcpy (mempcpy (p, " ", 1), dep_name (dep),
|
||||
strlen (dep_name (dep)));
|
||||
else if (ood == 0)
|
||||
ood = dep;
|
||||
|
||||
/* Copy order-only deps, if we have any. */
|
||||
for (sep = " | "; ood; ood = ood->next, sep = " ")
|
||||
if (ood->ignore_mtime)
|
||||
p = mempcpy (mempcpy (p, sep, strlen (sep)), dep_name (ood),
|
||||
strlen (dep_name (ood)));
|
||||
*p = '\0';
|
||||
assert (p - r->_defn < len);
|
||||
}
|
||||
|
||||
return r->_defn;
|
||||
}
|
||||
|
||||
|
||||
/* Compute the maximum dependency length and maximum number of dependencies of
|
||||
all implicit rules. Also sets the subdir flag for a rule when appropriate,
|
||||
@ -398,6 +447,7 @@ install_pattern_rule (struct pspec *p, int terminal)
|
||||
r->targets = xmalloc (sizeof (const char *));
|
||||
r->suffixes = xmalloc (sizeof (const char *));
|
||||
r->lens = xmalloc (sizeof (unsigned int));
|
||||
r->_defn = NULL;
|
||||
|
||||
r->lens[0] = (unsigned int) strlen (p->target);
|
||||
r->targets[0] = p->target;
|
||||
@ -439,6 +489,7 @@ freerule (struct rule *rule, struct rule *lastrule)
|
||||
free ((void *)rule->targets);
|
||||
free ((void *)rule->suffixes);
|
||||
free (rule->lens);
|
||||
free ((void *) rule->_defn);
|
||||
|
||||
/* We can't free the storage for the commands because there
|
||||
are ways that they could be in more than one place:
|
||||
@ -488,6 +539,7 @@ create_pattern_rule (const char **targets, const char **target_percents,
|
||||
r->targets = targets;
|
||||
r->suffixes = target_percents;
|
||||
r->lens = xmalloc (n * sizeof (unsigned int));
|
||||
r->_defn = NULL;
|
||||
|
||||
for (i = 0; i < n; ++i)
|
||||
{
|
||||
@ -505,17 +557,8 @@ create_pattern_rule (const char **targets, const char **target_percents,
|
||||
static void /* Useful to call from gdb. */
|
||||
print_rule (struct rule *r)
|
||||
{
|
||||
unsigned int i;
|
||||
|
||||
for (i = 0; i < r->num; ++i)
|
||||
{
|
||||
fputs (r->targets[i], stdout);
|
||||
putchar ((i + 1 == r->num) ? ':' : ' ');
|
||||
}
|
||||
if (r->terminal)
|
||||
putchar (':');
|
||||
|
||||
print_prereqs (r->deps);
|
||||
fputs (get_rule_defn (r), stdout);
|
||||
putchar ('\n');
|
||||
|
||||
if (r->cmds != 0)
|
||||
print_commands (r->cmds);
|
||||
|
@ -25,6 +25,7 @@ struct rule
|
||||
const char **suffixes; /* Suffixes (after '%') of each target. */
|
||||
struct dep *deps; /* Dependencies of the rule. */
|
||||
struct commands *cmds; /* Commands to execute. */
|
||||
char *_defn; /* Definition of the rule. */
|
||||
unsigned short num; /* Number of targets. */
|
||||
char terminal; /* If terminal (double-colon). */
|
||||
char in_use; /* If in use by a parent pattern_search. */
|
||||
@ -54,4 +55,5 @@ void install_pattern_rule (struct pspec *p, int terminal);
|
||||
void create_pattern_rule (const char **targets, const char **target_percents,
|
||||
unsigned short num, int terminal, struct dep *deps,
|
||||
struct commands *commands, int override);
|
||||
const char *get_rule_defn (struct rule *rule);
|
||||
void print_rule_data_base (void);
|
||||
|
Loading…
Reference in New Issue
Block a user