Imported Upstream version 4.4
[platform/upstream/make.git] / src / file.c
index a979ca5..226af61 100644 (file)
@@ -1,5 +1,5 @@
 /* Target file management for GNU Make.
-Copyright (C) 1988-2020 Free Software Foundation, Inc.
+Copyright (C) 1988-2022 Free Software Foundation, Inc.
 This file is part of GNU Make.
 
 GNU Make is free software; you can redistribute it and/or modify it under the
@@ -12,7 +12,7 @@ WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
 A PARTICULAR PURPOSE.  See the GNU General Public License for more details.
 
 You should have received a copy of the GNU General Public License along with
-this program.  If not, see <http://www.gnu.org/licenses/>.  */
+this program.  If not, see <https://www.gnu.org/licenses/>.  */
 
 #include "makeint.h"
 
@@ -25,6 +25,7 @@ this program.  If not, see <http://www.gnu.org/licenses/>.  */
 #include "variable.h"
 #include "debug.h"
 #include "hash.h"
+#include "shuffle.h"
 
 
 /* Remember whether snap_deps has been invoked: we need this to be sure we
@@ -62,6 +63,9 @@ static struct hash_table files;
 /* Whether or not .SECONDARY with no prerequisites was given.  */
 static int all_secondary = 0;
 
+/* Whether or not .NOTINTERMEDIATE with no prerequisites was given.  */
+static int no_intermediates = 0;
+
 /* Access the hash table of all file records.
    lookup_file  given a name, return the struct file * for that name,
                 or nil if there is none.
@@ -104,20 +108,10 @@ lookup_file (const char *name)
   while (name[0] == '<' && name[1] == '>' && name[2] != '\0')
       name += 2;
 #endif
-  while (name[0] == '.'
-#ifdef HAVE_DOS_PATHS
-         && (name[1] == '/' || name[1] == '\\')
-#else
-         && name[1] == '/'
-#endif
-         && name[2] != '\0')
+  while (name[0] == '.' && ISDIRSEP (name[1]) && name[2] != '\0')
     {
       name += 2;
-      while (*name == '/'
-#ifdef HAVE_DOS_PATHS
-             || *name == '\\'
-#endif
-             )
+      while (ISDIRSEP (*name))
         /* Skip following slashes: ".//foo" is "foo", not "/foo".  */
         ++name;
     }
@@ -270,14 +264,14 @@ rehash_file (struct file *from_file, const char *to_hname)
         {
           size_t l = strlen (from_file->name);
           /* We have two sets of commands.  We will go with the
-             one given in the rule explicitly mentioning this name,
+             one given in the rule found through directory search,
              but give a message to let the user know what's going on.  */
           if (to_file->cmds->fileinfo.filenm != 0)
             error (&from_file->cmds->fileinfo,
                    l + strlen (to_file->cmds->fileinfo.filenm) + INTSTR_LENGTH,
                    _("Recipe was specified for file '%s' at %s:%lu,"),
-                   from_file->name, to_file->cmds->fileinfo.filenm,
-                   to_file->cmds->fileinfo.lineno);
+                   from_file->name, from_file->cmds->fileinfo.filenm,
+                   from_file->cmds->fileinfo.lineno);
           else
             error (&from_file->cmds->fileinfo, l,
                    _("Recipe for file '%s' was found by implicit rule search,"),
@@ -288,7 +282,7 @@ rehash_file (struct file *from_file, const char *to_hname)
                  from_file->name, to_hname);
           error (&from_file->cmds->fileinfo, l,
                  _("Recipe for '%s' will be ignored in favor of the one for '%s'."),
-                 to_hname, from_file->name);
+                 from_file->name, to_hname);
         }
     }
 
@@ -327,14 +321,19 @@ rehash_file (struct file *from_file, const char *to_hname)
 
 #define MERGE(field) to_file->field |= from_file->field
   MERGE (precious);
+  MERGE (loaded);
   MERGE (tried_implicit);
   MERGE (updating);
   MERGE (updated);
   MERGE (is_target);
   MERGE (cmd_target);
   MERGE (phony);
-  MERGE (loaded);
+  /* Don't merge intermediate because this file might be pre-existing */
+  MERGE (is_explicit);
+  MERGE (secondary);
+  MERGE (notintermediate);
   MERGE (ignore_vpath);
