varname-dot-makeflags.mk revision 1.5 1 # $NetBSD: varname-dot-makeflags.mk,v 1.5 2023/02/25 11:11:16 rillig Exp $
2 #
3 # Tests for the special .MAKEFLAGS variable, which collects almost all
4 # command line arguments and passes them on to any child processes via
5 # the environment variable MAKEFLAGS (without leading '.').
6 #
7 # See also:
8 # varname-dot-makeoverrides.mk
9
10 all: spaces_stage_0 dollars_stage_0 append_stage_0 override_stage_0
11
12
13 # When options are parsed, the option and its argument are appended as
14 # separate words to .MAKEFLAGS. Special characters in the option argument
15 # are not quoted though. It seems to have not been necessary since at least
16 # 1993.
17 spaces_stage_0:
18 @echo '$@: MAKEFLAGS=<'${MAKEFLAGS:Q}'>'
19 @echo "$@: env MAKEFLAGS=<$$MAKEFLAGS>"
20 @${MAKE} -f ${MAKEFILE} spaces_stage_1 -d00000 -D"VARNAME WITH SPACES"
21
22 # At this point, the 'VARNAME WITH SPACES' is no longer recognizable as a
23 # single command line argument. In practice, variable names don't contain
24 # spaces.
25 spaces_stage_1:
26 @echo '$@: MAKEFLAGS=<'${MAKEFLAGS:Q}'>'
27 @echo "$@: env MAKEFLAGS=<$$MAKEFLAGS>"
28
29
30 # Demonstrate that '$' characters are altered when they are passed on to child
31 # make processes via MAKEFLAGS.
32 dollars_stage_0:
33 @echo '$@: MAKEFLAGS=<'${MAKEFLAGS:Q}'>'
34
35 # The '$$$$' becomes a literal '$$' when building the '${MAKE}'
36 # command line, making the actual argument 'DOLLARS=$${varname}'.
37 # At this stage, MAKEFLAGS is not yet involved.
38 @${MAKE} -f ${MAKEFILE} dollars_stage_1 DOLLARS='$$$${varname}'
39
40 .if make(dollars_stage_1)
41 # At this point, the variable 'DOLLARS' contains '$${varname}', which
42 # evaluates to a literal '$' followed by '{varname}'.
43 . if ${DOLLARS} != "\${varname}"
44 . error
45 . endif
46 .endif
47 dollars_stage_1:
48 # At this point, the stage 1 make provides the environment variable
49 # 'MAKEFLAGS' to its child processes, even if the child process is not
50 # another make.
51 #
52 # expect: dollars_stage_1: env MAKEFLAGS=< -r -k DOLLARS=\$\{varname\}>
53 #
54 # The 'DOLLARS=\$\{varname\}' assignment is escaped so that the stage
55 # 2 make will see it as a single word.
56 @echo "$@: env MAKEFLAGS=<$$MAKEFLAGS>"
57
58 # At this point, evaluating the environment variable 'MAKEFLAGS' leads
59 # to strange side effects as the string '\$\{varname\}' is interpreted
60 # as:
61 #
62 # \ a literal string of a single backslash
63 # $\ the value of the variable named '\'
64 # {varname\} a literal string
65 #
66 # Since the variable name '\' is not defined, the resulting value is
67 # '\{varname\}'. Make doesn't handle isolated '$' characters in
68 # strings well, instead each '$' has to be part of a '$$' or be part
69 # of a subexpression like '${VAR}'.
70 @echo '$@: MAKEFLAGS=<'${MAKEFLAGS:Q}'>'
71
72 # The modifier ':q' preserves a '$$' in an expression value instead of
73 # expanding it to a single '$', but it's already too late, as that
74 # modifier applies after the expression has been evaluated. Except
75 # for debug logging, there is no way to process strings that contain
76 # isolated '$'.
77 @echo '$@: MAKEFLAGS:q=<'${MAKEFLAGS:q}'>'
78
79 @${MAKE} -f ${MAKEFILE} dollars_stage_2
80
81 .if make(dollars_stage_2)
82 # At this point, the variable 'DOLLARS' contains '${varname}', and since
83 # 'varname' is undefined, that expression evaluates to an empty string.
84 . if ${DOLLARS} != ""
85 . error
86 . endif
87 varname= varvalue
88 . if ${DOLLARS} != "varvalue"
89 . error
90 . endif
91 . undef varname
92 .endif
93 dollars_stage_2:
94 @echo "$@: env MAKEFLAGS=<$$MAKEFLAGS>"
95 @echo '$@: dollars=<'${DOLLARS:Q}'>'
96 @echo '$@: MAKEFLAGS=<'${MAKEFLAGS:Q}'>'
97 @${MAKE} -f ${MAKEFILE} dollars_stage_3
98
99 dollars_stage_3:
100 @echo "$@: env MAKEFLAGS=<$$MAKEFLAGS>"
101 @echo '$@: dollars=<'${DOLLARS:Uundefined:Q}'>'
102 @echo '$@: MAKEFLAGS=<'${MAKEFLAGS:Q}'>'
103
104
105 # Demonstrates in which exact order the MAKEFLAGS are built together from the
106 # parent MAKEFLAGS and the flags from the command line, in particular that
107 # variable assignments are passed at the end, after the options.
108 append_stage_0:
109 @echo '$@: MAKEFLAGS=<'${MAKEFLAGS:Q}'>'
110 @${MAKE} -Dbefore-0 -f ${MAKEFILE} append_stage_1 VAR0=value -Dafter-0
111
112 append_stage_1:
113 @echo '$@: MAKEFLAGS=<'${MAKEFLAGS:Q}'>'
114 @${MAKE} -Dbefore-1 -f ${MAKEFILE} append_stage_2 VAR1=value -Dafter-1
115
116 append_stage_2:
117 @echo '$@: MAKEFLAGS=<'${MAKEFLAGS:Q}'>'
118 @${MAKE} -Dbefore-2 -f ${MAKEFILE} append_stage_3 VAR2=value -Dafter-2
119
120 append_stage_3:
121 @echo '$@: MAKEFLAGS=<'${MAKEFLAGS:Q}'>'
122
123
124 # Demonstrates the implementation details of 'MAKEFLAGS', in particular that
125 # it is an environment variable rather than a global variable.
126 override_stage_0:
127 @${MAKE} -f ${MAKEFILE} STAGE=1 VAR=value override_stage_1
128
129 .if make(override_stage_1)
130 # While parsing the makefiles, 'MAKEFLAGS' is the value of the environment
131 # variable, in this case provided by stage 0.
132 . if ${MAKEFLAGS:M*} != "-r -k"
133 . error
134 . endif
135 MAKEFLAGS= overridden # temporarily override it
136 . if ${MAKEFLAGS} != "overridden"
137 . error
138 . endif
139 .undef MAKEFLAGS # make the environment variable visible again
140 . if ${MAKEFLAGS:M*} != "-r -k"
141 . error
142 . endif
143 .endif
144 override_stage_1:
145 @echo '$@: run MAKEFLAGS=<'${MAKEFLAGS:Q}'>'
146 @${MAKE} -f ${MAKEFILE} STAGE=2 override_stage_2
147
148 override_stage_2:
149 @echo '$@: STAGE=<${STAGE}> VAR=<${VAR}>'
150