]> git.ipfire.org Git - thirdparty/make.git/commitdiff
[SV 35711] Check for special targets earlier
authorPaul Smith <psmith@gnu.org>
Fri, 27 Nov 2020 16:37:29 +0000 (11:37 -0500)
committerPaul Smith <psmith@gnu.org>
Sun, 29 Nov 2020 22:55:02 +0000 (17:55 -0500)
GNU make must recognize some special targets as they are defined.
Because of the way targets are defined, we were not recognizing these
special targets until we were handling the NEXT statement.  However
that's too late for some special targets such as .POSIX etc. which can
change the behavior of make during parsing.

Check for special targets earlier, as soon as we've finished parsing
the target introduction line (before we've even parsed the recipe).

* NEWS: Mention the change.
* src/read.c (check_specials): New function to look for special
targets.  Move checks from eval() and record_files() to this new
function.
(eval): Call check_specials() after we've completed parsing the target
introduction line.  Move default goal detection to check_specials().
(record_files): Move handling of .POSIX, .SECONDEXPANSION, and
.ONESHELL to check_specials().
* tests/scripts/misc/bs-nl: Remove workaround for late .POSIX issue.
* tests/scripts/targets/POSIX: Add a comment.

NEWS
src/read.c
tests/scripts/misc/bs-nl
tests/scripts/targets/POSIX

diff --git a/NEWS b/NEWS
index 95909582c62e73500030efbc9b697ef8c93c618e..bf6857f23911051e63096187a131e13ba6947e8d 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -34,6 +34,9 @@ https://sv.gnu.org/bugs/index.php?group=make&report_id=111&fix_release_id=109&se
   https://www.gnu.org/software/gnulib/manual/html_node/C99-features-assumed.html
   The configure script should verify the compiler has these features.
 
+* Special targets like .POSIX are detected upon definition, ensuring that any
+  change in behavior takes effect immediately, before the next line is parsed.
+
 * GNU Make can now be built for MS-Windows using the Tiny C tcc compiler.
 
 \f
index c55998c3dc7798dbc7be4bb605a9a50cfaecdd70..57903bc89cebc707fc309be9690925f35177c2b6 100644 (file)
@@ -142,6 +142,7 @@ static void do_undefine (char *name, enum variable_origin origin,
 static struct variable *do_define (char *name, enum variable_origin origin,
                                    struct ebuffer *ebuf);
 static int conditional_line (char *line, size_t len, const floc *flocp);
+static void check_specials (const struct nameseq *file, int set_default);
 static void record_files (struct nameseq *filenames, int are_also_makes,
                           const char *pattern,
                           const char *pattern_percent, char *depstr,
@@ -1313,79 +1314,7 @@ eval (struct ebuffer *ebuf, int set_default)
             commands[commands_idx++] = '\n';
           }
 
-        /* Determine if this target should be made default. We used to do
-           this in record_files() but because of the delayed target recording
-           and because preprocessor directives are legal in target's commands
-           it is too late. Consider this fragment for example:
-
-           foo:
-
-           ifeq ($(.DEFAULT_GOAL),foo)
-              ...
-           endif
-
-           Because the target is not recorded until after ifeq directive is
-           evaluated the .DEFAULT_GOAL does not contain foo yet as one
-           would expect. Because of this we have to move the logic here.  */
-
-        if (set_default && default_goal_var->value[0] == '\0')
-          {
-            struct dep *d;
-            struct nameseq *t = filenames;
-
-            for (; t != 0; t = t->next)
-              {
-                int reject = 0;
-                const char *name = t->name;
-
-                /* We have nothing to do if this is an implicit rule. */
-                if (strchr (name, '%') != 0)
-                  break;
-
-                /* See if this target's name does not start with a '.',
-                   unless it contains a slash.  */
-                if (*name == '.' && strchr (name, '/') == 0
-#ifdef HAVE_DOS_PATHS
-                    && strchr (name, '\\') == 0
-#endif
-                    )
-                  continue;
-
-
-                /* If this file is a suffix, don't let it be
-                   the default goal file.  */
-                for (d = suffix_file->deps; d != 0; d = d->next)
-                  {
-                    struct dep *d2;
-                    if (*dep_name (d) != '.' && streq (name, dep_name (d)))
-                      {
-                        reject = 1;
-                        break;
-                      }
-                    for (d2 = suffix_file->deps; d2 != 0; d2 = d2->next)
-                      {
-                        size_t l = strlen (dep_name (d2));
-                        if (!strneq (name, dep_name (d2), l))
-                          continue;
-                        if (streq (name + l, dep_name (d)))
-                          {
-                            reject = 1;
-                            break;
-                          }
-                      }
-
-                    if (reject)
-                      break;
-                  }
-
-                if (!reject)
-                  {
-                    define_variable_global (".DEFAULT_GOAL", 13, t->name,
-                                            o_file, 0, NILF);
-                    break;
-                  }
-              }
-          }
+        check_specials (filenames, set_default);
       }
     }
 
@@ -1926,6 +1855,107 @@ record_target_var (struct nameseq *filenames, char *defn,
     }
 }
 \f
