New variables, .VARIABLES and .TARGETS.
authorPaul Smith <psmith@gnu.org>
Thu, 1 Aug 2002 13:16:57 +0000 (13:16 +0000)
committerPaul Smith <psmith@gnu.org>
Thu, 1 Aug 2002 13:16:57 +0000 (13:16 +0000)
ChangeLog
NEWS
doc/make.texi
file.c
filedef.h
main.c
make.h
variable.c
variable.h

index 48adc238ad2e06b7e10f3f3f3def942336b9a4a9..0567746c8015a712a6a5b668c055bfff7b30840b 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,28 @@
+2002-08-01  Paul D. Smith  <psmith@gnu.org>
+
+       Add new introspection variables .VARIABLES and .TARGETS.
+
+       * variable.c (handle_special_var): New function.  If the variable
+       reference passed in is "special" (.VARIABLES or .TARGETS),
+       calculate the new value if necessary.  .VARIABLES is handled here:
+       walk through the hash of defined variables and construct a value
+       which is a list of the names.  .TARGETS is handled by
+       build_target_list().
+       (lookup_variable): Invoke handle_special_var().
+       * file.c (build_target_list): Walk through the hask of known files
+       and construct a list of the names of all the ones marked as
+       targets.
+       * main.c (main): Initialize them to empty (and as simple variables).
+       * doc/make.texi (Special Variables): Document them.
+       * NEWS: Mention them.
+
+       * variable.h (struct variable): Add a new flag "exportable" which
+       is true if the variable name is valid for export.
+       * variable.c (define_variable_in_set): Set "exportable" when a new
+       variable is defined.
+       (target_environment): Use the "exportable" flag instead of
+       re-checking the name here... an efficiency improvement.
+
 2002-07-10  Paul D. Smith  <psmith@gnu.org>
 
        * variable.c (pop_variable_scope): Remove variable made unused by
diff --git a/NEWS b/NEWS
index 724458ba4724c7792eb1b5f502a31c1a745ae50c..bd4af15018c9649248343e0b0c95ecf48346e86e 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -26,7 +26,7 @@ Version 3.80
   This syntax is only valid within explicit and static pattern rules: it
   cannot be used in implicit (suffix or pattern) rules.  Edouard G. Parmelan
   <egp@free.fr> provided a patch implementing this feature; however, I
-  decided to implemented it myself in a different way.
+  decided to implemented it in a different way.
 
 * A new function is defined: $(quote ...).  The argument to this
   function is the _name_ of a variable.  The result of the function is
@@ -44,6 +44,11 @@ Version 3.80
   list when a makefile is just being read (before any includes) is the
   name of the current makefile.
 
+* GNU make now supports some simple introspection capability: two new
+  built-in variables are defined: $(.VARIABLES) and $(.TARGETS).  These
+  expand to a complete list of variables and targets, respectively,
+  defined by all makefiles at the time the variables are expanded.
+
 * The arguments to $(call ...) functions were being stored in $1, $2,
   etc. as recursive variables, even though they are fully expanded
   before assignment.  This means that escaped dollar signs ($$ etc.)
index 9a13b78359803f29f6c783ccc4d38fc8c1b2a49b..291a2949a9f1b46fbfcbe75a9a0b41c010828b97 100644 (file)
@@ -149,6 +149,7 @@ Writing Makefiles
 * Include::                     How one makefile can use another makefile.
 * MAKEFILES Variable::          The environment can specify extra makefiles.
 * MAKEFILE_LIST Variable::      Discover which makefiles have been read.
+* Special Variables::           Other special variables.
 * Remaking Makefiles::          How makefiles get remade.
 * Overriding Makefiles::        How to override part of one makefile
                                   with another makefile.
@@ -929,6 +930,7 @@ reading a data base called the @dfn{makefile}.
 * Include::                     How one makefile can use another makefile.
 * MAKEFILES Variable::          The environment can specify extra makefiles.
 * MAKEFILE_LIST Variable::      Discover which makefiles have been read.
