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