1# $Id: varmisc.mk,v 1.26 2023/11/25 01:39:31 sjg Exp $
2# $NetBSD: varmisc.mk,v 1.33 2023/10/19 18:24:33 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	cmpv
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
50# big jumps to handle 3 digits per step
51M_cmpv.units=	1 1000 1000000
52M_cmpv=		S,., ,g:_:range:@i@+ $${_:[-$$i]} \* $${M_cmpv.units:[$$i]}@:S,^,expr 0 ,1:sh
53
54Version=	123.456.789
55cmpv.only=	target specific vars
56
57cmpv:
58	@echo Version=${Version} == ${Version:${M_cmpv}}
59	@echo Literal=3.4.5 == ${3.4.5:L:${M_cmpv}}
60	@echo We have ${${.TARGET:T}.only}
61
62
63# Test parsing of boolean values.
64# begin .MAKE.SAVE_DOLLARS; see Var_SetWithFlags and ParseBoolean.
65SD_VALUES=	0 1 2 False True false true Yes No yes no On Off ON OFF on off
66SD_4_DOLLARS=	$$$$
67
68.for val in ${SD_VALUES}
69# The assignment must be done using ':=' since a simple '=' would be
70# interpreted as 'yes', due to the leading '$'; see ParseBoolean.
71.MAKE.SAVE_DOLLARS:=	${val}
72SD.${val}:=		${SD_4_DOLLARS}
73.endfor
74.MAKE.SAVE_DOLLARS:=	yes
75
76save-dollars:
77.for val in ${SD_VALUES}
78	@printf '%s: %-8s = %s\n' $@ ${val} ${SD.${val}:Q}
79.endfor
80# end .MAKE.SAVE_DOLLARS
81
82# Appending to an undefined variable does not add a space in front.
83.undef APPENDED
84APPENDED+=	value
85.if ${APPENDED} != "value"
86.  error "${APPENDED}"
87.endif
88
89# Appending to an empty variable adds a space between the old value
90# and the additional value.
91APPENDED=	# empty
92APPENDED+=	value
93.if ${APPENDED} != " value"
94.  error "${APPENDED}"
95.endif
96
97# Appending to parameterized variables works as well.
98PARAM=		param
99VAR.${PARAM}=	1
100VAR.${PARAM}+=	2
101.if ${VAR.param} != "1 2"
102.  error "${VAR.param}"
103.endif
104
105# The variable name can contain arbitrary characters.
106# If the expanded variable name ends in a +, this still does not influence
107# the parser. The assignment operator is still a simple assignment.
108# Therefore, there is no need to add a space between the variable name
109# and the assignment operator.
110PARAM=		+
111VAR.${PARAM}=	1
112VAR.${PARAM}+=	2
113.if ${VAR.+} != "1 2"
114.  error "${VAR.+}"
115.endif
116.for param in : + ! ?
117VAR.${param}=	${param}
118.endfor
119.if ${VAR.${:U\:}} != ":" || ${VAR.+} != "+" || ${VAR.!} != "!" || ${VAR.?} != "?"
120.  error "${VAR.+}" "${VAR.!}" "${VAR.?}"
121.endif
122
123# Appending to a variable from the environment creates a copy of that variable
124# in the global scope.
125# The appended value is not exported automatically.
126# When a variable is exported, the exported value is taken at the time of the
127# .export directive. Later changes to the variable have no effect.
128.export FROM_ENV_BEFORE
129FROM_ENV+=		mk
130FROM_ENV_BEFORE+=	mk
131FROM_ENV_AFTER+=	mk
132.export FROM_ENV_AFTER
133
134export-appended:
135	@echo $@: "$$FROM_ENV"
136	@echo $@: "$$FROM_ENV_BEFORE"
137	@echo $@: "$$FROM_ENV_AFTER"
138
139# begin parse-dynamic
140#
141# Demonstrate that the target-specific variables are not evaluated in
142# the global scope. Their expressions are preserved until there is a local
143# scope in which resolving them makes sense.
144
145# There are different code paths for short names ...
146${:U>}=		before
147GS_TARGET:=	$@
148GS_MEMBER:=	$%
149GS_PREFIX:=	$*
150GS_ARCHIVE:=	$!
151GS_ALLSRC:=	$>
152${:U>}=		after
153# ... and for braced short names ...
154GB_TARGET:=	${@}
155GB_MEMBER:=	${%}
156GB_PREFIX:=	${*}
157GB_ARCHIVE:=	${!}
158GB_ALLSRC:=	${>}
159# ... and for long names.
160GL_TARGET:=	${.TARGET}
161GL_MEMBER:=	${.MEMBER}
162GL_PREFIX:=	${.PREFIX}
163GL_ARCHIVE:=	${.ARCHIVE}
164GL_ALLSRC:=	${.ALLSRC}
165
166parse-dynamic:
167	@echo $@: ${GS_TARGET} ${GS_MEMBER} ${GS_PREFIX} ${GS_ARCHIVE} ${GS_ALLSRC}
168	@echo $@: ${GB_TARGET} ${GB_MEMBER} ${GB_PREFIX} ${GB_ARCHIVE} ${GB_ALLSRC}
169	@echo $@: ${GL_TARGET} ${GL_MEMBER} ${GL_PREFIX} ${GL_ARCHIVE} ${GL_ALLSRC}
170
171# Since 2020-07-28, make complains about unclosed variables.
172# Before that, it had complained about unclosed variables only when
173# parsing the modifiers, but not when parsing the variable name.
174
175UNCLOSED_INDIR_1=	${UNCLOSED_ORIG
176UNCLOSED_INDIR_2=	${UNCLOSED_INDIR_1}
177
178FLAGS=	one two
179FLAGS+=	${FLAGS.${.ALLSRC:M*.c:T:u}}
180FLAGS.target2.c= three four
181
182target1.c:
183target2.c:
184
185all: target1-flags target2-flags
186target1-flags: target1.c
187	@echo $@: we have: ${FLAGS}
188
189target2-flags: target2.c
190	@echo $@: we have: ${FLAGS}
191
192varerror-unclosed:
193	@echo $@:begin
194	@echo $(
195	@echo $(UNCLOSED
196	@echo ${UNCLOSED
197	@echo ${UNCLOSED:M${PATTERN
198	@echo ${UNCLOSED.${param
199	@echo $
200.for i in 1 2 3
201	@echo ${UNCLOSED.${i}
202.endfor
203	@echo ${UNCLOSED_INDIR_2}
204	@echo $@:end
205