Imported Upstream version 4.4
[platform/upstream/make.git] / src / remake.c
index fb237c5..4ce3d2a 100644 (file)
@@ -1,5 +1,5 @@
 /* Basic dependency engine 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"
 #include "filedef.h"
@@ -34,7 +34,15 @@ this program.  If not, see <http://www.gnu.org/licenses/>.  */
 #include <starlet.h>
 #endif
 #ifdef WINDOWS32
+#include <windows.h>
 #include <io.h>
+#include <sys/stat.h>
+#if defined(_MSC_VER) && _MSC_VER > 1200
+/* VC7 or later supprots _stat64 to access 64-bit file size. */
+#define STAT _stat64
+#else
+#define STAT stat
+#endif
 #endif
 
 
@@ -71,8 +79,27 @@ static FILE_TIMESTAMP name_mtime (const char *name);
 static const char *library_search (const char *lib, FILE_TIMESTAMP *mtime_ptr);
 
 \f
-/* Remake all the goals in the 'struct dep' chain GOALS.  Return -1 if nothing
-   was done, 0 if all goals were updated successfully, or 1 if a goal failed.
+static void
+check_also_make (const struct file *file)
+{
+  struct dep *ad;
+  FILE_TIMESTAMP mtime = file->last_mtime;
+
+  if (mtime == UNKNOWN_MTIME)
+    mtime = name_mtime (file->name);
+
+  /* If we updated the file, check its also-make files.  */
+
+  if (is_ordinary_mtime (mtime) && mtime > file->mtime_before_update)
+    for (ad = file->also_make; ad; ad = ad->next)
+      if (ad->file->last_mtime == NONEXISTENT_MTIME)
+        OS (error, file->cmds ? &file->cmds->fileinfo : NILF,
+            _("warning: pattern recipe did not update peer target '%s'."),
+            ad->file->name);
+}
+
+/* Remake all the goals in the 'struct dep' chain GOALS.  Return update_status
+   representing the totality of the status of the goals.
 
    If rebuilding_makefiles is nonzero, these goals are makefiles, so -t, -q,
    and -n should be disabled for them unless they were also command-line
@@ -86,8 +113,8 @@ update_goal_chain (struct goaldep *goaldeps)
   enum update_status status = us_none;
 
   /* Duplicate the chain so we can remove things from it.  */
-
-  struct dep *goals = copy_dep_chain ((struct dep *)goaldeps);
+  struct dep *goals_orig = copy_dep_chain ((struct dep *)goaldeps);
+  struct dep *goals = goals_orig;
 
   goal_list = rebuilding_makefiles ? goaldeps : NULL;
 
