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