var-scope-local.mk revision 1.8 1 1.8 rillig # $NetBSD: var-scope-local.mk,v 1.8 2023/11/19 21:47:52 rillig Exp $
2 1.1 rillig #
3 1.3 rillig # Tests for target-local variables, such as ${.TARGET} or $@. These variables
4 1.3 rillig # are relatively short-lived as they are created just before making the
5 1.3 rillig # target. In contrast, global variables are typically created when the
6 1.3 rillig # makefiles are read in.
7 1.3 rillig #
8 1.3 rillig # The 7 built-in target-local variables are listed in the manual page. They
9 1.3 rillig # are defined just before the target is actually made. Additional
10 1.3 rillig # target-local variables can be defined in dependency lines like
11 1.3 rillig # 'target: VAR=value', one at a time.
12 1.3 rillig
13 1.3 rillig .MAIN: all
14 1.3 rillig
15 1.6 rillig # Target-local variables in a target rule
16 1.7 rillig #
17 1.7 rillig # In target rules, '$*' only strips the extension off the pathname if the
18 1.7 rillig # extension is listed in '.SUFFIXES'.
19 1.7 rillig #
20 1.7 rillig # expect: target-rule.ext: * = <target-rule.ext>
21 1.6 rillig all: target-rule.ext dir/subdir/target-rule.ext
22 1.6 rillig target-rule.ext dir/subdir/target-rule.ext: .PHONY
23 1.6 rillig @echo '$@: @ = <${@:Uundefined}>'
24 1.6 rillig @echo '$@: % = <${%:Uundefined}>'
25 1.6 rillig @echo '$@: ? = <${?:Uundefined}>'
26 1.6 rillig @echo '$@: < = <${<:Uundefined}>'
27 1.6 rillig @echo '$@: * = <${*:Uundefined}>'
28 1.6 rillig
29 1.6 rillig .SUFFIXES: .ir-gen-from .ir-from .ir-to
30 1.7 rillig
31 1.7 rillig # In target rules, '$*' strips the extension off the pathname of the target
32 1.7 rillig # if the extension is listed in '.SUFFIXES'.
33 1.7 rillig #
34 1.7 rillig # expect: target-rule.ir-gen-from: * = <target-rule>
35 1.7 rillig all: target-rule.ir-gen-from dir/subdir/target-rule-dir.ir-gen-from
36 1.7 rillig target-rule.ir-gen-from dir/subdir/target-rule-dir.ir-gen-from:
37 1.7 rillig @echo '$@: @ = <${@:Uundefined}>'
38 1.7 rillig @echo '$@: % = <${%:Uundefined}>'
39 1.7 rillig @echo '$@: ? = <${?:Uundefined}>'
40 1.7 rillig @echo '$@: < = <${<:Uundefined}>'
41 1.7 rillig @echo '$@: * = <${*:Uundefined}>'
42 1.7 rillig
43 1.6 rillig .ir-from.ir-to:
44 1.6 rillig @echo '$@: @ = <${@:Uundefined}>'
45 1.6 rillig @echo '$@: % = <${%:Uundefined}>'
46 1.6 rillig @echo '$@: ? = <${?:Uundefined}>'
47 1.6 rillig @echo '$@: < = <${<:Uundefined}>'
48 1.6 rillig @echo '$@: * = <${*:Uundefined}>'
49 1.6 rillig .ir-gen-from.ir-from:
50 1.6 rillig @echo '$@: @ = <${@:Uundefined}>'
51 1.6 rillig @echo '$@: % = <${%:Uundefined}>'
52 1.6 rillig @echo '$@: ? = <${?:Uundefined}>'
53 1.6 rillig @echo '$@: < = <${<:Uundefined}>'
54 1.6 rillig @echo '$@: * = <${*:Uundefined}>'
55 1.6 rillig
56 1.6 rillig # Target-local variables in an inference rule
57 1.6 rillig all: inference-rule.ir-to dir/subdir/inference-rule.ir-to
58 1.6 rillig inference-rule.ir-from: .PHONY
59 1.6 rillig dir/subdir/inference-rule.ir-from: .PHONY
60 1.6 rillig
61 1.6 rillig # Target-local variables in a chain of inference rules
62 1.6 rillig all: inference-rule-chain.ir-to dir/subdir/inference-rule-chain.ir-to
63 1.6 rillig inference-rule-chain.ir-gen-from: .PHONY
64 1.6 rillig dir/subdir/inference-rule-chain.ir-gen-from: .PHONY
65 1.6 rillig
66 1.7 rillig # The run-time 'check' directives from above happen after the parse-time
67 1.7 rillig # 'check' directives from below.
68 1.7 rillig #
69 1.7 rillig # expect-reset
70 1.6 rillig
71 1.6 rillig # Deferred evaluation during parsing
72 1.6 rillig #
73 1.3 rillig # The target-local variables can be used in expressions, just like other
74 1.3 rillig # variables. When these expressions are evaluated outside of a target, these
75 1.3 rillig # expressions are not yet expanded, instead their text is preserved, to allow
76 1.3 rillig # these expressions to expand right in time when the target-local variables
77 1.3 rillig # are actually set.
78 1.3 rillig #
79 1.5 rillig # Conditions from .if directives are evaluated in the scope of the command
80 1.3 rillig # line, which means that variables from the command line, from the global
81 1.6 rillig # scope and from the environment are resolved, in this precedence order (but
82 1.6 rillig # see the command line option '-e'). In that phase, expressions involving
83 1.3 rillig # target-local variables need to be preserved, including the exact names of
84 1.3 rillig # the variables.
85 1.3 rillig #
86 1.3 rillig # Each of the built-in target-local variables has two equivalent names, for
87 1.3 rillig # example '@' is equivalent to '.TARGET'. The implementation might
88 1.1 rillig # canonicalize these aliases at some point, and that might be surprising.
89 1.1 rillig # This aliasing happens for single-character variable names like $@ or $<
90 1.1 rillig # (see VarFind, CanonicalVarname), but not for braced or parenthesized
91 1.1 rillig # expressions like ${@}, ${.TARGET} ${VAR:Mpattern} (see Var_Parse,
92 1.1 rillig # ParseVarname).
93 1.3 rillig #
94 1.5 rillig # In the following condition, make expands '$@' to the long-format alias
95 1.5 rillig # '$(.TARGET)'; note that the alias is not written with braces, as would be
96 1.5 rillig # common in BSD makefiles, but with parentheses. This alternative spelling
97 1.5 rillig # behaves the same though.
98 1.3 rillig .if $@ != "\$\(.TARGET)"
99 1.3 rillig . error
100 1.3 rillig .endif
101 1.5 rillig # In the long form of writing a target-local variable, the text of the
102 1.5 rillig # expression is preserved exactly as written, no matter whether it is written
103 1.5 rillig # with '{' or '('.
104 1.3 rillig .if ${@} != "\$\{@}"
105 1.3 rillig . error
106 1.3 rillig .endif
107 1.3 rillig .if $(@) != "\$\(@)"
108 1.3 rillig . error
109 1.3 rillig .endif
110 1.8 rillig # If the expression contains modifiers, the behavior depends on the
111 1.3 rillig # actual modifiers. The modifier ':M' keeps the expression in the state
112 1.3 rillig # 'undefined'. Since the expression is still undefined after evaluating all
113 1.3 rillig # the modifiers, the value of the expression is discarded and the expression
114 1.3 rillig # text is used instead. This preserves the expressions based on target-local
115 1.3 rillig # variables as long as possible.
116 1.3 rillig .if ${@:M*} != "\$\{@:M*}"
117 1.3 rillig . error
118 1.3 rillig .endif
119 1.3 rillig # In the following examples, the expressions are based on target-local
120 1.3 rillig # variables but use the modifier ':L', which turns an undefined expression
121 1.3 rillig # into a defined one. At the end of evaluating the expression, the state of
122 1.5 rillig # the expression is not 'undefined' anymore. The value of the expression
123 1.3 rillig # is the name of the variable, since that's what the modifier ':L' does.
124 1.1 rillig .if ${@:L} != "@"
125 1.1 rillig . error
126 1.1 rillig .endif
127 1.1 rillig .if ${.TARGET:L} != ".TARGET"
128 1.1 rillig . error
129 1.1 rillig .endif
130 1.1 rillig .if ${@F:L} != "@F"
131 1.1 rillig . error
132 1.1 rillig .endif
133 1.1 rillig .if ${@D:L} != "@D"
134 1.1 rillig . error
135 1.1 rillig .endif
136 1.1 rillig
137 1.3 rillig
138 1.6 rillig # Custom local variables
139 1.6 rillig #
140 1.3 rillig # Additional target-local variables may be defined in dependency lines.
141 1.3 rillig .MAKEFLAGS: -dv
142 1.3 rillig # In the following line, the ':=' may either be interpreted as an assignment
143 1.3 rillig # operator or as the dependency operator ':', followed by an empty variable
144 1.3 rillig # name and the assignment operator '='. It is the latter since in an
145 1.6 rillig # assignment, the left-hand side must be a single word or empty.
146 1.6 rillig #
147 1.6 rillig # The empty variable name is expanded twice, once for 'one' and once for
148 1.6 rillig # 'two'.
149 1.3 rillig # expect: Var_SetExpand: variable name "" expands to empty string, with value "three" - ignored
150 1.3 rillig # expect: Var_SetExpand: variable name "" expands to empty string, with value "three" - ignored
151 1.3 rillig one two:=three
152 1.8 rillig # If the two targets to the left are generated by an expression, the
153 1.3 rillig # line is parsed as a variable assignment since its left-hand side is a single
154 1.3 rillig # word.
155 1.3 rillig # expect: Global: one two = three
156 1.3 rillig ${:Uone two}:=three
157 1.3 rillig .MAKEFLAGS: -d0
158 1.3 rillig
159 1.1 rillig
160 1.1 rillig .SUFFIXES: .c .o
161 1.1 rillig
162 1.3 rillig # One of the dynamic target-local variables is '.TARGET'. Since this is not
163 1.3 rillig # a suffix transformation rule, the variable '.IMPSRC' is not defined.
164 1.3 rillig # expect: : Making var-scope-local.c out of nothing.
165 1.3 rillig var-scope-local.c:
166 1.3 rillig : Making ${.TARGET} ${.IMPSRC:Dfrom ${.IMPSRC}:Uout of nothing}.
167 1.3 rillig
168 1.3 rillig # This is a suffix transformation rule, so both '.TARGET' and '.IMPSRC' are
169 1.3 rillig # defined.
170 1.3 rillig # expect: : Making var-scope-local.o from var-scope-local.c.
171 1.3 rillig # expect: : Making basename "var-scope-local.o" in "." from "var-scope-local.c" in ".".
172 1.1 rillig .c.o:
173 1.1 rillig : Making ${.TARGET} from ${.IMPSRC}.
174 1.1 rillig
175 1.1 rillig # The local variables @F, @D, <F, <D are legacy forms.
176 1.1 rillig # See the manual page for details.
177 1.3 rillig : Making basename "${@F}" in "${@D}" from "${<F}" in "${<D}".
178 1.1 rillig
179 1.3 rillig # expect: : all overwritten
180 1.3 rillig all: var-scope-local.o
181 1.1 rillig # The ::= modifier overwrites the .TARGET variable in the node
182 1.1 rillig # 'all', not in the global scope. This can be seen with the -dv
183 1.3 rillig # option, looking for "all: @ = overwritten".
184 1.3 rillig : ${.TARGET} ${.TARGET::=overwritten}${.TARGET}
185 1.3 rillig
186 1.3 rillig
187 1.3 rillig # Begin tests for custom target-local variables, for all 5 variable assignment
188 1.3 rillig # operators.
189 1.3 rillig all: var-scope-local-assign.o
190 1.3 rillig all: var-scope-local-append.o
191 1.3 rillig all: var-scope-local-append-global.o
192 1.3 rillig all: var-scope-local-default.o
193 1.3 rillig all: var-scope-local-subst.o
194 1.3 rillig all: var-scope-local-shell.o
195 1.3 rillig
196 1.3 rillig var-scope-local-assign.o \
197 1.3 rillig var-scope-local-append.o \
198 1.3 rillig var-scope-local-append-global.o \
199 1.3 rillig var-scope-local-default.o \
200 1.3 rillig var-scope-local-subst.o \
201 1.3 rillig var-scope-local-shell.o:
202 1.3 rillig : Making ${.TARGET} with VAR="${VAR}".
203 1.2 sjg
204 1.3 rillig # Target-local variables are enabled by default. Force them to be enabled
205 1.3 rillig # just in case a test above has disabled them.
206 1.2 sjg .MAKE.TARGET_LOCAL_VARIABLES= yes
207 1.2 sjg
208 1.3 rillig VAR= global
209 1.3 rillig
210 1.3 rillig # If the sources of a dependency line look like a variable assignment, make
211 1.3 rillig # treats them as such. There is only a single variable assignment per
212 1.3 rillig # dependency line, which makes whitespace around the assignment operator
213 1.3 rillig # irrelevant.
214 1.3 rillig #
215 1.3 rillig # expect-reset
216 1.3 rillig # expect: : Making var-scope-local-assign.o with VAR="local".
217 1.3 rillig var-scope-local-assign.o: VAR= local
218 1.3 rillig
219 1.3 rillig # Assignments using '+=' do *not* look up the global value, instead they only
220 1.3 rillig # look up the variable in the target's own scope.
221 1.3 rillig var-scope-local-append.o: VAR+= local
222 1.3 rillig # Once a variable is defined in the target-local scope, appending using '+='
223 1.3 rillig # behaves as expected. Note that the expression '${.TARGET}' is not resolved
224 1.3 rillig # when parsing the dependency line, its evaluation is deferred until the
225 1.3 rillig # target is actually made.
226 1.3 rillig # expect: : Making var-scope-local-append.o with VAR="local to var-scope-local-append.o".
227 1.3 rillig var-scope-local-append.o: VAR += to ${.TARGET}
228 1.8 rillig # To access the value of a global variable, use an expression. This
229 1.3 rillig # expression is expanded before parsing the whole dependency line. Since the
230 1.5 rillig # expansion happens to the right of the dependency operator ':', the expanded
231 1.5 rillig # text does not influence parsing of the dependency line. Since the expansion
232 1.5 rillig # happens to the right of the assignment operator '=', the expanded text does
233 1.5 rillig # not influence the parsing of the variable assignment. The effective
234 1.5 rillig # variable assignment, after expanding the whole line first, is thus
235 1.3 rillig # 'VAR= global+local'.
236 1.3 rillig # expect: : Making var-scope-local-append-global.o with VAR="global+local".
237 1.3 rillig var-scope-local-append-global.o: VAR= ${VAR}+local
238 1.3 rillig
239 1.3 rillig var-scope-local-default.o: VAR ?= first
240 1.3 rillig var-scope-local-default.o: VAR ?= second
241 1.3 rillig # XXX: '?=' does look at the global variable. That's a long-standing
242 1.3 rillig # inconsistency between the assignment operators '+=' and '?='. See
243 1.3 rillig # Var_AppendExpand and VarAssign_Eval.
244 1.3 rillig # expect: : Making var-scope-local-default.o with VAR="global".
245 1.3 rillig
246 1.3 rillig # Using the variable assignment operator ':=' provides another way of
247 1.3 rillig # accessing a global variable and extending it with local modifications. The
248 1.3 rillig # '$' has to be written as '$$' though to survive the expansion of the
249 1.5 rillig # dependency line as a whole. After that, the parser sees the variable
250 1.5 rillig # assignment as 'VAR := ${VAR}+local' and searches for the variable 'VAR' in
251 1.5 rillig # the usual scopes, picking up the variable from the global scope.
252 1.5 rillig # expect: : Making var-scope-local-subst.o with VAR="global+local".
253 1.3 rillig var-scope-local-subst.o: VAR := $${VAR}+local
254 1.3 rillig
255 1.3 rillig # The variable assignment operator '!=' assigns the output of the shell
256 1.5 rillig # command, as everywhere else. The shell command is run when the dependency
257 1.5 rillig # line is parsed.
258 1.3 rillig var-scope-local-shell.o: VAR != echo output
259 1.3 rillig
260 1.3 rillig
261 1.3 rillig # While VAR=use will be set for a .USE node, it will never be seen since only
262 1.3 rillig # the ultimate target's context is searched; the variable assignments from the
263 1.3 rillig # .USE target are not copied to the ultimate target's.
264 1.5 rillig # expect: : var-scope-local-use.o uses .USE VAR="global"
265 1.2 sjg a_use: .USE VAR=use
266 1.2 sjg : ${.TARGET} uses .USE VAR="${VAR}"
267 1.2 sjg
268 1.3 rillig all: var-scope-local-use.o
269 1.3 rillig var-scope-local-use.o: a_use
270