@@ -101,7 +128,7 @@ update_goal_chain (struct goaldep *goaldeps)
 
   while (goals != 0)
     {
-      struct dep *g, *lastgoal;
+      struct dep *gu, *g, *lastgoal;
 
       /* Start jobs that are waiting for the load to go down.  */
 
@@ -112,13 +139,15 @@ update_goal_chain (struct goaldep *goaldeps)
       reap_children (1, 0);
 
       lastgoal = 0;
-      g = goals;
-      while (g != 0)
+      gu = goals;
+      while (gu != 0)
         {
           /* Iterate over all double-colon entries for this file.  */
           struct file *file;
           int stop = 0, any_not_updated = 0;
 
+          g = gu->shuf ? gu->shuf : gu;
+
           goal_dep = g;
 
           for (file = g->file->double_colon ? g->file->double_colon : g->file;
@@ -178,8 +207,7 @@ update_goal_chain (struct goaldep *goaldeps)
                       FILE_TIMESTAMP mtime = MTIME (file);
                       check_renamed (file);
 
-                      if (file->updated && g->changed &&
-                           mtime != file->mtime_before_update)
+                      if (file->updated && mtime != file->mtime_before_update)
                         {
                           /* Updating was done.  If this is a makefile and
                              just_print_flag or question_flag is set (meaning
@@ -229,31 +257,30 @@ update_goal_chain (struct goaldep *goaldeps)
 
               /* This goal is finished.  Remove it from the chain.  */
               if (lastgoal == 0)
-                goals = g->next;
+                goals = gu->next;
               else
-                lastgoal->next = g->next;
-
-              /* Free the storage.  */
-              free (g);
+                lastgoal->next = gu->next;
 
-              g = lastgoal == 0 ? goals : lastgoal->next;
+              gu = lastgoal == 0 ? goals : lastgoal->next;
 
               if (stop)
                 break;
             }
           else
             {
-              lastgoal = g;
-              g = g->next;
+              lastgoal = gu;
+              gu = gu->next;
             }
         }
 
       /* If we reached the end of the dependency graph update CONSIDERED
          for the next pass.  */
-      if (g == 0)
+      if (gu == 0)
         ++considered;
     }
 
+  free_dep_chain (goals_orig);
+
   if (rebuilding_makefiles)
     {
       touch_flag = t;
@@ -281,7 +308,7 @@ show_goal_error (void)
         if (goal->error)
           {
             OSS (error, &goal->floc, "%s: %s",
-                 goal->file->name, strerror ((int)goal->error));
+                 goal->file->name, strerror (goal->error));
             goal->error = 0;
           }
         return;
@@ -337,7 +364,7 @@ update_file (struct file *file, unsigned int depth)
       check_renamed (f);
 
       /* Clean up any alloca() used during the update.  */
-      alloca (0);
+      free_alloca ();
 
       /* If we got an error, don't bother with double_colon etc.  */
       if (new && !keep_going_flag)
@@ -409,7 +436,7 @@ complain (struct file *file)
 }
 
 /* Consider a single 'struct file' and update it as appropriate.
-   Return 0 on success, or non-0 on failure.  */
+   Return an update_status value; use us_success if we aren't sure yet.  */
 
 static enum update_status
 update_file_1 (struct file *file, unsigned int depth)
@@ -418,7 +445,7 @@ update_file_1 (struct file *file, unsigned int depth)
   FILE_TIMESTAMP this_mtime;
   int noexist, must_make, deps_changed;
   struct file *ofile;
-  struct dep *d, *ad;
+  struct dep *du, *d, *ad;
   struct dep amake;
   int running = 0;
 
@@ -442,7 +469,7 @@ update_file_1 (struct file *file, unsigned int depth)
         }
 
       DBF (DB_VERBOSE, _("File '%s' was considered already.\n"));
-      return 0;
+      return us_success;
     }
 
   switch (file->command_state)
@@ -452,7 +479,7 @@ update_file_1 (struct file *file, unsigned int depth)
       break;
     case cs_running:
       DBF (DB_VERBOSE, _("Still updating file '%s'.\n"));
-      return 0;
+      return us_success;
     case cs_finished:
       DBF (DB_VERBOSE, _("Finished updating file '%s'.\n"));
       return file->update_status;
@@ -484,8 +511,7 @@ update_file_1 (struct file *file, unsigned int depth)
   noexist = this_mtime == NONEXISTENT_MTIME;
   if (noexist)
     DBF (DB_BASIC, _("File '%s' does not exist.\n"));
-  else if (ORDINARY_MTIME_MIN <= this_mtime && this_mtime <= ORDINARY_MTIME_MAX
-           && file->low_resolution_time)
+  else if (is_ordinary_mtime (this_mtime) && file->low_resolution_time)
     {
       /* Avoid spurious rebuilds due to low resolution time stamps.  */
       int ns = FILE_TIMESTAMP_NS (this_mtime);
@@ -496,17 +522,34 @@ update_file_1 (struct file *file, unsigned int depth)
       this_mtime += FILE_TIMESTAMPS_PER_S - 1 - ns;
     }
 
