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