[SV 45728] Detect changes in .VARIABLES more accurately.

For performance, we only recompute .VARIABLES when (a) it's expanded
and (b) when its value will change from a previous expansion.  To
determine (b) we were checking the number of entries in the hash
table which used to work until we started undefining entries: now if
you undefine and redefine the same number of entries in between
expanding .VARIABLES, it doesn't detect any change.  Instead, keep
an increasing change number.
* variables.c: Add variable_changenum.
(define_variable_in_set, merge_variable_sets): Increment
variable_changenum if adding a new variable to the global set.
(undefine_variable_in_set): Increment variable_changenum if
undefining a variable from the global set.
(lookup_special_var): Test variable_changenum not the hash table.
* tests/scripts/variables/special: Test undefining variables.
This commit is contained in:
Paul Smith 2016-03-13 18:13:00 -04:00
parent 247b71e690
commit 9ae02b7916
2 changed files with 49 additions and 32 deletions

View file

@ -14,14 +14,22 @@ X2 := $(sort $(filter FOO BAR,$(.VARIABLES)))
BAR := bar BAR := bar
all: all: ; @echo X1 = $(X1); echo X2 = $(X2); echo LAST = $(sort $(filter FOO BAR,$(.VARIABLES)))
@echo X1 = $(X1)
@echo X2 = $(X2)
@echo LAST = $(sort $(filter FOO BAR,$(.VARIABLES)))
', ',
'', "X1 =\nX2 = FOO\nLAST = BAR FOO\n"); '', "X1 =\nX2 = FOO\nLAST = BAR FOO\n");
# SV 45728: Test that undefining a variable is reflected properly
&run_make_test('
FOO := foo
BAR := bar
$(info one: $(sort $(filter FOO BAR BAZ,$(.VARIABLES))))
undefine BAR
BAZ := baz
$(info two: $(sort $(filter FOO BAR BAZ,$(.VARIABLES))))
all:;@:
',
'', "one: BAR FOO\ntwo: BAZ FOO\n");
# $makefile2 = &get_tmpfile; # $makefile2 = &get_tmpfile;
# open(MAKEFILE, "> $makefile2"); # open(MAKEFILE, "> $makefile2");
@ -31,9 +39,9 @@ all:
# X1 := $(sort $(.TARGETS)) # X1 := $(sort $(.TARGETS))
# all: foo # all: foo
# @echo X1 = $(X1) # @echo X1 = $(X1)
# @echo X2 = $(X2) # @echo X2 = $(X2)
# @echo LAST = $(sort $(.TARGETS)) # @echo LAST = $(sort $(.TARGETS))
# X2 := $(sort $(.TARGETS)) # X2 := $(sort $(.TARGETS))
@ -56,16 +64,16 @@ define foo
: foo-one\ : foo-one\
foo-two foo-two
: foo-three : foo-three
: foo-four : foo-four
endef endef
orig: ; : orig-one orig: ; : orig-one
: orig-two \ : orig-two \
orig-three \ orig-three \
orig-four \ orig-four \
orig-five \\\\ orig-five \\\\
: orig-six : orig-six
$(foo) $(foo)
.RECIPEPREFIX = > .RECIPEPREFIX = >
test: ; : test-one test: ; : test-one
@ -78,19 +86,19 @@ test-three \
.RECIPEPREFIX = .RECIPEPREFIX =
reset: ; : reset-one reset: ; : reset-one
: reset-two \ : reset-two \
reset-three \ reset-three \
reset-four \ reset-four \
reset-five \\\\ reset-five \\\\
: reset-six : reset-six
$(foo) $(foo)
', ',
'orig test reset', 'orig test reset',
': orig-one ': orig-one
: orig-two \ : orig-two \
orig-three \ orig-three \
orig-four \ orig-four \
orig-five \\\\ orig-five \\\\
: orig-six : orig-six
: foo-one foo-two : foo-one foo-two
: foo-three : foo-three
@ -99,7 +107,7 @@ orig-four \
: test-two \ : test-two \
test-three \ test-three \
test-four \ test-four \
test-five \\\\ test-five \\\\
: test-six : test-six
: foo-one foo-two : foo-one foo-two
: foo-three : foo-three
@ -108,7 +116,7 @@ test-four \
: reset-two \ : reset-two \
reset-three \ reset-three \
reset-four \ reset-four \
reset-five \\\\ reset-five \\\\
: reset-six : reset-six
: foo-one foo-two : foo-one foo-two
: foo-three : foo-three