+
+/* Check for special targets.  We used to do this in record_files() but that's
+   too late: by the time we get there we'll have already parsed the next line
+   and it have been mis-parsed because these special targets haven't been
+   considered yet.  */
+
+static void check_specials (const struct nameseq* files, int set_default)
+{
+  const struct nameseq *t = files;
+
+  /* Unlikely but ...  */
+  if (posix_pedantic && second_expansion && one_shell
+      && (!set_default || default_goal_var->value[0] == '\0'))
+    return;
+
+  for (; t != 0; t = t->next)
+    {
+      const char* nm = t->name;
+
+      if (!posix_pedantic && streq (nm, ".POSIX"))
+        {
+          posix_pedantic = 1;
+          define_variable_cname (".SHELLFLAGS", "-ec", o_default, 0);
+          /* These default values are based on IEEE Std 1003.1-2008.
+             It requires '-O 1' for [CF]FLAGS, but GCC doesn't allow
+             space between -O and the number so omit it here.  */
+          define_variable_cname ("ARFLAGS", "-rv", o_default, 0);
+          define_variable_cname ("CC", "c99", o_default, 0);
+          define_variable_cname ("CFLAGS", "-O1", o_default, 0);
+          define_variable_cname ("FC", "fort77", o_default, 0);
+          define_variable_cname ("FFLAGS", "-O1", o_default, 0);
+          define_variable_cname ("SCCSGETFLAGS", "-s", o_default, 0);
+          continue;
+        }
+
+      if (!second_expansion && streq (nm, ".SECONDEXPANSION"))
+        {
+          second_expansion = 1;
+          continue;
+        }
+
+#if !defined (__MSDOS__) && !defined (__EMX__)
+      if (!one_shell && streq (nm, ".ONESHELL"))
+        {
+          one_shell = 1;
+          continue;
+        }
+#endif
+
+      /* Determine if this target should be made default.  */
+
+      if (set_default && default_goal_var->value[0] == '\0')
+        {
+          struct dep *d;
+          int reject = 0;
+
+          /* We have nothing to do if this is an implicit rule. */
+          if (strchr (nm, '%') != 0)
+            break;
+
+          /* See if this target's name does not start with a '.',
+             unless it contains a slash.  */
+          if (*nm == '.' && strchr (nm, '/') == 0
+#ifdef HAVE_DOS_PATHS
+              && strchr (nm, '\\') == 0
+#endif
+              )
+            continue;
+
+          /* If this file is a suffix, it can't be the default goal file.  */
+          for (d = suffix_file->deps; d != 0; d = d->next)
+            {
+              struct dep *d2;
+              if (*dep_name (d) != '.' && streq (nm, dep_name (d)))
+                {
+                  reject = 1;
+                  break;
+                }
+              for (d2 = suffix_file->deps; d2 != 0; d2 = d2->next)
+                {
+                  size_t l = strlen (dep_name (d2));
+                  if (!strneq (nm, dep_name (d2), l))
+                    continue;
+                  if (streq (nm + l, dep_name (d)))
+                    {
+                      reject = 1;
+                      break;
+                    }
+                }
+
+              if (reject)
+                break;
+            }
+
+          if (!reject)
+            define_variable_global (".DEFAULT_GOAL", 13, t->name,
+                                    o_file, 0, NILF);
+        }
+    }
+}
+\f
 /* Record a description line for files FILENAMES,
    with dependencies DEPS, commands to execute described
    by COMMANDS and COMMANDS_IDX, coming from FILENAME:COMMANDS_STARTED.
@@ -2067,29 +2097,6 @@ record_files (struct nameseq *filenames, int are_also_makes,
 
       free_ns (filenames);
 
-      /* Check for special targets.  Do it here instead of, say, snap_deps()
-         so that we can immediately use the value.  */
-      if (!posix_pedantic && streq (name, ".POSIX"))
-        {
-          posix_pedantic = 1;
-          define_variable_cname (".SHELLFLAGS", "-ec", o_default, 0);
-          /* These default values are based on IEEE Std 1003.1-2008.
-             It requires '-O 1' for [CF]FLAGS, but GCC doesn't allow space
-             between -O and the number so omit it here.  */
-          define_variable_cname ("ARFLAGS", "-rv", o_default, 0);
-          define_variable_cname ("CC", "c99", o_default, 0);
-          define_variable_cname ("CFLAGS", "-O1", o_default, 0);
-          define_variable_cname ("FC", "fort77", o_default, 0);
-          define_variable_cname ("FFLAGS", "-O1", o_default, 0);
-          define_variable_cname ("SCCSGETFLAGS", "-s", o_default, 0);
-        }
-      else if (!second_expansion && streq (name, ".SECONDEXPANSION"))
-        second_expansion = 1;
-#if !defined (__MSDOS__) && !defined (__EMX__)
-      else if (!one_shell && streq (name, ".ONESHELL"))
-        one_shell = 1;
-#endif
-
       /* If this is a static pattern rule:
          'targets: target%pattern: prereq%pattern; recipe',
          make sure the pattern matches this target name.  */
index fdf4aabcb76f06d68f15684dec28e8e1bab9629e..e8ba046732a9955f3826f71ffaed44d7983e70b3 100644 (file)
@@ -88,7 +88,6 @@ var:;@echo '|$(var)|'!,
 # POSIX: Preserve trailing space
 run_make_test(q!
 .POSIX:
-x = y
 var = he  \
 llo
 var:;@echo '|$(var)|'!,
@@ -97,7 +96,6 @@ var:;@echo '|$(var)|'!,
 # POSIX: One space per bs-nl
 run_make_test(q!
 .POSIX:
-x = y
 var = he\
 \
 \
index d69b8bbdabb3931c566d8db599ebb19d6a90526d..c40b8dbe48693e2ba78a0b895f94e19d2f2f9150 100644 (file)
@@ -20,6 +20,8 @@ all: ; \@$script
               '', "#MAKE#: *** [#MAKEFILE#:3: all] Error $err\n", 512);
 
 # User settings must override .POSIX
+# In the standard .POSIX must be the first thing in the makefile
+# but we relax that rule in GNU make.
 $flags = '-xc';
 $out = `$sh_name $flags '$script' 2>&1`;
 run_make_test(qq!