1# $Id: varmisc.mk,v 1.23 2021/02/05 20:02:30 sjg Exp $ 2# $NetBSD: varmisc.mk,v 1.30 2021/02/04 21:42:47 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 misshandling of nested vars 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# begin .MAKE.SAVE_DOLLARS; see Var_SetWithFlags and ParseBoolean. 82SD_VALUES= 0 1 2 False True false true Yes No yes no On Off ON OFF on off 83SD_4_DOLLARS= $$$$ 84 85.for val in ${SD_VALUES} 86.MAKE.SAVE_DOLLARS:= ${val} # Must be := since a simple = has no effect. 87SD.${val}:= ${SD_4_DOLLARS} 88.endfor 89.MAKE.SAVE_DOLLARS:= yes 90 91save-dollars: 92.for val in ${SD_VALUES} 93 @printf '%s: %-8s = %s\n' $@ ${val} ${SD.${val}:Q} 94.endfor 95 96# Appending to an undefined variable does not add a space in front. 97.undef APPENDED 98APPENDED+= value 99.if ${APPENDED} != "value" 100. error "${APPENDED}" 101.endif 102 103# Appending to an empty variable adds a space between the old value 104# and the additional value. 105APPENDED= # empty 106APPENDED+= value 107.if ${APPENDED} != " value" 108. error "${APPENDED}" 109.endif 110 111# Appending to parameterized variables works as well. 112PARAM= param 113VAR.${PARAM}= 1 114VAR.${PARAM}+= 2 115.if ${VAR.param} != "1 2" 116. error "${VAR.param}" 117.endif 118 119# The variable name can contain arbitrary characters. 120# If the expanded variable name ends in a +, this still does not influence 121# the parser. The assignment operator is still a simple assignment. 122# Therefore, there is no need to add a space between the variable name 123# and the assignment operator. 124PARAM= + 125VAR.${PARAM}= 1 126VAR.${PARAM}+= 2 127.if ${VAR.+} != "1 2" 128. error "${VAR.+}" 129.endif 130.for param in + ! ? 131VAR.${param}= ${param} 132.endfor 133.if ${VAR.+} != "+" || ${VAR.!} != "!" || ${VAR.?} != "?" 134. error "${VAR.+}" "${VAR.!}" "${VAR.?}" 135.endif 136 137# Appending to a variable from the environment creates a copy of that variable 138# in the global scope. 139# The appended value is not exported automatically. 140# When a variable is exported, the exported value is taken at the time of the 141# .export directive. Later changes to the variable have no effect. 142.export FROM_ENV_BEFORE 143FROM_ENV+= mk 144FROM_ENV_BEFORE+= mk 145FROM_ENV_AFTER+= mk 146.export FROM_ENV_AFTER 147 148export-appended: 149 @echo $@: "$$FROM_ENV" 150 @echo $@: "$$FROM_ENV_BEFORE" 151 @echo $@: "$$FROM_ENV_AFTER" 152 153# begin parse-dynamic 154# 155# Demonstrate that the target-specific variables are not evaluated in 156# the global scope. Their expressions are preserved until there is a local 157# scope in which resolving them makes sense. 158 159# There are different code paths for short names ... 160${:U>}= before 161GS_TARGET:= $@ 162GS_MEMBER:= $% 163GS_PREFIX:= $* 164GS_ARCHIVE:= $! 165GS_ALLSRC:= $> 166${:U>}= after 167# ... and for braced short names ... 168GB_TARGET:= ${@} 169GB_MEMBER:= ${%} 170GB_PREFIX:= ${*} 171GB_ARCHIVE:= ${!} 172GB_ALLSRC:= ${>} 173# ... and for long names. 174GL_TARGET:= ${.TARGET} 175GL_MEMBER:= ${.MEMBER} 176GL_PREFIX:= ${.PREFIX} 177GL_ARCHIVE:= ${.ARCHIVE} 178GL_ALLSRC:= ${.ALLSRC} 179 180parse-dynamic: 181 @echo $@: ${GS_TARGET} ${GS_MEMBER} ${GS_PREFIX} ${GS_ARCHIVE} ${GS_ALLSRC} 182 @echo $@: ${GB_TARGET} ${GB_MEMBER} ${GB_PREFIX} ${GB_ARCHIVE} ${GB_ALLSRC} 183 @echo $@: ${GL_TARGET} ${GL_MEMBER} ${GL_PREFIX} ${GL_ARCHIVE} ${GL_ALLSRC} 184 185# Since 2020-07-28, make complains about unclosed variables. 186# Before that, it had complained about unclosed variables only when 187# parsing the modifiers, but not when parsing the variable name. 188 189UNCLOSED_INDIR_1= ${UNCLOSED_ORIG 190UNCLOSED_INDIR_2= ${UNCLOSED_INDIR_1} 191 192FLAGS= one two 193FLAGS+= ${FLAGS.${.ALLSRC:M*.c:T:u}} 194FLAGS.target2.c= three four 195 196target1.c: 197target2.c: 198 199all: target1-flags target2-flags 200target1-flags: target1.c 201 @echo $@: we have: ${FLAGS} 202 203target2-flags: target2.c 204 @echo $@: we have: ${FLAGS} 205 206varerror-unclosed: 207 @echo $@:begin 208 @echo $( 209 @echo $(UNCLOSED 210 @echo ${UNCLOSED 211 @echo ${UNCLOSED:M${PATTERN 212 @echo ${UNCLOSED.${param 213 @echo $ 214.for i in 1 2 3 215 @echo ${UNCLOSED.${i} 216.endfor 217 @echo ${UNCLOSED_INDIR_2} 218 @echo $@:end 219