+  /* If any also_make target doesn't exist, we must remake this one too.
+     If they do exist choose the oldest mtime so they will rebuild.  */
+
+  for (ad = file->also_make; ad && !noexist; ad = ad->next)
+    {
+      struct file *adfile = ad->file;
+      FILE_TIMESTAMP fmtime = file_mtime (adfile);
+
+      noexist = fmtime == NONEXISTENT_MTIME;
+      if (noexist)
+        {
+          check_renamed (adfile);
+          DBS (DB_BASIC,
+               (_("Grouped target peer '%s' of file '%s' does not exist.\n"),
+                adfile->name, file->name));
+        }
+      else if (fmtime < this_mtime)
+        this_mtime = fmtime;
+    }
+
   must_make = noexist;
 
-  /* If file was specified as a target with no commands,
-     come up with some default commands.  */
+  /* If file was specified as a target with no commands, come up with some
+     default commands.  This may also add more also_make files.  */
 
   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
@@ -528,17 +571,28 @@ update_file_1 (struct file *file, unsigned int depth)
     {
       struct dep *lastd = 0;
 
+      /* Perform second expansion and enter each dependency name as a file.
+         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 (second_expansion)
+        expand_deps (ad->file);
+
       /* Find the deps we're scanning */
-      d = ad->file->deps;
+      du = ad->file->deps;
       ad = ad->next;
 
-      while (d)
+      while (du)
         {
           enum update_status new;
           FILE_TIMESTAMP mtime;
           int maybe_make;
           int dontcare = 0;
 
+          d = du->shuf ? du->shuf : du;
+
+          if (d->wait_here && running)
+            break;
+
           check_renamed (d->file);
 
           mtime = file_mtime (d->file);
@@ -548,14 +602,16 @@ update_file_1 (struct file *file, unsigned int depth)
             {
               OSS (error, NILF, _("Circular %s <- %s dependency dropped."),
                    file->name, d->file->name);
+
               /* We cannot free D here because our the caller will still have
                  a reference to it when we were called recursively via
                  check_dep below.  */
               if (lastd == 0)
-                file->deps = d->next;
+                file->deps = du->next;
               else
-                lastd->next = d->next;
-              d = d->next;
+                lastd->next = du->next;
+
+              du = du->next;
               continue;
             }
 
@@ -604,8 +660,8 @@ update_file_1 (struct file *file, unsigned int depth)
             d->changed = ((file_mtime (d->file) != mtime)
                           || (mtime == NONEXISTENT_MTIME));
 
-          lastd = d;
-          d = d->next;
+          lastd = du;
+          du = du->next;
         }
     }
 
@@ -614,58 +670,65 @@ update_file_1 (struct file *file, unsigned int depth)
 
   if (must_make || always_make_flag)
     {
-      for (d = file->deps; d != 0; d = d->next)
-        if (d->file->intermediate)
-          {
-            enum update_status new;
-            int dontcare = 0;
+      for (du = file->deps; du != 0; du = du->next)
+        {
+          d = du->shuf ? du->shuf : du;
 
-            FILE_TIMESTAMP mtime = file_mtime (d->file);
-            check_renamed (d->file);
-            d->file->parent = file;
+          if (d->wait_here && running)
+            break;
 
-            /* Inherit dontcare flag from our parent. */
-            if (rebuilding_makefiles)
-              {
-                dontcare = d->file->dontcare;
-                d->file->dontcare = file->dontcare;
-              }
+          if (d->file->intermediate)
+            {
+              enum update_status new;
+              int dontcare = 0;
 
-            /* We may have already considered this file, when we didn't know
-               we'd need to update it.  Force update_file() to consider it and
-               not prune it.  */
-            d->file->considered = 0;
+              FILE_TIMESTAMP mtime = file_mtime (d->file);
+              check_renamed (d->file);
+              d->file->parent = file;
 
-            new = update_file (d->file, depth);
-            if (new > dep_status)
-              dep_status = new;
+              /* Inherit dontcare flag from our parent. */
+              if (rebuilding_makefiles)
+                {
+                  dontcare = d->file->dontcare;
+                  d->file->dontcare = file->dontcare;
+                }
 
-            /* Restore original dontcare flag. */
-            if (rebuilding_makefiles)
-              d->file->dontcare = dontcare;
+              /* We may have already considered this file, when we didn't know
+                 we'd need to update it.  Force update_file() to consider it and
+                 not prune it.  */
+              d->file->considered = 0;
 
-            check_renamed (d->file);
+              new = update_file (d->file, depth);
+              if (new > dep_status)
+                dep_status = new;
 
-            {
-              struct file *f = d->file;
-              if (f->double_colon)
-                f = f->double_colon;
-              do
-                {
-                  running |= (f->command_state == cs_running
-                              || f->command_state == cs_deps_running);
-                  f = f->prev;
-                }
-              while (f != 0);
-            }
+              /* Restore original dontcare flag. */
+              if (rebuilding_makefiles)
+                d->file->dontcare = dontcare;
 
-            if (dep_status && !keep_going_flag)
-              break;
+              check_renamed (d->file);
 
-            if (!running)
-              d->changed = ((file->phony && file->cmds != 0)
-                            || file_mtime (d->file) != mtime);
-          }
+              {
+                struct file *f = d->file;
+                if (f->double_colon)
+                  f = f->double_colon;
+                do
+                  {
+                    running |= (f->command_state == cs_running
+                                || f->command_state == cs_deps_running);
+                    f = f->prev;
+                  }
+                while (f != 0);
+              }
+
+              if (dep_status && !keep_going_flag)
+                break;
+
+              if (!running)
+                d->changed = ((file->phony && file->cmds != 0)
+                              || file_mtime (d->file) != mtime);
+            }
+        }
     }
 
   finish_updating (file);
