Source-Changes-HG archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

[src/trunk]: src/usr.bin/make make: skip a file protected by a multiple-inclu...



details:   https://anonhg.NetBSD.org/src/rev/5e99faa2e7ba
branches:  trunk
changeset: 376506:5e99faa2e7ba
user:      rillig <rillig%NetBSD.org@localhost>
date:      Wed Jun 21 14:33:36 2023 +0000

description:
make: skip a file protected by a multiple-inclusion guard more often

In practice, the common situation is that a file is first included,
defines its multiple-inclusion guard and is then skipped instead of
being included again.

The other way round is that the multiple-inclusion guard is defined when
the file is included first.  In that case, the file is now regarded as
guarded as well.

diffstat:

 usr.bin/make/parse.c                                |    6 +-
 usr.bin/make/unit-tests/directive-include-guard.exp |   22 ++-
 usr.bin/make/unit-tests/directive-include-guard.mk  |  117 +++++++++++++++----
 3 files changed, 108 insertions(+), 37 deletions(-)

diffs (truncated from 348 to 300 lines):

diff -r bb41cd240e2b -r 5e99faa2e7ba usr.bin/make/parse.c
--- a/usr.bin/make/parse.c      Wed Jun 21 12:27:50 2023 +0000
+++ b/usr.bin/make/parse.c      Wed Jun 21 14:33:36 2023 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: parse.c,v 1.702 2023/06/20 09:25:33 rillig Exp $       */
+/*     $NetBSD: parse.c,v 1.703 2023/06/21 14:33:36 rillig Exp $       */
 
 /*
  * Copyright (c) 1988, 1989, 1990, 1993
@@ -105,7 +105,7 @@
 #include "pathnames.h"
 
 /*     "@(#)parse.c    8.3 (Berkeley) 3/19/94" */
