1# $Id: varmisc.mk,v 1.25 2021/12/07 00:03:11 sjg Exp $ 2# $NetBSD: varmisc.mk,v 1.32 2021/12/05 10:02:51 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 strftime cmpv manok 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 50April1= 1459494000 51 52# slightly contorted syntax to use utc via variable 53strftime: 54 @echo ${year=%Y month=%m day=%d:L:gmtime=1459494000} 55 @echo date=${%Y%m%d:L:${gmtime=${April1}:L}} 56 57# big jumps to handle 3 digits per step 58M_cmpv.units= 1 1000 1000000 59M_cmpv= S,., ,g:_:range:@i@+ $${_:[-$$i]} \* $${M_cmpv.units:[$$i]}@:S,^,expr 0 ,1:sh 60 61Version= 123.456.789 62cmpv.only= target specific vars 63 64cmpv: 65 @echo Version=${Version} == ${Version:${M_cmpv}} 66 @echo Literal=3.4.5 == ${3.4.5:L:${M_cmpv}} 67 @echo We have ${${.TARGET:T}.only} 68 69# catch mishandling of nested variables in .for loop 70MAN= 71MAN1= make.1 72.for s in 1 2 73. if defined(MAN$s) && !empty(MAN$s) 74MAN+= ${MAN$s} 75. endif 76.endfor 77 78manok: 79 @echo MAN=${MAN} 80 81# Test parsing of boolean values. 82# begin .MAKE.SAVE_DOLLARS; see Var_SetWithFlags and ParseBoolean. 83SD_VALUES= 0 1 2 False True false true Yes No yes no On Off ON OFF on off 84SD_4_DOLLARS= $$$$ 85 86.for val in ${SD_VALUES} 87# The assignment must be done using ':=' since a simple '=' would be 88# interpreted as 'yes', due to the leading '$'; see ParseBoolean. 89.MAKE.SAVE_DOLLARS:= ${val} 90SD.${val}:= ${SD_4_DOLLARS} 91.endfor 92.MAKE.SAVE_DOLLARS:= yes 93 94save-dollars: 95.for val in ${SD_VALUES} 96 @printf '%s: %-8s = %s\n' $@ ${val} ${SD.${val}:Q} 97.endfor 98# end .MAKE.SAVE_DOLLARS 99 100# Appending to an undefined variable does not add a space in front. 101.undef APPENDED 102APPENDED+= value 103.if ${APPENDED} != "value" 104. error "${APPENDED}" 105.endif 106 107# Appending to an empty variable adds a space between the old value 108# and the additional value. 109APPENDED= # empty 110APPENDED+= value 111.if ${APPENDED} != " value" 112. error "${APPENDED}" 113.endif 114 115# Appending to parameterized variables works as well. 116PARAM= param 117VAR.${PARAM}= 1 118VAR.${PARAM}+= 2 119.if ${VAR.param} != "1 2" 120. error "${VAR.param}" 121.endif 122 123# The variable name can contain arbitrary characters. 124# If the expanded variable name ends in a +, this still does not influence 125# the parser. The assignment operator is still a simple assignment. 126# Therefore, there is no need to add a space between the variable name 127# and the assignment operator. 128PARAM= + 129VAR.${PARAM}= 1 130VAR.${PARAM}+= 2 131.if ${VAR.+} != "1 2" 132. error "${VAR.+}" 133.endif 134.for param in + ! ? 135VAR.${param}= ${param} 136.endfor 137.if ${VAR.+} != "+" || ${VAR.!} != "!" || ${VAR.?} != "?" 138. error "${VAR.+}" "${VAR.!}" "${VAR.?}" 139.endif 140 141# Appending to a variable from the environment creates a copy of that variable 142# in the global scope. 143# The appended value is not exported automatically. 144# When a variable is exported, the exported value is taken at the time of the 145# .export directive. Later changes to the variable have no effect. 146.export FROM_ENV_BEFORE 147FROM_ENV+= mk 148FROM_ENV_BEFORE+= mk 149FROM_ENV_AFTER+= mk 150.export FROM_ENV_AFTER 151 152export-appended: 153 @echo $@: "$$FROM_ENV" 154 @echo $@: "$$FROM_ENV_BEFORE" 155 @echo $@: "$$FROM_ENV_AFTER" 156 157# begin parse-dynamic 158# 159# Demonstrate that the target-specific variables are not evaluated in 160# the global scope. Their expressions are preserved until there is a local 161# scope in which resolving them makes sense. 162 163# There are different code paths for short names ... 164${:U>}= before 165GS_TARGET:= $@ 166GS_MEMBER:= $% 167GS_PREFIX:= $* 168GS_ARCHIVE:= $! 169GS_ALLSRC:= $> 170${:U>}= after 171# ... and for braced short names ... 172GB_TARGET:= ${@} 173GB_MEMBER:= ${%} 174GB_PREFIX:= ${*} 175GB_ARCHIVE:= ${!} 176GB_ALLSRC:= ${>} 177# ... and for long names. 178GL_TARGET:= ${.TARGET} 179GL_MEMBER:= ${.MEMBER} 180GL_PREFIX:= ${.PREFIX} 181GL_ARCHIVE:= ${.ARCHIVE} 182GL_ALLSRC:= ${.ALLSRC} 183 184parse-dynamic: 185 @echo $@: ${GS_TARGET} ${GS_MEMBER} ${GS_PREFIX} ${GS_ARCHIVE} ${GS_ALLSRC} 186 @echo $@: ${GB_TARGET} ${GB_MEMBER} ${GB_PREFIX} ${GB_ARCHIVE} ${GB_ALLSRC} 187 @echo $@: ${GL_TARGET} ${GL_MEMBER} ${GL_PREFIX} ${GL_ARCHIVE} ${GL_ALLSRC} 188 189# Since 2020-07-28, make complains about unclosed variables. 190# Before that, it had complained about unclosed variables only when 191# parsing the modifiers, but not when parsing the variable name. 192 193UNCLOSED_INDIR_1= ${UNCLOSED_ORIG 194UNCLOSED_INDIR_2= ${UNCLOSED_INDIR_1} 195 196FLAGS= one two 197FLAGS+= ${FLAGS.${.ALLSRC:M*.c:T:u}} 198FLAGS.target2.c= three four 199 200target1.c: 201target2.c: 202 203all: target1-flags target2-flags 204target1-flags: target1.c 205 @echo $@: we have: ${FLAGS} 206 207target2-flags: target2.c 208 @echo $@: we have: ${FLAGS} 209 210varerror-unclosed: 211 @echo $@:begin 212 @echo $( 213 @echo $(UNCLOSED 214 @echo ${UNCLOSED 215 @echo ${UNCLOSED:M${PATTERN 216 @echo ${UNCLOSED.${param 217 @echo $ 218.for i in 1 2 3 219 @echo ${UNCLOSED.${i} 220.endfor 221 @echo ${UNCLOSED_INDIR_2} 222 @echo $@:end 223