New command line option: --eval=STRING will cause STRING to be
authorPaul Smith <psmith@gnu.org>
Sun, 25 Oct 2009 00:46:52 +0000 (00:46 +0000)
committerPaul Smith <psmith@gnu.org>
Sun, 25 Oct 2009 00:46:52 +0000 (00:46 +0000)
evaluated as a makefile statement before the first makefile is
read.

ChangeLog
NEWS
doc/make.texi
job.c
main.c
tests/scripts/options/eval [new file with mode: 0644]

index eceada6d645ae394e98fbb404a73cdeb96dd994d..b475f4f5b1a3c2759df044be5b28e3f3551a861c 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,31 @@
+2009-10-24  Paul Smith  <psmith@gnu.org>
+
+       * main.c (usage): Add --eval to the usage string.
+       (switches): Add the --eval switch.
+       (main): If --eval is given, add them to the simply-expanded variable
+       -*-eval-flags-*- (necessary to allow recursion to work properly).
+       (define_makeflags): Add -*-eval-flags-*- to MAKEFLAGS.
+
+       * NEWS: Describe the new --eval command line argument.
+       * doc/make.texi (Options Summary): Document --eval.
+
+       * dep.h: eval_buffer() returns void.
+       * read.c (eval_buffer): Ditto.
+       (eval): Ditto.
+
+       * variable.h (define_variable_cname): New macro for constant
+       variable names.
+       * default.c (set_default_suffixes): Use it.
+       * main.c (main): Ditto.
+       (handle_non_switch_argument): Ditto.
+       (define_makeflags): Ditto.
+       * read.c (read_all_makefiles): Ditto.
+       * variable.c (define_automatic_variables): Ditto.
+
+       * commands.c (dep_hash_cmp): Avoid casts.
+       (dep_hash_1): Ditto.
+       (dep_hash_2): Ditto.
+
 2009-10-22  Boris Kolpackov  <boris@codesynthesis.com>
 
        * read.c (read_all_makefiles): Mark the default makefile dependency
diff --git a/NEWS b/NEWS
index e6bac3697dd29dc29acaa1929f31472a7942db02..f05010579eda4e328aa925a8cd6fe7fa0c79c5ce 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -1,6 +1,6 @@
 GNU make NEWS                                               -*-indented-text-*-
   History of user-visible changes.
-  25 May 2009
+  12 Oct 2009
 
 See the end of this file for copyrights and conditions.
 
@@ -28,12 +28,17 @@ Version 3.81.90
   variable.
 
 * WARNING: Backward-incompatibility!
-  The pattern-specific variables and pattern rules are now applied in the 
+  The pattern-specific variables and pattern rules are now applied in the
   shortest stem first order instead of the definition order (variables
   and rules with the same stem length are still applied in the definition
   order). This produces the usually-desired behavior where more specific
   patterns are preferred. To detect this feature search for 'shortest-stem'
-  in the .FEATURES special variable.  
+  in the .FEATURES special variable.
+
+* New command line option: --eval=STRING causes STRING to be evaluated as
+  makefile syntax (akin to using the $(eval ...) function).  The evaluation is
+  performed after all default rules and variables are defined, but before any
+  makefiles are read.
 
 * New special variable: .RECIPEPREFIX allows you to reset the recipe
   introduction character from the default (TAB) to something else.  The first
@@ -47,16 +52,16 @@ Version 3.81.90
   prerequisites.  This is most useful for target- and pattern-specific
   variables.
 
+* New make directive: 'undefine' allows you to undefine a variable so
+  that it appears as if it was never set. Both $(flavor) and $(origin)
+  functions will return 'undefined' for such a variable. To detect this
+  feature search for 'undefine in the .FEATURES special variable.
+
 * The parser for variable assignments has been enhanced to allow multiple
   modifiers ('export', 'override', 'private') on the same line as variables,
   including define/endef variables, and in any order.  Also, it is possible
   to create variables and targets named as these modifiers.
 
-* New make directive: 'undefine' allows you to undefine a variable so
-  that it appears as if it was never set. Both $(flavor) and $(origin)
-  functions will return 'undefined' for such a variable. To detect this 
-  feature search for 'undefine in the .FEATURES special variable.
-
 \f
 Version 3.81
 
index 52a56ef50eef230e348569800204e5cb88d54e61..7a3be3b03d920deb1700e76f80897ef8cbbfe1be 100644 (file)
@@ -8127,6 +8127,15 @@ Give variables taken from the environment precedence
 over variables from makefiles.
 @xref{Environment, ,Variables from the Environment}.
 
+@item --eval=@var{string}
+@cindex @code{--eval}
+@c Extra blank line here makes the table look better.
+
+Evaluate @var{string} as makefile syntax.  This is a command-line
+version of the @code{eval} function (@pxref{Eval Function}).  The
+evaluation is performed after the default rules and variables have
+been defined, but before any makefiles are read.
+
 @item -f @var{file}
 @cindex @code{-f}
 @itemx --file=@var{file}