+  MERGE (snapped);
 #undef MERGE
 
   to_file->builtin = 0;
@@ -386,7 +385,7 @@ remove_intermediates (int sig)
            given on the command line, and it's either a -include makefile or
            it's not precious.  */
         if (f->intermediate && (f->dontcare || !f->precious)
-            && !f->secondary && !f->cmd_target)
+            && !f->secondary && !f->notintermediate && !f->cmd_target)
           {
             int status;
             if (f->update_status == us_none)
@@ -424,7 +423,11 @@ remove_intermediates (int sig)
                       }
                   }
                 if (status < 0)
-                  perror_with_name ("unlink: ", f->name);
+                  {
+                    perror_with_name ("\nunlink: ", f->name);
+                    /* Start printing over.  */
+                    doneany = 0;
+                  }
               }
           }
       }
@@ -442,8 +445,7 @@ remove_intermediates (int sig)
 struct dep *
 split_prereqs (char *p)
 {
-  struct dep *new = PARSE_FILE_SEQ (&p, struct dep, MAP_PIPE, NULL,
-                                    PARSEFS_NONE);
+  struct dep *new = PARSE_FILE_SEQ (&p, struct dep, MAP_PIPE, NULL, PARSEFS_WAIT);
 
   if (*p)
     {
@@ -452,7 +454,7 @@ split_prereqs (char *p)
       struct dep *ood;
 
       ++p;
-      ood = PARSE_SIMPLE_SEQ (&p, struct dep);
+      ood = PARSE_FILE_SEQ (&p, struct dep, MAP_NUL, NULL, PARSEFS_WAIT);
 
       if (! new)
         new = ood;
@@ -486,7 +488,6 @@ enter_prereqs (struct dep *deps, const char *stem)
   if (stem)
     {
       const char *pattern = "%";
-      char *buffer = variable_expand ("");
       struct dep *dp = deps, *dl = 0;
 
       while (dp != 0)
@@ -506,14 +507,15 @@ enter_prereqs (struct dep *deps, const char *stem)
               if (stem[0] == '\0')
                 {
                   memmove (percent, percent+1, strlen (percent));
-                  o = variable_buffer_output (buffer, nm, strlen (nm) + 1);
+                  o = variable_buffer_output (variable_buffer, nm,
+                                              strlen (nm) + 1);
                 }
               else
-                o = patsubst_expand_pat (buffer, stem, pattern, nm,
+                o = patsubst_expand_pat (variable_buffer, stem, pattern, nm,
                                          pattern+1, percent+1);
 
               /* If the name expanded to the empty string, ignore it.  */
-              if (buffer[0] == '\0')
+              if (variable_buffer[0] == '\0')
                 {
                   struct dep *df = dp;
                   if (dp == deps)
@@ -525,7 +527,8 @@ enter_prereqs (struct dep *deps, const char *stem)
                 }
 
               /* Save the name.  */
-              dp->name = strcache_add_len (buffer, o - buffer);
+              dp->name = strcache_add_len (variable_buffer,
+                                           o - variable_buffer);
             }
           dp->stem = stem;
           dp->staticpattern = 1;
@@ -545,21 +548,29 @@ enter_prereqs (struct dep *deps, const char *stem)
         d1->file = enter_file (d1->name);
       d1->staticpattern = 0;
       d1->name = 0;
+      if (!stem)
+        /* This file is explicitly mentioned as a prereq.  */
+        d1->file->is_explicit = 1;
     }
 
   return deps;
 }
 
-/* Expand and parse each dependency line. */
-static void
+/* Expand and parse each dependency line.
+   For each dependency of the file, make the 'struct dep' point
+   at the appropriate 'struct file' (which may have to be created).  */
+void
 expand_deps (struct file *f)
 {
   struct dep *d;
   struct dep **dp;
-  const char *file_stem = f->stem;
+  const char *fstem;
   int initialized = 0;
+  int changed_dep = 0;
 
-  f->updating = 0;
+  if (f->snapped)
+    return;
+  f->snapped = 1;
 
   /* Walk through the dependencies.  For any dependency that needs 2nd
      expansion, expand it then insert the result into the list.  */
@@ -569,7 +580,6 @@ expand_deps (struct file *f)
     {
       char *p;
       struct dep *new, *next;
-      char *name = (char *)d->name;
 
       if (! d->name || ! d->need_2nd_expansion)
         {
@@ -579,16 +589,46 @@ expand_deps (struct file *f)
           continue;
         }
 
-      /* If it's from a static pattern rule, convert the patterns into
-         "$*" so they'll expand properly.  */
+      /* If it's from a static pattern rule, convert the initial pattern in
+         each word to "$*" so they'll expand properly.  */
       if (d->staticpattern)
         {
-          char *o = variable_expand ("");
-          o = subst_expand (o, name, "%", "$*", 1, 2, 0);
-          *o = '\0';
-          free (name);
-          d->name = name = xstrdup (variable_buffer);
-          d->staticpattern = 0;
+          const char *cs = d->name;
+          size_t nperc = 0;
+
+          /* Count the number of % in the string.  */
+          while ((cs = strchr (cs, '%')) != NULL)
+            {
+              ++nperc;
+              ++cs;
+            }
+
+          if (nperc)
+            {
+              /* Allocate enough space to replace all % with $*.  */
+              size_t slen = strlen (d->name) + nperc + 1;
+              const char *pcs = d->name;
+              char *name = xmalloc (slen);
+              char *s = name;
+
+              /* Substitute the first % in each word.  */
+              cs = strchr (pcs, '%');
+
+              while (cs)
+                {
+                  s = mempcpy (s, pcs, cs - pcs);
+                  *(s++) = '$';
+                  *(s++) = '*';
+                  pcs = ++cs;
+
+                  /* Find the first % after the next whitespace.  */
+                  cs = strchr (end_of_token (cs), '%');
+                }
+              strcpy (s, pcs);
+
+              free ((char*)d->name);
+              d->name = name;
+            }
         }
 
       /* We're going to do second expansion so initialize file variables for
@@ -600,39 +640,53 @@ expand_deps (struct file *f)
           initialized = 1;
         }
 
-      if (d->stem != 0)
-        f->stem = d->stem;
-
-      set_file_variables (f);
+      set_file_variables (f, d->stem ? d->stem : f->stem);
 
+      /* Perform second expansion.  */
       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);
+      /* Free the un-expanded name.  */
+      free ((char*)d->name);
 
       /* Parse the prerequisites and enter them into the file database.  */
-      new = enter_prereqs (split_prereqs (p), d->stem);
+      new = split_prereqs (p);
 
       /* If there were no prereqs here (blank!) then throw this one out.  */
       if (new == 0)
         {
           *dp = d->next;
+          changed_dep = 1;
           free_dep (d);
           d = *dp;
           continue;
         }
 
       /* Add newly parsed prerequisites.  */
+      fstem = d->stem;
       next = d->next;
+      changed_dep = 1;
+      free_dep (d);
       *dp = new;
-      for (dp = &new->next, d = new->next; d != 0; dp = &d->next, d = d->next)
-        ;
+      for (dp = &new, d = new; d != 0; dp = &d->next, d = d->next)
+        {
+          d->file = lookup_file (d->name);
+          if (d->file == 0)
+            d->file = enter_file (d->name);
+          d->name = 0;
+          d->stem = fstem;
+          if (!fstem)
+            /* This file is explicitly mentioned as a prereq.  */
+            d->file->is_explicit = 1;
+        }
       *dp = next;
       d = *dp;
     }
+
+    /* Shuffle mode assumes '->next' and '->shuf' links both traverse the same
+       dependencies (in different sequences).  Regenerate '->shuf' so we don't
+       refer to stale data.  */
+    if (changed_dep)
+      shuffle_deps_recursive (f->deps);
 }
 
 /* Add extra prereqs to the file in question.  */
