mirror of
https://github.com/mirror/make.git
synced 2025-03-28 13:00:47 +08:00
New variables, .VARIABLES and .TARGETS.
This commit is contained in:
parent
a56563badd
commit
bccb277dda
25
ChangeLog
25
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
|
||||
|
7
NEWS
7
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.)
|
||||
|
@ -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
|
||||
|
49
file.c
49
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 ()
|
||||
{
|
||||
|
@ -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) \
|
||||
|
4
main.c
4
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. */
|
||||
|
4
make.h
4
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
|
||||
|
95
variable.c
95
variable.c
@ -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;
|
||||
}
|
||||
|
||||
/* 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.
|
||||
@ -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:
|
||||
|
10
variable.h
10
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. */
|
||||
|
Loading…
Reference in New Issue
Block a user