-MAKE_RCSID("$NetBSD: parse.c,v 1.702 2023/06/20 09:25:33 rillig Exp $");
+MAKE_RCSID("$NetBSD: parse.c,v 1.703 2023/06/21 14:33:36 rillig Exp $");
 
 /* Detects a multiple-inclusion guard in a makefile. */
 typedef enum {
@@ -2681,7 +2681,7 @@ ReadHighLevelLine(void)
                condResult = Cond_EvalLine(line);
                if (curFile->guardState == GS_START) {
                        Guard *guard;
-                       if (condResult == CR_TRUE
+                       if (condResult != CR_ERROR
                            && (guard = Cond_ExtractGuard(line)) != NULL) {
                                curFile->guardState = GS_COND;
                                curFile->guard = guard;
diff -r bb41cd240e2b -r 5e99faa2e7ba usr.bin/make/unit-tests/directive-include-guard.exp
--- a/usr.bin/make/unit-tests/directive-include-guard.exp       Wed Jun 21 12:27:50 2023 +0000
+++ b/usr.bin/make/unit-tests/directive-include-guard.exp       Wed Jun 21 14:33:36 2023 +0000
@@ -1,9 +1,13 @@
 Parse_PushInput: file variable-ifndef.tmp, line 1
 Skipping 'variable-ifndef.tmp' because 'VARIABLE_IFNDEF' is defined
+Parse_PushInput: file variable-ifndef-reuse.tmp, line 1
+Skipping 'variable-ifndef-reuse.tmp' because 'VARIABLE_IFNDEF' is defined
 Parse_PushInput: file comments.tmp, line 1
 Skipping 'comments.tmp' because 'COMMENTS' is defined
 Parse_PushInput: file variable-if.tmp, line 1
 Skipping 'variable-if.tmp' because 'VARIABLE_IF' is defined
+Parse_PushInput: file variable-if-reuse.tmp, line 1
+Skipping 'variable-if-reuse.tmp' because 'VARIABLE_IF' is defined
 Parse_PushInput: file variable-if-triple-negation.tmp, line 1
 Parse_PushInput: file variable-if-triple-negation.tmp, line 1
 Parse_PushInput: file variable-ifdef-negated.tmp, line 1
@@ -32,11 +36,13 @@ Parse_PushInput: file variable-assign-ne
 Parse_PushInput: .for loop in variable-assign-nested.tmp, line 3
 Skipping 'variable-assign-nested.tmp' because 'VARIABLE_ASSIGN_NESTED' is defined
 Parse_PushInput: file variable-already-defined.tmp, line 1
-Parse_PushInput: file variable-already-defined.tmp, line 1
+Skipping 'variable-already-defined.tmp' because 'VARIABLE_ALREADY_DEFINED' is defined
+Parse_PushInput: file variable-defined-then-undefined.tmp, line 1
+Parse_PushInput: file variable-defined-then-undefined.tmp, line 1
 Parse_PushInput: file variable-two-times.tmp, line 1
 Parse_PushInput: file variable-two-times.tmp, line 1
 Parse_PushInput: file variable-clash.tmp, line 1
-Parse_PushInput: file variable-clash.tmp, line 1
+Skipping 'variable-clash.tmp' because 'VARIABLE_IF' is defined
 Parse_PushInput: file variable-swapped.tmp, line 1
 Parse_PushInput: file variable-swapped.tmp, line 1
 Parse_PushInput: file variable-undef-between.tmp, line 1
@@ -47,8 +53,12 @@ Parse_PushInput: file variable-not-defin
 Parse_PushInput: file variable-not-defined.tmp, line 1
 Parse_PushInput: file if-elif.tmp, line 1
 Parse_PushInput: file if-elif.tmp, line 1
+Parse_PushInput: file if-elif-reuse.tmp, line 1
+Parse_PushInput: file if-elif-reuse.tmp, line 1
 Parse_PushInput: file if-else.tmp, line 1
 Parse_PushInput: file if-else.tmp, line 1
+Parse_PushInput: file if-else-reuse.tmp, line 1
+Parse_PushInput: file if-else-reuse.tmp, line 1
 Parse_PushInput: file inner-if-elif-else.tmp, line 1
 Skipping 'inner-if-elif-else.tmp' because 'INNER_IF_ELIF_ELSE' is defined
 Parse_PushInput: file target.tmp, line 1
@@ -62,13 +72,13 @@ Skipping 'target-indirect-PARSEFILE.tmp'
 Parse_PushInput: file target-indirect-PARSEFILE2.tmp, line 1
 Skipping 'target-indirect-PARSEFILE2.tmp' because '__target-indirect-PARSEFILE2.tmp__' is defined
 Parse_PushInput: file subdir/target-indirect-PARSEFILE.tmp, line 1
-Parse_PushInput: file subdir/target-indirect-PARSEFILE.tmp, line 1
+Skipping 'subdir/target-indirect-PARSEFILE.tmp' because '__target-indirect-PARSEFILE.tmp__' is defined
 Parse_PushInput: file target-indirect-PARSEFILE-tA.tmp, line 1
 Skipping 'target-indirect-PARSEFILE-tA.tmp' because '__target-indirect-PARSEFILE-tA.tmp__' is defined
 Parse_PushInput: file subdir/target-indirect-PARSEFILE-tA.tmp, line 1
 Skipping 'subdir/target-indirect-PARSEFILE-tA.tmp' because '__target-indirect-PARSEFILE-tA.tmp__' is defined
 Parse_PushInput: file subdir2/target-indirect-PARSEFILE-tA.tmp, line 1
-Parse_PushInput: file subdir2/target-indirect-PARSEFILE-tA.tmp, line 1
+Skipping 'subdir2/target-indirect-PARSEFILE-tA.tmp' because '__target-indirect-PARSEFILE-tA.tmp__' is defined
 Parse_PushInput: file target-indirect-PARSEDIR-PARSEFILE.tmp, line 1
 Skipping 'target-indirect-PARSEDIR-PARSEFILE.tmp' because '__target-indirect-PARSEDIR-PARSEFILE.tmp__' is defined
 Parse_PushInput: file subdir/target-indirect-PARSEDIR-PARSEFILE.tmp, line 1
@@ -77,8 +87,8 @@ Parse_PushInput: file target-unguarded.t
 Parse_PushInput: file target-unguarded.tmp, line 1
 Parse_PushInput: file target-plus.tmp, line 1
 Parse_PushInput: file target-plus.tmp, line 1
-Parse_PushInput: file target-already-set.tmp, line 1
-Parse_PushInput: file target-already-set.tmp, line 1
+Parse_PushInput: file target-already-defined.tmp, line 1
+Skipping 'target-already-defined.tmp' because 'target-already-defined' is defined
 Parse_PushInput: file target-name-exclamation.tmp, line 1
 Parse_PushInput: file target-name-exclamation.tmp, line 1
 exit status 0
diff -r bb41cd240e2b -r 5e99faa2e7ba usr.bin/make/unit-tests/directive-include-guard.mk
--- a/usr.bin/make/unit-tests/directive-include-guard.mk        Wed Jun 21 12:27:50 2023 +0000
+++ b/usr.bin/make/unit-tests/directive-include-guard.mk        Wed Jun 21 14:33:36 2023 +0000
@@ -1,4 +1,4 @@
-# $NetBSD: directive-include-guard.mk,v 1.9 2023/06/21 12:16:31 rillig Exp $
+# $NetBSD: directive-include-guard.mk,v 1.10 2023/06/21 14:33:36 rillig Exp $
 #
 # Tests for multiple-inclusion guards in makefiles.
 #
@@ -15,8 +15,8 @@
 #      .endif
 #
 # When such a file is included for the second or later time, and the guard
-# variable is set or the guard target defined, including the file has no
-# effect, as all its content is skipped.
+# variable or the guard target is defined, including the file has no effect,
+# as all its content is skipped.
 #
 # See also:
 #      https://gcc.gnu.org/onlinedocs/cppinternals/Guard-Macros.html
@@ -35,6 +35,17 @@ LINES.variable-ifndef= \
 # expect: Parse_PushInput: file variable-ifndef.tmp, line 1
 # expect: Skipping 'variable-ifndef.tmp' because 'VARIABLE_IFNDEF' is defined
 
+# A file that reuses a guard from a previous file (or whose guard is defined
+# for any other reason) is only processed once, to see whether it is guarded.
+# Its content is skipped, therefore the syntax error is not detected.
+INCS+= variable-ifndef-reuse
+LINES.variable-ifndef-reuse= \
+       '.ifndef VARIABLE_IFNDEF' \
+       'syntax error' \
+       '.endif'
+# expect: Parse_PushInput: file variable-ifndef-reuse.tmp, line 1
+# expect: Skipping 'variable-ifndef-reuse.tmp' because 'VARIABLE_IFNDEF' is defined
+
 # Comments and empty lines do not affect the multiple-inclusion guard.
 INCS+= comments
 LINES.comments= \
@@ -59,6 +70,17 @@ LINES.variable-if= \
 # expect: Parse_PushInput: file variable-if.tmp, line 1
 # expect: Skipping 'variable-if.tmp' because 'VARIABLE_IF' is defined
 
+# A file that reuses a guard from a previous file (or whose guard is defined
+# for any other reason) is only processed once, to see whether it is guarded.
+# Its content is skipped, therefore the syntax error is not detected.
+INCS+= variable-if-reuse
+LINES.variable-if-reuse= \
+       '.if !defined(VARIABLE_IF)' \
+       'syntax error' \
+       '.endif'
+# expect: Parse_PushInput: file variable-if-reuse.tmp, line 1
+# expect: Skipping 'variable-if-reuse.tmp' because 'VARIABLE_IF' is defined
+
 # Triple negation is so uncommon that it's not recognized, even though it has
 # the same effect as a single negation.
 INCS+= variable-if-triple-negation
@@ -168,7 +190,8 @@ LINES.variable-if-indirect= \
 
 # The variable name in the guard condition must only contain alphanumeric
 # characters and underscores.  The guard variable is more flexible, it can be
-# set anywhere, as long as it is set when the guarded file is included next.
+# defined anywhere, as long as it is defined at the point where the file is
+# included the next time.
 INCS+= variable-assign-indirect
 LINES.variable-assign-indirect= \
        '.ifndef VARIABLE_ASSIGN_INDIRECT' \
@@ -177,8 +200,8 @@ LINES.variable-assign-indirect= \
 # expect: Parse_PushInput: file variable-assign-indirect.tmp, line 1
 # expect: Skipping 'variable-assign-indirect.tmp' because 'VARIABLE_ASSIGN_INDIRECT' is defined
 
-# The time at which the guard variable is set doesn't matter, as long as it is
-# set when the file is included the next time.
+# The time at which the guard variable is defined doesn't matter, as long as
+# it is defined at the point where the file is included the next time.
 INCS+= variable-assign-late
 LINES.variable-assign-late= \
        '.ifndef VARIABLE_ASSIGN_LATE' \
@@ -188,8 +211,8 @@ LINES.variable-assign-late= \
 # expect: Parse_PushInput: file variable-assign-late.tmp, line 1
 # expect: Skipping 'variable-assign-late.tmp' because 'VARIABLE_ASSIGN_LATE' is defined
 
-# The time at which the guard variable is set doesn't matter, as long as it is
-# set when the file is included the next time.
+# The time at which the guard variable is defined doesn't matter, as long as
+# it is defined at the point where the file is included the next time.
 INCS+= variable-assign-nested
 LINES.variable-assign-nested= \
        '.ifndef VARIABLE_ASSIGN_NESTED' \
@@ -203,8 +226,10 @@ LINES.variable-assign-nested= \
 # expect: Skipping 'variable-assign-nested.tmp' because 'VARIABLE_ASSIGN_NESTED' is defined
 
 # If the guard variable is defined before the file is included for the first
-# time, the file is not considered guarded.  This behavior is not finally
-# decided yet, as it is only a consequence of the current implementation.
+# time, the file is considered guarded as well.  In such a case, the parser
+# skips almost all lines, as they are irrelevant, but the structure of the
+# top-level '.if/.endif' conditional can be determined reliably enough to
+# decide whether the file is guarded.
 INCS+= variable-already-defined
 LINES.variable-already-defined= \
        '.ifndef VARIABLE_ALREADY_DEFINED' \
@@ -212,7 +237,21 @@ LINES.variable-already-defined= \
        '.endif'
 VARIABLE_ALREADY_DEFINED=
 # expect: Parse_PushInput: file variable-already-defined.tmp, line 1
-# expect: Parse_PushInput: file variable-already-defined.tmp, line 1
+# expect: Skipping 'variable-already-defined.tmp' because 'VARIABLE_ALREADY_DEFINED' is defined
+
+# If the guard variable is defined before the file is included the first time,
+# the file is processed but its content is skipped.  If that same guard
+# variable is undefined when the file is included the second time, the file is
+# processed as usual.
+INCS+= variable-defined-then-undefined
+LINES.variable-defined-then-undefined= \
+       '.ifndef VARIABLE_DEFINED_THEN_UNDEFINED' \
+       '.endif'
+VARIABLE_DEFINED_THEN_UNDEFINED=
+UNDEF_BETWEEN.variable-defined-then-undefined= \
+       VARIABLE_DEFINED_THEN_UNDEFINED
+# expect: Parse_PushInput: file variable-defined-then-undefined.tmp, line 1
+# expect: Parse_PushInput: file variable-defined-then-undefined.tmp, line 1
 
 # The whole file content must be guarded by a single '.if' conditional, not by
 # several, even if they have the same effect.  This case is not expected to
@@ -230,8 +269,8 @@ LINES.variable-two-times= \
 # expect: Parse_PushInput: file variable-two-times.tmp, line 1
 
 # When multiple files use the same guard variable name, the optimization of
-# skipping the file only affects the file that is included first.  The content
-# of the other files is still read but skipped, these files are not optimized.
+# skipping the file affects each of these files.
+#
 # Choosing unique guard names is the responsibility of the makefile authors.
 # A typical pattern of guard variable names is '${PROJECT}_${DIR}_${FILE}_MK'.
 # System-provided files typically start the guard names with '_'.
@@ -239,7 +278,7 @@ INCS+=      variable-clash
 LINES.variable-clash= \
        ${LINES.variable-if}
 # expect: Parse_PushInput: file variable-clash.tmp, line 1
-# expect: Parse_PushInput: file variable-clash.tmp, line 1
+# expect: Skipping 'variable-clash.tmp' because 'VARIABLE_IF' is defined
 
 # The conditional must come before the assignment, otherwise the conditional
 # is useless, as it always evaluates to false.
@@ -286,7 +325,7 @@ LINES.variable-not-defined= \
 
 # The outermost '.if' must not have an '.elif' branch.
 INCS+= if-elif
-LINES.if-elif = \
+LINES.if-elif= \
        '.ifndef IF_ELIF' \
        'IF_ELIF=' \
        '.elif 1' \
@@ -294,9 +333,20 @@ LINES.if-elif = \
 # expect: Parse_PushInput: file if-elif.tmp, line 1
 # expect: Parse_PushInput: file if-elif.tmp, line 1
 
+# When a file with an '.if/.elif/.endif' conditional at the top level is
+# included, it is never optimized, as one of its branches is taken.
+INCS+= if-elif-reuse
+LINES.if-elif-reuse= \
+       '.ifndef IF_ELIF' \
+       'syntax error' \
+       '.elif 1' \
+       '.endif'
+# expect: Parse_PushInput: file if-elif-reuse.tmp, line 1
+# expect: Parse_PushInput: file if-elif-reuse.tmp, line 1
+
 # The outermost '.if' must not have an '.else' branch.
 INCS+= if-else
-LINES.if-else = \
+LINES.if-else= \
        '.ifndef IF_ELSE' \
        'IF_ELSE=' \
        '.else' \
@@ -304,10 +354,21 @@ LINES.if-else = \
 # expect: Parse_PushInput: file if-else.tmp, line 1
 # expect: Parse_PushInput: file if-else.tmp, line 1
 
+# When a file with an '.if/.else/.endif' conditional at the top level is
+# included, it is never optimized, as one of its branches is taken.
+INCS+= if-else-reuse
+LINES.if-else-reuse= \
+       '.ifndef IF_ELSE' \
+       'syntax error' \
+       '.else' \
+       '.endif'
+# expect: Parse_PushInput: file if-else-reuse.tmp, line 1
+# expect: Parse_PushInput: file if-else-reuse.tmp, line 1
+
 # The inner '.if' directives may have an '.elif' or '.else', and it doesn't
 # matter which of their branches are taken.
 INCS+= inner-if-elif-else
-LINES.inner-if-elif-else = \
+LINES.inner-if-elif-else= \
        '.ifndef INNER_IF_ELIF_ELSE' \
        'INNER_IF_ELIF_ELSE=' \
        '.  if 0' \
@@ -389,15 +450,15 @@ LINES.target-indirect-PARSEFILE2= \
 # expect: Skipping 'target-indirect-PARSEFILE2.tmp' because '__target-indirect-PARSEFILE2.tmp__' is defined



Home | Main Index | Thread Index | Old Index