@@ -667,10 +721,18 @@ snap_file (const void *item, void *arg)
   if (!second_expansion)
     f->updating = 0;
 
-  /* If .SECONDARY is set with no deps, mark all targets as intermediate.  */
-  if (all_secondary)
+  /* More specific setting has priority.  */
+
+  /* If .SECONDARY is set with no deps, mark all targets as intermediate,
+     unless the target is a prereq of .NOTINTERMEDIATE.  */
+  if (all_secondary && !f->notintermediate)
     f->intermediate = 1;
 
+  /* If .NOTINTERMEDIATE is set with no deps, mark all targets as
+     notintermediate, unless the target is a prereq of .INTERMEDIATE.  */
+  if (no_intermediates && !f->intermediate && !f->secondary)
+      f->notintermediate = 1;
+
   /* If .EXTRA_PREREQS is set, add them as ignored by automatic variables.  */
   if (f->variables)
     prereqs = expand_extra_prereqs (lookup_variable_in_set (STRING_SIZE_TUPLE(".EXTRA_PREREQS"), f->variables->set));
@@ -701,10 +763,7 @@ snap_file (const void *item, void *arg)
     }
 }
 
-/* For each dependency of each file, make the 'struct dep' point
-   at the appropriate 'struct file' (which may have to be created).
-
-   Also mark the files depended on by .PRECIOUS, .PHONY, .SILENT,
+/* Mark the files depended on by .PRECIOUS, .PHONY, .SILENT,
    and various other special targets.  */
 
 void
