1# $NetBSD: directive-include-guard.mk,v 1.11 2023/06/21 21:21:52 sjg Exp $
2#
3# Tests for multiple-inclusion guards in makefiles.
4#
5# A file that is guarded by a multiple-inclusion guard has one of the
6# following forms:
7#
8#	.ifndef GUARD_VARIABLE
9#	.endif
10#
11#	.if !defined(GUARD_VARIABLE)
12#	.endif
13#
14#	.if !target(guard-target)
15#	.endif
16#
17# When such a file is included for the second or later time, and the guard
18# variable or the guard target is defined, including the file has no effect,
19# as all its content is skipped.
20#
21# See also:
22#	https://gcc.gnu.org/onlinedocs/cppinternals/Guard-Macros.html
23
24# Each of the following test cases creates a temporary file named after the
25# test case and writes some lines of text to that file.  That file is then
26# included twice, to see whether the second '.include' is skipped.
27
28
29# This is the canonical form of a variable-based multiple-inclusion guard.
30INCS+=	variable-ifndef
31LINES.variable-ifndef= \
32	'.ifndef VARIABLE_IFNDEF' \
33	'VARIABLE_IFNDEF=' \
34	'.endif'
35# expect: Parse_PushInput: file variable-ifndef.tmp, line 1
36# expect: Skipping 'variable-ifndef.tmp' because 'VARIABLE_IFNDEF' is defined
37
38# A file that reuses a guard from a previous file (or whose guard is defined
39# for any other reason) is only processed once, to see whether it is guarded.
40# Its content is skipped, therefore the syntax error is not detected.
41INCS+=	variable-ifndef-reuse
42LINES.variable-ifndef-reuse= \
43	'.ifndef VARIABLE_IFNDEF' \
44	'syntax error' \
45	'.endif'
46# expect: Parse_PushInput: file variable-ifndef-reuse.tmp, line 1
47# expect: Skipping 'variable-ifndef-reuse.tmp' because 'VARIABLE_IFNDEF' is defined
48
49# Comments and empty lines do not affect the multiple-inclusion guard.
50INCS+=	comments
51LINES.comments= \
52	'\# comment' \
53	'' \
54	'.ifndef COMMENTS' \
55	'\# comment' \
56	'COMMENTS=\#comment' \
57	'.endif' \
58	'\# comment'
59# expect: Parse_PushInput: file comments.tmp, line 1
60# expect: Skipping 'comments.tmp' because 'COMMENTS' is defined
61
62# An alternative form uses the 'defined' function.  It is more verbose than
63# the canonical form but avoids the '.ifndef' directive, as that directive is
64# not commonly used.
65INCS+=	variable-if
66LINES.variable-if= \
67	'.if !defined(VARIABLE_IF)' \
68	'VARIABLE_IF=' \
69	'.endif'
70# expect: Parse_PushInput: file variable-if.tmp, line 1
71# expect: Skipping 'variable-if.tmp' because 'VARIABLE_IF' is defined
72
73# A file that reuses a guard from a previous file (or whose guard is defined
74# for any other reason) is only processed once, to see whether it is guarded.
75# Its content is skipped, therefore the syntax error is not detected.
76INCS+=	variable-if-reuse
77LINES.variable-if-reuse= \
78	'.if !defined(VARIABLE_IF)' \
79	'syntax error' \
80	'.endif'
81# expect: Parse_PushInput: file variable-if-reuse.tmp, line 1
82# expect: Skipping 'variable-if-reuse.tmp' because 'VARIABLE_IF' is defined
83
84# Triple negation is so uncommon that it's not recognized, even though it has
85# the same effect as a single negation.
86INCS+=	variable-if-triple-negation
87LINES.variable-if-triple-negation= \
88	'.if !!!defined(VARIABLE_IF_TRIPLE_NEGATION)' \
89	'VARIABLE_IF_TRIPLE_NEGATION=' \
90	'.endif'
91# expect: Parse_PushInput: file variable-if-triple-negation.tmp, line 1
92# expect: Parse_PushInput: file variable-if-triple-negation.tmp, line 1
93
94# A conditional other than '.if' or '.ifndef' does not guard the file, even if
95# it is otherwise equivalent to the above accepted forms.
96INCS+=	variable-ifdef-negated
97LINES.variable-ifdef-negated= \
98	'.ifdef !VARIABLE_IFDEF_NEGATED' \
99	'VARIABLE_IFDEF_NEGATED=' \
100	'.endif'
101# expect: Parse_PushInput: file variable-ifdef-negated.tmp, line 1
102# expect: Parse_PushInput: file variable-ifdef-negated.tmp, line 1
103
104# The variable names in the '.if' and the assignment must be the same.
105INCS+=	variable-name-mismatch
106LINES.variable-name-mismatch= \
107	'.ifndef VARIABLE_NAME_MISMATCH' \
108	'VARIABLE_NAME_DIFFERENT=' \
109	'.endif'
110# expect: Parse_PushInput: file variable-name-mismatch.tmp, line 1
111# expect: Parse_PushInput: file variable-name-mismatch.tmp, line 1
112
113# The variable name '!VARNAME' cannot be used in an '.ifndef' directive, as
114# the '!' would be a negation.  It is syntactically valid in a '.if !defined'
115# condition, but ignored there.  Furthermore, when defining the variable, the
116# character '!' has to be escaped, to prevent it from being interpreted as the
117# '!' dependency operator.
118INCS+=	variable-name-exclamation
119LINES.variable-name-exclamation= \
120	'.if !defined(!VARIABLE_NAME_EXCLAMATION)' \
121	'${:U!}VARIABLE_NAME_EXCLAMATION=' \
122	'.endif'
123# expect: Parse_PushInput: file variable-name-exclamation.tmp, line 1
124# expect: Parse_PushInput: file variable-name-exclamation.tmp, line 1
125
126# A variable name can contain a '!' in the middle, as that character is
127# interpreted as an ordinary character in conditions as well as on the left
128# side of a variable assignment.  For guard variable names, the '!' is not
129# supported in any place, though.
130INCS+=	variable-name-exclamation-middle
131LINES.variable-name-exclamation-middle= \
132	'.ifndef VARIABLE_NAME!MIDDLE' \
133	'VARIABLE_NAME!MIDDLE=' \
134	'.endif'
135# expect: Parse_PushInput: file variable-name-exclamation-middle.tmp, line 1
136# expect: Parse_PushInput: file variable-name-exclamation-middle.tmp, line 1
137
138# A variable name can contain balanced parentheses, at least in conditions and
139# on the left side of a variable assignment.  There are enough places in make
140# where parentheses or braces are handled inconsistently to make this naming
141# choice a bad idea, therefore these characters are not allowed in guard
142# variable names.
143INCS+=	variable-name-parentheses
144LINES.variable-name-parentheses= \
145	'.ifndef VARIABLE_NAME(&)PARENTHESES' \
146	'VARIABLE_NAME(&)PARENTHESES=' \
147	'.endif'
148# expect: Parse_PushInput: file variable-name-parentheses.tmp, line 1
149# expect: Parse_PushInput: file variable-name-parentheses.tmp, line 1
150
151# The guard condition must consist of only the guard variable, nothing else.
152INCS+=	variable-ifndef-plus
153LINES.variable-ifndef-plus= \
154	'.ifndef VARIABLE_IFNDEF_PLUS && VARIABLE_IFNDEF_SECOND' \
155	'VARIABLE_IFNDEF_PLUS=' \
156	'VARIABLE_IFNDEF_SECOND=' \
157	'.endif'
158# expect: Parse_PushInput: file variable-ifndef-plus.tmp, line 1
159# expect: Parse_PushInput: file variable-ifndef-plus.tmp, line 1
160
161# The guard condition must consist of only the guard variable, nothing else.
162INCS+=	variable-if-plus
163LINES.variable-if-plus= \
164	'.if !defined(VARIABLE_IF_PLUS) && !defined(VARIABLE_IF_SECOND)' \
165	'VARIABLE_IF_PLUS=' \
166	'VARIABLE_IF_SECOND=' \
167	'.endif'
168# expect: Parse_PushInput: file variable-if-plus.tmp, line 1
169# expect: Parse_PushInput: file variable-if-plus.tmp, line 1
170
171# The variable name in an '.ifndef' guard must be given directly, it must not
172# contain any '$' expression.
173INCS+=	variable-ifndef-indirect
174LINES.variable-ifndef-indirect= \
175	'.ifndef $${VARIABLE_IFNDEF_INDIRECT:L}' \
176	'VARIABLE_IFNDEF_INDIRECT=' \
177	'.endif'
178# expect: Parse_PushInput: file variable-ifndef-indirect.tmp, line 1
179# expect: Parse_PushInput: file variable-ifndef-indirect.tmp, line 1
180
181# The variable name in an '.if' guard must be given directly, it must not
182# contain any '$' expression.
183INCS+=	variable-if-indirect
184LINES.variable-if-indirect= \
185	'.if !defined($${VARIABLE_IF_INDIRECT:L})' \
186	'VARIABLE_IF_INDIRECT=' \
187	'.endif'
188# expect: Parse_PushInput: file variable-if-indirect.tmp, line 1
189# expect: Parse_PushInput: file variable-if-indirect.tmp, line 1
190
191# The variable name in the guard condition must only contain alphanumeric
192# characters and underscores.  The guard variable is more flexible, it can be
193# defined anywhere, as long as it is defined at the point where the file is
194# included the next time.
195INCS+=	variable-assign-indirect
196LINES.variable-assign-indirect= \
197	'.ifndef VARIABLE_ASSIGN_INDIRECT' \
198	'$${VARIABLE_ASSIGN_INDIRECT:L}=' \
199	'.endif'
200# expect: Parse_PushInput: file variable-assign-indirect.tmp, line 1
201# expect: Skipping 'variable-assign-indirect.tmp' because 'VARIABLE_ASSIGN_INDIRECT' is defined
202
203# The time at which the guard variable is defined doesn't matter, as long as
204# it is defined at the point where the file is included the next time.
205INCS+=	variable-assign-late
206LINES.variable-assign-late= \
207	'.ifndef VARIABLE_ASSIGN_LATE' \
208	'VARIABLE_ASSIGN_LATE_OTHER=' \
209	'VARIABLE_ASSIGN_LATE=' \
210	'.endif'
211# expect: Parse_PushInput: file variable-assign-late.tmp, line 1
212# expect: Skipping 'variable-assign-late.tmp' because 'VARIABLE_ASSIGN_LATE' is defined
213
214# The time at which the guard variable is defined doesn't matter, as long as
215# it is defined at the point where the file is included the next time.
216INCS+=	variable-assign-nested
217LINES.variable-assign-nested= \
218	'.ifndef VARIABLE_ASSIGN_NESTED' \
219	'.  if 1' \
220	'.    for i in once' \
221	'VARIABLE_ASSIGN_NESTED=' \
222	'.    endfor' \
223	'.  endif' \
224	'.endif'
225# expect: Parse_PushInput: file variable-assign-nested.tmp, line 1
226# expect: Skipping 'variable-assign-nested.tmp' because 'VARIABLE_ASSIGN_NESTED' is defined
227
228# If the guard variable is defined before the file is included for the first
229# time, the file is considered guarded as well.  In such a case, the parser
230# skips almost all lines, as they are irrelevant, but the structure of the
231# top-level '.if/.endif' conditional can be determined reliably enough to
232# decide whether the file is guarded.
233INCS+=	variable-already-defined
234LINES.variable-already-defined= \
235	'.ifndef VARIABLE_ALREADY_DEFINED' \
236	'VARIABLE_ALREADY_DEFINED=' \
237	'.endif'
238VARIABLE_ALREADY_DEFINED=
239# expect: Parse_PushInput: file variable-already-defined.tmp, line 1
240# expect: Skipping 'variable-already-defined.tmp' because 'VARIABLE_ALREADY_DEFINED' is defined
241
242# If the guard variable is defined before the file is included the first time,
243# the file is processed but its content is skipped.  If that same guard
244# variable is undefined when the file is included the second time, the file is
245# processed as usual.
246INCS+=	variable-defined-then-undefined
247LINES.variable-defined-then-undefined= \
248	'.ifndef VARIABLE_DEFINED_THEN_UNDEFINED' \
249	'.endif'
250VARIABLE_DEFINED_THEN_UNDEFINED=
251UNDEF_BETWEEN.variable-defined-then-undefined= \
252	VARIABLE_DEFINED_THEN_UNDEFINED
253# expect: Parse_PushInput: file variable-defined-then-undefined.tmp, line 1
254# expect: Parse_PushInput: file variable-defined-then-undefined.tmp, line 1
255
256# The whole file content must be guarded by a single '.if' conditional, not by
257# several, even if they have the same effect.  This case is not expected to
258# occur in practice, as the two parts would rather be split into separate
259# files.
260INCS+=	variable-two-times
261LINES.variable-two-times= \
262	'.ifndef VARIABLE_TWO_TIMES_1' \
263	'VARIABLE_TWO_TIMES_1=' \
264	'.endif' \
265	'.ifndef VARIABLE_TWO_TIMES_2' \
266	'VARIABLE_TWO_TIMES_2=' \
267	'.endif'
268# expect: Parse_PushInput: file variable-two-times.tmp, line 1
269# expect: Parse_PushInput: file variable-two-times.tmp, line 1
270
271# When multiple files use the same guard variable name, the optimization of
272# skipping the file affects each of these files.
273#
274# Choosing unique guard names is the responsibility of the makefile authors.
275# A typical pattern of guard variable names is '${PROJECT}_${DIR}_${FILE}_MK'.
276# System-provided files typically start the guard names with '_'.
277INCS+=	variable-clash
278LINES.variable-clash= \
279	${LINES.variable-if}
280# expect: Parse_PushInput: file variable-clash.tmp, line 1
281# expect: Skipping 'variable-clash.tmp' because 'VARIABLE_IF' is defined
282
283# The conditional must come before the assignment, otherwise the conditional
284# is useless, as it always evaluates to false.
285INCS+=	variable-swapped
286LINES.variable-swapped= \
287	'SWAPPED=' \
288	'.ifndef SWAPPED' \
289	'.  error' \
290	'.endif'
291# expect: Parse_PushInput: file variable-swapped.tmp, line 1
292# expect: Parse_PushInput: file variable-swapped.tmp, line 1
293
294# If the guard variable is undefined between the first and the second time the
295# file is included, the guarded file is included again.
296INCS+=	variable-undef-between
297LINES.variable-undef-between= \
298	'.ifndef VARIABLE_UNDEF_BETWEEN' \
299	'VARIABLE_UNDEF_BETWEEN=' \
300	'.endif'
301UNDEF_BETWEEN.variable-undef-between= \
302	VARIABLE_UNDEF_BETWEEN
303# expect: Parse_PushInput: file variable-undef-between.tmp, line 1
304# expect: Parse_PushInput: file variable-undef-between.tmp, line 1
305
306# If the guard variable is undefined while the file is included the first
307# time, the guard does not have an effect, and the file is included again.
308INCS+=	variable-undef-inside
309LINES.variable-undef-inside= \
310	'.ifndef VARIABLE_UNDEF_INSIDE' \
311	'VARIABLE_UNDEF_INSIDE=' \
312	'.undef VARIABLE_UNDEF_INSIDE' \
313	'.endif'
314# expect: Parse_PushInput: file variable-undef-inside.tmp, line 1
315# expect: Parse_PushInput: file variable-undef-inside.tmp, line 1
316
317# If the file does not define the guard variable, the guard does not have an
318# effect, and the file is included again.
319INCS+=	variable-not-defined
320LINES.variable-not-defined= \
321	'.ifndef VARIABLE_NOT_DEFINED' \
322	'.endif'
323# expect: Parse_PushInput: file variable-not-defined.tmp, line 1
324# expect: Parse_PushInput: file variable-not-defined.tmp, line 1
325
326# The outermost '.if' must not have an '.elif' branch.
327INCS+=	if-elif
328LINES.if-elif= \
329	'.ifndef IF_ELIF' \
330	'IF_ELIF=' \
331	'.elif 1' \
332	'.endif'
333# expect: Parse_PushInput: file if-elif.tmp, line 1
334# expect: Parse_PushInput: file if-elif.tmp, line 1
335
336# When a file with an '.if/.elif/.endif' conditional at the top level is
337# included, it is never optimized, as one of its branches is taken.
338INCS+=	if-elif-reuse
339LINES.if-elif-reuse= \
340	'.ifndef IF_ELIF' \
341	'syntax error' \
342	'.elif 1' \
343	'.endif'
344# expect: Parse_PushInput: file if-elif-reuse.tmp, line 1
345# expect: Parse_PushInput: file if-elif-reuse.tmp, line 1
346
347# The outermost '.if' must not have an '.else' branch.
348INCS+=	if-else
349LINES.if-else= \
350	'.ifndef IF_ELSE' \
351	'IF_ELSE=' \
352	'.else' \
353	'.endif'
354# expect: Parse_PushInput: file if-else.tmp, line 1
355# expect: Parse_PushInput: file if-else.tmp, line 1
356
357# When a file with an '.if/.else/.endif' conditional at the top level is
358# included, it is never optimized, as one of its branches is taken.
359INCS+=	if-else-reuse
360LINES.if-else-reuse= \
361	'.ifndef IF_ELSE' \
362	'syntax error' \
363	'.else' \
364	'.endif'
365# expect: Parse_PushInput: file if-else-reuse.tmp, line 1
366# expect: Parse_PushInput: file if-else-reuse.tmp, line 1
367
368# The inner '.if' directives may have an '.elif' or '.else', and it doesn't
369# matter which of their branches are taken.
370INCS+=	inner-if-elif-else
371LINES.inner-if-elif-else= \
372	'.ifndef INNER_IF_ELIF_ELSE' \
373	'INNER_IF_ELIF_ELSE=' \
374	'.  if 0' \
375	'.  elif 0' \
376	'.  else' \
377	'.  endif' \
378	'.  if 0' \
379	'.  elif 1' \
380	'.  else' \
381	'.  endif' \
382	'.  if 1' \
383	'.  elif 1' \
384	'.  else' \
385	'.  endif' \
386	'.endif'
387# expect: Parse_PushInput: file inner-if-elif-else.tmp, line 1
388# expect: Skipping 'inner-if-elif-else.tmp' because 'INNER_IF_ELIF_ELSE' is defined
389
390# The guard can also be a target instead of a variable.  Using a target as a
391# guard has the benefit that a target cannot be undefined once it is defined.
392# The target should be declared '.NOTMAIN'.  Since the target names are
393# usually chosen according to a pattern that doesn't interfere with real
394# target names, they don't need to be declared '.PHONY' as they don't generate
395# filesystem operations.
396INCS+=	target
397LINES.target= \
398	'.if !target(__target.tmp__)' \
399	'__target.tmp__: .NOTMAIN' \
400	'.endif'
401# expect: Parse_PushInput: file target.tmp, line 1
402# expect: Skipping 'target.tmp' because '__target.tmp__' is defined
403
404# When used for system files, the target name may include '<' and '>', for
405# symmetry with the '.include <sys.mk>' directive.  The characters '<' and '>'
406# are ordinary characters.
407INCS+=	target-sys
408LINES.target-sys= \
409	'.if !target(__<target-sys.tmp>__)' \
410	'__<target-sys.tmp>__: .NOTMAIN' \
411	'.endif'
412# expect: Parse_PushInput: file target-sys.tmp, line 1
413# expect: Skipping 'target-sys.tmp' because '__<target-sys.tmp>__' is defined
414
415# The target name may include variable references.  These references are
416# expanded as usual.  Due to the current implementation, the expressions are
417# evaluated twice:  Once for checking whether the condition evaluates to true,
418# and once for determining the guard name.  This double evaluation should not
419# matter in practice, as guard expressions are expected to be simple,
420# deterministic and without side effects.
421INCS+=	target-indirect
422LINES.target-indirect= \
423	'.if !target($${target-indirect.tmp:L})' \
424	'target-indirect.tmp: .NOTMAIN' \
425	'.endif'
426# expect: Parse_PushInput: file target-indirect.tmp, line 1
427# expect: Skipping 'target-indirect.tmp' because 'target-indirect.tmp' is defined
428
429# A common form of guard target is __${.PARSEFILE}__.  This form can only be
430# used if all files using this form have unique basenames.  To get a robust
431# pattern based on the same idea, use __${.PARSEDIR}/${.PARSEFILE}__ instead.
432# This form does not work when the basename contains whitespace characters, as
433# it is not possible to define a target with whitespace, not even by cheating.
434INCS+=	target-indirect-PARSEFILE
435LINES.target-indirect-PARSEFILE= \
436	'.if !target(__$${.PARSEFILE}__)' \
437	'__$${.PARSEFILE}__: .NOTMAIN' \
438	'.endif'
439# expect: Parse_PushInput: file target-indirect-PARSEFILE.tmp, line 1
440# expect: Skipping 'target-indirect-PARSEFILE.tmp' because '__target-indirect-PARSEFILE.tmp__' is defined
441
442# Two files with different basenames can both use the same syntactic pattern
443# for the target guard name, as the expressions expand to different strings.
444INCS+=	target-indirect-PARSEFILE2
445LINES.target-indirect-PARSEFILE2= \
446	'.if !target(__$${.PARSEFILE}__)' \
447	'__$${.PARSEFILE}__: .NOTMAIN' \
448	'.endif'
449# expect: Parse_PushInput: file target-indirect-PARSEFILE2.tmp, line 1
450# expect: Skipping 'target-indirect-PARSEFILE2.tmp' because '__target-indirect-PARSEFILE2.tmp__' is defined
451
452# Using plain .PARSEFILE without .PARSEDIR leads to name clashes.  The include
453# guard is the same as in the test case 'target-indirect-PARSEFILE', as the
454# guard name only contains the basename but not the directory name.
455INCS+=	subdir/target-indirect-PARSEFILE
456LINES.subdir/target-indirect-PARSEFILE= \
457	'.if !target(__$${.PARSEFILE}__)' \
458	'__$${.PARSEFILE}__: .NOTMAIN' \
459	'.endif'
460# expect: Parse_PushInput: file subdir/target-indirect-PARSEFILE.tmp, line 1
461# expect: Skipping 'subdir/target-indirect-PARSEFILE.tmp' because '__target-indirect-PARSEFILE.tmp__' is defined
462
463# Another common form of guard target is __${.PARSEDIR}/${.PARSEFILE}__
464# or __${.PARSEDIR:tA}/${.PARSEFILE}__ to be truely unique.
465INCS+=	target-indirect-PARSEDIR-PARSEFILE
466LINES.target-indirect-PARSEDIR-PARSEFILE= \
467	'.if !target(__$${.PARSEDIR}/$${.PARSEFILE}__)' \
468	'__$${.PARSEDIR}/$${.PARSEFILE}__: .NOTMAIN' \
469	'.endif'
470# expect: Parse_PushInput: file target-indirect-PARSEDIR-PARSEFILE.tmp, line 1
471# expect: Skipping 'target-indirect-PARSEDIR-PARSEFILE.tmp' because '__target-indirect-PARSEDIR-PARSEFILE.tmp__' is defined
472# The actual target starts with '__${.OBJDIR}/', see the .rawout file, but the
473# string '${.OBJDIR}/' gets stripped in post processing.
474
475# Using the combination of '.PARSEDIR' and '.PARSEFILE', a file in a
476# subdirectory gets a different guard target name than the previous one.
477INCS+=	subdir/target-indirect-PARSEDIR-PARSEFILE
478LINES.subdir/target-indirect-PARSEDIR-PARSEFILE= \
479	'.if !target(__$${.PARSEDIR}/$${.PARSEFILE}__)' \
480	'__$${.PARSEDIR}/$${.PARSEFILE}__: .NOTMAIN' \
481	'.endif'
482# expect: Parse_PushInput: file subdir/target-indirect-PARSEDIR-PARSEFILE.tmp, line 1
483# expect: Skipping 'subdir/target-indirect-PARSEDIR-PARSEFILE.tmp' because '__subdir/target-indirect-PARSEDIR-PARSEFILE.tmp__' is defined
484# The actual target starts with '__${.OBJDIR}/', see the .rawout file, but the
485# string '${.OBJDIR}/' gets stripped in post processing.
486
487# If the guard target is not defined when including the file the next time,
488# the file is processed again.
489INCS+=	target-unguarded
490LINES.target-unguarded= \
491	'.if !target(target-unguarded)' \
492	'.endif'
493# expect: Parse_PushInput: file target-unguarded.tmp, line 1
494# expect: Parse_PushInput: file target-unguarded.tmp, line 1
495
496# The guard condition must consist of only the guard target, nothing else.
497INCS+=	target-plus
498LINES.target-plus= \
499	'.if !target(target-plus) && 1' \
500	'target-plus: .NOTMAIN' \
501	'.endif'
502# expect: Parse_PushInput: file target-plus.tmp, line 1
503# expect: Parse_PushInput: file target-plus.tmp, line 1
504
505# If the guard target is defined before the file is included the first time,
506# the file is not considered guarded.
507INCS+=	target-already-defined
508LINES.target-already-defined= \
509	'.if !target(target-already-defined)' \
510	'target-already-defined: .NOTMAIN' \
511	'.endif'
512target-already-defined: .NOTMAIN
513# expect: Parse_PushInput: file target-already-defined.tmp, line 1
514# expect: Skipping 'target-already-defined.tmp' because 'target-already-defined' is defined
515
516# A target name cannot contain the character '!'.  In the condition, the '!'
517# is syntactically valid, but in the dependency declaration line, the '!' is
518# interpreted as the '!' dependency operator, no matter whether it occurs at
519# the beginning or in the middle of a target name.  Escaping it as '${:U!}'
520# doesn't work, as the whole line is first expanded and then scanned for the
521# dependency operator.  Escaping it as '\!' doesn't work either, even though
522# the '\' escapes the '!' from being a dependency operator, but when reading
523# the target name, the '\' is kept, resulting in the target name
524# '\!target-name-exclamation' instead of '!target-name-exclamation'.
525INCS+=	target-name-exclamation
526LINES.target-name-exclamation= \
527	'.if !target(!target-name-exclamation)' \
528	'\!target-name-exclamation: .NOTMAIN' \
529	'.endif'
530# expect: Parse_PushInput: file target-name-exclamation.tmp, line 1
531# expect: Parse_PushInput: file target-name-exclamation.tmp, line 1
532
533# Now run all test cases by including each of the files twice and looking at
534# the debug output.  The files that properly guard against multiple inclusion
535# generate a 'Skipping' line, the others repeat the 'Parse_PushInput' line.
536#
537# Some debug output lines are suppressed in the .exp file, see ./Makefile.
538.for i in ${INCS}
539.  for fname in $i.tmp
540_:=	${fname:H:N.:@dir@${:!mkdir -p ${dir}!}@}
541_!=	printf '%s\n' ${LINES.$i} > ${fname}
542.MAKEFLAGS: -dp
543.include "${.CURDIR}/${fname}"
544.undef ${UNDEF_BETWEEN.$i:U}
545.include "${.CURDIR}/${fname}"
546.MAKEFLAGS: -d0
547_!=	rm ${fname}
548_:=	${fname:H:N.:@dir@${:!rmdir ${dir}!}@}
549.  endfor
550.endfor
551
552all:
553