View file

@ -29,6 +29,9 @@ this program. If not, see <http://www.gnu.org/licenses/>. */
#endif #endif
#include "hash.h" #include "hash.h"
/* Incremented every time we add or remove a global variable. */
static unsigned int variable_changenum;
/* Chain of all pattern-specific variables. */ /* Chain of all pattern-specific variables. */
static struct pattern_var *pattern_vars; static struct pattern_var *pattern_vars;
@ -268,6 +271,9 @@ define_variable_in_set (const char *name, unsigned int length,
v->name = xstrndup (name, length); v->name = xstrndup (name, length);
v->length = length; v->length = length;
hash_insert_at (&set->table, v, var_slot); hash_insert_at (&set->table, v, var_slot);
if (set == &global_variable_set)
++variable_changenum;
v->value = xstrdup (value); v->value = xstrdup (value);
if (flocp != 0) if (flocp != 0)
v->fileinfo = *flocp; v->fileinfo = *flocp;
@ -350,12 +356,14 @@ undefine_variable_in_set (const char *name, unsigned int length,
before the switches were parsed, it wasn't affected by -e. */ before the switches were parsed, it wasn't affected by -e. */
v->origin = o_env_override; v->origin = o_env_override;
/* If the definition is from a stronger source than this one, don't /* Undefine only if this undefinition is from an equal or stronger
undefine it. */ source than the variable definition. */
if ((int) origin >= (int) v->origin) if ((int) origin >= (int) v->origin)
{ {
hash_delete_at (&set->table, var_slot); hash_delete_at (&set->table, var_slot);
free_variable_name_and_value (v); free_variable_name_and_value (v);
if (set == &global_variable_set)
++variable_changenum;
} }
} }
} }
@ -373,7 +381,7 @@ undefine_variable_in_set (const char *name, unsigned int length,
static struct variable * static struct variable *
lookup_special_var (struct variable *var) lookup_special_var (struct variable *var)
{ {
static unsigned long last_var_count = 0; static unsigned long last_changenum = 0;
/* This one actually turns out to be very hard, due to the way the parser /* This one actually turns out to be very hard, due to the way the parser
@ -401,8 +409,7 @@ lookup_special_var (struct variable *var)
else else
*/ */
if (streq (var->name, ".VARIABLES") if (variable_changenum != last_changenum && streq (var->name, ".VARIABLES"))
&& global_variable_set.table.ht_fill != last_var_count)
{ {
unsigned long max = EXPANSION_INCREMENT (strlen (var->value)); unsigned long max = EXPANSION_INCREMENT (strlen (var->value));
unsigned long len; unsigned long len;
@ -438,11 +445,8 @@ lookup_special_var (struct variable *var)
} }
*(p-1) = '\0'; *(p-1) = '\0';
/* Remember how many variables are in our current count. Since we never /* Remember the current variable change number. */
remove variables from the list, this is a reliable way to know whether last_changenum = variable_changenum;
the list is up to date or needs to be recomputed. */
last_var_count = global_variable_set.table.ht_fill;
} }
return var; return var;
@ -753,6 +757,8 @@ merge_variable_sets (struct variable_set *to_set,
struct variable **from_var_slot = (struct variable **) from_set->table.ht_vec; struct variable **from_var_slot = (struct variable **) from_set->table.ht_vec;
struct variable **from_var_end = from_var_slot + from_set->table.ht_size; struct variable **from_var_end = from_var_slot + from_set->table.ht_size;
int inc = to_set == &global_variable_set ? 1 : 0;
for ( ; from_var_slot < from_var_end; from_var_slot++) for ( ; from_var_slot < from_var_end; from_var_slot++)
if (! HASH_VACANT (*from_var_slot)) if (! HASH_VACANT (*from_var_slot))
{ {
@ -760,7 +766,10 @@ merge_variable_sets (struct variable_set *to_set,
struct variable **to_var_slot struct variable **to_var_slot
= (struct variable **) hash_find_slot (&to_set->table, *from_var_slot); = (struct variable **) hash_find_slot (&to_set->table, *from_var_slot);
if (HASH_VACANT (*to_var_slot)) if (HASH_VACANT (*to_var_slot))
hash_insert_at (&to_set->table, from_var, to_var_slot); {
hash_insert_at (&to_set->table, from_var, to_var_slot);
variable_changenum += inc;
}
else else
{ {
/* GKM FIXME: delete in from_set->table */ /* GKM FIXME: delete in from_set->table */