]> git.ipfire.org Git - thirdparty/make.git/commitdiff
[SV 61042] Enhance logging of implicit rule search
authorDmitry Goncharov <dgoncharov@users.sf.net>
Sun, 17 Oct 2021 22:03:04 +0000 (18:03 -0400)
committerPaul Smith <psmith@gnu.org>
Tue, 19 Oct 2021 03:00:21 +0000 (23:00 -0400)
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.

bootstrap.conf
src/config.h-vms.template
src/config.h.W32.template
src/implicit.c
src/job.c
src/makeint.h
src/misc.c
src/remake.c
src/rule.c
src/rule.h

index 7c4c9ab7e0a3e7b175a4313fe64596d4340d293b..bd37f1b918b53a96cdfe2808850cc7d08bd98212 100644 (file)
@@ -49,5 +49,6 @@ fdl
 findprog-in
 getloadavg
 host-cpu-c-abi
+mempcpy
 strerror
 make-glob"
index 7cd393db43001953e2e4af12971cff93a23e3876..62daac2d1a369aecd2564d4c126649579ac28f2b 100644 (file)
@@ -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 */
 
index f847be87221004c4442ceaf931a69b350f1ea166..bd3b47630478ace68853a5bb74d8fe2d6f69cee5 100644 (file)
@@ -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 */
 
index 3c7fba764dd2a7603503810ecb3a928f4abb63cd..7505ff69bfb836c1045568f0cf8d1e1661094b8f 100644 (file)
@@ -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. */
-
-                  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;
-                    }
+                  df = lookup_file (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;
+                        }
 
-                  /* 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 (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;
 }
index ee59b95b6816652247b421d1f1f7ddf82a383d72..54fadf000805c75f5b24a5ba77f39fa9af464288 100644 (file)
--- a/src/job.c
+++ b/src/job.c
@@ -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))
index eb78b4025af749b30d148ba0c3db498026d20870..15dc07d5f0abae47bf5e5dd1846f0f41f7f125ba 100644 (file)
@@ -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
index 3072952c66e3d5f2830cffbbac29abba2c14054f..f400135b62b4721c65b53388641fad84c8950b2a 100644 (file)
@@ -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
index 9b71ce61be6db38a033c541074e48efd357428b6..bd6d8e51103819c8ff1fb642f26396d50f2c6a90 100644 (file)
@@ -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
index 7efca58bc61c74502ce15655502932a9d799e2a5..16aec7fefbe4fab95760d61f38191c44cc6800b4 100644 (file)
@@ -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;
+}
+
 \f
 /* 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);
index 120a6827b1632e7420b5ec523dfe017dc74244ed..c18ae518db9bc91e105bbb5d193045d18757ffab 100644 (file)
@@ -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);