xref: /freebsd/contrib/bmake/unit-tests/var-scope-cmdline.mk (revision 9f45a3c8c82ffead7044ae836d9257113c630d3b)
1*9f45a3c8SSimon J. Gerraty# $NetBSD: var-scope-cmdline.mk,v 1.1 2022/01/23 16:25:54 rillig Exp $
2*9f45a3c8SSimon J. Gerraty#
3*9f45a3c8SSimon J. Gerraty# Tests for variables specified on the command line.
4*9f45a3c8SSimon J. Gerraty#
5*9f45a3c8SSimon J. Gerraty# Variables that are specified on the command line override those from the
6*9f45a3c8SSimon J. Gerraty# global scope.
7*9f45a3c8SSimon J. Gerraty#
8*9f45a3c8SSimon J. Gerraty# For performance reasons, the actual implementation is more complex than the
9*9f45a3c8SSimon J. Gerraty# above single-sentence rule, in order to avoid unnecessary lookups in scopes,
10*9f45a3c8SSimon J. Gerraty# which before var.c 1.586 from 2020-10-25 calculated the hash value of the
11*9f45a3c8SSimon J. Gerraty# variable name once for each lookup.  Instead, when looking up the value of
12*9f45a3c8SSimon J. Gerraty# a variable, the search often starts in the global scope since that is where
13*9f45a3c8SSimon J. Gerraty# most of the variables are stored.  This conflicts with the statement that
14*9f45a3c8SSimon J. Gerraty# variables from the cmdline scope override global variables, since after the
15*9f45a3c8SSimon J. Gerraty# common case of finding a variable in the global scope, another lookup would
16*9f45a3c8SSimon J. Gerraty# be needed in the cmdline scope to ensure that there is no overriding
17*9f45a3c8SSimon J. Gerraty# variable there.
18*9f45a3c8SSimon J. Gerraty#
19*9f45a3c8SSimon J. Gerraty# Instead of this costly lookup scheme, make implements it in a different
20*9f45a3c8SSimon J. Gerraty# way:
21*9f45a3c8SSimon J. Gerraty#
22*9f45a3c8SSimon J. Gerraty#	Whenever a global variable is created, this creation is ignored if
23*9f45a3c8SSimon J. Gerraty#	there is a cmdline variable of the same name.
24*9f45a3c8SSimon J. Gerraty#
25*9f45a3c8SSimon J. Gerraty#	Whenever a cmdline variable is created, any global variable of the
26*9f45a3c8SSimon J. Gerraty#	same name is deleted.
27*9f45a3c8SSimon J. Gerraty#
28*9f45a3c8SSimon J. Gerraty#	Whenever a global variable is deleted, nothing special happens.
29*9f45a3c8SSimon J. Gerraty#
30*9f45a3c8SSimon J. Gerraty#	Deleting a cmdline variable is not possible.
31*9f45a3c8SSimon J. Gerraty#
32*9f45a3c8SSimon J. Gerraty# These 4 rules provide the guarantee that whenever a global variable exists,
33*9f45a3c8SSimon J. Gerraty# there cannot be a cmdline variable of the same name.  Therefore, after
34*9f45a3c8SSimon J. Gerraty# finding a variable in the global scope, no additional lookup is needed in
35*9f45a3c8SSimon J. Gerraty# the cmdline scope.
36*9f45a3c8SSimon J. Gerraty#
37*9f45a3c8SSimon J. Gerraty# The above ruleset provides the same guarantees as the simple rule "cmdline
38*9f45a3c8SSimon J. Gerraty# overrides global".  Due to an implementation mistake, the actual behavior
39*9f45a3c8SSimon J. Gerraty# was not entirely equivalent to the simple rule though.  The mistake was
40*9f45a3c8SSimon J. Gerraty# that when a cmdline variable with '$$' in its name was added, a global
41*9f45a3c8SSimon J. Gerraty# variable was deleted, but not with the exact same name as the cmdline
42*9f45a3c8SSimon J. Gerraty# variable.  Instead, the name of the global variable was expanded one more
43*9f45a3c8SSimon J. Gerraty# time than the name of the cmdline variable.  For variable names that didn't
44*9f45a3c8SSimon J. Gerraty# have a '$$' in their name, it was implemented correctly all the time.
45*9f45a3c8SSimon J. Gerraty#
46*9f45a3c8SSimon J. Gerraty# The bug was added in var.c 1.183 on 2013-07-16, when Var_Set called
47*9f45a3c8SSimon J. Gerraty# Var_Delete to delete the global variable.  Just two months earlier, in var.c
48*9f45a3c8SSimon J. Gerraty# 1.174 from 2013-05-18, Var_Delete had started to expand the variable name.
49*9f45a3c8SSimon J. Gerraty# Together, these two changes made the variable name be expanded twice in a
50*9f45a3c8SSimon J. Gerraty# row.  This bug was fixed in var.c 1.835 from 2021-02-22.
51*9f45a3c8SSimon J. Gerraty#
52*9f45a3c8SSimon J. Gerraty# Another bug was the wrong assumption that "deleting a cmdline variable is
53*9f45a3c8SSimon J. Gerraty# not possible".  Deleting such a variable has been possible since var.c 1.204
54*9f45a3c8SSimon J. Gerraty# from 2016-02-19, when the variable modifier ':@' started to delete the
55*9f45a3c8SSimon J. Gerraty# temporary loop variable after finishing the loop.  It was probably not
56*9f45a3c8SSimon J. Gerraty# intended back then that a side effect of this seemingly simple change was
57*9f45a3c8SSimon J. Gerraty# that both global and cmdline variables could now be undefined at will as a
58*9f45a3c8SSimon J. Gerraty# side effect of evaluating a variable expression.  As of 2021-02-23, this is
59*9f45a3c8SSimon J. Gerraty# still possible.
60*9f45a3c8SSimon J. Gerraty#
61*9f45a3c8SSimon J. Gerraty# Most cmdline variables are set at the very beginning, when parsing the
62*9f45a3c8SSimon J. Gerraty# command line arguments.  Using the special target '.MAKEFLAGS', it is
63*9f45a3c8SSimon J. Gerraty# possible to set cmdline variables at any later time.
64*9f45a3c8SSimon J. Gerraty
65*9f45a3c8SSimon J. Gerraty# A normal global variable, without any cmdline variable nearby.
66*9f45a3c8SSimon J. GerratyVAR=	global
67*9f45a3c8SSimon J. Gerraty.info ${VAR}
68*9f45a3c8SSimon J. Gerraty
69*9f45a3c8SSimon J. Gerraty# The global variable is "overridden" by simply deleting it and then
70*9f45a3c8SSimon J. Gerraty# installing the cmdline variable instead.  Since there is no obvious way to
71*9f45a3c8SSimon J. Gerraty# undefine a cmdline variable, there is no need to remember the old value
72*9f45a3c8SSimon J. Gerraty# of the global variable could become visible again.
73*9f45a3c8SSimon J. Gerraty#
74*9f45a3c8SSimon J. Gerraty# See varmod-loop.mk for a non-obvious way to undefine a cmdline variable.
75*9f45a3c8SSimon J. Gerraty.MAKEFLAGS: VAR=makeflags
76*9f45a3c8SSimon J. Gerraty.info ${VAR}
77*9f45a3c8SSimon J. Gerraty
78*9f45a3c8SSimon J. Gerraty# If Var_SetWithFlags should ever forget to delete the global variable,
79*9f45a3c8SSimon J. Gerraty# the below line would print "global" instead of the current "makeflags".
80*9f45a3c8SSimon J. Gerraty.MAKEFLAGS: -V VAR
81