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