@@ -678,7 +741,7 @@ update_file_1 (struct file *file, unsigned int depth)
       set_command_state (file, cs_deps_running);
       --depth;
       DBF (DB_VERBOSE, _("The prerequisites of '%s' are being made.\n"));
-      return 0;
+      return us_success;
     }
 
   /* If any dependency failed, give up now.  */
@@ -806,6 +869,10 @@ update_file_1 (struct file *file, unsigned int depth)
           fflush (stdout);
         }
 
+      /* Since make has not created this file, make should not remove it,
+         even if the file is intermediate. */
+      file->secondary = 1;
+
       notice_finished_file (file);
 
       /* Since we don't need to remake the file, convert it to use the
@@ -818,7 +885,7 @@ update_file_1 (struct file *file, unsigned int depth)
           file = file->prev;
         }
 
-      return 0;
+      return us_success;
     }
 
   DBF (DB_BASIC, _("Must remake target '%s'.\n"));
@@ -837,7 +904,7 @@ update_file_1 (struct file *file, unsigned int depth)
   if (file->command_state != cs_finished)
     {
       DBF (DB_VERBOSE, _("Recipe of '%s' is being run.\n"));
-      return 0;
+      return us_success;
     }
 
   switch (file->update_status)
@@ -972,23 +1039,30 @@ notice_finished_file (struct file *file)
     }
 
   if (ran && file->update_status != us_none)
-    /* We actually tried to update FILE, which has
-       updated its also_make's as well (if it worked).
-       If it didn't work, it wouldn't work again for them.
-       So mark them as updated with the same status.  */
-    for (d = file->also_make; d != 0; d = d->next)
-      {
-        d->file->command_state = cs_finished;
-        d->file->updated = 1;
-        d->file->update_status = file->update_status;
-
-        if (ran && !d->file->phony)
-          /* Fetch the new modification time.
-             We do this instead of just invalidating the cached time
-             so that a vpath_search can happen.  Otherwise, it would
-             never be done because the target is already updated.  */
-          f_mtime (d->file, 0);
-      }
+    {
+      /* We actually tried to update FILE, which has
+         updated its also_make's as well (if it worked).
+         If it didn't work, it wouldn't work again for them.
+         So mark them as updated with the same status.  */
+      for (d = file->also_make; d != 0; d = d->next)
+        {
+          d->file->command_state = cs_finished;
+          d->file->updated = 1;
+          d->file->update_status = file->update_status;
+
+          if (ran && !d->file->phony)
+            /* Fetch the new modification time.
+               We do this instead of just invalidating the cached time
+               so that a vpath_search can happen.  Otherwise, it would
+               never be done because the target is already updated.  */
+            f_mtime (d->file, 0);
+        }
+
+      /* If the target was created by an implicit rule, and it was updated,
+         warn about any of its also_make targets that don't exist.  */
+      if (file->tried_implicit && file->also_make)
+        check_also_make (file);
+    }
   else if (file->update_status == us_none)
     /* Nothing was done for FILE, but it needed nothing done.
        So mark it now as "succeeded".  */
