Module Name: src Committed By: rillig Date: Tue Feb 23 21:59:31 UTC 2021
Modified Files: src/usr.bin/make/unit-tests: var-class-cmdline.exp var-class-cmdline.mk Log Message: make: document the history of bugs in "cmdline overrides global" For performance reasons, the implementation of the simple rule "cmdline overrides global" grew into code that is much more complicated than a straight-forward implementation. This added complexity made it easy for bugs to sneak in. To generate a diff of this commit: cvs rdiff -u -r1.3 -r1.4 src/usr.bin/make/unit-tests/var-class-cmdline.exp cvs rdiff -u -r1.4 -r1.5 src/usr.bin/make/unit-tests/var-class-cmdline.mk Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files.
Modified files: Index: src/usr.bin/make/unit-tests/var-class-cmdline.exp diff -u src/usr.bin/make/unit-tests/var-class-cmdline.exp:1.3 src/usr.bin/make/unit-tests/var-class-cmdline.exp:1.4 --- src/usr.bin/make/unit-tests/var-class-cmdline.exp:1.3 Tue Feb 23 14:17:21 2021 +++ src/usr.bin/make/unit-tests/var-class-cmdline.exp Tue Feb 23 21:59:31 2021 @@ -1,4 +1,4 @@ -make: "var-class-cmdline.mk" line 23: global -make: "var-class-cmdline.mk" line 32: makeflags +make: "var-class-cmdline.mk" line 67: global +make: "var-class-cmdline.mk" line 76: makeflags makeflags exit status 0 Index: src/usr.bin/make/unit-tests/var-class-cmdline.mk diff -u src/usr.bin/make/unit-tests/var-class-cmdline.mk:1.4 src/usr.bin/make/unit-tests/var-class-cmdline.mk:1.5 --- src/usr.bin/make/unit-tests/var-class-cmdline.mk:1.4 Tue Feb 23 14:17:21 2021 +++ src/usr.bin/make/unit-tests/var-class-cmdline.mk Tue Feb 23 21:59:31 2021 @@ -1,18 +1,62 @@ -# $NetBSD: var-class-cmdline.mk,v 1.4 2021/02/23 14:17:21 rillig Exp $ +# $NetBSD: var-class-cmdline.mk,v 1.5 2021/02/23 21:59:31 rillig Exp $ # # Tests for variables specified on the command line. # # Variables that are specified on the command line override those from the # global scope. # -# For performance reasons, variable lookup often starts in the global scope -# since that is where most practically used variables are stored. But even -# in these cases, variables from the command line scope must override the -# global variables. Therefore, whenever a global variable is tried to be -# set, it is ignored when there is already a variable of the same name in -# the cmdline scope. In the same vein, when a cmdline variable is set and -# there is already a variable of the same name in the global scope, that -# global variable is deleted first. +# For performance reasons, the actual implementation is more complex than the +# above single-sentence rule, in order to avoid unnecessary lookups in scopes, +# which before var.c 1.586 from 2020-10-25 calculated the hash value of the +# variable name once for each lookup. Instead, when looking up the value of +# a variable, the search often starts in the global scope since that is where +# most of the variables are stored. This conflicts with the statement that +# variables from the cmdline scope override global variables, since after the +# common case of finding a variable in the global scope, another lookup would +# be needed in the cmdline scope to ensure that there is no overriding +# variable there. +# +# Instead of this costly lookup scheme, make implements it in a different +# way: +# +# Whenever a global variable is created, this creation is ignored if +# there is a cmdline variable of the same name. +# +# Whenever a cmdline variable is created, any global variable of the +# same name is deleted. +# +# Whenever a global variable is deleted, nothing special happens. +# +# Deleting a cmdline variable is not possible. +# +# These 4 rules provide the guarantee that whenever a global variable exists, +# there cannot be a cmdline variable of the same name. Therefore, after +# finding a variable in the global scope, no additional lookup is needed in +# the cmdline scope. +# +# The above ruleset provides the same guarantees as the simple rule "cmdline +# overrides global". Due to an implementation mistake, the actual behavior +# was not entirely equivalent to the simple rule though. The mistake was +# that when a cmdline variable with '$$' in its name was added, a global +# variable was deleted, but not with the exact same name as the cmdline +# variable. Instead, the name of the global variable was expanded one more +# time than the name of the cmdline variable. For variable names that didn't +# have a '$$' in their name, it was implemented correctly all the time. +# +# The bug was added in var.c 1.183 on 2013-07-16, when Var_Set called +# Var_Delete to delete the global variable. Just two months earlier, in var.c +# 1.174 from 2013-05-18, Var_Delete had started to expand the variable name. +# Together, these two changes made the variable name be expanded twice in a +# row. This bug was fixed in var.c 1.835 from 2021-02-22. +# +# Another bug was the wrong assumption that "deleting a cmdline variable is +# not possible". Deleting such a variable has been possible since var.c 1.204 +# from 2016-02-19, when the variable modifier ':@' started to delete the +# temporary loop variable after finishing the loop. It was probably not +# intended back then that a side effect of this seemingly simple change was +# that both global and cmdline variables could now be undefined at will as a +# side effect of evaluating a variable expression. As of 2021-02-23, this is +# still possible. # # Most cmdline variables are set at the very beginning, when parsing the # command line arguments. Using the special target '.MAKEFLAGS', it is