var-scope-local.mk revision 1.4 1 1.4 rillig # $NetBSD: var-scope-local.mk,v 1.4 2022/02/05 10:41:15 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.3 rillig # The target-local variables can be used in expressions, just like other
16 1.3 rillig # variables. When these expressions are evaluated outside of a target, these
17 1.3 rillig # expressions are not yet expanded, instead their text is preserved, to allow
18 1.3 rillig # these expressions to expand right in time when the target-local variables
19 1.3 rillig # are actually set.
20 1.3 rillig #
21 1.3 rillig # Conditions like the ones below are evaluated in the scope of the command
22 1.3 rillig # line, which means that variables from the command line, from the global
23 1.3 rillig # scope and from the environment are resolved, in this order (but see the
24 1.3 rillig # command line option '-e'). In that phase, expressions involving
25 1.3 rillig # target-local variables need to be preserved, including the exact names of
26 1.3 rillig # the variables.
27 1.3 rillig #
28 1.3 rillig # Each of the built-in target-local variables has two equivalent names, for
29 1.3 rillig # example '@' is equivalent to '.TARGET'. The implementation might
30 1.1 rillig # canonicalize these aliases at some point, and that might be surprising.
31 1.1 rillig # This aliasing happens for single-character variable names like $@ or $<
32 1.1 rillig # (see VarFind, CanonicalVarname), but not for braced or parenthesized
33 1.1 rillig # expressions like ${@}, ${.TARGET} ${VAR:Mpattern} (see Var_Parse,
34 1.1 rillig # ParseVarname).
35 1.3 rillig #
36 1.3 rillig # In the following condition, make does not expand '$@' but instead changes it
37 1.3 rillig # to the long-format alias '$(.TARGET)'; note that the alias is not written
38 1.3 rillig # with braces, as would be common in BSD makefiles, but with parentheses.
39 1.3 rillig # This alternative form behaves equivalently though.
40 1.3 rillig .if $@ != "\$\(.TARGET)"
41 1.3 rillig . error
42 1.3 rillig .endif
43 1.3 rillig # In the long form of writing a target-local variable, the expression is
44 1.3 rillig # preserved exactly as written, no matter whether with '{' or '('.
45 1.3 rillig .if ${@} != "\$\{@}"
46 1.3 rillig . error
47 1.3 rillig .endif
48 1.3 rillig .if $(@) != "\$\(@)"
49 1.3 rillig . error
50 1.3 rillig .endif
51 1.3 rillig # If the variable expression contains modifiers, the behavior depends on the
52 1.3 rillig # actual modifiers. The modifier ':M' keeps the expression in the state
53 1.3 rillig # 'undefined'. Since the expression is still undefined after evaluating all
54 1.3 rillig # the modifiers, the value of the expression is discarded and the expression
55 1.3 rillig # text is used instead. This preserves the expressions based on target-local
56 1.3 rillig # variables as long as possible.
57 1.3 rillig .if ${@:M*} != "\$\{@:M*}"
58 1.3 rillig . error
59 1.3 rillig .endif
60 1.3 rillig # In the following examples, the expressions are based on target-local
61 1.3 rillig # variables but use the modifier ':L', which turns an undefined expression
62 1.3 rillig # into a defined one. At the end of evaluating the expression, the state of
63 1.3 rillig # the expression is not 'undefined' anymore, and the value of the expression
64 1.3 rillig # is the name of the variable, since that's what the modifier ':L' does.
65 1.1 rillig .if ${@:L} != "@"
66 1.1 rillig . error
67 1.1 rillig .endif
68 1.1 rillig .if ${.TARGET:L} != ".TARGET"
69 1.1 rillig . error
70 1.1 rillig .endif
71 1.1 rillig .if ${@F:L} != "@F"
72 1.1 rillig . error
73 1.1 rillig .endif
74 1.1 rillig .if ${@D:L} != "@D"
75 1.1 rillig . error
76 1.1 rillig .endif
77 1.1 rillig
78 1.3 rillig
79 1.3 rillig # Additional target-local variables may be defined in dependency lines.
80 1.3 rillig .MAKEFLAGS: -dv
81 1.3 rillig # In the following line, the ':=' may either be interpreted as an assignment
82 1.3 rillig # operator or as the dependency operator ':', followed by an empty variable
83 1.3 rillig # name and the assignment operator '='. It is the latter since in an
84 1.3 rillig # assignment, the left-hand side must be at most a single word. The empty
85 1.3 rillig # variable name is expanded twice, once for 'one' and once for 'two'.
86 1.3 rillig # expect: Var_SetExpand: variable name "" expands to empty string, with value "three" - ignored
87 1.3 rillig # expect: Var_SetExpand: variable name "" expands to empty string, with value "three" - ignored
88 1.3 rillig one two:=three
89 1.3 rillig # If the two targets to the left are generated by a variable expression, the
90 1.3 rillig # line is parsed as a variable assignment since its left-hand side is a single
91 1.3 rillig # word.
92 1.3 rillig # expect: Global: one two = three
93 1.3 rillig ${:Uone two}:=three
94 1.3 rillig .MAKEFLAGS: -d0
95 1.3 rillig
96 1.1 rillig
97 1.1 rillig .SUFFIXES: .c .o
98 1.1 rillig
99 1.3 rillig # One of the dynamic target-local variables is '.TARGET'. Since this is not
100 1.3 rillig # a suffix transformation rule, the variable '.IMPSRC' is not defined.
101 1.3 rillig # expect: : Making var-scope-local.c out of nothing.
102 1.3 rillig var-scope-local.c:
103 1.3 rillig : Making ${.TARGET} ${.IMPSRC:Dfrom ${.IMPSRC}:Uout of nothing}.
104 1.3 rillig
105 1.3 rillig # This is a suffix transformation rule, so both '.TARGET' and '.IMPSRC' are
106 1.3 rillig # defined.
107 1.3 rillig # expect: : Making var-scope-local.o from var-scope-local.c.
108 1.3 rillig # expect: : Making basename "var-scope-local.o" in "." from "var-scope-local.c" in ".".
109 1.1 rillig .c.o:
110 1.1 rillig : Making ${.TARGET} from ${.IMPSRC}.
111 1.1 rillig
112 1.1 rillig # The local variables @F, @D, <F, <D are legacy forms.
113 1.1 rillig # See the manual page for details.
114 1.3 rillig : Making basename "${@F}" in "${@D}" from "${<F}" in "${<D}".
115 1.1 rillig
116 1.3 rillig # expect: : all overwritten
117 1.3 rillig all: var-scope-local.o
118 1.1 rillig # The ::= modifier overwrites the .TARGET variable in the node
119 1.1 rillig # 'all', not in the global scope. This can be seen with the -dv
120 1.3 rillig # option, looking for "all: @ = overwritten".
121 1.3 rillig : ${.TARGET} ${.TARGET::=overwritten}${.TARGET}
122 1.3 rillig
123 1.3 rillig
124 1.3 rillig # Begin tests for custom target-local variables, for all 5 variable assignment
125 1.3 rillig # operators.
126 1.3 rillig all: var-scope-local-assign.o
127 1.3 rillig all: var-scope-local-append.o
128 1.3 rillig all: var-scope-local-append-global.o
129 1.3 rillig all: var-scope-local-default.o
130 1.3 rillig all: var-scope-local-subst.o
131 1.3 rillig all: var-scope-local-shell.o
132 1.3 rillig
133 1.3 rillig var-scope-local-assign.o \
134 1.3 rillig var-scope-local-append.o \
135 1.3 rillig var-scope-local-append-global.o \
136 1.3 rillig var-scope-local-default.o \
137 1.3 rillig var-scope-local-subst.o \
138 1.3 rillig var-scope-local-shell.o:
139 1.3 rillig : Making ${.TARGET} with VAR="${VAR}".
140 1.2 sjg
141 1.3 rillig # Target-local variables are enabled by default. Force them to be enabled
142 1.3 rillig # just in case a test above has disabled them.
143 1.2 sjg .MAKE.TARGET_LOCAL_VARIABLES= yes
144 1.2 sjg
145 1.3 rillig VAR= global
146 1.3 rillig
147 1.3 rillig # If the sources of a dependency line look like a variable assignment, make
148 1.3 rillig # treats them as such. There is only a single variable assignment per
149 1.3 rillig # dependency line, which makes whitespace around the assignment operator
150 1.3 rillig # irrelevant.
151 1.3 rillig #
152 1.3 rillig # expect-reset
153 1.3 rillig # expect: : Making var-scope-local-assign.o with VAR="local".
154 1.3 rillig var-scope-local-assign.o: VAR= local
155 1.3 rillig
156 1.3 rillig # Assignments using '+=' do *not* look up the global value, instead they only
157 1.3 rillig # look up the variable in the target's own scope.
158 1.3 rillig var-scope-local-append.o: VAR+= local
159 1.3 rillig # Once a variable is defined in the target-local scope, appending using '+='
160 1.3 rillig # behaves as expected. Note that the expression '${.TARGET}' is not resolved
161 1.3 rillig # when parsing the dependency line, its evaluation is deferred until the
162 1.3 rillig # target is actually made.
163 1.3 rillig # expect: : Making var-scope-local-append.o with VAR="local to var-scope-local-append.o".
164 1.3 rillig var-scope-local-append.o: VAR += to ${.TARGET}
165 1.3 rillig # To access the value of a global variable, use a variable expression. This
166 1.3 rillig # expression is expanded before parsing the whole dependency line. Since the
167 1.3 rillig # expansion happens to the right of both the dependency operator ':' and also
168 1.3 rillig # to the right of the assignment operator '=', the expanded text does not
169 1.3 rillig # affect the dependency or the variable assignment structurally. The
170 1.3 rillig # effective variable assignment, after expanding the whole line first, is thus
171 1.3 rillig # 'VAR= global+local'.
172 1.3 rillig # expect: : Making var-scope-local-append-global.o with VAR="global+local".
173 1.3 rillig var-scope-local-append-global.o: VAR= ${VAR}+local
174 1.3 rillig
175 1.3 rillig var-scope-local-default.o: VAR ?= first
176 1.3 rillig var-scope-local-default.o: VAR ?= second
177 1.3 rillig # XXX: '?=' does look at the global variable. That's a long-standing
178 1.3 rillig # inconsistency between the assignment operators '+=' and '?='. See
179 1.3 rillig # Var_AppendExpand and VarAssign_Eval.
180 1.3 rillig # expect: : Making var-scope-local-default.o with VAR="global".
181 1.3 rillig
182 1.3 rillig # Using the variable assignment operator ':=' provides another way of
183 1.3 rillig # accessing a global variable and extending it with local modifications. The
184 1.3 rillig # '$' has to be written as '$$' though to survive the expansion of the
185 1.3 rillig # dependency line as a whole.
186 1.3 rillig var-scope-local-subst.o: VAR := $${VAR}+local
187 1.3 rillig
188 1.3 rillig # The variable assignment operator '!=' assigns the output of the shell
189 1.3 rillig # command, as everywhere else.
190 1.3 rillig var-scope-local-shell.o: VAR != echo output
191 1.3 rillig
192 1.3 rillig
193 1.3 rillig # While VAR=use will be set for a .USE node, it will never be seen since only
194 1.3 rillig # the ultimate target's context is searched; the variable assignments from the
195 1.3 rillig # .USE target are not copied to the ultimate target's.
196 1.2 sjg a_use: .USE VAR=use
197 1.2 sjg : ${.TARGET} uses .USE VAR="${VAR}"
198 1.2 sjg
199 1.3 rillig all: var-scope-local-use.o
200 1.3 rillig var-scope-local-use.o: a_use
201 1.4 rillig
202 1.4 rillig
203 1.4 rillig # Since parse.c 1.656 from 2022-01-27 and before parse.c 1.662 from
204 1.4 rillig # 2022-02-05, there was an out-of-bounds read in Parse_IsVar when looking for
205 1.4 rillig # a variable assignment in a dependency line with trailing whitespace. Lines
206 1.4 rillig # without trailing whitespace were not affected. Global variable assignments
207 1.4 rillig # were guaranteed to have no trailing whitespace and were thus not affected.
208 1.4 rillig #
209 1.4 rillig # Try to reproduce some variants that may lead to a crash, depending on the
210 1.4 rillig # memory allocator. To get a crash, the terminating '\0' of the line must be
211 1.4 rillig # the last byte of a memory page. The expression '${:U}' forces this trailing
212 1.4 rillig # whitespace.
213 1.4 rillig
214 1.4 rillig # On FreeBSD x86_64, a crash could in some cases be forced using the following
215 1.4 rillig # line, which has length 47, so the terminating '\0' may end up at an address
216 1.4 rillig # of the form 0xXXXX_XXXX_XXXX_Xfff:
217 1.4 rillig Try_to_crash_FreeBSD.xxxxxxxxxxxxxxxxxx: 12345 ${:U}
218 1.4 rillig
219 1.4 rillig # The following line has length 4095, so line[4095] == '\0'. If the line is
220 1.4 rillig # allocated on a page boundary and the following page is not mapped, this line
221 1.4 rillig # leads to a segmentation fault.
222 1.4 rillig ${:U:range=511:@_@1234567@:ts.}: 12345 ${:U}
223 1.4 rillig
224 1.4 rillig # The following line has length 8191, so line[8191] == '\0'. If the line is
225 1.4 rillig # allocated on a page boundary and the following page is not mapped, this line
226 1.4 rillig # leads to a segmentation fault.
227 1.4 rillig ${:U:range=1023:@_@1234567@:ts.}: 12345 ${:U}
228 1.4 rillig
229 1.4 rillig 12345:
230