@@ -718,37 +777,6 @@ snap_deps (void)
      longer define new targets.  */
   snapped_deps = 1;
 
-  /* 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.
-
-     We only need to do this if second_expansion has been defined; if it
-     hasn't then all deps were expanded as the makefile was read in.  If we
-     ever change make to be able to unset .SECONDARY_EXPANSION this will have
-     to change.  */
-
-  if (second_expansion)
-    {
-      struct file **file_slot_0 = (struct file **) hash_dump (&files, 0, 0);
-      struct file **file_end = file_slot_0 + files.ht_fill;
-      struct file **file_slot;
-      const char *suffixes;
-
-      /* Expand .SUFFIXES: its prerequisites are used for $$* calc.  */
-      f = lookup_file (".SUFFIXES");
-      suffixes = f ? f->name : 0;
-      for (; f != 0; f = f->prev)
-        expand_deps (f);
-
-      /* 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);
-    }
-
   /* Now manage all the special targets.  */
 
   for (f = lookup_file (".PRECIOUS"); f != 0; f = f->prev)
@@ -772,11 +800,32 @@ snap_deps (void)
           f2->mtime_before_update = NONEXISTENT_MTIME;
         }
 
+  for (f = lookup_file (".NOTINTERMEDIATE"); f != 0; f = f->prev)
+    /* Mark .NOTINTERMEDIATE deps as notintermediate files.  */
+    if (f->deps)
+        for (d = f->deps; d != 0; d = d->next)
+          for (f2 = d->file; f2 != 0; f2 = f2->prev)
+            f2->notintermediate = 1;
+    /* .NOTINTERMEDIATE with no deps marks all files as notintermediate.  */
+    else
+      no_intermediates = 1;
+
+  /* The same file connot be both .INTERMEDIATE and .NOTINTERMEDIATE.
+     However, it is possible for a file to be .INTERMEDIATE and also match a
+     .NOTINTERMEDIATE pattern.  In that case, the intermediate file has
+     priority over the notintermediate pattern.  This priority is enforced by
+     pattern_search.  */
+
   for (f = lookup_file (".INTERMEDIATE"); f != 0; f = f->prev)
     /* Mark .INTERMEDIATE deps as intermediate files.  */
     for (d = f->deps; d != 0; d = d->next)
       for (f2 = d->file; f2 != 0; f2 = f2->prev)
-        f2->intermediate = 1;
+        if (f2->notintermediate)
+          OS (fatal, NILF,
+              _("%s cannot be both .NOTINTERMEDIATE and .INTERMEDIATE"),
+              f2->name);
+        else
+          f2->intermediate = 1;
     /* .INTERMEDIATE with no deps does nothing.
        Marking all files as intermediates is useless since the goal targets
        would be deleted after they are built.  */
@@ -786,11 +835,20 @@ snap_deps (void)
     if (f->deps)
       for (d = f->deps; d != 0; d = d->next)
         for (f2 = d->file; f2 != 0; f2 = f2->prev)
