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: if a makefile is protected by a guard, on...



details:   https://anonhg.NetBSD.org/src/rev/c235f4878c78
branches:  trunk
changeset: 376465:c235f4878c78
user:      rillig <rillig%NetBSD.org@localhost>
date:      Mon Jun 19 12:53:57 2023 +0000

description:
make: if a makefile is protected by a guard, only include it once

"looks reasonable" sjg@

diffstat:

 usr.bin/make/cond.c                                 |  58 +++++++++++++++-
 usr.bin/make/make.h                                 |   5 +-
 usr.bin/make/parse.c                                |  76 ++++++++++++++++++++-
 usr.bin/make/unit-tests/directive-include-guard.exp |  14 +-
 usr.bin/make/unit-tests/directive-include-guard.mk  |  62 ++++++++--------
 5 files changed, 170 insertions(+), 45 deletions(-)

diffs (truncated from 496 to 300 lines):

diff -r 5b742e3e407a -r c235f4878c78 usr.bin/make/cond.c
--- a/usr.bin/make/cond.c       Mon Jun 19 12:33:43 2023 +0000
+++ b/usr.bin/make/cond.c       Mon Jun 19 12:53:57 2023 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: cond.c,v 1.346 2023/06/16 07:12:46 rillig Exp $        */
+/*     $NetBSD: cond.c,v 1.347 2023/06/19 12:53:57 rillig Exp $        */
 
 /*
  * Copyright (c) 1988, 1989, 1990 The Regents of the University of California.
@@ -92,7 +92,7 @@
 #include "dir.h"
 
 /*     "@(#)cond.c     8.2 (Berkeley) 1/2/94"  */
-MAKE_RCSID("$NetBSD: cond.c,v 1.346 2023/06/16 07:12:46 rillig Exp $");
+MAKE_RCSID("$NetBSD: cond.c,v 1.347 2023/06/19 12:53:57 rillig Exp $");
 
 /*
  * Conditional expressions conform to this grammar:
@@ -1123,6 +1123,7 @@ Cond_EvalLine(const char *line)
 
                /* Return state for previous conditional */
                cond_depth--;
+               Parse_GuardEndif();
                return cond_states[cond_depth] & IFS_ACTIVE
                    ? CR_TRUE : CR_FALSE;
        }
@@ -1150,6 +1151,7 @@ Cond_EvalLine(const char *line)
                                Parse_Error(PARSE_FATAL, "if-less else");
                                return CR_TRUE;
                        }
+                       Parse_GuardElse();
 
                        state = cond_states[cond_depth];
                        if (state == IFS_INITIAL) {
@@ -1185,6 +1187,7 @@ Cond_EvalLine(const char *line)
                        Parse_Error(PARSE_FATAL, "if-less elif");
                        return CR_TRUE;
                }
+               Parse_GuardElse();
                state = cond_states[cond_depth];
                if (state & IFS_SEEN_ELSE) {
                        Parse_Error(PARSE_WARNING, "extra elif");
@@ -1234,6 +1237,57 @@ Cond_EvalLine(const char *line)
        return res;
 }
 