diff --git a/job.c b/job.c
index 54e17c4decee3fe499e20894b45bbc9a0591a5cf..a0e4d558d23d6d571b7919bb302a39b6d399158e 100644 (file)
--- a/job.c
+++ b/job.c
@@ -1,7 +1,7 @@
 /* Job execution and handling for GNU Make.
 Copyright (C) 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997,
-1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007 Free Software
-Foundation, Inc.
+1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 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
diff --git a/main.c b/main.c
index 4d84b6635367d5a0ff9d39eaace400f6fba58250..babf21d3e0ebff340795f2eb432461d500b7da6c 100644 (file)
--- a/main.c
+++ b/main.c
@@ -1,7 +1,7 @@
 /* Argument parsing and main program of GNU Make.
 Copyright (C) 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997,
-1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007 Free Software
-Foundation, Inc.
+1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 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
@@ -263,6 +263,9 @@ static struct stringlist *old_files = 0;
 
 static struct stringlist *new_files = 0;
 
+/* List of strings to be eval'd.  */
+static struct stringlist *eval_strings = 0;
+
 /* If nonzero, we should just print usage and exit.  */
 
 static int print_usage_flag = 0;
@@ -313,6 +316,8 @@ static const char *const usage[] =
   -e, --environment-overrides\n\
                               Environment variables override makefiles.\n"),
     N_("\
+  --eval=STRING               Evaluate STRING as a makefile statement.\n"),
+    N_("\
   -f FILE, --file=FILE, --makefile=FILE\n\
                               Read FILE as a makefile.\n"),
     N_("\
@@ -418,6 +423,7 @@ static const struct command_switch switches[] =
     { 'W', filename, &new_files, 0, 0, 0, 0, 0, "what-if" },
     { CHAR_MAX+5, flag, &warn_undefined_variables_flag, 1, 1, 0, 0, 0,
       "warn-undefined-variables" },
+    { CHAR_MAX+6, string, &eval_strings, 1, 0, 0, 0, 0, "eval" },
     { 0, 0, 0, 0, 0, 0, 0, 0, 0 }
   };
 
@@ -1114,15 +1120,15 @@ main (int argc, char **argv, char **envp)
 #endif
 
   /* Initialize the special variables.  */
-  define_variable (".VARIABLES", 10, "", o_default, 0)->special = 1;
-  /* define_variable (".TARGETS", 8, "", o_default, 0)->special = 1; */
-  define_variable (".RECIPEPREFIX", 13, "", o_default, 0)->special = 1;
+  define_variable_cname (".VARIABLES", "", o_default, 0)->special = 1;
+  /* define_variable_cname (".TARGETS", "", o_default, 0)->special = 1; */
+  define_variable_cname (".RECIPEPREFIX", "", o_default, 0)->special = 1;
 
   /* Set up .FEATURES */
-  define_variable (".FEATURES", 9,
-                   "target-specific order-only second-expansion else-if"
-                   "shortest-stem undefine",
-                   o_default, 0);
+  define_variable_cname (".FEATURES",
+                         "target-specific order-only second-expansion else-if"
+                         "shortest-stem undefine",
+                         o_default, 0);
 #ifndef NO_ARCHIVES
   do_variable_definition (NILF, ".FEATURES", "archives",
                           o_default, f_append, 0);
@@ -1204,9 +1210,8 @@ main (int argc, char **argv, char **envp)
      * either the first mispelled value or an empty string
      */
     if (!unix_path)