+        if (f2->notintermediate)
+          OS (fatal, NILF,
+              _("%s cannot be both .NOTINTERMEDIATE and .SECONDARY"),
+              f2->name);
+        else
           f2->intermediate = f2->secondary = 1;
     /* .SECONDARY with no deps listed marks *all* files that way.  */
     else
       all_secondary = 1;
 
+  if (no_intermediates && all_secondary)
+    O (fatal, NILF,
+       _(".NOTINTERMEDIATE and .SECONDARY are mutually exclusive"));
+
   f = lookup_file (".EXPORT_ALL_VARIABLES");
   if (f != 0 && f->is_target)
     export_all_variables = 1;
@@ -819,7 +877,19 @@ snap_deps (void)
 
   f = lookup_file (".NOTPARALLEL");
   if (f != 0 && f->is_target)
-    not_parallel = 1;
+    {
+      struct dep *d2;
+
+      if (!f->deps)
+        not_parallel = 1;
+      else
+        /* Set a wait point between every prerequisite of each target.  */
+        for (d = f->deps; d != NULL; d = d->next)
+          for (f2 = d->file; f2 != NULL; f2 = f2->prev)
+            if (f2->deps)
+              for (d2 = f2->deps->next; d2 != NULL; d2 = d2->next)
+                d2->wait_here = 1;
+    }
 
   {
     struct dep *prereqs = expand_extra_prereqs (lookup_variable (STRING_SIZE_TUPLE(".EXTRA_PREREQS")));
@@ -938,13 +1008,16 @@ file_timestamp_sprintf (char *p, FILE_TIMESTAMP ts)
   struct tm *tm = localtime (&t);
 
   if (tm)
-    sprintf (p, "%04d-%02d-%02d %02d:%02d:%02d",
-             tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday,
-             tm->tm_hour, tm->tm_min, tm->tm_sec);
+    {
+      intmax_t year = tm->tm_year;
+      sprintf (p, "%04" PRIdMAX "-%02d-%02d %02d:%02d:%02d",
+               year + 1900, tm->tm_mon + 1, tm->tm_mday,
+               tm->tm_hour, tm->tm_min, tm->tm_sec);
+    }
   else if (t < 0)
-    sprintf (p, "%ld", (long) t);
+    sprintf (p, "%" PRIdMAX, (intmax_t) t);
   else
-    sprintf (p, "%lu", (unsigned long) t);
+    sprintf (p, "%" PRIuMAX, (uintmax_t) t);
   p += strlen (p);
 
   /* Append nanoseconds as a fraction, but remove trailing zeros.  We don't
@@ -970,17 +1043,17 @@ print_prereqs (const struct dep *deps)
   /* Print all normal dependencies; note any order-only deps.  */
   for (; deps != 0; deps = deps->next)
     if (! deps->ignore_mtime)
-      printf (" %s", dep_name (deps));
+      printf (" %s%s", deps->wait_here ? ".WAIT " : "", dep_name (deps));
     else if (! ood)
       ood = deps;
 
   /* Print order-only deps, if we have any.  */
   if (ood)
     {
-      printf (" | %s", dep_name (ood));
+      printf (" | %s%s", ood->wait_here ? ".WAIT " : "", dep_name (ood));
       for (ood = ood->next; ood != 0; ood = ood->next)
         if (ood->ignore_mtime)
-          printf (" %s", dep_name (ood));
+          printf (" %s%s", ood->wait_here ? ".WAIT " : "", dep_name (ood));
     }
 
   putchar ('\n');
@@ -1034,6 +1107,10 @@ print_file (const void *item)
     printf (_("#  Implicit/static pattern stem: '%s'\n"), f->stem);
   if (f->intermediate)
     puts (_("#  File is an intermediate prerequisite."));
+  if (f->notintermediate)
+    puts (_("#  File is a prerequisite of .NOTINTERMEDIATE."));
+  if (f->secondary)
+    puts (_("#  File is secondary (prerequisite of .SECONDARY)."));
   if (f->also_make != 0)
     {
       const struct dep *d;
@@ -1181,8 +1258,7 @@ build_target_list (char *value)
                 p = &value[off];
               }
 
-            memcpy (p, f->name, l);
-            p += l;
+            p = mempcpy (p, f->name, l);
             *(p++) = ' ';
           }
       *(p-1) = '\0';