1 # $NetBSD: varname.mk,v 1.18 2025/06/28 22:39:29 rillig Exp $ 2 # 3 # Tests for variable names. 4 5 .MAKEFLAGS: -dv 6 7 # In a variable assignment, braces are allowed in the variable name, but they 8 # must be balanced. Parentheses and braces may be mixed. 9 VAR{{{}}}= 3 braces 10 .if "${VAR{{{}}}}" != "3 braces" 11 . error 12 .endif 13 14 # In expressions, the parser works differently. It doesn't treat 15 # braces and parentheses equally, therefore the first closing brace already 16 # marks the end of the variable name. 17 VARNAME= VAR((( 18 ${VARNAME}= 3 open parentheses 19 .if "${VAR(((}}}}" != "3 open parentheses}}}" 20 . error 21 .endif 22 23 # In the above test, the variable name is constructed indirectly. Neither 24 # of the following expressions produces the intended effect. 25 # 26 # This is not a variable assignment since the parentheses and braces are not 27 # balanced. At the end of the line, there are still 3 levels open, which 28 # means the variable name is not finished. 29 # expect+2: Missing ")" in archive specification 30 # expect+1: Error in archive specification: "VAR" 31 ${:UVAR(((}= try1 32 # On the left-hand side of a variable assignments, the backslash is not parsed 33 # as an escape character, therefore the parentheses still count to the nesting 34 # level, which at the end of the line is still 3. Therefore this is not a 35 # variable assignment as well. 36 # expect+1: Invalid line "${:UVAR\(\(\(}= try2", expanded to "VAR\(\(\(= try2" 37 ${:UVAR\(\(\(}= try2 38 # To assign to a variable with an arbitrary name, the variable name has to 39 # come from an external source, not the text that is parsed in the assignment 40 # itself. This is exactly the reason why further above, the indirect 41 # ${VARNAME} works, while all other attempts fail. 42 ${VARNAME}= try3 43 44 .MAKEFLAGS: -d0 45 46 # All variable names of a scope are stored in the same hash table, using a 47 # simple hash function. Ensure that HashTable_Find handles collisions 48 # correctly and that the correct variable is looked up. The strings "0x" and 49 # "1Y" have the same hash code, as 31 * '0' + 'x' == 31 * '1' + 'Y'. 50 V.0x= 0x 51 V.1Y= 1Y 52 .if ${V.0x} != "0x" || ${V.1Y} != "1Y" 53 . error 54 .endif 55 56 # The string "ASDZguv", when used as a prefix of a variable name, keeps the 57 # hash code unchanged, its own hash code is 0. 58 ASDZguvV.0x= 0x 59 ASDZguvV.1Y= 1Y 60 .if ${ASDZguvV.0x} != "0x" 61 . error 62 .elif ${ASDZguvV.1Y} != "1Y" 63 . error 64 .endif 65 66 # Ensure that variables with the same hash code whose name is a prefix of the 67 # other can be accessed. In this case, the shorter variable name is defined 68 # first to make it appear later in the bucket of the hash table. 69 ASDZguv= once 70 ASDZguvASDZguv= twice 71 .if ${ASDZguv} != "once" 72 . error 73 .elif ${ASDZguvASDZguv} != "twice" 74 . error 75 .endif 76 77 # Ensure that variables with the same hash code whose name is a prefix of the 78 # other can be accessed. In this case, the longer variable name is defined 79 # first to make it appear later in the bucket of the hash table. 80 ASDZguvASDZguv.param= twice 81 ASDZguv.param= once 82 .if ${ASDZguv.param} != "once" 83 . error 84 .elif ${ASDZguvASDZguv.param} != "twice" 85 . error 86 .endif 87 88 89 # Warn about expressions in the style of GNU make, as these would silently 90 # expand to an empty string instead. 91 # 92 # https://pubs.opengroup.org/onlinepubs/9799919799/utilities/make.html says: 93 # a macro name shall not contain an <equals-sign>, <blank>, or control 94 # character. 95 # 96 GNU_MAKE_IF= $(if ${HAVE_STRLEN},yes,no) 97 # expect+1: warning: Invalid character " " in variable name "if ,yes,no" 98 .if ${GNU_MAKE_IF} != "" 99 . error 100 .endif 101 # 102 # This requirement needs to be ignored for expressions with a ":L" or ":?:" 103 # modifier, as these modifiers rely on arbitrary characters in the expression 104 # name. 105 .if ${"left" == "right":?equal:unequal} != "unequal" 106 . error 107 .endif 108 # 109 # In fact, this requirement is ignored for any expression that has a modifier. 110 # In this indirect case, though, the expression with the space in the name is 111 # a nested expression, so the ":U" modifier doesn't affect the warning. 112 # expect+1: warning: Invalid character " " in variable name "if ,yes,no" 113 .if ${GNU_MAKE_IF:Ufallback} != "" 114 . error 115 .endif 116 # 117 # A modifier in a nested expression does not affect the warning. 118 GNU_MAKE_IF_EXPR= $(if ${HAVE_STRLEN},${HEADERS:.h=.c},) 119 # expect+1: warning: Invalid character " " in variable name "if ,," 120 .if ${GNU_MAKE_IF_EXPR} != "" 121 . error 122 .endif 123 # 124 # When the GNU make expression contains a colon, chances are good that the 125 # colon is interpreted as an unknown modifier. 126 GNU_MAKE_IF_MODIFIER= $(if ${HAVE_STRLEN},answer:yes,answer:no) 127 # expect+1: Unknown modifier ":yes,answer" 128 .if ${GNU_MAKE_IF_MODIFIER} != "no)" 129 . error 130 .endif 131 # 132 # If the variable name contains a non-printable character, the warning 133 # contains the numeric character value instead, to prevent control sequences 134 # in the output. 135 CONTROL_CHARACTER= ${:U a b:ts\t} 136 # expect+2: warning: Invalid character "\x09" in variable name "a b" 137 # expect+1: Variable "a b" is undefined 138 .if ${${CONTROL_CHARACTER}} != "" 139 .endif 140 # 141 # For now, only whitespace generates a warning, non-ASCII characters don't. 142 UMLAUT= 143 # expect+1: Variable "" is undefined 144 .if ${${UMLAUT}} != "" 145 .endif 146