+static bool
+skip_identifier(const char **pp)
+{
+       const char *p = *pp;
+
+       if (ch_isalpha(*p) || *p == '_') {
+               while (ch_isalnum(*p) || *p == '_')
+                       p++;
+               *pp = p;
+               return true;
+       }
+       return false;
+}
+
+/*
+ * Tests whether the line is a conditional that forms a multiple-inclusion
+ * guard, and if so, extracts the guard variable name.
+ */
+char *
+Cond_ExtractGuard(const char *line)
+{
+       const char *p = line, *dir, *varname;
+       size_t dir_len;
+
+       if (!skip_string(&p, "."))
+               return NULL;
+       cpp_skip_hspace(&p);
+
+       dir = p;
+       while (ch_isalpha(*p))
+               p++;
+       dir_len = (size_t)(p - dir);
+       cpp_skip_hspace(&p);
+
+       if (dir_len == 2 && memcmp(dir, "if", 2) == 0) {
+               if (!skip_string(&p, "!defined("))
+                       return NULL;
+               varname = p;
+               skip_identifier(&p);
+               if (p > varname && strcmp(p, ")") == 0)
+                       return bmake_strsedup(varname, p);
+       }
+       if (dir_len == 6 && memcmp(dir, "ifndef", 6) == 0) {
+               varname = p;
+               skip_identifier(&p);
+               if (p > varname && *p == '\0')
+                       return bmake_strsedup(varname, p);
+       }
+       return NULL;
+}
+
 void
 Cond_EndFile(void)
 {
diff -r 5b742e3e407a -r c235f4878c78 usr.bin/make/make.h
--- a/usr.bin/make/make.h       Mon Jun 19 12:33:43 2023 +0000
+++ b/usr.bin/make/make.h       Mon Jun 19 12:53:57 2023 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: make.h,v 1.321 2023/06/16 07:12:46 rillig Exp $        */
+/*     $NetBSD: make.h,v 1.322 2023/06/19 12:53:57 rillig Exp $        */
 
 /*
  * Copyright (c) 1988, 1989, 1990, 1993
@@ -793,6 +793,7 @@ void Compat_Make(GNode *, GNode *);
 extern unsigned int cond_depth;
 CondResult Cond_EvalCondition(const char *) MAKE_ATTR_USE;
 CondResult Cond_EvalLine(const char *) MAKE_ATTR_USE;
+char *Cond_ExtractGuard(const char *) MAKE_ATTR_USE;
 void Cond_EndFile(void);
 
 /* dir.c; see also dir.h */
@@ -857,6 +858,8 @@ void Parse_PushInput(const char *, unsig
 void Parse_MainName(GNodeList *);
 int Parse_NumErrors(void) MAKE_ATTR_USE;
 unsigned int CurFile_CondMinDepth(void) MAKE_ATTR_USE;
+void Parse_GuardElse(void);
+void Parse_GuardEndif(void);
 
 
 /* suff.c */
diff -r 5b742e3e407a -r c235f4878c78 usr.bin/make/parse.c
--- a/usr.bin/make/parse.c      Mon Jun 19 12:33:43 2023 +0000
+++ b/usr.bin/make/parse.c      Mon Jun 19 12:53:57 2023 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: parse.c,v 1.699 2023/06/01 06:25:34 rillig Exp $       */
+/*     $NetBSD: parse.c,v 1.700 2023/06/19 12:53:57 rillig Exp $       */
 
 /*
  * Copyright (c) 1988, 1989, 1990, 1993
@@ -105,7 +105,15 @@
 #include "pathnames.h"
 
 /*     "@(#)parse.c    8.3 (Berkeley) 3/19/94" */
-MAKE_RCSID("$NetBSD: parse.c,v 1.699 2023/06/01 06:25:34 rillig Exp $");
+MAKE_RCSID("$NetBSD: parse.c,v 1.700 2023/06/19 12:53:57 rillig Exp $");
+
+/* Detects a multiple-inclusion guard in a makefile. */
+typedef enum {
+       GS_START,               /* at the beginning of the file */
+       GS_COND,                /* after the guard condition */
+       GS_DONE,                /* after the closing .endif */
+       GS_NO                   /* the file is not guarded */
+} GuardState;
 
 /*
  * A file being read.
@@ -128,6 +136,9 @@ typedef struct IncludedFile {
        char *buf_ptr;          /* next char to be read */
        char *buf_end;          /* buf_end[-1] == '\n' */
 
+       GuardState guard;
+       char *guardVarname;
+
        struct ForLoop *forLoop;
 } IncludedFile;
 
@@ -299,6 +310,8 @@ static const struct {
 
 enum PosixState posix_state = PS_NOT_YET;
 
+static HashTable guards;
+
 static IncludedFile *
 GetInclude(size_t i)
 {
@@ -1212,6 +1225,7 @@ IncludeFile(const char *file, bool isSys
 {
        Buffer buf;
        char *fullname;         /* full pathname of file */
+       char *guardVarname;
        int fd;
 
        fullname = file[0] == '/' ? bmake_strdup(file) : NULL;
@@ -1231,6 +1245,14 @@ IncludeFile(const char *file, bool isSys
                return;
        }
 
+       guardVarname = HashTable_FindValue(&guards, fullname);
+       if (guardVarname != NULL
+           && GNode_ValueDirect(SCOPE_GLOBAL, guardVarname) != NULL) {
+               DEBUG2(PARSE, "Skipping '%s' because '%s' is already set\n",
+                   fullname, guardVarname);
+               return;
+       }
+
        if ((fd = open(fullname, O_RDONLY)) == -1) {
                if (!silent)
                        Parse_Error(PARSE_FATAL, "Cannot open %s", fullname);
@@ -2174,6 +2196,8 @@ Parse_PushInput(const char *name, unsign
        curFile->forBodyReadLines = readLines;
        curFile->buf = buf;
        curFile->depending = doing_depend;      /* restore this on EOF */
+       curFile->guard = forLoop == NULL ? GS_START : GS_NO;
+       curFile->guardVarname = NULL;
        curFile->forLoop = forLoop;
 
        if (forLoop != NULL && !For_NextIteration(forLoop, &curFile->buf))
@@ -2316,8 +2340,15 @@ ParseEOF(void)
 
        Cond_EndFile();
 
+       if (curFile->guard == GS_DONE) {
+               HashTable_Set(&guards,
+                   curFile->name.str, curFile->guardVarname);
+               curFile->guardVarname = NULL;
+       }
+
        FStr_Done(&curFile->name);
        Buf_Done(&curFile->buf);
+       free(curFile->guardVarname);
        if (curFile->forLoop != NULL)
                ForLoop_Free(curFile->forLoop);
        Vector_Pop(&includes);
@@ -2616,8 +2647,10 @@ static char *
 ReadHighLevelLine(void)
 {
        char *line;
+       CondResult condResult;
 
        for (;;) {
+               IncludedFile *curFile = CurFile();
                line = ReadLowLevelLine(LK_NONEMPTY);
                if (posix_state == PS_MAYBE_NEXT_LINE)
                        posix_state = PS_NOW_OR_NEVER;
@@ -2626,10 +2659,24 @@ ReadHighLevelLine(void)
                if (line == NULL)
                        return NULL;
 
+               if (curFile->guard != GS_NO
+                   && ((curFile->guard == GS_START && line[0] != '.')
+                       || curFile->guard == GS_DONE))
+                       curFile->guard = GS_NO;
                if (line[0] != '.')
                        return line;
 
-               switch (Cond_EvalLine(line)) {
+               condResult = Cond_EvalLine(line);
+               if (curFile->guard == GS_START) {
+                       char *varname;
+                       if (condResult == CR_TRUE
+                           && (varname = Cond_ExtractGuard(line)) != NULL) {
+                               curFile->guard = GS_COND;
+                               curFile->guardVarname = varname;
+                       } else
+                               curFile->guard = GS_NO;
+               }
+               switch (condResult) {
                case CR_FALSE:  /* May also mean a syntax error. */
                        if (!SkipIrrelevantBranches())
                                return NULL;
@@ -2784,6 +2831,22 @@ Parse_VarAssign(const char *line, bool f
        return true;
 }
 
+void
+Parse_GuardElse(void)
+{
+       IncludedFile *curFile = CurFile();
+       if (cond_depth == curFile->condMinDepth + 1)
+               curFile->guard = GS_NO;
+}
+
+void
+Parse_GuardEndif(void)
+{
+       IncludedFile *curFile = CurFile();
+       if (cond_depth == curFile->condMinDepth && curFile->guard == GS_COND)
+               curFile->guard = GS_DONE;
+}
+
 static char *
 FindSemicolon(char *p)
 {
@@ -2974,6 +3037,7 @@ Parse_Init(void)
        sysIncPath = SearchPath_New();
        defSysIncPath = SearchPath_New();
        Vector_Init(&includes, sizeof(IncludedFile));
+       HashTable_Init(&guards);
 }
 
 /* Clean up the parsing module. */
@@ -2981,6 +3045,8 @@ void
 Parse_End(void)
 {
 #ifdef CLEANUP
+       HashIter hi;
+
        Lst_DoneCall(&targCmds, free);
        assert(targets == NULL);
        SearchPath_Free(defSysIncPath);
@@ -2988,6 +3054,10 @@ Parse_End(void)
        SearchPath_Free(parseIncPath);
        assert(includes.len == 0);
        Vector_Done(&includes);



Home | Main Index | Thread Index | Old Index