xref: /freebsd/contrib/bmake/unit-tests/var-scope-cmdline.mk (revision d5e0a182cf153f8993a633b93d9220c99a89e760)
1*d5e0a182SSimon J. Gerraty# $NetBSD: var-scope-cmdline.mk,v 1.4 2023/11/19 21:47:52 rillig Exp $
29f45a3c8SSimon J. Gerraty#
39f45a3c8SSimon J. Gerraty# Tests for variables specified on the command line.
49f45a3c8SSimon J. Gerraty#
59f45a3c8SSimon J. Gerraty# Variables that are specified on the command line override those from the
69f45a3c8SSimon J. Gerraty# global scope.
79f45a3c8SSimon J. Gerraty#
89f45a3c8SSimon J. Gerraty# For performance reasons, the actual implementation is more complex than the
99f45a3c8SSimon J. Gerraty# above single-sentence rule, in order to avoid unnecessary lookups in scopes,
109f45a3c8SSimon J. Gerraty# which before var.c 1.586 from 2020-10-25 calculated the hash value of the
119f45a3c8SSimon J. Gerraty# variable name once for each lookup.  Instead, when looking up the value of
129f45a3c8SSimon J. Gerraty# a variable, the search often starts in the global scope since that is where
139f45a3c8SSimon J. Gerraty# most of the variables are stored.  This conflicts with the statement that
149f45a3c8SSimon J. Gerraty# variables from the cmdline scope override global variables, since after the
159f45a3c8SSimon J. Gerraty# common case of finding a variable in the global scope, another lookup would
169f45a3c8SSimon J. Gerraty# be needed in the cmdline scope to ensure that there is no overriding
179f45a3c8SSimon J. Gerraty# variable there.
189f45a3c8SSimon J. Gerraty#
199f45a3c8SSimon J. Gerraty# Instead of this costly lookup scheme, make implements it in a different
209f45a3c8SSimon J. Gerraty# way:
219f45a3c8SSimon J. Gerraty#
229f45a3c8SSimon J. Gerraty#	Whenever a global variable is created, this creation is ignored if
239f45a3c8SSimon J. Gerraty#	there is a cmdline variable of the same name.
249f45a3c8SSimon J. Gerraty#
259f45a3c8SSimon J. Gerraty#	Whenever a cmdline variable is created, any global variable of the
269f45a3c8SSimon J. Gerraty#	same name is deleted.
279f45a3c8SSimon J. Gerraty#
289f45a3c8SSimon J. Gerraty#	Whenever a global variable is deleted, nothing special happens.
299f45a3c8SSimon J. Gerraty#
309f45a3c8SSimon J. Gerraty#	Deleting a cmdline variable is not possible.
319f45a3c8SSimon J. Gerraty#
329f45a3c8SSimon J. Gerraty# These 4 rules provide the guarantee that whenever a global variable exists,
339f45a3c8SSimon J. Gerraty# there cannot be a cmdline variable of the same name.  Therefore, after
349f45a3c8SSimon J. Gerraty# finding a variable in the global scope, no additional lookup is needed in
359f45a3c8SSimon J. Gerraty# the cmdline scope.
369f45a3c8SSimon J. Gerraty#
379f45a3c8SSimon J. Gerraty# The above ruleset provides the same guarantees as the simple rule "cmdline
389f45a3c8SSimon J. Gerraty# overrides global".  Due to an implementation mistake, the actual behavior
399f45a3c8SSimon J. Gerraty# was not entirely equivalent to the simple rule though.  The mistake was
409f45a3c8SSimon J. Gerraty# that when a cmdline variable with '$$' in its name was added, a global
419f45a3c8SSimon J. Gerraty# variable was deleted, but not with the exact same name as the cmdline
429f45a3c8SSimon J. Gerraty# variable.  Instead, the name of the global variable was expanded one more
439f45a3c8SSimon J. Gerraty# time than the name of the cmdline variable.  For variable names that didn't
449f45a3c8SSimon J. Gerraty# have a '$$' in their name, it was implemented correctly all the time.
459f45a3c8SSimon J. Gerraty#
469f45a3c8SSimon J. Gerraty# The bug was added in var.c 1.183 on 2013-07-16, when Var_Set called
479f45a3c8SSimon J. Gerraty# Var_Delete to delete the global variable.  Just two months earlier, in var.c
489f45a3c8SSimon J. Gerraty# 1.174 from 2013-05-18, Var_Delete had started to expand the variable name.
499f45a3c8SSimon J. Gerraty# Together, these two changes made the variable name be expanded twice in a
509f45a3c8SSimon J. Gerraty# row.  This bug was fixed in var.c 1.835 from 2021-02-22.
519f45a3c8SSimon J. Gerraty#
529f45a3c8SSimon J. Gerraty# Another bug was the wrong assumption that "deleting a cmdline variable is
539f45a3c8SSimon J. Gerraty# not possible".  Deleting such a variable has been possible since var.c 1.204
549f45a3c8SSimon J. Gerraty# from 2016-02-19, when the variable modifier ':@' started to delete the
559f45a3c8SSimon J. Gerraty# temporary loop variable after finishing the loop.  It was probably not
569f45a3c8SSimon J. Gerraty# intended back then that a side effect of this seemingly simple change was
579f45a3c8SSimon J. Gerraty# that both global and cmdline variables could now be undefined at will as a
58*d5e0a182SSimon J. Gerraty# side effect of evaluating an expression.  As of 2021-02-23, this is
599f45a3c8SSimon J. Gerraty# still possible.
609f45a3c8SSimon J. Gerraty#
619f45a3c8SSimon J. Gerraty# Most cmdline variables are set at the very beginning, when parsing the
629f45a3c8SSimon J. Gerraty# command line arguments.  Using the special target '.MAKEFLAGS', it is
639f45a3c8SSimon J. Gerraty# possible to set cmdline variables at any later time.
648c973ee2SSimon J. Gerraty#
658c973ee2SSimon J. Gerraty# See also:
668c973ee2SSimon J. Gerraty#	varcmd.mk
678c973ee2SSimon J. Gerraty#	varname-makeflags.mk
689f45a3c8SSimon J. Gerraty
699f45a3c8SSimon J. Gerraty# A normal global variable, without any cmdline variable nearby.
709f45a3c8SSimon J. GerratyVAR=	global
71148ee845SSimon J. Gerraty# expect+1: global
729f45a3c8SSimon J. Gerraty.info ${VAR}
739f45a3c8SSimon J. Gerraty
749f45a3c8SSimon J. Gerraty# The global variable is "overridden" by simply deleting it and then
759f45a3c8SSimon J. Gerraty# installing the cmdline variable instead.  Since there is no obvious way to
769f45a3c8SSimon J. Gerraty# undefine a cmdline variable, there is no need to remember the old value
779f45a3c8SSimon J. Gerraty# of the global variable could become visible again.
789f45a3c8SSimon J. Gerraty#
799f45a3c8SSimon J. Gerraty# See varmod-loop.mk for a non-obvious way to undefine a cmdline variable.
809f45a3c8SSimon J. Gerraty.MAKEFLAGS: VAR=makeflags
81148ee845SSimon J. Gerraty# expect+1: makeflags
829f45a3c8SSimon J. Gerraty.info ${VAR}
839f45a3c8SSimon J. Gerraty
849f45a3c8SSimon J. Gerraty# If Var_SetWithFlags should ever forget to delete the global variable,
859f45a3c8SSimon J. Gerraty# the below line would print "global" instead of the current "makeflags".
869f45a3c8SSimon J. Gerraty.MAKEFLAGS: -V VAR
87