summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPaul Smith <psmith@gnu.org>2002-08-01 13:16:57 +0000
committerPaul Smith <psmith@gnu.org>2002-08-01 13:16:57 +0000
commitbccb277dda1a4dcc6729824a7c9d544086f147c3 (patch)
tree693bb06d69dd6e4829d8d1b1d339a694ff162ad3
parenta56563badd9b3cab2624c35f3a8104a3bb3b5f52 (diff)
downloadgunmake-bccb277dda1a4dcc6729824a7c9d544086f147c3.tar.gz
New variables, .VARIABLES and .TARGETS.
-rw-r--r--ChangeLog25
-rw-r--r--NEWS7
-rw-r--r--doc/make.texi36
-rw-r--r--file.c49
-rw-r--r--filedef.h1
-rw-r--r--main.c4
-rw-r--r--make.h4
-rw-r--r--variable.c95
-rw-r--r--variable.h10
9 files changed, 210 insertions, 21 deletions
diff --git a/ChangeLog b/ChangeLog
index 48adc23..0567746 100644
--- 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 724458b..bd4af15 100644
--- 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.)
diff --git a/doc/make.texi b/doc/make.texi
index 9a13b78..291a294 100644
--- a/doc/make.texi
+++ b/doc/make.texi
@@ -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 cfb11bb..ecb83d8 100644
--- 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 ()
{
diff --git a/filedef.h b/filedef.h
index 7ee2902..b7d6e67 100644
--- 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 7079e01..10d6124 100644
--- 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 c69bd96..44d7b39 100644
--- 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
diff --git a/variable.c b/variable.c
index 5495fbc..7f55f8f 100644
--- a/variable.c
+++ b/variable.c
@@ -157,9 +157,87 @@ 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;
}
+/* 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;
+}
+
+
/* Lookup a variable whose name is a string starting at NAME
and with LENGTH chars. NAME need not be null-terminated.
Returns address of the `struct variable' containing all info
@@ -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:
diff --git a/variable.h b/variable.h
index 806f9e1..15661b5 100644
--- a/variable.h
+++ b/variable.h
@@ -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. */