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