1 1.11 rillig # $NetBSD: var-scope-local.mk,v 1.11 2024/03/05 23:07:58 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.9 rillig # expect: one: ignoring ' = three' as the variable name '' expands to empty 150 1.9 rillig # expect: two: ignoring ' = three' as the variable name '' expands to empty 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.11 rillig @echo "Making ${.TARGET} with make '"${VAR:Q}"' and env '$$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.10 sjg .export VAR 210 1.3 rillig 211 1.3 rillig # If the sources of a dependency line look like a variable assignment, make 212 1.3 rillig # treats them as such. There is only a single variable assignment per 213 1.3 rillig # dependency line, which makes whitespace around the assignment operator 214 1.3 rillig # irrelevant. 215 1.3 rillig # 216 1.3 rillig # expect-reset 217 1.11 rillig # expect: Making var-scope-local-assign.o with make 'local' and env 'local'. 218 1.3 rillig var-scope-local-assign.o: VAR= local 219 1.3 rillig 220 1.3 rillig # Assignments using '+=' do *not* look up the global value, instead they only 221 1.3 rillig # look up the variable in the target's own scope. 222 1.3 rillig var-scope-local-append.o: VAR+= local 223 1.3 rillig # Once a variable is defined in the target-local scope, appending using '+=' 224 1.3 rillig # behaves as expected. Note that the expression '${.TARGET}' is not resolved 225 1.3 rillig # when parsing the dependency line, its evaluation is deferred until the 226 1.3 rillig # target is actually made. 227 1.11 rillig # expect: Making var-scope-local-append.o with make 'local to var-scope-local-append.o' and env 'local to var-scope-local-append.o'. 228 1.3 rillig var-scope-local-append.o: VAR += to ${.TARGET} 229 1.8 rillig # To access the value of a global variable, use an expression. This 230 1.3 rillig # expression is expanded before parsing the whole dependency line. Since the 231 1.5 rillig # expansion happens to the right of the dependency operator ':', the expanded 232 1.5 rillig # text does not influence parsing of the dependency line. Since the expansion 233 1.5 rillig # happens to the right of the assignment operator '=', the expanded text does 234 1.5 rillig # not influence the parsing of the variable assignment. The effective 235 1.5 rillig # variable assignment, after expanding the whole line first, is thus 236 1.3 rillig # 'VAR= global+local'. 237 1.11 rillig # expect: Making var-scope-local-append-global.o with make 'global+local' and env 'global+local'. 238 1.3 rillig var-scope-local-append-global.o: VAR= ${VAR}+local 239 1.3 rillig 240 1.3 rillig var-scope-local-default.o: VAR ?= first 241 1.3 rillig var-scope-local-default.o: VAR ?= second 242 1.3 rillig # XXX: '?=' does look at the global variable. That's a long-standing 243 1.3 rillig # inconsistency between the assignment operators '+=' and '?='. See 244 1.3 rillig # Var_AppendExpand and VarAssign_Eval. 245 1.11 rillig # expect: Making var-scope-local-default.o with make 'global' and env 'global'. 246 1.3 rillig 247 1.3 rillig # Using the variable assignment operator ':=' provides another way of 248 1.3 rillig # accessing a global variable and extending it with local modifications. The 249 1.3 rillig # '$' has to be written as '$$' though to survive the expansion of the 250 1.5 rillig # dependency line as a whole. After that, the parser sees the variable 251 1.5 rillig # assignment as 'VAR := ${VAR}+local' and searches for the variable 'VAR' in 252 1.5 rillig # the usual scopes, picking up the variable from the global scope. 253 1.11 rillig # expect: Making var-scope-local-subst.o with make 'global+local' and env 'global+local'. 254 1.3 rillig var-scope-local-subst.o: VAR := $${VAR}+local 255 1.3 rillig 256 1.3 rillig # The variable assignment operator '!=' assigns the output of the shell 257 1.5 rillig # command, as everywhere else. The shell command is run when the dependency 258 1.5 rillig # line is parsed. 259 1.3 rillig var-scope-local-shell.o: VAR != echo output 260 1.3 rillig 261 1.3 rillig 262 1.3 rillig # While VAR=use will be set for a .USE node, it will never be seen since only 263 1.3 rillig # the ultimate target's context is searched; the variable assignments from the 264 1.3 rillig # .USE target are not copied to the ultimate target's. 265 1.11 rillig # expect: Making .USE var-scope-local-use.o with make 'global' and env 'global'. 266 1.2 sjg a_use: .USE VAR=use 267 1.11 rillig @echo "Making .USE ${.TARGET} with make '"${VAR:Q}"' and env '$$VAR'." 268 1.2 sjg 269 1.3 rillig all: var-scope-local-use.o 270 1.3 rillig var-scope-local-use.o: a_use 271