1# $NetBSD: var-op-expand.mk,v 1.11 2021/01/01 23:07:48 sjg Exp $ 2# 3# Tests for the := variable assignment operator, which expands its 4# right-hand side. 5 6.MAKE.SAVE_DOLLARS:= yes 7 8# If the right-hand side does not contain a dollar sign, the ':=' assignment 9# operator has the same effect as the '=' assignment operator. 10VAR:= value 11.if ${VAR} != "value" 12. error 13.endif 14 15# When a ':=' assignment is performed, its right-hand side is evaluated and 16# expanded as far as possible. Contrary to other situations, '$$' and 17# variable expressions based on undefined variables are preserved though. 18# 19# Whether a variable expression is undefined or not is determined at the end 20# of evaluating the expression. The consequence is that ${:Ufallback} expands 21# to "fallback"; initially this expression is undefined since it is based on 22# the variable named "", which is guaranteed to be never defined, but at the 23# end of evaluating the expression ${:Ufallback}, the modifier ':U' has turned 24# the expression into a defined expression. 25 26 27# literal dollar signs 28VAR:= $$ $$$$ $$$$$$$$ 29.if ${VAR} != "\$ \$\$ \$\$\$\$" 30. error 31.endif 32 33 34# reference to a variable containing a literal dollar sign 35REF= $$ $$$$ $$$$$$$$ 36VAR:= ${REF} 37REF= too late 38.if ${VAR} != "\$ \$\$ \$\$\$\$" 39. error 40.endif 41 42 43# reference to an undefined variable 44.undef UNDEF 45VAR:= <${UNDEF}> 46UNDEF= after 47.if ${VAR} != "<after>" 48. error 49.endif 50 51 52# reference to a variable whose name is computed from another variable 53REF2= referred to 54REF= REF2 55VAR:= ${${REF}} 56REF= too late 57.if ${VAR} != "referred to" 58. error 59.endif 60 61 62# expression with an indirect modifier referring to an undefined variable 63.undef UNDEF 64VAR:= ${:${UNDEF}} 65UNDEF= Uwas undefined 66.if ${VAR} != "was undefined" 67. error 68.endif 69 70 71# expression with an indirect modifier referring to another variable that 72# in turn refers to an undefined variable 73# 74# XXX: Even though this is a ':=' assignment, the '${UNDEF}' in the part of 75# the variable modifier is not preserved. To preserve it, ParseModifierPart 76# would have to call VarSubstExpr somehow since this is the only piece of 77# code that takes care of this global variable. 78.undef UNDEF 79REF= U${UNDEF} 80#.MAKEFLAGS: -dv 81VAR:= ${:${REF}} 82#.MAKEFLAGS: -d0 83REF= too late 84UNDEF= Uwas undefined 85.if ${VAR} != "" 86. error 87.endif 88 89 90# In variable assignments using the ':=' operator, undefined variables are 91# preserved, no matter how indirectly they are referenced. 92.undef REF3 93REF2= <${REF3}> 94REF= ${REF2} 95VAR:= ${REF} 96REF3= too late 97.if ${VAR} != "<too late>" 98. error 99.endif 100 101 102# In variable assignments using the ':=' operator, '$$' are preserved, no 103# matter how indirectly they are referenced. 104REF2= REF2:$$ $$$$ 105REF= REF:$$ $$$$ ${REF2} 106VAR:= VAR:$$ $$$$ ${REF} 107.if ${VAR} != "VAR:\$ \$\$ REF:\$ \$\$ REF2:\$ \$\$" 108. error 109.endif 110 111 112# In variable assignments using the ':=' operator, '$$' are preserved in the 113# expressions of the top level, but not in expressions that are nested. 114VAR:= top:$$ ${:Unest1\:\$\$} ${:Unest2${:U\:\$\$}} 115.if ${VAR} != "top:\$ nest1:\$ nest2:\$" 116. error 117.endif 118 119 120# In variable assignments using the ':=' operator, there may be expressions 121# containing variable modifiers, and these modifiers may refer to other 122# variables. These referred-to variables are expanded at the time of 123# assignment. The undefined variables are kept as-is and are later expanded 124# when evaluating the condition. 125# 126# Contrary to the assignment operator '=', the assignment operator ':=' 127# consumes the '$' from modifier parts. 128REF.word= 1:$$ 2:$$$$ 4:$$$$$$$$ 129.undef REF.undef 130VAR:= ${:Uword undef:@word@${REF.${word}}@}, direct: ${REF.word} ${REF.undef} 131REF.word= word.after 132REF.undef= undef.after 133.if ${VAR} != "1:2:\$ 4:\$\$ undef.after, direct: 1:\$ 2:\$\$ 4:\$\$\$\$ undef.after" 134. error 135.endif 136 137# Just for comparison, the previous example using the assignment operator '=' 138# instead of ':='. The right-hand side of the assignment is not evaluated at 139# the time of assignment but only later, when ${VAR} appears in the condition. 140# 141# At that point, both REF.word and REF.undef are defined. 142REF.word= 1:$$ 2:$$$$ 4:$$$$$$$$ 143.undef REF.undef 144VAR= ${:Uword undef:@word@${REF.${word}}@}, direct: ${REF.word} ${REF.undef} 145REF.word= word.after 146REF.undef= undef.after 147.if ${VAR} != "word.after undef.after, direct: word.after undef.after" 148. error 149.endif 150 151 152# Between var.c 1.42 from 2000-05-11 and before parse.c 1.520 from 2020-12-27, 153# if the variable name in a ':=' assignment referred to an undefined variable, 154# there were actually 2 assignments to different variables: 155# 156# Global["VAR_SUBST_${UNDEF}"] = "" 157# Global["VAR_SUBST_"] = "" 158# 159# The variable name with the empty value actually included a dollar sign. 160# Variable names with dollars are not used in practice. 161# 162# It might be a good idea to forbid undefined variables on the left-hand side 163# of a variable assignment. 164.undef UNDEF 165VAR_ASSIGN_${UNDEF}= assigned by '=' 166VAR_SUBST_${UNDEF}:= assigned by ':=' 167.if ${VAR_ASSIGN_} != "assigned by '='" 168. error 169.endif 170.if defined(${:UVAR_SUBST_\${UNDEF\}}) 171. error 172.endif 173.if ${VAR_SUBST_} != "assigned by ':='" 174. error 175.endif 176 177all: 178 @:; 179