1# $Id: varmisc.mk,v 1.27 2024/07/06 18:23:18 sjg Exp $ 2# $NetBSD: varmisc.mk,v 1.35 2024/07/05 18:59:33 rillig Exp $ 3# 4# Miscellaneous variable tests. 5 6all: unmatched_var_paren D_true U_true D_false U_false Q_lhs Q_rhs NQ_none \ 7 cmpv 8all: save-dollars 9all: export-appended 10all: parse-dynamic 11all: varerror-unclosed 12 13unmatched_var_paren: 14 @echo ${foo::=foo-text} 15 16True= ${echo true >&2:L:sh}TRUE 17False= ${echo false >&2:L:sh}FALSE 18 19VSET= is set 20.undef UNDEF 21 22U_false: 23 @echo :U skipped when var set 24 @echo ${VSET:U${False}} 25 26D_false: 27 @echo :D skipped if var undef 28 @echo ${UNDEF:D${False}} 29 30U_true: 31 @echo :U expanded when var undef 32 @echo ${UNDEF:U${True}} 33 34D_true: 35 @echo :D expanded when var set 36 @echo ${VSET:D${True}} 37 38Q_lhs: 39 @echo :? only lhs when value true 40 @echo ${1:L:?${True}:${False}} 41 42Q_rhs: 43 @echo :? only rhs when value false 44 @echo ${0:L:?${True}:${False}} 45 46NQ_none: 47 @echo do not evaluate or expand :? if discarding 48 @echo ${VSET:U${1:L:?${True}:${False}}} 49 50# big jumps to handle 3 digits per step 51M_cmpv.units= 1 1000 1000000 52M_cmpv= S,., ,g:_:range:@i@+ $${_:[-$$i]} \* $${M_cmpv.units:[$$i]}@:S,^,expr 0 ,1:sh 53 54Version= 123.456.789 55cmpv.only= target specific vars 56 57cmpv: 58 @echo Version=${Version} == ${Version:${M_cmpv}} 59 @echo Literal=3.4.5 == ${3.4.5:L:${M_cmpv}} 60 @echo We have ${${.TARGET:T}.only} 61 62 63# Test parsing of boolean values. 64# begin .MAKE.SAVE_DOLLARS; see Var_SetWithFlags and ParseBoolean. 65SD_VALUES= 0 1 2 False True false true Yes No yes no On Off ON OFF on off 66SD_4_DOLLARS= $$$$ 67 68.for val in ${SD_VALUES} 69# The assignment must be done using ':=' since a simple '=' would be 70# interpreted as 'yes', due to the leading '$'; see ParseBoolean. 71.MAKE.SAVE_DOLLARS:= ${val} 72SD.${val}:= ${SD_4_DOLLARS} 73.endfor 74.MAKE.SAVE_DOLLARS:= yes 75 76save-dollars: 77.for val in ${SD_VALUES} 78 @printf '%s: %-8s = %s\n' $@ ${val} ${SD.${val}:Q} 79.endfor 80# end .MAKE.SAVE_DOLLARS 81 82# Appending to an undefined variable does not add a space in front. 83.undef APPENDED 84APPENDED+= value 85.if ${APPENDED} != "value" 86. error "${APPENDED}" 87.endif 88 89# Appending to an empty variable adds a space between the old value 90# and the additional value. 91APPENDED= # empty 92APPENDED+= value 93.if ${APPENDED} != " value" 94. error "${APPENDED}" 95.endif 96 97# Appending to parameterized variables works as well. 98PARAM= param 99VAR.${PARAM}= 1 100VAR.${PARAM}+= 2 101.if ${VAR.param} != "1 2" 102. error "${VAR.param}" 103.endif 104 105# The variable name can contain arbitrary characters. 106# If the expanded variable name ends in a +, this still does not influence 107# the parser. The assignment operator is still a simple assignment. 108# Therefore, there is no need to add a space between the variable name 109# and the assignment operator. 110PARAM= + 111VAR.${PARAM}= 1 112VAR.${PARAM}+= 2 113.if ${VAR.+} != "1 2" 114. error "${VAR.+}" 115.endif 116.for param in : + ! ? 117VAR.${param}= ${param} 118.endfor 119.if ${VAR.${:U\:}} != ":" || ${VAR.+} != "+" || ${VAR.!} != "!" || ${VAR.?} != "?" 120. error "${VAR.+}" "${VAR.!}" "${VAR.?}" 121.endif 122 123# Appending to a variable from the environment creates a copy of that variable 124# in the global scope. 125# The appended value is not exported automatically. 126# When a variable is exported, the exported value is taken at the time of the 127# .export directive. Later changes to the variable have no effect. 128.export FROM_ENV_BEFORE 129FROM_ENV+= mk 130FROM_ENV_BEFORE+= mk 131FROM_ENV_AFTER+= mk 132.export FROM_ENV_AFTER 133 134export-appended: 135 @echo $@: "$$FROM_ENV" 136 @echo $@: "$$FROM_ENV_BEFORE" 137 @echo $@: "$$FROM_ENV_AFTER" 138 139# begin parse-dynamic 140# 141# Demonstrate that the target-specific variables are not evaluated in 142# the global scope. Their expressions are preserved until there is a local 143# scope in which resolving them makes sense. 144 145# There are different code paths for short names ... 146${:U>}= before 147GS_TARGET:= $@ 148GS_MEMBER:= $% 149GS_PREFIX:= $* 150GS_ARCHIVE:= $! 151GS_ALLSRC:= $> 152${:U>}= after 153# ... and for braced short names ... 154GB_TARGET:= ${@} 155GB_MEMBER:= ${%} 156GB_PREFIX:= ${*} 157GB_ARCHIVE:= ${!} 158GB_ALLSRC:= ${>} 159# ... and for long names. 160GL_TARGET:= ${.TARGET} 161GL_MEMBER:= ${.MEMBER} 162GL_PREFIX:= ${.PREFIX} 163GL_ARCHIVE:= ${.ARCHIVE} 164GL_ALLSRC:= ${.ALLSRC} 165 166parse-dynamic: 167 @echo $@: ${GS_TARGET} ${GS_MEMBER} ${GS_PREFIX} ${GS_ARCHIVE} ${GS_ALLSRC} 168 @echo $@: ${GB_TARGET} ${GB_MEMBER} ${GB_PREFIX} ${GB_ARCHIVE} ${GB_ALLSRC} 169 @echo $@: ${GL_TARGET} ${GL_MEMBER} ${GL_PREFIX} ${GL_ARCHIVE} ${GL_ALLSRC} 170 171# Since 2020-07-28, make complains about unclosed variables. 172# Before that, it had complained about unclosed variables only when 173# parsing the modifiers, but not when parsing the variable name. 174 175UNCLOSED_INDIR_1= ${UNCLOSED_ORIG 176UNCLOSED_INDIR_2= ${UNCLOSED_INDIR_1} 177 178FLAGS= one two 179FLAGS+= ${FLAGS.${.ALLSRC:M*.c:T:u}} 180FLAGS.target2.c= three four 181 182target1.c: 183target2.c: 184 185all: target1-flags target2-flags 186target1-flags: target1.c 187 @echo $@: we have: ${FLAGS} 188 189target2-flags: target2.c 190 @echo $@: we have: ${FLAGS} 191 192varerror-unclosed: 193 @echo $@:begin 194# expect: make: in target "varerror-unclosed": Unclosed variable "" 195 @echo $( 196# expect: make: in target "varerror-unclosed": Unclosed variable "UNCLOSED" 197 @echo $(UNCLOSED 198# expect: make: in target "varerror-unclosed": Unclosed variable "UNCLOSED" 199 @echo ${UNCLOSED 200# expect: make: in target "varerror-unclosed": while evaluating variable "UNCLOSED" with value "": Unclosed expression, expecting '}' for modifier "M${PATTERN" 201 @echo ${UNCLOSED:M${PATTERN 202# expect: make: in target "varerror-unclosed": Unclosed variable "param" 203# expect: make: in target "varerror-unclosed": Unclosed variable "UNCLOSED." 204 @echo ${UNCLOSED.${param 205 @echo $ 206.for i in 1 2 3 207# expect: make: in target "varerror-unclosed": Unclosed variable "UNCLOSED.1" 208# expect: make: in target "varerror-unclosed": Unclosed variable "UNCLOSED.2" 209# expect: make: in target "varerror-unclosed": Unclosed variable "UNCLOSED.3" 210 @echo ${UNCLOSED.${i} 211.endfor 212 @echo ${UNCLOSED_INDIR_2} 213 @echo $@:end 214