-      define_variable("PATH", 4,
-                      windows32_path ? windows32_path : "",
-                      o_env, 1)->export = v_export;
+      define_variable_cname ("PATH", windows32_path ? windows32_path : "",
+                             o_env, 1)->export = v_export;
 #endif
 #else /* For Amiga, read the ENV: device, ignoring all dirs */
     {
@@ -1248,7 +1253,9 @@ main (int argc, char **argv, char **envp)
      and we set the -p, -i and -e switches.  Doesn't seem quite right.  */
   decode_env_switches (STRING_SIZE_TUPLE ("MFLAGS"));
 #endif
+
   decode_switches (argc, argv, 0);
+
 #ifdef WINDOWS32
   if (suspend_flag) {
         fprintf(stderr, "%s (pid = %ld)\n", argv[0], GetCurrentProcessId());
@@ -1328,8 +1335,8 @@ main (int argc, char **argv, char **envp)
 
   /* The extra indirection through $(MAKE_COMMAND) is done
      for hysterical raisins.  */
-  (void) define_variable ("MAKE_COMMAND", 12, argv[0], o_default, 0);
-  (void) define_variable ("MAKE", 4, "$(MAKE_COMMAND)", o_default, 1);
+  define_variable_cname ("MAKE_COMMAND", argv[0], o_default, 0);
+  define_variable_cname ("MAKE", "$(MAKE_COMMAND)", o_default, 1);
 
   if (command_variables != 0)
     {
@@ -1367,8 +1374,7 @@ main (int argc, char **argv, char **envp)
 
       /* Define an unchangeable variable with a name that no POSIX.2
         makefile could validly use for its own variable.  */
-      (void) define_variable ("-*-command-variables-*-", 23,
-                             value, o_automatic, 0);
+      define_variable_cname ("-*-command-variables-*-", value, o_automatic, 0);
 
       /* Define the variable; this will not override any user definition.
          Normally a reference to this variable is written into the value of
@@ -1376,8 +1382,8 @@ main (int argc, char **argv, char **envp)
          exported value of MAKEFLAGS.  In POSIX-pedantic mode, we cannot
          allow the user's setting of MAKEOVERRIDES to affect MAKEFLAGS, so
          a reference to this hidden variable is written instead. */
-      (void) define_variable ("MAKEOVERRIDES", 13,
-                             "${-*-command-variables-*-}", o_env, 1);
+      define_variable_cname ("MAKEOVERRIDES", "${-*-command-variables-*-}",
+                             o_env, 1);
     }
 
   /* If there were -C flags, move ourselves about.  */
@@ -1464,7 +1470,7 @@ main (int argc, char **argv, char **envp)
        starting_directory = current_directory;
     }
 
-  (void) define_variable ("CURDIR", 6, current_directory, o_file, 0);
+  define_variable_cname ("CURDIR", current_directory, o_file, 0);
 
   /* Read any stdin makefiles into temporary files.  */
 
@@ -1604,7 +1610,37 @@ main (int argc, char **argv, char **envp)
 
   default_file = enter_file (strcache_add (".DEFAULT"));
 
-  default_goal_var = define_variable (".DEFAULT_GOAL", 13, "", o_file, 0);
+  default_goal_var = define_variable_cname (".DEFAULT_GOAL", "", o_file, 0);
+
+  /* Evaluate all strings provided with --eval.
+     Also set up the $(-*-eval-flags-*-) variable.  */
+
+  if (eval_strings)
+    {
+      char *p, *value;
+      unsigned int i;
+      unsigned int len = sizeof ("--eval=") * eval_strings->idx;
+
+      for (i = 0; i < eval_strings->idx; ++i)
+        {
+          p = xstrdup (eval_strings->list[i]);
+          len += 2 * strlen (p);
+          eval_buffer (p);
+          free (p);
+        }
+
+      p = value = alloca (len);
+      for (i = 0; i < eval_strings->idx; ++i)
+        {
+          strcpy (p, "--eval=");
+          p += strlen (p);
+          p = quote_for_env (p, eval_strings->list[i]);
+          *(p++) = ' ';
+        }
+      p[-1] = '\0';
+
+      define_variable_cname ("-*-eval-flags-*-", value, o_automatic, 0);
+    }
 
   /* Read all the makefiles.  */
 
@@ -2402,7 +2438,7 @@ handle_non_switch_argument (char *arg, int env)
             memcpy (&vp[oldlen + 1], f->name, newlen + 1);
             value = vp;
           }
-        define_variable ("MAKECMDGOALS", 12, value, o_default, 0);
+        define_variable_cname ("MAKECMDGOALS", value, o_default, 0);
       }
     }
 }
@@ -2504,8 +2540,16 @@ decode_switches (int argc, char **argv, int env)
                    optarg = xstrdup (cs->noarg_value);
                   else if (*optarg == '\0')
                     {
-                      error (NILF, _("the `-%c' option requires a non-empty string argument"),
-                             cs->c);
+                      char opt[2] = "c";
+                      const char *op = opt;
+
+                      if (short_option (cs->c))
+                        opt[0] = cs->c;
+                      else
+                        op = cs->long_name;
+
+                      error (NILF, _("the `%s%s' option requires a non-empty string argument"),
+                             short_option (cs->c) ? "-" : "--", op);
                       bad = 1;
                     }
 
