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