1 # $NetBSD: varname-makeflags.mk,v 1.8 2023/06/01 07:27:30 rillig Exp $ 2 # 3 # Tests for the environment variable 'MAKEFLAGS', from which additional 4 # command line arguments are read before the actual command line arguments. 5 # 6 # After reading the makefiles and before making the targets, the arguments 7 # that were collected in '.MAKEFLAGS' and '.MAKEOVERRIDES' are written back to 8 # the environment variable 'MAKEFLAGS'. 9 10 all: spaces_stage_0 dollars_stage_0 append_stage_0 override_stage_0 11 12 13 .if !make(*stage*) 14 15 # The unit tests are run with an almost empty environment. In particular, 16 # the variable MAKEFLAGS is not set. 17 . if ${MAKEFLAGS:Uundefined} != "undefined" 18 . error 19 . endif 20 21 # The special variable .MAKEFLAGS is influenced though. 22 # See varname-dot-makeflags.mk for more details. 23 . if ${.MAKEFLAGS} != " -r -k" 24 . error 25 . endif 26 27 28 # In POSIX mode, the environment variable MAKEFLAGS can contain letters only, 29 # for compatibility. These letters are exploded to form regular options. 30 OUTPUT!= env MAKEFLAGS=ikrs ${MAKE} -f /dev/null -v .MAKEFLAGS 31 . if ${OUTPUT} != " -i -k -r -s -V .MAKEFLAGS" 32 . error 33 . endif 34 35 # As soon as there is a single non-alphabetic character in the environment 36 # variable MAKEFLAGS, it is no longer split. In this example, the word 37 # "d0ikrs" is treated as a target, but the option '-v' prevents any targets 38 # from being built. 39 OUTPUT!= env MAKEFLAGS=d0ikrs ${MAKE} -r -f /dev/null -v .MAKEFLAGS 40 . if ${OUTPUT} != " -r -V .MAKEFLAGS" 41 . error ${OUTPUT} 42 . endif 43 44 .endif 45 46 47 # When options are parsed, the option and its argument are appended as 48 # separate words to the MAKEFLAGS for the child processes. Special characters 49 # in the option arguments are not quoted though. 50 spaces_stage_0: 51 @echo '$@: MAKEFLAGS=<'${MAKEFLAGS:Q}'>' 52 @echo "$@: env MAKEFLAGS=<$$MAKEFLAGS>" 53 @${MAKE} -f ${MAKEFILE} spaces_stage_1 -d00000 -D"VARNAME WITH SPACES" 54 55 # At this point, the 'VARNAME WITH SPACES' is no longer recognizable as a 56 # single command line argument. In practice, variable names don't contain 57 # spaces. 58 spaces_stage_1: 59 @echo '$@: MAKEFLAGS=<'${MAKEFLAGS:Q}'>' 60 @echo "$@: env MAKEFLAGS=<$$MAKEFLAGS>" 61 62 63 # Demonstrate that '$' characters are altered when they are passed on to child 64 # make processes via MAKEFLAGS. 65 dollars_stage_0: 66 @echo '$@: MAKEFLAGS=<'${MAKEFLAGS:Q}'>' 67 68 # The '$$$$' becomes a literal '$$' when building the '${MAKE}' 69 # command line, making the actual argument 'DOLLARS=$${varname}'. 70 # At this stage, MAKEFLAGS is not yet involved. 71 @${MAKE} -f ${MAKEFILE} dollars_stage_1 DOLLARS='$$$${varname}' 72 73 .if make(dollars_stage_1) 74 # At this point, the variable 'DOLLARS' contains '$${varname}', which 75 # evaluates to a literal '$' followed by '{varname}'. 76 . if ${DOLLARS} != "\${varname}" 77 . error 78 . endif 79 .endif 80 dollars_stage_1: 81 # At this point, the stage 1 make provides the environment variable 82 # 'MAKEFLAGS' to its child processes, even if the child process is not 83 # another make. 84 # 85 # expect: dollars_stage_1: env MAKEFLAGS=< -r -k DOLLARS=\$\{varname\}> 86 # 87 # The 'DOLLARS=\$\{varname\}' assignment is escaped so that the stage 88 # 2 make will see it as a single word. 89 @echo "$@: env MAKEFLAGS=<$$MAKEFLAGS>" 90 91 # At this point, evaluating the environment variable 'MAKEFLAGS' leads 92 # to strange side effects as the string '\$\{varname\}' is interpreted 93 # as: 94 # 95 # \ a literal string of a single backslash 96 # $\ the value of the variable named '\' 97 # {varname\} a literal string 98 # 99 # Since the variable named '\' is not defined, the resulting value is 100 # '\{varname\}'. Make doesn't handle isolated '$' characters in 101 # strings well, instead each '$' has to be part of a '$$' or be part 102 # of a subexpression like '${VAR}'. 103 @echo '$@: MAKEFLAGS=<'${MAKEFLAGS:Q}'>' 104 105 # The modifier ':q' preserves a '$$' in an expression value instead of 106 # expanding it to a single '$', but it's already too late, as that 107 # modifier applies after the expression has been evaluated. Except 108 # for debug logging, there is no way to process strings that contain 109 # isolated '$'. 110 @echo '$@: MAKEFLAGS:q=<'${MAKEFLAGS:q}'>' 111 112 @${MAKE} -f ${MAKEFILE} dollars_stage_2 113 114 .if make(dollars_stage_2) 115 # At this point, the variable 'DOLLARS' contains '${varname}', and since 116 # 'varname' is undefined, that expression evaluates to an empty string. 117 . if ${DOLLARS} != "" 118 . error 119 . endif 120 varname= varvalue 121 . if ${DOLLARS} != "varvalue" 122 . error 123 . endif 124 . undef varname 125 .endif 126 dollars_stage_2: 127 @echo "$@: env MAKEFLAGS=<$$MAKEFLAGS>" 128 @echo '$@: dollars=<'${DOLLARS:Q}'>' 129 @echo '$@: MAKEFLAGS=<'${MAKEFLAGS:Q}'>' 130 @${MAKE} -f ${MAKEFILE} dollars_stage_3 131 132 dollars_stage_3: 133 @echo "$@: env MAKEFLAGS=<$$MAKEFLAGS>" 134 @echo '$@: dollars=<'${DOLLARS:Uundefined:Q}'>' 135 @echo '$@: MAKEFLAGS=<'${MAKEFLAGS:Q}'>' 136 137 138 # Demonstrates in which exact order the MAKEFLAGS are built from the parent 139 # MAKEFLAGS and the flags from the command line, in particular that variable 140 # assignments are passed at the end, after the options. 141 append_stage_0: 142 @echo '$@: MAKEFLAGS=<'${MAKEFLAGS:Q}'>' 143 @${MAKE} -Dbefore-0 -f ${MAKEFILE} append_stage_1 VAR0=value -Dafter-0 144 145 append_stage_1: 146 @echo '$@: MAKEFLAGS=<'${MAKEFLAGS:Q}'>' 147 @${MAKE} -Dbefore-1 -f ${MAKEFILE} append_stage_2 VAR1=value -Dafter-1 148 149 append_stage_2: 150 @echo '$@: MAKEFLAGS=<'${MAKEFLAGS:Q}'>' 151 @${MAKE} -Dbefore-2 -f ${MAKEFILE} append_stage_3 VAR2=value -Dafter-2 152 153 append_stage_3: 154 @echo '$@: MAKEFLAGS=<'${MAKEFLAGS:Q}'>' 155 156 157 # Demonstrates the implementation details of 'MAKEFLAGS', in particular that 158 # it is an environment variable rather than a global variable. 159 override_stage_0: 160 @${MAKE} -f ${MAKEFILE} STAGE=1 VAR=value override_stage_1 161 162 .if make(override_stage_1) 163 # While parsing the makefiles, 'MAKEFLAGS' is the value of the environment 164 # variable, in this case provided by stage 0. 165 . if ${MAKEFLAGS:M*} != "-r -k" 166 . error 167 . endif 168 MAKEFLAGS= overridden # temporarily override it 169 . if ${MAKEFLAGS} != "overridden" 170 . error 171 . endif 172 .undef MAKEFLAGS # make the environment variable visible again 173 . if ${MAKEFLAGS:M*} != "-r -k" 174 . error 175 . endif 176 .endif 177 override_stage_1: 178 @echo '$@: run MAKEFLAGS=<'${MAKEFLAGS:Q}'>' 179 @${MAKE} -f ${MAKEFILE} STAGE=2 override_stage_2 180 181 override_stage_2: 182 @echo '$@: STAGE=<${STAGE}> VAR=<${VAR}>' 183