@@ -2703,9 +2747,10 @@ quote_for_env (char *out, const char *in)
 static const char *
 define_makeflags (int all, int makefile)
 {
-  static const char ref[] = "$(MAKEOVERRIDES)";
-  static const char posixref[] = "$(-*-command-variables-*-)";
-  register const struct command_switch *cs;
+  const char ref[] = "$(MAKEOVERRIDES)";
+  const char posixref[] = "$(-*-command-variables-*-)";
+  const char evalref[] = "$(-*-eval-flags-*-)";
+  const struct command_switch *cs;
   char *flagstring;
   register char *p;
   unsigned int words;
@@ -2726,7 +2771,7 @@ define_makeflags (int all, int makefile)
   unsigned int flagslen = 0;
 #define        ADD_FLAG(ARG, LEN) \
   do {                                                                       \
-    struct flag *new = alloca (sizeof (struct flag));                         \
+    struct flag *new = alloca (sizeof (struct flag));                        \
     new->cs = cs;                                                            \
     new->arg = (ARG);                                                        \
     new->next = flags;                                                       \
@@ -2734,7 +2779,8 @@ define_makeflags (int all, int makefile)
     if (new->arg == 0)                                                       \
       ++flagslen;              /* Just a single flag letter.  */             \
     else                                                                     \
-      flagslen += 1 + 1 + 1 + 1 + 3 * (LEN); /* " -x foo" */                 \
+      /* " -x foo", plus space to expand "foo".  */                          \
+      flagslen += 1 + 1 + 1 + 1 + (3 * (LEN));                               \
     if (!short_option (cs->c))                                               \
       /* This switch has no single-letter version, so we use the long.  */    \
       flagslen += 2 + strlen (cs->long_name);                                \
@@ -2821,7 +2867,8 @@ define_makeflags (int all, int makefile)
          abort ();
        }
 
-  flagslen += 4 + sizeof posixref; /* Four more for the possible " -- ".  */
+  /* Four more for the possible " -- ".  */
+  flagslen += 4 + sizeof (posixref) + sizeof (evalref);
 
 #undef ADD_FLAG
 
@@ -2893,7 +2940,20 @@ define_makeflags (int all, int makefile)
 
   /* Since MFLAGS is not parsed for flags, there is no reason to
      override any makefile redefinition.  */
-  (void) define_variable ("MFLAGS", 6, flagstring, o_env, 1);
+  define_variable_cname ("MFLAGS", flagstring, o_env, 1);
+
+  /* Write a reference to -*-eval-flags-*-, which contains all the --eval
+     flag options.  */
+  if (eval_strings)
+    {
+      if (p == &flagstring[1])
+       /* No flags written, so elide the leading dash already written.  */
+       p = flagstring;
+      else
+        *p++ = ' ';
+      memcpy (p, evalref, sizeof (evalref) - 1);
+      p += sizeof (evalref) - 1;
+    }
 
   if (all && command_variables != 0)
     {
@@ -2920,13 +2980,13 @@ define_makeflags (int all, int makefile)
       /* Copy in the string.  */
       if (posix_pedantic)
        {
-         memcpy (p, posixref, sizeof posixref - 1);
-         p += sizeof posixref - 1;
+         memcpy (p, posixref, sizeof (posixref) - 1);
+         p += sizeof (posixref) - 1;
        }
       else
        {
-         memcpy (p, ref, sizeof ref - 1);
-         p += sizeof ref - 1;
+         memcpy (p, ref, sizeof (ref) - 1);
+         p += sizeof (ref) - 1;
        }
     }
   else if (p == &flagstring[1])
@@ -2945,14 +3005,14 @@ define_makeflags (int all, int makefile)
   if (flagstring[0] == '-' && flagstring[1] != '-')
     ++flagstring;
 
-  v = define_variable ("MAKEFLAGS", 9, flagstring,
-                      /* This used to use o_env, but that lost when a
-                         makefile defined MAKEFLAGS.  Makefiles set
-                         MAKEFLAGS to add switches, but we still want
-                         to redefine its value with the full set of
-                         switches.  Of course, an override or command
-                         definition will still take precedence.  */
-                      o_file, 1);
+  v = define_variable_cname ("MAKEFLAGS", flagstring,
+                             /* This used to use o_env, but that lost when a
+                                makefile defined MAKEFLAGS.  Makefiles set
+                                MAKEFLAGS to add switches, but we still want
+                                to redefine its value with the full set of
+                                switches.  Of course, an override or command
+                                definition will still take precedence.  */
+                             o_file, 1);
 
   if (! all)
     /* The first time we are called, set MAKEFLAGS to always be exported.
diff --git a/tests/scripts/options/eval b/tests/scripts/options/eval
new file mode 100644 (file)
index 0000000..06a035c
--- /dev/null
@@ -0,0 +1,19 @@
+#                                                                    -*-perl-*-
+
+$description = "Test the --eval option.";
+
+$details = "Verify that --eval options take effect,
+and are passed to sub-makes.";
+
+# Verify that --eval is evaluated first
+run_make_test(q!
+BAR = bar
+all: ; @echo all
+recurse: ; @$(MAKE) -f #MAKEFILE# && echo recurse!,
+              '--eval=\$\(info\ eval\) FOO=\$\(BAR\)', "eval\nall");
+
+# Make sure that --eval is handled correctly during recursion
+run_make_test(undef, '--no-print-directory --eval=\$\(info\ eval\) recurse',
+              "eval\neval\nall\nrecurse");
+
+1;