+* Special Variables::           Other special variables.
 * Remaking Makefiles::          How makefiles get remade.
 * Overriding Makefiles::        How to override part of one makefile
                                   with another makefile.
@@ -1184,7 +1186,7 @@ This is a very bad idea, because such makefiles will fail to work if run by
 anyone else.  It is much better to write explicit @code{include} directives
 in the makefiles.  @xref{Include, , Including Other Makefiles}.
 
-@node MAKEFILE_LIST Variable, Remaking Makefiles, MAKEFILES Variable, Makefiles
+@node MAKEFILE_LIST Variable, Special Variables, MAKEFILES Variable, Makefiles
 @comment  node-name,  next,  previous,  up
 @section The Variable @code{MAKEFILE_LIST}
 @cindex makefiles, and @code{MAKEFILE_LIST} variable
@@ -1232,7 +1234,37 @@ name2 = inc.mk
 Variables}, for more information on simply-expanded (@code{:=})
 variable definitions.
 
-@node Remaking Makefiles, Overriding Makefiles, MAKEFILE_LIST Variable, Makefiles
+@node Special Variables, Remaking Makefiles, MAKEFILE_LIST Variable, Makefiles
+@comment  node-name,  next,  previous,  up
+@section Other Special Variables
+@cindex makefiles, and special variables
+@cindex special variables
+
+GNU @code{make} also supports two other special variables.  Note that
+any value you assign to these variables will be ignored; they will
+always return their special value.
+
+@vindex $(.VARIABLES)
+@vindex .VARIABLES @r{(list of variables)}
+The first special variable is @code{.VARIABLES}.  When expanded, the
+value consists of a list of the @emph{names} of all global variables
+defined in all makefiles read up until that point.  This includes
+variables which have empty values, as well as built-in variables
+(@pxref{Implicit Variables, , Variables Used by Implicit Rules}), but
+does not include any variables which are only defined in a
+target-specific context.
+
+@vindex $(.TARGETS)
+@vindex .TARGETS @r{(list of targets)}
+The second special variable is @code{.TARGETS}.  When expanded, the
+value consists of a list of all targets defined in all makefiles read
+up until that point.  Note it's not enough for a file to be simply
+mentioned in the makefile to be listed in this variable, even if it
+would match an implicit rule and become an ``implicit target''.  The
+file must appear as a target, on the left-hand side of a ``:'', to be
+considered a target for the purposes of this variable.
+
+@node Remaking Makefiles, Overriding Makefiles, Special Variables, Makefiles
 @section How Makefiles Are Remade
 
 @cindex updating makefiles
diff --git a/file.c b/file.c
index cfb11bb3d3bc2e624d8ab0e045ec62b4d13f5292..ecb83d8978f139f6e1c2a8cb3ab4e7076fb71082 100644 (file)
--- a/file.c
+++ b/file.c
@@ -765,6 +765,55 @@ print_file_data_base ()
   hash_print_stats (&files, stdout);
 }
 