@@ -1035,10 +1109,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
@@ -1077,6 +1148,12 @@ check_dep (struct file *file, unsigned int depth,
             }
 
           ld = 0;
+          /* Perform second expansion and enter each dependency name as a file.
+             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 (second_expansion)
+            expand_deps (file);
+
           d = file->deps;
           while (d != 0)
             {
@@ -1414,7 +1491,7 @@ f_mtime (struct file *file, int search)
                     / 1e9));
               char from_now_string[100];
 
-              if (from_now >= 99 && from_now <= ULONG_MAX)
+              if (from_now >= 100.0 && from_now < (double) ULONG_MAX)
                 sprintf (from_now_string, "%lu", (unsigned long) from_now);
               else
                 sprintf (from_now_string, "%.2g", from_now);
@@ -1466,12 +1543,16 @@ static FILE_TIMESTAMP
 name_mtime (const char *name)
 {
   FILE_TIMESTAMP mtime;
+#if defined(WINDOWS32)
+  struct STAT st;
+#else
   struct stat st;
+#endif
   int e;
 
 #if defined(WINDOWS32)
   {
-    char tem[MAXPATHLEN], *tstart, *tend;
+    char tem[MAX_PATH+1], *tstart, *tend;
     const char *p = name + strlen (name);
 
     /* Remove any trailing slashes and "."/"..".  MS-Windows stat
@@ -1489,7 +1570,7 @@ name_mtime (const char *name)
           tend--;
         if (*tend == '.' && tend > tstart)
           tend--;
-        for ( ; tend > tstart && (*tend == '/' || *tend == '\\'); tend--)
+        for ( ; tend > tstart && ISDIRSEP (*tend); tend--)
           *tend = '\0';
       }
     else
@@ -1498,7 +1579,11 @@ name_mtime (const char *name)
         tend = &tem[0];
       }
 
+#if defined(WINDOWS32)
+    e = STAT (tem, &st);
+#else
     e = stat (tem, &st);
+#endif
     if (e == 0 && !_S_ISDIR (st.st_mode) && tend < tem + (p - name - 1))
       {
         errno = ENOTDIR;
@@ -1563,7 +1648,7 @@ name_mtime (const char *name)
             mtime = ltime;
 
           /* Set up to check the file pointed to by this link.  */
-          EINTRLOOP (llen, readlink (lpath, lbuf, GET_PATH_MAX));
+          EINTRLOOP (llen, readlink (lpath, lbuf, GET_PATH_MAX - 1));
           if (llen < 0)
             {
               /* Eh?  Just take what we have.  */
@@ -1646,7 +1731,7 @@ library_search (const char *lib, FILE_TIMESTAMP *mtime_ptr)
       static size_t buflen = 0;
       static size_t libdir_maxlen = 0;
       static unsigned int std_dirs = 0;
-      char *libbuf = variable_expand ("");
+      char *libbuf;
 
       /* Expand the pattern using LIB as a replacement.  */
       {
@@ -1663,10 +1748,12 @@ library_search (const char *lib, FILE_TIMESTAMP *mtime_ptr)
             p[len] = c;
             continue;
           }
-        p4 = variable_buffer_output (libbuf, p, p3-p);
+        p4 = variable_buffer_output (variable_buffer, p, p3-p);
         p4 = variable_buffer_output (p4, lib, liblen);
         p4 = variable_buffer_output (p4, p3+1, len - (p3-p));
         p[len] = c;
+
+        libbuf = variable_buffer;
       }
 
       /* Look first for 'libNAME.a' in the current directory.  */