xref: /freebsd/contrib/bmake/unit-tests/var-op-expand.mk (revision cfd6422a5217410fbd66f7a7a8a64d9d85e61229)
1# $NetBSD: var-op-expand.mk,v 1.11 2021/01/01 23:07:48 sjg Exp $
2#
3# Tests for the := variable assignment operator, which expands its
4# right-hand side.
5
6.MAKE.SAVE_DOLLARS:=      yes
7
8# If the right-hand side does not contain a dollar sign, the ':=' assignment
9# operator has the same effect as the '=' assignment operator.
10VAR:=			value
11.if ${VAR} != "value"
12.  error
13.endif
14
15# When a ':=' assignment is performed, its right-hand side is evaluated and
16# expanded as far as possible.  Contrary to other situations, '$$' and
17# variable expressions based on undefined variables are preserved though.
18#
19# Whether a variable expression is undefined or not is determined at the end
20# of evaluating the expression.  The consequence is that ${:Ufallback} expands
21# to "fallback"; initially this expression is undefined since it is based on
22# the variable named "", which is guaranteed to be never defined, but at the
23# end of evaluating the expression ${:Ufallback}, the modifier ':U' has turned
24# the expression into a defined expression.
25
26
27# literal dollar signs
28VAR:=		$$ $$$$ $$$$$$$$
29.if ${VAR} != "\$ \$\$ \$\$\$\$"
30.  error
31.endif
32
33
34# reference to a variable containing a literal dollar sign
35REF=		$$ $$$$ $$$$$$$$
36VAR:=		${REF}
37REF=		too late
38.if ${VAR} != "\$ \$\$ \$\$\$\$"
39.  error
40.endif
41
42
43# reference to an undefined variable
44.undef UNDEF
45VAR:=		<${UNDEF}>
46UNDEF=		after
47.if ${VAR} != "<after>"
48.  error
49.endif
50
51
52# reference to a variable whose name is computed from another variable
53REF2=		referred to
54REF=		REF2
55VAR:=		${${REF}}
56REF=		too late
57.if ${VAR} != "referred to"
58.  error
59.endif
60
61
62# expression with an indirect modifier referring to an undefined variable
63.undef UNDEF
64VAR:=		${:${UNDEF}}
65UNDEF=		Uwas undefined
66.if ${VAR} != "was undefined"
67.  error
68.endif
69
70
71# expression with an indirect modifier referring to another variable that
72# in turn refers to an undefined variable
73#
74# XXX: Even though this is a ':=' assignment, the '${UNDEF}' in the part of
75# the variable modifier is not preserved.  To preserve it, ParseModifierPart
76# would have to call VarSubstExpr somehow since this is the only piece of
77# code that takes care of this global variable.
78.undef UNDEF
79REF=		U${UNDEF}
80#.MAKEFLAGS: -dv
81VAR:=		${:${REF}}
82#.MAKEFLAGS: -d0
83REF=		too late
84UNDEF=		Uwas undefined
85.if ${VAR} != ""
86.  error
87.endif
88
89
90# In variable assignments using the ':=' operator, undefined variables are
91# preserved, no matter how indirectly they are referenced.
92.undef REF3
93REF2=		<${REF3}>
94REF=		${REF2}
95VAR:=		${REF}
96REF3=		too late
97.if ${VAR} != "<too late>"
98.  error
99.endif
100
101
102# In variable assignments using the ':=' operator, '$$' are preserved, no
103# matter how indirectly they are referenced.
104REF2=		REF2:$$ $$$$
105REF=		REF:$$ $$$$ ${REF2}
106VAR:=		VAR:$$ $$$$ ${REF}
107.if ${VAR} != "VAR:\$ \$\$ REF:\$ \$\$ REF2:\$ \$\$"
108.  error
109.endif
110
111
112# In variable assignments using the ':=' operator, '$$' are preserved in the
113# expressions of the top level, but not in expressions that are nested.
114VAR:=		top:$$ ${:Unest1\:\$\$} ${:Unest2${:U\:\$\$}}
115.if ${VAR} != "top:\$ nest1:\$ nest2:\$"
116.  error
117.endif
118
119
120# In variable assignments using the ':=' operator, there may be expressions
121# containing variable modifiers, and these modifiers may refer to other
122# variables.  These referred-to variables are expanded at the time of
123# assignment.  The undefined variables are kept as-is and are later expanded
124# when evaluating the condition.
125#
126# Contrary to the assignment operator '=', the assignment operator ':='
127# consumes the '$' from modifier parts.
128REF.word=	1:$$ 2:$$$$ 4:$$$$$$$$
129.undef REF.undef
130VAR:=		${:Uword undef:@word@${REF.${word}}@}, direct: ${REF.word} ${REF.undef}
131REF.word=	word.after
132REF.undef=	undef.after
133.if ${VAR} != "1:2:\$ 4:\$\$ undef.after, direct: 1:\$ 2:\$\$ 4:\$\$\$\$ undef.after"
134.  error
135.endif
136
137# Just for comparison, the previous example using the assignment operator '='
138# instead of ':='.  The right-hand side of the assignment is not evaluated at
139# the time of assignment but only later, when ${VAR} appears in the condition.
140#
141# At that point, both REF.word and REF.undef are defined.
142REF.word=	1:$$ 2:$$$$ 4:$$$$$$$$
143.undef REF.undef
144VAR=		${:Uword undef:@word@${REF.${word}}@}, direct: ${REF.word} ${REF.undef}
145REF.word=	word.after
146REF.undef=	undef.after
147.if ${VAR} != "word.after undef.after, direct: word.after undef.after"
148.  error
149.endif
150
151
152# Between var.c 1.42 from 2000-05-11 and before parse.c 1.520 from 2020-12-27,
153# if the variable name in a ':=' assignment referred to an undefined variable,
154# there were actually 2 assignments to different variables:
155#
156#	Global["VAR_SUBST_${UNDEF}"] = ""
157#	Global["VAR_SUBST_"] = ""
158#
159# The variable name with the empty value actually included a dollar sign.
160# Variable names with dollars are not used in practice.
161#
162# It might be a good idea to forbid undefined variables on the left-hand side
163# of a variable assignment.
164.undef UNDEF
165VAR_ASSIGN_${UNDEF}=	assigned by '='
166VAR_SUBST_${UNDEF}:=	assigned by ':='
167.if ${VAR_ASSIGN_} != "assigned by '='"
168.  error
169.endif
170.if defined(${:UVAR_SUBST_\${UNDEF\}})
171.  error
172.endif
173.if ${VAR_SUBST_} != "assigned by ':='"
174.  error
175.endif
176
177all:
178	@:;
179