+#define EXPANSION_INCREMENT(_l)  ((((_l) / 500) + 1) * 500)
+
+char *
+build_target_list (value)
+     char *value;
+{
+  static unsigned long last_targ_count = 0;
+
+  if (files.ht_fill != last_targ_count)
+    {
+      unsigned long max = EXPANSION_INCREMENT (strlen (value));
+      unsigned long len;
+      char *p;
+      struct file **fp = (struct file **) files.ht_vec;
+      struct file **end = &fp[files.ht_size];
+
+      /* Make sure we have at least MAX bytes in the allocated buffer.  */
+      value = xrealloc (value, max);
+
+      p = value;
+      len = 0;
+      for (; fp < end; ++fp)
+        if (!HASH_VACANT (*fp) && (*fp)->is_target)
+          {
+            struct file *f = *fp;
+            int l = strlen (f->name);
+
+            len += l + 1;
+            if (len > max)
+              {
+                unsigned long off = p - value;
+
+                max += EXPANSION_INCREMENT (l + 1);
+                value = xrealloc (value, max);
+                p = &value[off];
+              }
+
+            bcopy (f->name, p, l);
+            p += l;
+            *(p++) = ' ';
+          }
+      *(p-1) = '\0';
+
+      last_targ_count = files.ht_fill;
+    }
+
+  return value;
+}
+
 void
 init_hash_files ()
 {
index 7ee29029b41d781367c5d6e23cef48185854854d..b7d6e6769da0d4d6fe879e64270da65751de5374 100644 (file)
--- a/filedef.h
+++ b/filedef.h
@@ -111,6 +111,7 @@ extern void rehash_file PARAMS ((struct file *file, char *name));
 extern void set_command_state PARAMS ((struct file *file, int state));
 extern void notice_finished_file PARAMS ((struct file *file));
 extern void init_hash_files PARAMS ((void));
+extern char *build_target_list PARAMS ((char *old_list));
 
 #if FILE_TIMESTAMP_HI_RES
 # define FILE_TIMESTAMP_STAT_MODTIME(fname, st) \
diff --git a/main.c b/main.c
index 7079e01a475ba1060623a9733b2470cda836e9de..10d6124406e8bc2a829d8e81c18da5fc47a92585 100644 (file)
--- a/main.c
+++ b/main.c
@@ -988,6 +988,10 @@ int main (int argc, char ** argv)
   atexit (msdos_return_to_initial_directory);
 #endif
 
+  /* Initialize the special variables.  */
+  define_variable (".VARIABLES", 10, "", o_default, 0);
+  define_variable (".TARGETS", 8, "", o_default, 0);
+
   /* Read in variables from the environment.  It is important that this be
      done before $(MAKE) is figured out so its definitions will not be
      from the environment.  */
diff --git a/make.h b/make.h
index c69bd96da9a264e966cf8ea044410510cf601aac..44d7b3974a5318593985f611dc3ce7f61d8ed7c0 100644 (file)
--- a/make.h
+++ b/make.h
@@ -297,10 +297,10 @@ extern char *strsignal PARAMS ((int signum));
    - It's guaranteed to evaluate its argument exactly once.
       NOTE!  Make relies on this behavior, don't change it!
    - It's typically faster.
-   Posix 1003.2-1992 section 2.5.2.1 page 50 lines 1556-1558 says that
+   POSIX 1003.2-1992 section 2.5.2.1 page 50 lines 1556-1558 says that
    only '0' through '9' are digits.  Prefer ISDIGIT to isdigit() unless
    it's important to use the locale's definition of `digit' even when the
-   host does not conform to Posix.  */
+   host does not conform to POSIX.  */
 #define ISDIGIT(c) ((unsigned) (c) - '0' <= 9)
 
 #ifndef iAPX286
index 5495fbc231a7e9e60be9d2243031c70abb21ed44..7f55f8feae6841f5e94893497fcc30c9b627e645 100644 (file)
@@ -157,8 +157,86 @@ define_variable_in_set (name, length, value, origin, recursive, set, flocp)
   v->append = 0;
   v->export = v_default;
 
+  v->exportable = 1;
+  if (*name != '_' && (*name < 'A' || *name > 'Z')
+      && (*name < 'a' || *name > 'z'))
+    v->exportable = 0;
+  else
+    {
+      for (++name; *name != '\0'; ++name)
+        if (*name != '_' && (*name < 'a' || *name > 'z')
+            && (*name < 'A' || *name > 'Z') && !ISDIGIT(*name))
+          break;
+
+      if (*name != '\0')
+        v->exportable = 0;
+    }
+
   return v;
 }
+\f
+/* If the variable passed in is "special", handle its special nature.
+   Currently there are two such variables, both used for introspection:
+   .MAKE_VARS expands to a list of all the variables defined in this instance
+   of make.
+   .MAKE_TARGETS expands to a list of all the targets defined in this
+   instance of make.
+   Returns the variable reference passed in.  */
+
+#define EXPANSION_INCREMENT(_l)  ((((_l) / 500) + 1) * 500)
+
+static struct variable *
+handle_special_var (var)
+     struct variable *var;
+{
+  static unsigned long last_var_count = 0;
+
+
+  if (streq (var->name, ".MAKE_TARGETS"))
+    var->value = build_target_list (var->value);
+
+  else if (streq (var->name, ".MAKE_VARS")
+      && global_variable_set.table.ht_fill != last_var_count)
+    {
+      unsigned long max = EXPANSION_INCREMENT (strlen (var->value));
+      unsigned long len;
+      char *p;
+      struct variable **vp = (struct variable **) global_variable_set.table.ht_vec;
+      struct variable **end = &vp[global_variable_set.table.ht_size];
+
+      /* Make sure we have at least MAX bytes in the allocated buffer.  */
+      var->value = xrealloc (var->value, max);
+
+      p = var->value;
+      len = 0;
+      for (; vp < end; ++vp)
+        if (!HASH_VACANT (*vp))
+          {
+            struct variable *v = *vp;
+            int l = v->length;
+
+            len += l + 1;
+            if (len > max)
+              {
+                unsigned long off = p - var->value;
+
+                max += EXPANSION_INCREMENT (l + 1);
+                var->value = xrealloc (var->value, max);
+                p = &var->value[off];
+              }
+
+            bcopy (v->name, p, l);
+            p += l;
+            *(p++) = ' ';
+          }
+      *(p-1) = '\0';
+
+      last_var_count = global_variable_set.table.ht_fill;
+    }
+
+  return var;
+}
+
 \f
 /* Lookup a variable whose name is a string starting at NAME
    and with LENGTH chars.  NAME need not be null-terminated.
@@ -184,7 +262,7 @@ lookup_variable (name, length)
 
       v = (struct variable *) hash_find_item ((struct hash_table *) &set->table, &var_key);
       if (v)
-       return v;
+       return handle_special_var (v);
     }
 
 #ifdef VMS
@@ -570,7 +648,6 @@ target_environment (file)
          {
            struct variable **new_slot;
            struct variable *v = *v_slot;
-           char *p = v->name;
 
            /* If this is a per-target variable and it hasn't been touched
               already then look up the global version and take its export
@@ -592,20 +669,14 @@ target_environment (file)
                  /* Only export default variables by explicit request.  */
                  continue;
 
+                /* The variable doesn't have a name that can be exported.  */
+                if (! v->exportable)
+                  continue;
+
                if (! export_all_variables
                    && v->origin != o_command
                    && v->origin != o_env && v->origin != o_env_override)
                  continue;
-
-               if (*p != '_' && (*p < 'A' || *p > 'Z')
-                    && (*p < 'a' || *p > 'z'))
-                 continue;
-               for (++p; *p != '\0'; ++p)
-                 if (*p != '_' && (*p < 'a' || *p > 'z')
-                     && (*p < 'A' || *p > 'Z') && (*p < '0' || *p > '9'))
-                   continue;
-               if (*p != '\0')
-                 continue;
                break;
 
              case v_export:
index 806f9e11928a58400055fb8c1dd59fdb51437e16..15661b587473d2f6370d658140ba88f3eb6990bc 100644 (file)
@@ -57,17 +57,19 @@ struct variable
     char *value;               /* Variable value.  */
     struct floc fileinfo;       /* Where the variable was defined.  */
     unsigned int recursive:1;  /* Gets recursively re-evaluated.  */
-    unsigned int expanding:1;  /* Nonzero if currently being expanded.  */
-    unsigned int exp_count:EXP_COUNT_BITS;
-                                /* If >1, allow this many self-referential
-                                   expansions */
     unsigned int per_target:1; /* Nonzero if a target-specific variable.  */
     unsigned int append:1;     /* Nonzero if an appending target-specific
                                    variable.  */
+    unsigned int expanding:1;  /* Nonzero if currently being expanded.  */
+    unsigned int exp_count:EXP_COUNT_BITS;
+                                /* If >1, allow this many self-referential
+                                   expansions.  */
 
     enum variable_origin
       origin ENUM_BITFIELD (3);        /* Variable origin.  */
 
+    unsigned int exportable:1;  /* Nonzero if the variable _could_ be
+                                   exported.  */
     enum variable_export
       {
        v_export,               /* Export this variable.  */