diff --git a/contrib/bmake/ChangeLog b/contrib/bmake/ChangeLog index dc45a2e59274..7e9d10654840 100644 --- a/contrib/bmake/ChangeLog +++ b/contrib/bmake/ChangeLog @@ -1,3 +1,55 @@ +2023-04-14 Simon J Gerraty + + * VERSION (_MAKE_VERSION): 20230414 + Merge with NetBSD make, pick up + o minor cleanup + +2023-03-25 Simon J Gerraty + + * main.c: on some systems (eg OS/X) setting RLIMIT_NOFILE to + unlimited results in an insane number (0x7fffffffffffffff). + If BMAKE_NOFILE_MAX is defined, use that instead. + +2023-03-22 Simon J Gerraty + + * VERSION (_MAKE_VERSION): 20230321 + Merge with NetBSD make, pick up + * make.1: document seemingly unexplained Error code 6. + +2023-03-18 Simon J Gerraty + + * VERSION (_MAKE_VERSION): 20230317 + Merge with NetBSD make, pick up + o compat.c: CompatDeleteTarget skip .PHONY targets to be + consistent with JobDeleteTarget. + o job.c: fix memory leak in handling sysv :from=to modifiers + +2023-03-04 Simon J Gerraty + + * VERSION (_MAKE_VERSION): 20230303 + Merge with NetBSD make, pick up + o several updated unit-tests + +2023-02-22 Simon J Gerraty + + * VERSION (_MAKE_VERSION): 20230222 + Merge with NetBSD make, pick up + o unit tests for .MAKE.META.IGNORE_{FILTER,PATHS,PATTERNS} + +2023-02-20 Simon J Gerraty + + * VERSION (_MAKE_VERSION): 20230218 + Merge with NetBSD make, pick up + o var.c: fix parsing of unevaluated subexpressions with + unbalanced '{}' + +2023-02-17 Simon J Gerraty + + * VERSION (_MAKE_VERSION): 20230215 + Merge with NetBSD make, pick up + o inline macros for some variable names + o cond.c: reduce complexity of evaluating expressions + 2023-02-08 Simon J Gerraty * VERSION (_MAKE_VERSION): 20230208 diff --git a/contrib/bmake/FILES b/contrib/bmake/FILES index b88aa64271bf..642b1bae7a6b 100644 --- a/contrib/bmake/FILES +++ b/contrib/bmake/FILES @@ -428,6 +428,7 @@ unit-tests/make-exported.exp unit-tests/make-exported.mk unit-tests/meta-cmd-cmp.exp unit-tests/meta-cmd-cmp.mk +unit-tests/meta-ignore.inc unit-tests/moderrs.exp unit-tests/moderrs.mk unit-tests/modmatch.exp diff --git a/contrib/bmake/Makefile b/contrib/bmake/Makefile index 4ad9ac92b266..212885f7b900 100644 --- a/contrib/bmake/Makefile +++ b/contrib/bmake/Makefile @@ -1,4 +1,4 @@ -# $Id: Makefile,v 1.123 2023/01/28 02:49:20 sjg Exp $ +# $Id: Makefile,v 1.124 2023/02/25 20:27:44 sjg Exp $ PROG= bmake @@ -176,9 +176,7 @@ SHAREDIR= ${SHAREDIR.bmake:U${prefix}/share} BINDIR= ${BINDIR.bmake:U${prefix}/bin} MANDIR= ${MANDIR.bmake:U${SHAREDIR}/man} -.if !exists(.depend) ${OBJS}: config.h -.endif # start-delete2 for bsd.after-import.mk diff --git a/contrib/bmake/VERSION b/contrib/bmake/VERSION index 4d0b127caf7c..2631e0deeb1e 100644 --- a/contrib/bmake/VERSION +++ b/contrib/bmake/VERSION @@ -1,2 +1,2 @@ # keep this compatible with sh and make -_MAKE_VERSION=20230208 +_MAKE_VERSION=20230414 diff --git a/contrib/bmake/arch.c b/contrib/bmake/arch.c index 15816fd0b606..6d2c6e0f1875 100644 --- a/contrib/bmake/arch.c +++ b/contrib/bmake/arch.c @@ -1,4 +1,4 @@ -/* $NetBSD: arch.c,v 1.212 2022/12/07 10:28:48 rillig Exp $ */ +/* $NetBSD: arch.c,v 1.213 2023/02/14 21:08:00 rillig Exp $ */ /* * Copyright (c) 1988, 1989, 1990, 1993 @@ -147,7 +147,7 @@ struct ar_hdr { #include "dir.h" /* "@(#)arch.c 8.2 (Berkeley) 1/2/94" */ -MAKE_RCSID("$NetBSD: arch.c,v 1.212 2022/12/07 10:28:48 rillig Exp $"); +MAKE_RCSID("$NetBSD: arch.c,v 1.213 2023/02/14 21:08:00 rillig Exp $"); typedef struct List ArchList; typedef struct ListNode ArchListNode; @@ -269,8 +269,7 @@ Arch_ParseArchive(char **pp, GNodeList *gns, GNode *scope) bool isError; /* XXX: is expanded twice: once here and once below */ - (void)Var_Parse(&nested_p, scope, - VARE_UNDEFERR, &result); + result = Var_Parse(&nested_p, scope, VARE_UNDEFERR); /* TODO: handle errors */ isError = result.str == var_Error; FStr_Done(&result); @@ -308,8 +307,8 @@ Arch_ParseArchive(char **pp, GNodeList *gns, GNode *scope) bool isError; const char *nested_p = cp; - (void)Var_Parse(&nested_p, scope, - VARE_UNDEFERR, &result); + result = Var_Parse(&nested_p, scope, + VARE_UNDEFERR); /* TODO: handle errors */ isError = result.str == var_Error; FStr_Done(&result); diff --git a/contrib/bmake/bmake.1 b/contrib/bmake/bmake.1 index 13bb9e9235b9..1d5ee8f1f3aa 100644 --- a/contrib/bmake/bmake.1 +++ b/contrib/bmake/bmake.1 @@ -1,4 +1,4 @@ -.\" $NetBSD: make.1,v 1.360 2023/01/26 20:48:17 sjg Exp $ +.\" $NetBSD: make.1,v 1.361 2023/03/23 03:29:28 sjg Exp $ .\" .\" Copyright (c) 1990, 1993 .\" The Regents of the University of California. All rights reserved. @@ -29,7 +29,7 @@ .\" .\" from: @(#)make.1 8.4 (Berkeley) 3/19/94 .\" -.Dd January 26, 2023 +.Dd March 22, 2023 .Dt BMAKE 1 .Os .Sh NAME @@ -267,7 +267,9 @@ cooperate to avoid overloading the system. Specify the maximum number of jobs that .Nm may have running at any one time. -The value is saved in +The value of +.Ar max_jobs +is saved in .Va .MAKE.JOBS . Turns compatibility mode off, unless the .Fl B @@ -280,6 +282,13 @@ command invocation and then expect to start with a fresh environment on the next line. It is more efficient to correct the scripts rather than turn backwards compatibility on. +.Pp +A job token pool with +.Ar max_jobs +tokens is used to control the total number of jobs running. +Each instance of +.Nm +will wait for a token from the pool before running a new job. .It Fl k Continue processing after errors are encountered, but only on those targets that do not depend on the target whose creation caused the error. @@ -2716,3 +2725,15 @@ make just counts {} and () in order to find the end of a variable expansion. .Pp There is no way of escaping a space character in a filename. +.Pp +In jobs mode, when a target fails; +make +will put an error token into the job token pool. +This will cause all other instances of +make +using that token pool to abort the build and exit with error code 6. +Sometimes the attempt to suppress a cascade of unnecessary errors, +can result in a seemingly unexplained +.Ql *** Error code 6 + + diff --git a/contrib/bmake/bmake.cat1 b/contrib/bmake/bmake.cat1 index 7cb47607417f..9715bd908f18 100644 --- a/contrib/bmake/bmake.cat1 +++ b/contrib/bmake/bmake.cat1 @@ -157,15 +157,19 @@ BMAKE(1) FreeBSD General Commands Manual BMAKE(1) -j max_jobs Specify the maximum number of jobs that bmake may have running at - any one time. The value is saved in .MAKE.JOBS. Turns compati- - bility mode off, unless the -B option is also specified. When - compatibility mode is off, all commands associated with a target - are executed in a single shell invocation as opposed to the tra- - ditional one shell invocation per line. This can break tradi- - tional scripts which change directories on each command invoca- - tion and then expect to start with a fresh environment on the - next line. It is more efficient to correct the scripts rather - than turn backwards compatibility on. + any one time. The value of max_jobs is saved in .MAKE.JOBS. + Turns compatibility mode off, unless the -B option is also speci- + fied. When compatibility mode is off, all commands associated + with a target are executed in a single shell invocation as op- + posed to the traditional one shell invocation per line. This can + break traditional scripts which change directories on each com- + mand invocation and then expect to start with a fresh environment + on the next line. It is more efficient to correct the scripts + rather than turn backwards compatibility on. + + A job token pool with max_jobs tokens is used to control the to- + tal number of jobs running. Each instance of bmake will wait for + a token from the pool before running a new job. -k Continue processing after errors are encountered, but only on those targets that do not depend on the target whose creation @@ -1740,4 +1744,12 @@ BMAKE(1) FreeBSD General Commands Manual BMAKE(1) There is no way of escaping a space character in a filename. -FreeBSD 13.0 January 26, 2023 FreeBSD 13.0 + In jobs mode, when a target fails; make will put an error token into the + job token pool. This will cause all other instances of make using that + token pool to abort the build and exit with error code 6. Sometimes the + attempt to suppress a cascade of unnecessary errors, can result in a + seemingly unexplained `*** Error code 6' + + + +FreeBSD 13.0 March 22, 2023 FreeBSD 13.0 diff --git a/contrib/bmake/compat.c b/contrib/bmake/compat.c index 13063d8abd7e..521c3a364028 100644 --- a/contrib/bmake/compat.c +++ b/contrib/bmake/compat.c @@ -1,4 +1,4 @@ -/* $NetBSD: compat.c,v 1.244 2023/01/17 21:35:19 christos Exp $ */ +/* $NetBSD: compat.c,v 1.246 2023/03/18 22:20:11 sjg Exp $ */ /* * Copyright (c) 1988, 1989, 1990 The Regents of the University of California. @@ -94,7 +94,7 @@ #include "pathnames.h" /* "@(#)compat.c 8.2 (Berkeley) 3/19/94" */ -MAKE_RCSID("$NetBSD: compat.c,v 1.244 2023/01/17 21:35:19 christos Exp $"); +MAKE_RCSID("$NetBSD: compat.c,v 1.246 2023/03/18 22:20:11 sjg Exp $"); static GNode *curTarg = NULL; static pid_t compatChild; @@ -107,7 +107,8 @@ static int compatSigno; static void CompatDeleteTarget(GNode *gn) { - if (gn != NULL && !GNode_IsPrecious(gn)) { + if (gn != NULL && !GNode_IsPrecious(gn) && + (gn->type & OP_PHONY) == 0) { const char *file = GNode_VarTarget(gn); if (!opts.noExecute && unlink_file(file) == 0) { @@ -241,7 +242,7 @@ Compat_RunCommand(const char *cmdp, GNode *gn, StringListNode *ln) errCheck = !(gn->type & OP_IGNORE); doIt = false; - (void)Var_Subst(cmd, gn, VARE_WANTRES, &cmdStart); + cmdStart = Var_Subst(cmd, gn, VARE_WANTRES); /* TODO: handle errors */ if (cmdStart[0] == '\0') { diff --git a/contrib/bmake/cond.c b/contrib/bmake/cond.c index fb7f789af0d1..a7cd7e833f5d 100644 --- a/contrib/bmake/cond.c +++ b/contrib/bmake/cond.c @@ -1,4 +1,4 @@ -/* $NetBSD: cond.c,v 1.342 2022/09/24 16:13:48 rillig Exp $ */ +/* $NetBSD: cond.c,v 1.344 2023/02/14 21:08:00 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.342 2022/09/24 16:13:48 rillig Exp $"); +MAKE_RCSID("$NetBSD: cond.c,v 1.344 2023/02/14 21:08:00 rillig Exp $"); /* * Conditional expressions conform to this grammar: @@ -235,8 +235,7 @@ ParseWord(const char **pp, bool doEval) VarEvalMode emode = doEval ? VARE_UNDEFERR : VARE_PARSE_ONLY; - FStr nestedVal; - (void)Var_Parse(&p, SCOPE_CMDLINE, emode, &nestedVal); + FStr nestedVal = Var_Parse(&p, SCOPE_CMDLINE, emode); /* TODO: handle errors */ Buf_AddStr(&word, nestedVal.str); FStr_Done(&nestedVal); @@ -380,7 +379,9 @@ is_separator(char ch) /* * In a quoted or unquoted string literal or a number, parse a variable - * expression. + * expression and add its value to the buffer. + * + * Return whether to continue parsing the leaf. * * Example: .if x${CENTER}y == "${PREFIX}${SUFFIX}" || 0x${HEX} */ @@ -392,7 +393,6 @@ CondParser_StringExpr(CondParser *par, const char *start, VarEvalMode emode; const char *p; bool atStart; - VarParseResult parseResult; emode = doEval && quoted ? VARE_WANTRES : doEval ? VARE_UNDEFERR @@ -400,27 +400,10 @@ CondParser_StringExpr(CondParser *par, const char *start, p = par->p; atStart = p == start; - parseResult = Var_Parse(&p, SCOPE_CMDLINE, emode, inout_str); + *inout_str = Var_Parse(&p, SCOPE_CMDLINE, emode); /* TODO: handle errors */ if (inout_str->str == var_Error) { - if (parseResult == VPR_ERR) { - /* - * FIXME: Even if an error occurs, there is no - * guarantee that it is reported. - * - * See cond-token-plain.mk $$$$$$$$. - */ - par->printedError = true; - } - /* - * XXX: Can there be any situation in which a returned - * var_Error needs to be freed? - */ FStr_Done(inout_str); - /* - * Even if !doEval, we still report syntax errors, which is - * what getting var_Error back with !doEval means. - */ *inout_str = FStr_InitRefer(NULL); return false; } @@ -428,8 +411,8 @@ CondParser_StringExpr(CondParser *par, const char *start, /* * If the '$' started the string literal (which means no quotes), and - * the variable expression is followed by a space, looks like a - * comparison operator or is the end of the expression, we are done. + * the expression is followed by a space, a comparison operator or + * the end of the expression, we are done. */ if (atStart && is_separator(par->p[0])) return false; @@ -691,8 +674,8 @@ CondParser_FuncCallEmpty(CondParser *par, bool doEval, Token *out_token) return false; cp--; /* Make cp[1] point to the '('. */ - (void)Var_Parse(&cp, SCOPE_CMDLINE, - doEval ? VARE_WANTRES : VARE_PARSE_ONLY, &val); + val = Var_Parse(&cp, SCOPE_CMDLINE, + doEval ? VARE_WANTRES : VARE_PARSE_ONLY); /* TODO: handle errors */ if (val.str == var_Error) diff --git a/contrib/bmake/for.c b/contrib/bmake/for.c index bbe6171326f4..089d32efed74 100644 --- a/contrib/bmake/for.c +++ b/contrib/bmake/for.c @@ -1,4 +1,4 @@ -/* $NetBSD: for.c,v 1.170 2022/09/03 00:50:07 rillig Exp $ */ +/* $NetBSD: for.c,v 1.171 2023/02/14 21:38:31 rillig Exp $ */ /* * Copyright (c) 1992, The Regents of the University of California. @@ -58,7 +58,7 @@ #include "make.h" /* "@(#)for.c 8.1 (Berkeley) 6/6/93" */ -MAKE_RCSID("$NetBSD: for.c,v 1.170 2022/09/03 00:50:07 rillig Exp $"); +MAKE_RCSID("$NetBSD: for.c,v 1.171 2023/02/14 21:38:31 rillig Exp $"); typedef struct ForLoop { @@ -168,7 +168,9 @@ ForLoop_ParseItems(ForLoop *f, const char *p) cpp_skip_whitespace(&p); - if (Var_Subst(p, SCOPE_GLOBAL, VARE_WANTRES, &items) != VPR_OK) { + items = Var_Subst(p, SCOPE_GLOBAL, VARE_WANTRES); + if (items == var_Error) { + /* TODO: Make this part of the code reachable. */ Parse_Error(PARSE_FATAL, "Error in .for loop items"); return false; } diff --git a/contrib/bmake/job.c b/contrib/bmake/job.c index b9b5a5d36e47..22e21192281b 100644 --- a/contrib/bmake/job.c +++ b/contrib/bmake/job.c @@ -1,4 +1,4 @@ -/* $NetBSD: job.c,v 1.457 2023/01/17 21:35:19 christos Exp $ */ +/* $NetBSD: job.c,v 1.459 2023/02/15 06:52:58 rillig Exp $ */ /* * Copyright (c) 1988, 1989, 1990 The Regents of the University of California. @@ -155,7 +155,7 @@ #include "trace.h" /* "@(#)job.c 8.2 (Berkeley) 3/19/94" */ -MAKE_RCSID("$NetBSD: job.c,v 1.457 2023/01/17 21:35:19 christos Exp $"); +MAKE_RCSID("$NetBSD: job.c,v 1.459 2023/02/15 06:52:58 rillig Exp $"); /* * A shell defines how the commands are run. All commands for a target are @@ -940,7 +940,7 @@ JobWriteCommand(Job *job, ShellWriter *wr, StringListNode *ln, const char *ucmd) run = GNode_ShouldExecute(job->node); - (void)Var_Subst(ucmd, job->node, VARE_WANTRES, &xcmd); + xcmd = Var_Subst(ucmd, job->node, VARE_WANTRES); /* TODO: handle errors */ xcmdStart = xcmd; @@ -1069,7 +1069,7 @@ JobSaveCommands(Job *job) * variables such as .TARGET, .IMPSRC. It is not intended to * expand the other variables as well; see deptgt-end.mk. */ - (void)Var_Subst(cmd, job->node, VARE_WANTRES, &expanded_cmd); + expanded_cmd = Var_Subst(cmd, job->node, VARE_WANTRES); /* TODO: handle errors */ Lst_Append(&Targ_GetEndNode()->commands, expanded_cmd); } @@ -1105,8 +1105,7 @@ DebugFailedJob(const Job *job) debug_printf("\t%s\n", cmd); if (strchr(cmd, '$') != NULL) { - char *xcmd; - (void)Var_Subst(cmd, job->node, VARE_WANTRES, &xcmd); + char *xcmd = Var_Subst(cmd, job->node, VARE_WANTRES); debug_printf("\t=> %s\n", xcmd); free(xcmd); } @@ -2232,12 +2231,12 @@ Job_SetPrefix(void) { if (targPrefix != NULL) { free(targPrefix); - } else if (!Var_Exists(SCOPE_GLOBAL, MAKE_JOB_PREFIX)) { - Global_Set(MAKE_JOB_PREFIX, "---"); + } else if (!Var_Exists(SCOPE_GLOBAL, ".MAKE.JOB.PREFIX")) { + Global_Set(".MAKE.JOB.PREFIX", "---"); } - (void)Var_Subst("${" MAKE_JOB_PREFIX "}", - SCOPE_GLOBAL, VARE_WANTRES, &targPrefix); + targPrefix = Var_Subst("${.MAKE.JOB.PREFIX}", + SCOPE_GLOBAL, VARE_WANTRES); /* TODO: handle errors */ } diff --git a/contrib/bmake/main.c b/contrib/bmake/main.c index 23350b49e536..b0a4d003ddf1 100644 --- a/contrib/bmake/main.c +++ b/contrib/bmake/main.c @@ -1,4 +1,4 @@ -/* $NetBSD: main.c,v 1.589 2023/01/26 20:48:17 sjg Exp $ */ +/* $NetBSD: main.c,v 1.593 2023/03/28 14:39:31 rillig Exp $ */ /* * Copyright (c) 1988, 1989, 1990, 1993 @@ -111,7 +111,7 @@ #include "trace.h" /* "@(#)main.c 8.3 (Berkeley) 3/19/94" */ -MAKE_RCSID("$NetBSD: main.c,v 1.589 2023/01/26 20:48:17 sjg Exp $"); +MAKE_RCSID("$NetBSD: main.c,v 1.593 2023/03/28 14:39:31 rillig Exp $"); #if defined(MAKE_NATIVE) && !defined(lint) __COPYRIGHT("@(#) Copyright (c) 1988, 1989, 1990, 1993 " "The Regents of the University of California. " @@ -129,7 +129,7 @@ bool allPrecious; /* .PRECIOUS given on line by itself */ bool deleteOnError; /* .DELETE_ON_ERROR: set */ static int maxJobTokens; /* -j argument */ -bool enterFlagObj; /* -w and objdir != srcdir */ +static bool enterFlagObj; /* -w and objdir != srcdir */ static int jp_0 = -1, jp_1 = -1; /* ends of parent job pipe */ bool doing_depend; /* Set while reading .depend */ @@ -436,7 +436,7 @@ MainParseArgSysInc(const char *argvalue) } static bool -MainParseArg(char c, const char *argvalue) +MainParseOption(char c, const char *argvalue) { switch (c) { case '\0': @@ -444,7 +444,7 @@ MainParseArg(char c, const char *argvalue) case 'B': opts.compatMake = true; Global_Append(MAKEFLAGS, "-B"); - Global_Set(MAKE_MODE, "compat"); + Global_Set(".MAKE.MODE", "compat"); break; case 'C': MainParseArgChdir(argvalue); @@ -628,7 +628,7 @@ MainParseArgs(int argc, char **argv) dashDash = true; break; default: - if (!MainParseArg(c, argvalue)) + if (!MainParseOption(c, argvalue)) goto noarg; } argv += arginc; @@ -806,9 +806,8 @@ siginfo(int signo MAKE_ATTR_UNUSED) static void MakeMode(void) { - char *mode; - - (void)Var_Subst("${" MAKE_MODE ":tl}", SCOPE_GLOBAL, VARE_WANTRES, &mode); + char *mode = Var_Subst("${.MAKE.MODE:tl}", + SCOPE_GLOBAL, VARE_WANTRES); /* TODO: handle errors */ if (mode[0] != '\0') { @@ -831,16 +830,14 @@ static void PrintVar(const char *varname, bool expandVars) { if (strchr(varname, '$') != NULL) { - char *evalue; - (void)Var_Subst(varname, SCOPE_GLOBAL, VARE_WANTRES, &evalue); + char *evalue = Var_Subst(varname, SCOPE_GLOBAL, VARE_WANTRES); /* TODO: handle errors */ printf("%s\n", evalue); free(evalue); } else if (expandVars) { char *expr = str_concat3("${", varname, "}"); - char *evalue; - (void)Var_Subst(expr, SCOPE_GLOBAL, VARE_WANTRES, &evalue); + char *evalue = Var_Subst(expr, SCOPE_GLOBAL, VARE_WANTRES); /* TODO: handle errors */ free(expr); printf("%s\n", evalue); @@ -866,7 +863,7 @@ GetBooleanExpr(const char *expr, bool fallback) char *value; bool res; - (void)Var_Subst(expr, SCOPE_GLOBAL, VARE_WANTRES, &value); + value = Var_Subst(expr, SCOPE_GLOBAL, VARE_WANTRES); /* TODO: handle errors */ res = ParseBoolean(value, fallback); free(value); @@ -1098,6 +1095,11 @@ UnlimitFiles(void) struct rlimit rl; if (getrlimit(RLIMIT_NOFILE, &rl) != -1 && rl.rlim_cur != rl.rlim_max) { +#ifdef BMAKE_NOFILE_MAX + if (BMAKE_NOFILE_MAX < rl.rlim_max) + rl.rlim_cur = BMAKE_NOFILE_MAX; + else +#endif rl.rlim_cur = rl.rlim_max; (void)setrlimit(RLIMIT_NOFILE, &rl); } @@ -1232,7 +1234,7 @@ InitMaxJobs(void) !Var_Exists(SCOPE_GLOBAL, ".MAKE.JOBS")) return; - (void)Var_Subst("${.MAKE.JOBS}", SCOPE_GLOBAL, VARE_WANTRES, &value); + value = Var_Subst("${.MAKE.JOBS}", SCOPE_GLOBAL, VARE_WANTRES); /* TODO: handle errors */ n = (int)strtol(value, NULL, 0); if (n < 1) { @@ -1267,7 +1269,7 @@ InitVpath(void) if (!Var_Exists(SCOPE_CMDLINE, "VPATH")) return; - (void)Var_Subst("${VPATH}", SCOPE_CMDLINE, VARE_WANTRES, &vpath); + vpath = Var_Subst("${VPATH}", SCOPE_CMDLINE, VARE_WANTRES); /* TODO: handle errors */ path = vpath; do { @@ -1303,10 +1305,8 @@ ReadFirstDefaultMakefile(void) { StringList makefiles = LST_INIT; StringListNode *ln; - char *prefs; - - (void)Var_Subst("${" MAKE_MAKEFILE_PREFERENCE "}", - SCOPE_CMDLINE, VARE_WANTRES, &prefs); + char *prefs = Var_Subst("${.MAKE.MAKEFILE_PREFERENCE}", + SCOPE_CMDLINE, VARE_WANTRES); /* TODO: handle errors */ (void)str2Lst_Append(&makefiles, prefs); @@ -1384,7 +1384,7 @@ main_Init(int argc, char **argv) /* This is the traditional preference for makefiles. */ # define MAKEFILE_PREFERENCE_LIST "makefile Makefile" #endif - Global_Set(MAKE_MAKEFILE_PREFERENCE, MAKEFILE_PREFERENCE_LIST); + Global_Set(".MAKE.MAKEFILE_PREFERENCE", MAKEFILE_PREFERENCE_LIST); Global_Set(".MAKE.DEPENDFILE", ".depend"); CmdOpts_Init(); @@ -1410,7 +1410,7 @@ main_Init(int argc, char **argv) Parse_Init(); InitVarMake(argv[0]); Global_Set(MAKEFLAGS, ""); - Global_Set(MAKEOVERRIDES, ""); + Global_Set(".MAKEOVERRIDES", ""); Global_Set("MFLAGS", ""); Global_Set(".ALLTARGETS", ""); Var_Set(SCOPE_CMDLINE, ".MAKE.LEVEL.ENV", MAKE_LEVEL_ENV); @@ -1423,7 +1423,7 @@ main_Init(int argc, char **argv) if (makelevel < 0) makelevel = 0; snprintf(buf, sizeof buf, "%d", makelevel); - Global_Set(MAKE_LEVEL, buf); + Global_Set(".MAKE.LEVEL", buf); snprintf(buf, sizeof buf, "%u", myPid); Global_Set_ReadOnly(".MAKE.PID", buf); snprintf(buf, sizeof buf, "%u", getppid()); @@ -1525,8 +1525,8 @@ main_PrepareMaking(void) { /* In particular suppress .depend for '-r -V .OBJDIR -f /dev/null' */ if (!opts.noBuiltins || opts.printVars == PVM_NONE) { - (void)Var_Subst("${.MAKE.DEPENDFILE}", - SCOPE_CMDLINE, VARE_WANTRES, &makeDependfile); + makeDependfile = Var_Subst("${.MAKE.DEPENDFILE}", + SCOPE_CMDLINE, VARE_WANTRES); if (makeDependfile[0] != '\0') { /* TODO: handle errors */ doing_depend = true; @@ -2088,9 +2088,9 @@ PrintOnError(GNode *gn, const char *msg) SetErrorVars(gn); { - char *errorVarsValues; - (void)Var_Subst("${MAKE_PRINT_VAR_ON_ERROR:@v@$v='${$v}'\n@}", - SCOPE_GLOBAL, VARE_WANTRES, &errorVarsValues); + char *errorVarsValues = Var_Subst( + "${MAKE_PRINT_VAR_ON_ERROR:@v@$v='${$v}'\n@}", + SCOPE_GLOBAL, VARE_WANTRES); /* TODO: handle errors */ printf("%s", errorVarsValues); free(errorVarsValues); @@ -2118,9 +2118,9 @@ Main_ExportMAKEFLAGS(bool first) return; once = false; - (void)Var_Subst( + flags = Var_Subst( "${.MAKEFLAGS} ${.MAKEOVERRIDES:O:u:@v@$v=${$v:Q}@}", - SCOPE_CMDLINE, VARE_WANTRES, &flags); + SCOPE_CMDLINE, VARE_WANTRES); /* TODO: handle errors */ if (flags[0] != '\0') { #ifdef POSIX @@ -2141,8 +2141,8 @@ getTmpdir(void) return tmpdir; /* Honor $TMPDIR if it is valid, strip a trailing '/'. */ - (void)Var_Subst("${TMPDIR:tA:U" _PATH_TMP ":S,/$,,W}/", - SCOPE_GLOBAL, VARE_WANTRES, &tmpdir); + tmpdir = Var_Subst("${TMPDIR:tA:U" _PATH_TMP ":S,/$,,W}/", + SCOPE_GLOBAL, VARE_WANTRES); /* TODO: handle errors */ if (stat(tmpdir, &st) < 0 || !S_ISDIR(st.st_mode)) { diff --git a/contrib/bmake/make.1 b/contrib/bmake/make.1 index 5a28d2f83ca3..f3de112172cc 100644 --- a/contrib/bmake/make.1 +++ b/contrib/bmake/make.1 @@ -1,4 +1,4 @@ -.\" $NetBSD: make.1,v 1.360 2023/01/26 20:48:17 sjg Exp $ +.\" $NetBSD: make.1,v 1.361 2023/03/23 03:29:28 sjg Exp $ .\" .\" Copyright (c) 1990, 1993 .\" The Regents of the University of California. All rights reserved. @@ -29,7 +29,7 @@ .\" .\" from: @(#)make.1 8.4 (Berkeley) 3/19/94 .\" -.Dd January 26, 2023 +.Dd March 22, 2023 .Dt MAKE 1 .Os .Sh NAME @@ -267,7 +267,9 @@ cooperate to avoid overloading the system. Specify the maximum number of jobs that .Nm may have running at any one time. -The value is saved in +The value of +.Ar max_jobs +is saved in .Va .MAKE.JOBS . Turns compatibility mode off, unless the .Fl B @@ -280,6 +282,13 @@ command invocation and then expect to start with a fresh environment on the next line. It is more efficient to correct the scripts rather than turn backwards compatibility on. +.Pp +A job token pool with +.Ar max_jobs +tokens is used to control the total number of jobs running. +Each instance of +.Nm +will wait for a token from the pool before running a new job. .It Fl k Continue processing after errors are encountered, but only on those targets that do not depend on the target whose creation caused the error. @@ -2723,3 +2732,15 @@ In many places just counts {} and () in order to find the end of a variable expansion. .Pp There is no way of escaping a space character in a filename. +.Pp +In jobs mode, when a target fails; +.Nm +will put an error token into the job token pool. +This will cause all other instances of +.Nm +using that token pool to abort the build and exit with error code 6. +Sometimes the attempt to suppress a cascade of unnecessary errors, +can result in a seemingly unexplained +.Ql *** Error code 6 + + diff --git a/contrib/bmake/make.c b/contrib/bmake/make.c index c9e59c40a033..b636800d33cb 100644 --- a/contrib/bmake/make.c +++ b/contrib/bmake/make.c @@ -1,4 +1,4 @@ -/* $NetBSD: make.c,v 1.258 2022/12/05 23:28:08 rillig Exp $ */ +/* $NetBSD: make.c,v 1.259 2023/02/14 21:38:31 rillig Exp $ */ /* * Copyright (c) 1988, 1989, 1990, 1993 @@ -104,7 +104,7 @@ #include "job.h" /* "@(#)make.c 8.1 (Berkeley) 6/6/93" */ -MAKE_RCSID("$NetBSD: make.c,v 1.258 2022/12/05 23:28:08 rillig Exp $"); +MAKE_RCSID("$NetBSD: make.c,v 1.259 2023/02/14 21:38:31 rillig Exp $"); /* Sequence # to detect recursion. */ static unsigned int checked_seqno = 1; @@ -445,7 +445,7 @@ Make_HandleUse(GNode *cgn, GNode *pgn) } else { free(gn->name); } - (void)Var_Subst(gn->uname, pgn, VARE_WANTRES, &gn->name); + gn->name = Var_Subst(gn->uname, pgn, VARE_WANTRES); /* TODO: handle errors */ if (gn->uname != NULL && strcmp(gn->name, gn->uname) != 0) { /* See if we have a target for this node. */ diff --git a/contrib/bmake/make.h b/contrib/bmake/make.h index d62e2a3f507b..d2e6c28be1ff 100644 --- a/contrib/bmake/make.h +++ b/contrib/bmake/make.h @@ -1,4 +1,4 @@ -/* $NetBSD: make.h,v 1.311 2023/01/26 20:48:17 sjg Exp $ */ +/* $NetBSD: make.h,v 1.319 2023/03/28 14:39:31 rillig Exp $ */ /* * Copyright (c) 1988, 1989, 1990, 1993 @@ -625,14 +625,6 @@ extern GNode *mainNode; extern pid_t myPid; #define MAKEFLAGS ".MAKEFLAGS" -#define MAKEOVERRIDES ".MAKEOVERRIDES" -/* prefix when printing the target of a job */ -#define MAKE_JOB_PREFIX ".MAKE.JOB.PREFIX" -#define MAKE_EXPORTED ".MAKE.EXPORTED" /* exported variables */ -#define MAKE_MAKEFILES ".MAKE.MAKEFILES" /* all loaded makefiles */ -#define MAKE_LEVEL ".MAKE.LEVEL" /* recursion level */ -#define MAKE_MAKEFILE_PREFERENCE ".MAKE.MAKEFILE_PREFERENCE" -#define MAKE_MODE ".MAKE.MODE" #ifndef MAKE_LEVEL_ENV # define MAKE_LEVEL_ENV "MAKELEVEL" #endif @@ -792,6 +784,8 @@ typedef struct CmdOpts { } CmdOpts; extern CmdOpts opts; +extern bool forceJobs; +extern char **environ; /* arch.c */ void Arch_Init(void); @@ -935,6 +929,14 @@ typedef enum VarEvalMode { */ VARE_PARSE_ONLY, + /* + * Parse text in which '${...}' and '$(...)' are not parsed as + * subexpressions (with all their individual escaping rules) but + * instead simply as text with balanced '${}' or '$()'. Other '$' + * are copied verbatim. + */ + VARE_PARSE_BALANCED, + /* Parse and evaluate the expression. */ VARE_WANTRES, @@ -984,35 +986,12 @@ typedef enum VarSetFlags { /* * Make the variable read-only. No further modification is possible, - * except for another call to Var_Set with the same flag. + * except for another call to Var_Set with the same flag. See the + * special targets '.NOREADONLY' and '.READONLY'. */ VAR_SET_READONLY = 1 << 1 } VarSetFlags; -/* The state of error handling returned by Var_Parse. */ -typedef enum VarParseResult { - - /* Both parsing and evaluation succeeded. */ - VPR_OK, - - /* Parsing or evaluating failed, with an error message. */ - VPR_ERR, - - /* - * Parsing succeeded, undefined expressions are allowed and the - * expression was still undefined after applying all modifiers. - * No error message is printed in this case. - * - * Some callers handle this case differently, so return this - * information to them, for now. - * - * TODO: Instead of having this special return value, rather ensure - * that VARE_EVAL_KEEP_UNDEF is processed properly. - */ - VPR_UNDEF - -} VarParseResult; - typedef enum VarExportMode { /* .export-env */ VEM_ENV, @@ -1033,8 +1012,8 @@ bool Var_Exists(GNode *, const char *) MAKE_ATTR_USE; bool Var_ExistsExpand(GNode *, const char *) MAKE_ATTR_USE; FStr Var_Value(GNode *, const char *) MAKE_ATTR_USE; const char *GNode_ValueDirect(GNode *, const char *) MAKE_ATTR_USE; -VarParseResult Var_Parse(const char **, GNode *, VarEvalMode, FStr *); -VarParseResult Var_Subst(const char *, GNode *, VarEvalMode, char **); +FStr Var_Parse(const char **, GNode *, VarEvalMode); +char *Var_Subst(const char *, GNode *, VarEvalMode); void Var_Expand(FStr *, GNode *, VarEvalMode); void Var_Stats(void); void Var_Dump(GNode *); @@ -1224,6 +1203,7 @@ pp_skip_hspace(char **pp) } #if defined(lint) +extern void do_not_define_rcsid(void); /* for lint */ # define MAKE_RCSID(id) extern void do_not_define_rcsid(void) #elif defined(MAKE_NATIVE) # include diff --git a/contrib/bmake/meta.c b/contrib/bmake/meta.c index f31a4666fce7..f1b08e61b49d 100644 --- a/contrib/bmake/meta.c +++ b/contrib/bmake/meta.c @@ -1,4 +1,4 @@ -/* $NetBSD: meta.c,v 1.201 2022/09/28 16:34:47 sjg Exp $ */ +/* $NetBSD: meta.c,v 1.205 2023/03/28 14:39:31 rillig Exp $ */ /* * Implement 'meta' mode. @@ -87,8 +87,6 @@ static bool metaCmpFilter = false; /* do we have CMP_FILTER ? */ static bool metaCurdirOk = false; /* write .meta in .CURDIR Ok? */ static bool metaSilent = false; /* if we have a .meta be SILENT */ -extern bool forceJobs; -extern char **environ; #define MAKE_META_PREFIX ".MAKE.META.PREFIX" @@ -328,7 +326,7 @@ is_submake(const char *cmd, GNode *gn) p_len = strlen(p_make); } if (strchr(cmd, '$') != NULL) { - (void)Var_Subst(cmd, gn, VARE_WANTRES, &mp); + mp = Var_Subst(cmd, gn, VARE_WANTRES); /* TODO: handle errors */ cmd = mp; } @@ -482,10 +480,8 @@ meta_create(BuildMon *pbm, GNode *gn) dname.str = objdir_realpath; if (metaVerbose) { - char *mp; - /* Describe the target we are building */ - (void)Var_Subst("${" MAKE_META_PREFIX "}", gn, VARE_WANTRES, &mp); + char *mp = Var_Subst("${" MAKE_META_PREFIX "}", gn, VARE_WANTRES); /* TODO: handle errors */ if (mp[0] != '\0') fprintf(stdout, "%s\n", mp); @@ -621,8 +617,8 @@ meta_mode_init(const char *make_mode) /* * We consider ourselves master of all within ${.MAKE.META.BAILIWICK} */ - (void)Var_Subst("${.MAKE.META.BAILIWICK:O:u:tA}", - SCOPE_GLOBAL, VARE_WANTRES, &metaBailiwickStr); + metaBailiwickStr = Var_Subst("${.MAKE.META.BAILIWICK:O:u:tA}", + SCOPE_GLOBAL, VARE_WANTRES); /* TODO: handle errors */ str2Lst_Append(&metaBailiwick, metaBailiwickStr); /* @@ -630,8 +626,8 @@ meta_mode_init(const char *make_mode) */ Global_Append(MAKE_META_IGNORE_PATHS, "/dev /etc /proc /tmp /var/run /var/tmp ${TMPDIR}"); - (void)Var_Subst("${" MAKE_META_IGNORE_PATHS ":O:u:tA}", - SCOPE_GLOBAL, VARE_WANTRES, &metaIgnorePathsStr); + metaIgnorePathsStr = Var_Subst("${" MAKE_META_IGNORE_PATHS ":O:u:tA}", + SCOPE_GLOBAL, VARE_WANTRES); /* TODO: handle errors */ str2Lst_Append(&metaIgnorePaths, metaIgnorePathsStr); @@ -643,6 +639,13 @@ meta_mode_init(const char *make_mode) metaCmpFilter = Var_Exists(SCOPE_GLOBAL, MAKE_META_CMP_FILTER); } +MAKE_INLINE BuildMon * +BM(Job *job) +{ + + return ((job != NULL) ? &job->bm : &Mybm); +} + /* * In each case below we allow for job==NULL */ @@ -651,11 +654,7 @@ meta_job_start(Job *job, GNode *gn) { BuildMon *pbm; - if (job != NULL) { - pbm = &job->bm; - } else { - pbm = &Mybm; - } + pbm = BM(job); pbm->mfp = meta_create(pbm, gn); #ifdef USE_FILEMON_ONCE /* compat mode we open the filemon dev once per command */ @@ -682,11 +681,7 @@ meta_job_child(Job *job MAKE_ATTR_UNUSED) #ifdef USE_FILEMON BuildMon *pbm; - if (job != NULL) { - pbm = &job->bm; - } else { - pbm = &Mybm; - } + pbm = BM(job); if (pbm->mfp != NULL) { close(fileno(pbm->mfp)); if (useFilemon && pbm->filemon != NULL) { @@ -707,11 +702,7 @@ meta_job_parent(Job *job MAKE_ATTR_UNUSED, pid_t pid MAKE_ATTR_UNUSED) #if defined(USE_FILEMON) && !defined(USE_FILEMON_DEV) BuildMon *pbm; - if (job != NULL) { - pbm = &job->bm; - } else { - pbm = &Mybm; - } + pbm = BM(job); if (useFilemon && pbm->filemon != NULL) { filemon_setpid_parent(pbm->filemon, pid); } @@ -724,11 +715,7 @@ meta_job_fd(Job *job MAKE_ATTR_UNUSED) #if defined(USE_FILEMON) && !defined(USE_FILEMON_DEV) BuildMon *pbm; - if (job != NULL) { - pbm = &job->bm; - } else { - pbm = &Mybm; - } + pbm = BM(job); if (useFilemon && pbm->filemon != NULL) { return filemon_readfd(pbm->filemon); } @@ -742,11 +729,7 @@ meta_job_event(Job *job MAKE_ATTR_UNUSED) #if defined(USE_FILEMON) && !defined(USE_FILEMON_DEV) BuildMon *pbm; - if (job != NULL) { - pbm = &job->bm; - } else { - pbm = &Mybm; - } + pbm = BM(job); if (useFilemon && pbm->filemon != NULL) { return filemon_process(pbm->filemon); } @@ -760,13 +743,9 @@ meta_job_error(Job *job, GNode *gn, bool ignerr, int status) char cwd[MAXPATHLEN]; BuildMon *pbm; - if (job != NULL) { - pbm = &job->bm; - if (gn == NULL) + pbm = BM(job); + if (job != NULL && gn == NULL) gn = job->node; - } else { - pbm = &Mybm; - } if (pbm->mfp != NULL) { fprintf(pbm->mfp, "\n*** Error code %d%s\n", status, ignerr ? "(ignored)" : ""); @@ -788,11 +767,7 @@ meta_job_output(Job *job, char *cp, const char *nl) { BuildMon *pbm; - if (job != NULL) { - pbm = &job->bm; - } else { - pbm = &Mybm; - } + pbm = BM(job); if (pbm->mfp != NULL) { if (metaVerbose) { static char *meta_prefix = NULL; @@ -801,8 +776,8 @@ meta_job_output(Job *job, char *cp, const char *nl) if (meta_prefix == NULL) { char *cp2; - (void)Var_Subst("${" MAKE_META_PREFIX "}", - SCOPE_GLOBAL, VARE_WANTRES, &meta_prefix); + meta_prefix = Var_Subst("${" MAKE_META_PREFIX "}", + SCOPE_GLOBAL, VARE_WANTRES); /* TODO: handle errors */ if ((cp2 = strchr(meta_prefix, '$')) != NULL) meta_prefix_len = (size_t)(cp2 - meta_prefix); @@ -860,11 +835,7 @@ meta_job_finish(Job *job) int error = 0; int x; - if (job != NULL) { - pbm = &job->bm; - } else { - pbm = &Mybm; - } + pbm = BM(job); if (pbm->mfp != NULL) { error = meta_cmd_finish(pbm); x = fclose(pbm->mfp); @@ -989,7 +960,7 @@ meta_ignore(GNode *gn, const char *p) */ Var_Set(gn, ".p.", p); expr = "${" MAKE_META_IGNORE_PATTERNS ":@m@${.p.:M$m}@}"; - (void)Var_Subst(expr, gn, VARE_WANTRES, &pm); + pm = Var_Subst(expr, gn, VARE_WANTRES); /* TODO: handle errors */ if (pm[0] != '\0') { #ifdef DEBUG_META_MODE @@ -1008,7 +979,7 @@ meta_ignore(GNode *gn, const char *p) snprintf(fname, sizeof fname, "${%s:L:${%s:ts:}}", p, MAKE_META_IGNORE_FILTER); - (void)Var_Subst(fname, gn, VARE_WANTRES, &fm); + fm = Var_Subst(fname, gn, VARE_WANTRES); /* TODO: handle errors */ if (*fm == '\0') { #ifdef DEBUG_META_MODE @@ -1066,7 +1037,9 @@ static char * meta_filter_cmd(GNode *gn, char *s) { Var_Set(gn, META_CMD_FILTER_VAR, s); - Var_Subst("${" META_CMD_FILTER_VAR ":${" MAKE_META_CMP_FILTER ":ts:}}", gn, VARE_WANTRES, &s); + s = Var_Subst( + "${" META_CMD_FILTER_VAR ":${" MAKE_META_CMP_FILTER ":ts:}}", + gn, VARE_WANTRES); return s; } @@ -1534,7 +1507,7 @@ meta_oodate(GNode *gn, bool oodate) DEBUG2(META, "%s: %u: cannot compare command using .OODATE\n", fname, lineno); } - (void)Var_Subst(cmd, gn, VARE_UNDEFERR, &cmd); + cmd = Var_Subst(cmd, gn, VARE_UNDEFERR); /* TODO: handle errors */ if ((cp = strchr(cmd, '\n')) != NULL) { diff --git a/contrib/bmake/mk/ChangeLog b/contrib/bmake/mk/ChangeLog index 7e3bd1da6976..2e4b6516c5cc 100644 --- a/contrib/bmake/mk/ChangeLog +++ b/contrib/bmake/mk/ChangeLog @@ -1,3 +1,62 @@ +2023-04-20 Simon J Gerraty + + * install-mk (MK_VERSION): 20230420 + + * lib.mk: include LDFLAGS and LDADD when linking shared libs + + * gendirdeps.mk: document setting GENDIRDEPS_FILTER_VARS etc + via local.meta.sys.mk rather than local.gendirdeps.mk + so DEP_* variables can be set at level 1+ to avoid syntax errors + when used in conditionals in manually maintained Makefile.depend + files. + + * dirdeps.mk: ensure M_dep_qual_fixes is applied to all _machines + +2023-04-18 Simon J Gerraty + + * dirdeps.mk: check we were not included by + Makefile.depend.options as the result is bad. + +2023-04-14 Simon J Gerraty + + * install-mk (MK_VERSION): 20230414 + + * meta.sys.mk: since we have :range we can put the logic for + processing TARGET_SPEC from env here. + + * dirdeps.mk: reset DIRDEPS and DEP_RELDIR before including + local.dirdeps-missing.mk, also improve debug output. + + * dirdeps.mk: to allow make -f dirdeps.mk include.$TARGET_SPEC + we need to use :M*[/.]* same as for when actually setting DIRDEPS + from the targets on command line. + +2023-04-12 Simon J Gerraty + + * Add jobs.mk + +2023-03-21 Simon J Gerraty + + * install-mk (MK_VERSION): 20230321 + + * meta.stage.mk: allow STAGE_SHLIB_LINKS_FILTER to filter + STAGE_LIBS for SHLIB_LINKS. + + * autoconf.mk: add .WAIT after config.status + +2023-02-17 Simon J Gerraty + + * sys.vars.mk: add M_Index to report the index of a word in a list. + +2023-02-15 Simon J Gerraty + + * install-mk (MK_VERSION): 20230215 + + * warnings.mk: allow better control of -Werror + allow -Wno-error or similar to be added if + WARNINGS_SET < WERROR_SET + account for COMPILER_TYPE + 2023-01-29 Simon J Gerraty * autoconf.mk: hook config.status to beforebuild. diff --git a/contrib/bmake/mk/FILES b/contrib/bmake/mk/FILES index 8c9c2d12b2b4..45450595f390 100644 --- a/contrib/bmake/mk/FILES +++ b/contrib/bmake/mk/FILES @@ -20,6 +20,7 @@ inc.mk init.mk install-mk java.mk +jobs.mk ldorder.mk lib.mk libnames.mk diff --git a/contrib/bmake/mk/autoconf.mk b/contrib/bmake/mk/autoconf.mk index fb97e9d3f2f8..b50c7187ed1c 100644 --- a/contrib/bmake/mk/autoconf.mk +++ b/contrib/bmake/mk/autoconf.mk @@ -1,4 +1,4 @@ -# $Id: autoconf.mk,v 1.17 2023/01/29 17:31:16 sjg Exp $ +# $Id: autoconf.mk,v 1.18 2023/03/22 15:37:19 sjg Exp $ # # @(#) Copyright (c) 1996-2009, Simon J. Gerraty # @@ -34,7 +34,7 @@ config.status: config.recheck config.status: config.gen .endif -beforebuild: .NOTMAIN config.status +beforebuild: .NOTMAIN config.status .WAIT config.recheck: .NOTMAIN ${CONFIGURE_DEPS} config.gen ./config.status --recheck diff --git a/contrib/bmake/mk/dirdeps.mk b/contrib/bmake/mk/dirdeps.mk index 94b493a77fa6..6fedd00310e9 100644 --- a/contrib/bmake/mk/dirdeps.mk +++ b/contrib/bmake/mk/dirdeps.mk @@ -1,6 +1,8 @@ -# $Id: dirdeps.mk,v 1.152 2022/08/01 23:09:19 sjg Exp $ +# $Id: dirdeps.mk,v 1.157 2023/04/22 21:07:51 sjg Exp $ -# Copyright (c) 2010-2022, Simon J. Gerraty +# SPDX-License-Identifier: BSD-2-Clause +# +# Copyright (c) 2010-2023, Simon J. Gerraty # Copyright (c) 2010-2018, Juniper Networks, Inc. # All rights reserved. # @@ -179,7 +181,7 @@ _DIRDEP_USE_LEVEL?= 0 _CURDIR ?= ${.CURDIR} _OBJDIR ?= ${.OBJDIR} -.if ${MAKEFILE:T} == ${.PARSEFILE} && empty(DIRDEPS) && ${.TARGETS:Uall:M*/*} != "" +.if ${MAKEFILE:T} == ${.PARSEFILE} && empty(DIRDEPS) && ${.TARGETS:Uall:M*[/.]*} != "" # This little trick let's us do # # mk -f dirdeps.mk some/dir.${TARGET_SPEC} @@ -347,6 +349,10 @@ BUILD_DIRDEPS ?= yes DIRDEPS_CACHE ?= ${_OBJDIR:tA}/dirdeps.cache${_TARGETS:U${.TARGETS}:Nall:O:u:ts-:S,/,_,g:S,^,.,:N.} .endif +# sanity check: Makefile.depend.options should *not* include us +.if ${.INCLUDEDFROMFILE:U:M${.MAKE.DEPENDFILE_PREFIX}.options} != "" +.error ${DEP_RELDIR}/${.MAKE.DEPENDFILE_PREFIX}.options: should include dirdeps-options.mk +.endif # pickup customizations # as below you can use !target(_DIRDEP_USE) to protect things @@ -577,7 +583,7 @@ ${DIRDEPS_CACHE}: .META .NOMETA_CMP ${"${DEBUG_DIRDEPS:Nno}":?DEBUG_DIRDEPS='${DEBUG_DIRDEPS}':} \ ${.MAKEFLAGS:tW:S,-D ,-D,g:tw:M*WITH*} \ ${.MAKEFLAGS:tW:S,-d ,-d,g:tw:M-d*} \ - 3>&1 1>&2 | sed 's,${SRCTOP},_{SRCTOP},g;s,_{,$${,g' >> ${.TARGET}.new && \ + 3>&1 1>&2 | sed 's,${SRCTOP},_{SRCTOP},g;s,_{SRCTOP}/_{SRCTOP},_{SRCTOP},g;s,_{,$${,g' >> ${.TARGET}.new && \ mv ${.TARGET}.new ${.TARGET} .endif @@ -639,9 +645,9 @@ _dm := ${DEP_MACHINE} # apply the same filtering that we do when qualifying DIRDEPS. # M_dep_qual_fixes expects .${MACHINE}* so add (and remove) '.' # Again we expect that any already qualified machines are fully qualified. -_machines := ${_machines:M*,*} ${_machines:N*,*:@DEP_MACHINE@${DEP_TARGET_SPEC}@:S,^,.,:${M_dep_qual_fixes:ts:}:O:u:S,^.,,} +_machines := ${_machines:M*,*} ${_machines:N*,*:@DEP_MACHINE@${DEP_TARGET_SPEC}@:S,^,.,:S,^.,,} DEP_MACHINE := ${_dm} -_machines := ${_machines:O:u} +_machines := ${_machines:${M_dep_qual_fixes:ts:}:O:u} .endif # reset each time through @@ -788,8 +794,9 @@ ${_this_dir}.$m: ${_build_dirs:M*.$m:N${_this_dir}.$m} .if !target(_dirdeps_checked.$d) # once only _dirdeps_checked.$d: +_dr := ${d:S,^${SRCTOP}/,,} .if ${_debug_search} -.info checking ${d:S,^${SRCTOP}/,,} +.info checking ${_dr} .endif # Note: _build_all_dirs is fully qualifed so d:R is always the directory .if exists(${d:R}) @@ -822,10 +829,16 @@ DEP_RELDIR := ${_m:H:S,^${SRCTOP}/,,} # and reset this DIRDEPS = .if ${_debug_reldir} && ${_qm} != ${_m} -.info loading ${_m} for ${d:E} +.info loading ${_m:S,${SRCTOP}/,,} for ${_dr} .endif .include <${_m}> .else +# set these as if we found Makefile.depend* +DEP_RELDIR := ${_dr:R} +DIRDEPS = +.if ${_debug_reldir} +.info loading local.dirdeps-missing.mk for ${_dr} +.endif .-include .endif .endif diff --git a/contrib/bmake/mk/gendirdeps.mk b/contrib/bmake/mk/gendirdeps.mk index 1ff2036237ed..ec4e188cdf78 100644 --- a/contrib/bmake/mk/gendirdeps.mk +++ b/contrib/bmake/mk/gendirdeps.mk @@ -1,5 +1,7 @@ -# $Id: gendirdeps.mk,v 1.48 2022/09/09 17:44:29 sjg Exp $ +# $Id: gendirdeps.mk,v 1.49 2023/04/20 17:45:03 sjg Exp $ +# SPDX-License-Identifier: BSD-2-Clause +# # Copyright (c) 2011-2020, Simon J. Gerraty # Copyright (c) 2010-2018, Juniper Networks, Inc. # All rights reserved. @@ -41,6 +43,37 @@ # symlink to another filesystem. # _objroot must be a prefix match for _objtop +# If any of GENDIRDEPS_FILTER, GENDIRDEPS_FILTER_DIR_VARS +# or GENDIRDEPS_FILTER_VARS are set, we use them to filter the +# output from filemon(4). +# Any references to variables that dirdeps.mk will set +# such as DEP_MACHINE, DEP_RELDIR etc, should use that form. +# Thus we want ${DEP_MACHINE} not ${MACHINE} used in DIRDEPS. +# +# If any manually maintained Makefile.depend files will use any +# DEP_* variables in conditionals, precautions are needed to avoid +# errors when Makefile.depend is read at level 1+ (ie not via +# dirdeps.mk) +# Using MACHINE as an example; such makefiles can do: +# +# DEP_MACHINE ?= ${MACHINE} +# .if ${DEP_MACHINE} == "xyz" +# +# or: +# +# .if ${DEP_MACHINE:U${MACHINE}} == "xyz" +# +# but it might be safer to set GENDIRDEPS_FILTER_DIR_VARS and +# GENDIRDEPS_FILTER_VARS via local.meta.sys.mk rather than +# local.gendirdeps.mk and then: +# +# .if ${.MAKE.LEVEL} > 0 +# .for V in ${GENDIRDEPS_FILTER_DIR_VARS:MDEP_*} \ +# ${GENDIRDEPS_FILTER_VARS:MDEP_*} +# $V ?= ${${V:S,DEP_,,}} +# .endfor +# .endif +# .MAIN: all # keep this simple diff --git a/contrib/bmake/mk/install-mk b/contrib/bmake/mk/install-mk index c3c868b75186..89c222cd0ee3 100644 --- a/contrib/bmake/mk/install-mk +++ b/contrib/bmake/mk/install-mk @@ -59,7 +59,7 @@ # Simon J. Gerraty # RCSid: -# $Id: install-mk,v 1.226 2023/01/28 16:52:12 sjg Exp $ +# $Id: install-mk,v 1.231 2023/04/20 17:45:03 sjg Exp $ # # @(#) Copyright (c) 1994-2023 Simon J. Gerraty # @@ -74,7 +74,7 @@ # sjg@crufty.net # -MK_VERSION=20230127 +MK_VERSION=20230420 OWNER= GROUP= MODE=444 diff --git a/contrib/bmake/mk/jobs.mk b/contrib/bmake/mk/jobs.mk new file mode 100644 index 000000000000..f465ea06310b --- /dev/null +++ b/contrib/bmake/mk/jobs.mk @@ -0,0 +1,88 @@ +# $Id: jobs.mk,v 1.7 2023/04/18 23:32:28 sjg Exp $ +# +# @(#) Copyright (c) 2012-2023, Simon J. Gerraty +# +# This file is provided in the hope that it will +# be of use. There is absolutely NO WARRANTY. +# Permission to copy, redistribute or otherwise +# use this file is hereby granted provided that +# the above copyright notice and this notice are +# left intact. +# +# Please send copies of changes and bug-fixes to: +# sjg@crufty.net +# + +# This makefile is used by top-level makefile. +# With the following: +# +# .if make(*-jobs) +# .include +# .endif +# +# +# Then if you do: +# +# mk target-jobs +# +# We will run: +# +# ${MAKE} -j${JOB_MAX} target > ${JOB_LOGDIR}/target.log 2>&1 +# +# JOB_MAX defaults to 8 but should normally be derrived based on the +# number of cpus available. The wrapper script 'mk' makes that easy. +# + +now_utc ?= ${%s:L:gmtime} +.if !defined(start_utc) +start_utc := ${now_utc} +.endif + +.info ${.newline}${TIME_STAMP} Start ${.TARGETS} + +.if make(*-jobs) + +JOB_LOGDIR ?= ${SRCTOP:H} +JOB_LOG = ${JOB_LOGDIR}/${.TARGET:S,-jobs,,:S,/,_,g}.log +JOB_LOG_GENS ?= 4 +# we like to rotate logs +.if empty(NEWLOG_SH) +.ifdef M_whence +NEWLOG_SH := ${newlog.sh:L:${M_whence}} +.else +NEWLOG_SH := ${(type newlog.sh) 2> /dev/null:L:sh:M/*} +.endif +.endif +.if !empty(NEWLOG_SH) && exists(${NEWLOG_SH}) +NEWLOG := sh ${NEWLOG_SH} +JOB_NEWLOG_ARGS ?= -S -n ${JOB_LOG_GENS} +.else +NEWLOG = : +.endif + +.if ${.MAKE.JOBS:U0} > 0 +JOB_MAX= ${.MAKE.JOBS} +.else +# This should be derrived from number of cpu's +JOB_MAX?= 8 +JOB_ARGS+= -j${JOB_MAX} +.endif + +# we need to reset .MAKE.LEVEL to 0 do that +# build orchestration works as expected (DIRDEPS_BUILD) +${.TARGETS:M*-jobs}: + @${NEWLOG} ${JOB_NEWLOG_ARGS} ${JOB_LOG} + @echo Logging to ${JOB_LOG} + @cd ${.CURDIR} && env MAKELEVEL=0 \ + ${.MAKE} ${JOB_ARGS} _TARGETS=${.TARGET:S,-jobs,,} ${.TARGET:S,-jobs,,} >> ${JOB_LOG} 2>&1 + +.endif + +.END: _build_finish +.ERROR: _build_failed + +_build_finish: .NOMETA + @echo "${TIME_STAMP} Finished ${.TARGETS} seconds=`expr ${now_utc} - ${start_utc}`" + +_build_failed: .NOMETA + @echo "${TIME_STAMP} Failed ${.TARGETS} seconds=`expr ${now_utc} - ${start_utc}`" diff --git a/contrib/bmake/mk/lib.mk b/contrib/bmake/mk/lib.mk index 259107458ae9..cc507ac6e75d 100644 --- a/contrib/bmake/mk/lib.mk +++ b/contrib/bmake/mk/lib.mk @@ -1,4 +1,4 @@ -# $Id: lib.mk,v 1.73 2021/12/08 05:56:50 sjg Exp $ +# $Id: lib.mk,v 1.74 2023/04/20 23:45:56 sjg Exp $ .if !target(__${.PARSEFILE}__) __${.PARSEFILE}__: .NOTMAIN @@ -448,18 +448,19 @@ lib${LIB}_pic.a: ${SOBJS} lib${LIB}.${LD_so}: ${SOLIB} ${DPADD} @${META_NOECHO} building shared ${LIB} library \(version ${SHLIB_FULLVERSION}\) @rm -f ${.TARGET} -.if ${TARGET_OSNAME} == "NetBSD" || ${TARGET_OSNAME} == "FreeBSD" +.if ${TARGET_OSNAME:NFreeBSD:NNetBSD} == "" .if ${OBJECT_FMT} == "ELF" - ${SHLIB_LD} -x -shared ${SHLIB_SHFLAGS} -o ${.TARGET} \ + ${SHLIB_LD} -x -shared ${SHLIB_SHFLAGS} ${LDFLAGS} -o ${.TARGET} \ ${SHLIB_LDSTARTFILE} \ - --whole-archive ${SOLIB} --no-whole-archive ${SHLIB_LDADD} \ - ${SHLIB_LDENDFILE} + --whole-archive ${SOLIB} --no-whole-archive \ + ${LDADD} ${SHLIB_LDADD} ${SHLIB_LDENDFILE} .else - ${SHLIB_LD} ${LD_x} ${LD_shared} \ - -o ${.TARGET} ${SOLIB} ${SHLIB_LDADD} + ${SHLIB_LD} ${LD_x} ${LD_shared} ${LDFLAGS} \ + -o ${.TARGET} ${SOLIB} ${LDADD} ${SHLIB_LDADD} .endif .else - ${SHLIB_LD} -o ${.TARGET} ${LD_shared} ${LD_solib} ${DLLIB} ${SHLIB_LDADD} + ${SHLIB_LD} ${LDFLAGS} -o ${.TARGET} \ + ${LD_shared} ${LD_solib} ${DLLIB} ${LDADD} ${SHLIB_LDADD} .endif .endif .if !empty(SHLIB_LINKS) diff --git a/contrib/bmake/mk/meta.stage.mk b/contrib/bmake/mk/meta.stage.mk index e4ca45820110..168e46d22a82 100644 --- a/contrib/bmake/mk/meta.stage.mk +++ b/contrib/bmake/mk/meta.stage.mk @@ -1,4 +1,4 @@ -# $Id: meta.stage.mk,v 1.65 2022/09/09 17:44:29 sjg Exp $ +# $Id: meta.stage.mk,v 1.67 2023/04/17 01:22:10 sjg Exp $ # # @(#) Copyright (c) 2011-2017, Simon J. Gerraty # @@ -54,7 +54,7 @@ _objroot ?= ${_OBJROOT:tA} # make sure this is global _STAGED_DIRS ?= .export _STAGED_DIRS -# add each dir we stage to to _STAGED_DIRS +# add each dir we stage to _STAGED_DIRS # and make sure we have absolute paths so that bmake # will match against .MAKE.META.BAILIWICK STAGE_DIR_FILTER = tA:@d@$${_STAGED_DIRS::+=$$d}$$d@ @@ -173,7 +173,7 @@ stage_libs: .dirdep .if !defined(NO_SHLIB_LINKS) .if !empty(SHLIB_LINKS) @${STAGE_LINKS_SCRIPT}; StageLinks -s ${STAGE_LIBDIR:${STAGE_DIR_FILTER}} \ - ${SHLIB_LINKS:@t@${STAGE_LIBS:T:M$t.*} $t@} + ${SHLIB_LINKS:@t@${STAGE_LIBS:T:M$t.*:${STAGE_SHLIB_LINKS_FILTER:U}} $t@} .elif !empty(SHLIB_LINK) && !empty(SHLIB_NAME) @${STAGE_LINKS_SCRIPT}; StageLinks -s ${STAGE_LIBDIR:${STAGE_DIR_FILTER}} ${SHLIB_NAME} ${SHLIB_LINK} .endif diff --git a/contrib/bmake/mk/meta.sys.mk b/contrib/bmake/mk/meta.sys.mk index 7cc802e2f2fe..1fc58a226cb1 100644 --- a/contrib/bmake/mk/meta.sys.mk +++ b/contrib/bmake/mk/meta.sys.mk @@ -1,4 +1,4 @@ -# $Id: meta.sys.mk,v 1.42 2021/12/13 05:50:55 sjg Exp $ +# $Id: meta.sys.mk,v 1.46 2023/04/18 18:43:00 sjg Exp $ # # @(#) Copyright (c) 2010-2021, Simon J. Gerraty @@ -20,7 +20,44 @@ .if ${MAKE_VERSION:U0} > 20100901 .if !target(.ERROR) -.-include +.-include + +# If TARGET_SPEC_VARS is other than just MACHINE +# it should be set by now. +# TARGET_SPEC must not contain any '.'s. +TARGET_SPEC_VARS ?= MACHINE + +.if !target(_meta_tspec_env_done_) +_meta_tspec_env_done_: .NOTMAIN +# Allow for local.meta.sys.env.mk to have done this + +.if ${TARGET_SPEC:Uno:M*,*} != "" +# deal with TARGET_SPEC from env +_tspec := ${TARGET_SPEC:S/,/ /g} +.for i in ${TARGET_SPEC_VARS:${M_RANGE:Urange}} +${TARGET_SPEC_VARS:[$i]} := ${_tspec:[$i]} +.endfor +# We need to stop that TARGET_SPEC affecting any submakes +TARGET_SPEC= +# so export but do not track +.export-env TARGET_SPEC +.export ${TARGET_SPEC_VARS} +.for v in ${TARGET_SPEC_VARS:O:u} +.if empty($v) +.undef $v +.endif +.endfor +.endif +.endif + +# Now make sure we know what TARGET_SPEC is +# as we may need it to find Makefile.depend* +.if ${MACHINE:Mhost*} != "" +# host is special +TARGET_SPEC = ${MACHINE} +.else +TARGET_SPEC = ${TARGET_SPEC_VARS:@v@${$v:U}@:ts,} +.endif # absolute path to what we are reading. _PARSEDIR = ${.PARSEDIR:tA} @@ -177,3 +214,5 @@ META_NOPHONY= .PHONY META_NOECHO= echo .endif .endif + +.-include diff --git a/contrib/bmake/mk/mk-files.txt b/contrib/bmake/mk/mk-files.txt index ca0a2868fd8f..337df19613e0 100644 --- a/contrib/bmake/mk/mk-files.txt +++ b/contrib/bmake/mk/mk-files.txt @@ -76,7 +76,8 @@ When bmake starts, it looks for ``sys.mk`` and reads it before doing anything else. Thus, this is the place to setup the environment for everyone else. -In this distribution, ``sys.mk`` avoids doing anything platform dependent. +In this distribution, ``sys.mk`` avoids doing anything platform or +site dependent. It is quite short, and includes a number of other files (which may or may not exists) @@ -315,7 +316,7 @@ obj.mk One of the cool aspects of BSD make, is its support for separating object files from the src tree. This is also the source of much -confusion to some. +confusion for people unfamiliar with it. Traditionally one had to do a separate ``make obj`` pass through the tree. If ``MK_AUTO_OBJ`` is set we include auto.obj.mk_. @@ -326,8 +327,9 @@ In fact if ``MKOBJDIRS`` is set to "auto", `sys.mk`_ will set auto.obj.mk ----------- -This leverages the ``.OBJDIR`` target introduced some years ago to -NetBSD make, to automatically create and use the desired object dir. +Creates object dirs and leverages the ``.OBJDIR`` target introduced +some years ago to NetBSD make, to use them. + subdir.mk --------- @@ -461,7 +463,7 @@ would add all the warnings in ``${HIGH_WARNINGS}`` to CFLAGS, but on sparc, ``-Wno-unused`` would replace ``-Wunused``. You should never need to edit ``warnings.mk``, it will include -``warnings-sets.mk`` if it exists and you use that to make any local +``warnings-sets.mk`` and/or ``local.warnings.mk`` to pick up customizations. rst2htm.mk @@ -492,6 +494,21 @@ In the past, making use of compiler wrappers like ``ccache``, ``distcc`` or the newer ``icecc`` could get quite ugly. Using ``cc-wrap.mk`` it could not be simpler. +jobs.mk +------- + +This should be included by the top-level makefile. +If you do:: + + make something-jobs + +then ``jobs.mk`` will run:: + + make -j${JOB_MAX} someting > ${JOB_LOGDIR}/something.log 2>&1 + +this ensures you get a build log and JOB_MAX is assumed to be set +optimally for the host. + Meta mode ========= @@ -525,5 +542,5 @@ where you unpacked the tar file, you can:: .. _mk.tar.gz: http://www.crufty.net/ftp/pub/sjg/mk.tar.gz :Author: sjg@crufty.net -:Revision: $Id: mk-files.txt,v 1.21 2022/02/04 19:01:05 sjg Exp $ +:Revision: $Id: mk-files.txt,v 1.22 2023/04/16 23:43:33 sjg Exp $ :Copyright: Crufty.NET diff --git a/contrib/bmake/mk/prog.mk b/contrib/bmake/mk/prog.mk index b281cf08b320..e01a92ba9a0e 100644 --- a/contrib/bmake/mk/prog.mk +++ b/contrib/bmake/mk/prog.mk @@ -1,4 +1,4 @@ -# $Id: prog.mk,v 1.38 2022/07/22 20:08:56 sjg Exp $ +# $Id: prog.mk,v 1.39 2023/04/20 23:45:56 sjg Exp $ .if !target(__${.PARSEFILE}__) __${.PARSEFILE}__: .NOTMAIN @@ -97,7 +97,7 @@ LOBJS+= ${LSRCS:.c=.ln} ${SRCS:M*.c:.c=.ln} .NOPATH: ${OBJS} ${PROG} ${SRCS:M*.[ly]:C/\..$/.c/} ${YHEADER:D${SRCS:M*.y:.y=.h}} # this is known to work for NetBSD 1.6 and FreeBSD 4.2 -.if ${TARGET_OSNAME} == "NetBSD" || ${TARGET_OSNAME} == "FreeBSD" +.if ${TARGET_OSNAME:NFreeBSD:NNetBSD} == "" _PROGLDOPTS= .if ${SHLINKDIR} != "/usr/libexec" # XXX: change or remove if ld.so moves _PROGLDOPTS+= -Wl,-dynamic-linker=${_SHLINKER} diff --git a/contrib/bmake/mk/sys.vars.mk b/contrib/bmake/mk/sys.vars.mk index f62adbcf08ba..c3dcf6a7e7ef 100644 --- a/contrib/bmake/mk/sys.vars.mk +++ b/contrib/bmake/mk/sys.vars.mk @@ -1,4 +1,4 @@ -# $Id: sys.vars.mk,v 1.12 2023/01/20 17:34:06 sjg Exp $ +# $Id: sys.vars.mk,v 1.14 2023/02/17 22:32:47 sjg Exp $ # # @(#) Copyright (c) 2003-2023, Simon J. Gerraty # @@ -121,3 +121,11 @@ M_Onr = O M_On = On M_Onr = Onr .endif + +# Index of a word in a list. +# eg. ${LIST:${M_Index:S,K,key,}} is the index of +# the word "key" in ${LIST}, of course any pattern can be used. +# If "key" appears more than once, there will be multiple +# index values use ${M_Index:S,K,key,}:[1] to select only the first. +M_Index = _:${M_RANGE}:@i@$${"$${_:[$$i]:MK}":?$$i:}@ + diff --git a/contrib/bmake/mk/warnings.mk b/contrib/bmake/mk/warnings.mk index 77635fbc8a29..18d3273c9465 100644 --- a/contrib/bmake/mk/warnings.mk +++ b/contrib/bmake/mk/warnings.mk @@ -1,7 +1,7 @@ # RCSid: -# $Id: warnings.mk,v 1.15 2020/08/19 17:51:53 sjg Exp $ +# $Id: warnings.mk,v 1.17 2023/02/16 17:55:52 sjg Exp $ # -# @(#) Copyright (c) 2002, Simon J. Gerraty +# @(#) Copyright (c) 2002-2023, Simon J. Gerraty # # This file is provided in the hope that it will # be of use. There is absolutely NO WARRANTY. @@ -20,21 +20,23 @@ # Any number of warnings sets can be added. .-include +# This is more in keeping with our current practice +.-include # Modest defaults - put more elaborate sets in warnings-sets.mk # -Wunused etc are here so you can set # W_unused=-Wno-unused etc. -MIN_WARNINGS?= -Wall \ +MIN_WARNINGS ?= -Wall \ -Wformat \ -Wimplicit \ -Wunused \ -Wuninitialized -LOW_WARNINGS?= ${MIN_WARNINGS} -W -Wstrict-prototypes -Wmissing-prototypes +LOW_WARNINGS ?= ${MIN_WARNINGS} -W -Wstrict-prototypes -Wmissing-prototypes -MEDIUM_WARNINGS?= ${LOW_WARNINGS} -Werror +MEDIUM_WARNINGS ?= ${LOW_WARNINGS} -HIGH_WARNINGS?= ${MEDIUM_WARNINGS} \ +HIGH_WARNINGS ?= ${MEDIUM_WARNINGS} \ -Wcast-align \ -Wcast-qual \ -Wparentheses \ @@ -44,19 +46,46 @@ HIGH_WARNINGS?= ${MEDIUM_WARNINGS} \ -Wswitch \ -Wwrite-strings -EXTRA_WARNINGS?= ${HIGH_WARNINGS} -Wextra +EXTRA_WARNINGS ?= ${HIGH_WARNINGS} -Wextra # The two step default makes it easier to test build with different defaults. -DEFAULT_WARNINGS_SET?= MIN -WARNINGS_SET?= ${DEFAULT_WARNINGS_SET} +DEFAULT_WARNINGS_SET ?= MIN +WARNINGS_SET ?= ${DEFAULT_WARNINGS_SET} # There is always someone who wants more... .if !empty(WARNINGS_XTRAS) ${WARNINGS_SET}_WARNINGS += ${WARNINGS_XTRAS} .endif -# If you add sets, besure to list them (you don't have to touch this list). -ALL_WARNINGS_SETS+= MIN LOW MEDIUM HIGH EXTRA +# Keep this list ordered! +WARNINGS_SET_LIST ?= MIN LOW MEDIUM HIGH EXTRA + +# We assume WARNINGS_SET_LIST is an ordered list. +# if WARNINGS_SET is < WERROR_SET we add WARNINGS_NO_ERROR +# otherwise we add WARNINGS_ERROR +DEFAULT_WERROR_SET ?= MEDIUM +WERROR_SET ?= ${DEFAULT_WERROR_SET} +WARNINGS_ERROR ?= -Werror +WARNINGS_NO_ERROR ?= + +.if ${MAKE_VERSION} >= 20170130 +.for i in ${WARNINGS_SET_LIST:range} +.if ${WARNINGS_SET_LIST:[$i]} == ${WARNINGS_SET} +WARNINGS_SETx = $i +.endif +.if ${WARNINGS_SET_LIST:[$i]} == ${WERROR_SET} +WERROR_SETx = $i +.if ${MAKE_VERSION} >= 20220924 +.break +.endif +.endif +.endfor +.if ${WARNINGS_SETx:U${WERROR_SETx:U0}} < ${WERROR_SETx:U0} +${WARNINGS_SET}_WARNINGS += ${WARNINGS_NO_ERROR:U} +.else +${WARNINGS_SET}_WARNINGS += ${WARNINGS_ERROR} +.endif +.endif .if !empty(WARNINGS_SET) .for ws in ${WARNINGS_SET} @@ -68,7 +97,7 @@ _empty_warnings: .PHONY .BEGIN: .endif @echo "ERROR: Invalid: WARNINGS_SET=${ws}" - @echo "ERROR: Try one of: ${ALL_WARNINGS_SETS:O:u}"; exit 1 + @echo "ERROR: Try one of: ${WARNINGS_SET_LIST}"; exit 1 .endif .endfor @@ -96,15 +125,19 @@ W_uninitialized= # which makes it easy to turn off override individual flags # (see W_uninitialized above). # -# The last bit expands to ${W_foo_${.TARGET:T}:U${W_foo}} +# The last bit expands to +# ${W_foo_${.TARGET:T:${TARGET_PREFIX_FILTER:ts:}}:U${W_foo}} # which is the bit we ultimately want. It allows W_* to be set on a # per target basis. # # NOTE: that we force the target extension to be .o +# TARGET_PREFIX_FILTER defaults to R # +TARGET_PREFIX_FILTER ?= R + # define this once, we use it a couple of times below (hence the doubled $$). -M_warnings_list = @s@$${$$s_WARNINGS}@:O:u:@w@$${$${w:C/-(.)/\1_/}::?=$$w} $${$${w:C/-(.)/\1_/}_${MACHINE_ARCH}_${.TARGET:T:R}.o:U$${$${w:C/-(.)/\1_/}_${.TARGET:T:R}.o:U$${$${w:C/-(.)/\1_/}_${MACHINE_ARCH}:U$${$${w:C/-(.)/\1_/}}}}}@ +M_warnings_list = @s@$${$$s_WARNINGS} $${$$s_WARNINGS.${COMPILER_TYPE}:U}@:O:u:@w@$${$${w:C/-(.)/\1_/}::?=$$w} $${$${w:C/-(.)/\1_/}_${MACHINE_ARCH}_${.TARGET:T:${TARGET_PREFIX_FILTER:ts:}}.o:U$${$${w:C/-(.)/\1_/}_${.TARGET:T:${TARGET_PREFIX_FILTER:ts:}}.o:U$${$${w:C/-(.)/\1_/}_${MACHINE_ARCH}:U$${$${w:C/-(.)/\1_/}}}}}@ # first a list of warnings from the chosen set _warnings = ${WARNINGS_SET_${MACHINE_ARCH}:U${WARNINGS_SET}:${M_warnings_list}} @@ -112,13 +145,13 @@ _warnings = ${WARNINGS_SET_${MACHINE_ARCH}:U${WARNINGS_SET}:${M_warnings_list}} # since things like -Wall imply lots of others. # this should be a super-set of the -Wno-* in _warnings, but # just in case... -_no_warnings = ${_warnings:M-Wno-*} ${ALL_WARNINGS_SETS:${M_warnings_list}:M-Wno-*} +_no_warnings = ${_warnings:M-Wno-*} ${WARNINGS_SET_LIST:${M_warnings_list}:M-Wno-*} # -Wno-* must follow any others WARNINGS += ${_warnings:N-Wno-*} ${_no_warnings:O:u} .ifndef NO_CFLAGS_WARNINGS # Just ${WARNINGS} should do, but this is more flexible? -CFLAGS+= ${WARNINGS_${.TARGET:T:R}.o:U${WARNINGS}} +CFLAGS+= ${WARNINGS_${.TARGET:T:${TARGET_PREFIX_FILTER:ts:}}.o:U${WARNINGS}} .endif # it is rather silly that g++ blows up on some warning flags @@ -130,9 +163,10 @@ NO_CXX_WARNINGS+= \ shadow \ strict-prototypes -.for s in ${SRCS:M*.c*:N*.c:N*h} +WARNINGS_CXX_SRCS += ${SRCS:M*.c*:N*.c:N*h} +.for s in ${WARNINGS_CXX_SRCS:O:u} .for w in ${NO_CXX_WARNINGS} -W_$w_${s:T:R}.o= +W_$w_${s:T:${TARGET_PREFIX_FILTER:ts:}}.o= .endfor .endfor diff --git a/contrib/bmake/os.sh b/contrib/bmake/os.sh old mode 100644 new mode 100755 diff --git a/contrib/bmake/parse.c b/contrib/bmake/parse.c index 3193543f56bf..9d8b840c4418 100644 --- a/contrib/bmake/parse.c +++ b/contrib/bmake/parse.c @@ -1,4 +1,4 @@ -/* $NetBSD: parse.c,v 1.692 2023/01/24 00:24:02 sjg Exp $ */ +/* $NetBSD: parse.c,v 1.696 2023/02/15 06:52:58 rillig Exp $ */ /* * Copyright (c) 1988, 1989, 1990, 1993 @@ -121,7 +121,7 @@ #include "pathnames.h" /* "@(#)parse.c 8.3 (Berkeley) 3/19/94" */ -MAKE_RCSID("$NetBSD: parse.c,v 1.692 2023/01/24 00:24:02 sjg Exp $"); +MAKE_RCSID("$NetBSD: parse.c,v 1.696 2023/02/15 06:52:58 rillig Exp $"); /* * A file being read. @@ -594,7 +594,7 @@ HandleMessage(ParseErrorLevel level, const char *levelName, const char *umsg) return; } - (void)Var_Subst(umsg, SCOPE_CMDLINE, VARE_WANTRES, &xmsg); + xmsg = Var_Subst(umsg, SCOPE_CMDLINE, VARE_WANTRES); /* TODO: handle errors */ Parse_Error(level, "%s", xmsg); @@ -913,10 +913,8 @@ ParseDependencyTargetWord(char **pp, const char *lstart) * have been discovered in the initial Var_Subst and * we wouldn't be here. */ - FStr val; - - (void)Var_Parse(&cp, SCOPE_CMDLINE, - VARE_PARSE_ONLY, &val); + FStr val = Var_Parse(&cp, SCOPE_CMDLINE, + VARE_PARSE_ONLY); FStr_Done(&val); } else cp++; @@ -1792,10 +1790,8 @@ VarCheckSyntax(VarAssignOp type, const char *uvalue, GNode *scope) { if (opts.strict) { if (type != VAR_SUBST && strchr(uvalue, '$') != NULL) { - char *expandedValue; - - (void)Var_Subst(uvalue, scope, VARE_PARSE_ONLY, - &expandedValue); + char *expandedValue = Var_Subst(uvalue, + scope, VARE_PARSE_ONLY); /* TODO: handle errors */ free(expandedValue); } @@ -1821,7 +1817,7 @@ VarAssign_EvalSubst(GNode *scope, const char *name, const char *uvalue, if (!Var_ExistsExpand(scope, name)) Var_SetExpand(scope, name, ""); - (void)Var_Subst(uvalue, scope, VARE_KEEP_DOLLAR_UNDEF, &evalue); + evalue = Var_Subst(uvalue, scope, VARE_KEEP_DOLLAR_UNDEF); /* TODO: handle errors */ Var_SetExpand(scope, name, evalue); @@ -1890,7 +1886,7 @@ VarAssign_Eval(const char *name, VarAssignOp op, const char *uvalue, static void VarAssignSpecial(const char *name, const char *avalue) { - if (strcmp(name, MAKEOVERRIDES) == 0) + if (strcmp(name, ".MAKEOVERRIDES") == 0) Main_ExportMAKEFLAGS(false); /* re-export MAKEFLAGS */ else if (strcmp(name, ".CURDIR") == 0) { /* @@ -1900,9 +1896,9 @@ VarAssignSpecial(const char *name, const char *avalue) */ Dir_InitCur(avalue); Dir_SetPATH(); - } else if (strcmp(name, MAKE_JOB_PREFIX) == 0) + } else if (strcmp(name, ".MAKE.JOB.PREFIX") == 0) Job_SetPrefix(); - else if (strcmp(name, MAKE_EXPORTED) == 0) + else if (strcmp(name, ".MAKE.EXPORTED") == 0) Var_ExportVars(avalue); } @@ -2166,8 +2162,8 @@ VarContainsWord(const char *varname, const char *word) static void TrackInput(const char *name) { - if (!VarContainsWord(MAKE_MAKEFILES, name)) - Global_Append(MAKE_MAKEFILES, name); + if (!VarContainsWord(".MAKE.MAKEFILES", name)) + Global_Append(".MAKE.MAKEFILES", name); } @@ -2258,7 +2254,7 @@ ParseTraditionalInclude(char *line) pp_skip_whitespace(&file); - (void)Var_Subst(file, SCOPE_CMDLINE, VARE_WANTRES, &all_files); + all_files = Var_Subst(file, SCOPE_CMDLINE, VARE_WANTRES); /* TODO: handle errors */ for (file = all_files; !done; file = cp + 1) { @@ -2303,7 +2299,7 @@ ParseGmakeExport(char *line) /* * Expand the value before putting it in the environment. */ - (void)Var_Subst(value, SCOPE_CMDLINE, VARE_WANTRES, &value); + value = Var_Subst(value, SCOPE_CMDLINE, VARE_WANTRES); /* TODO: handle errors */ setenv(variable, value, 1); @@ -2880,7 +2876,7 @@ ParseDependencyLine(char *line) * Var_Subst. */ emode = opts.strict ? VARE_WANTRES : VARE_UNDEFERR; - (void)Var_Subst(line, SCOPE_CMDLINE, emode, &expanded_line); + expanded_line = Var_Subst(line, SCOPE_CMDLINE, emode); /* TODO: handle errors */ /* Need a fresh list for the target nodes */ diff --git a/contrib/bmake/suff.c b/contrib/bmake/suff.c index 5ee2b3dec30b..01ae43cb21b4 100644 --- a/contrib/bmake/suff.c +++ b/contrib/bmake/suff.c @@ -1,4 +1,4 @@ -/* $NetBSD: suff.c,v 1.366 2022/03/04 23:17:16 sjg Exp $ */ +/* $NetBSD: suff.c,v 1.368 2023/02/14 21:38:31 rillig Exp $ */ /* * Copyright (c) 1988, 1989, 1990, 1993 @@ -115,7 +115,7 @@ #include "dir.h" /* "@(#)suff.c 8.4 (Berkeley) 3/21/94" */ -MAKE_RCSID("$NetBSD: suff.c,v 1.366 2022/03/04 23:17:16 sjg Exp $"); +MAKE_RCSID("$NetBSD: suff.c,v 1.368 2023/02/14 21:38:31 rillig Exp $"); typedef List SuffixList; typedef ListNode SuffixListNode; @@ -1312,9 +1312,7 @@ ExpandChildrenRegular(char *cp, GNode *pgn, GNodeList *members) } else if (*cp == '$') { /* Skip over the variable expression. */ const char *nested_p = cp; - FStr junk; - - (void)Var_Parse(&nested_p, pgn, VARE_PARSE_ONLY, &junk); + FStr junk = Var_Parse(&nested_p, pgn, VARE_PARSE_ONLY); /* TODO: handle errors */ if (junk.str == var_Error) { Parse_Error(PARSE_FATAL, @@ -1385,7 +1383,7 @@ ExpandChildren(GNodeListNode *cln, GNode *pgn) } DEBUG1(SUFF, "Expanding \"%s\"...", cgn->name); - (void)Var_Subst(cgn->name, pgn, VARE_UNDEFERR, &cp); + cp = Var_Subst(cgn->name, pgn, VARE_UNDEFERR); /* TODO: handle errors */ { diff --git a/contrib/bmake/trace.c b/contrib/bmake/trace.c index 2753b20752d2..9674cec7becb 100644 --- a/contrib/bmake/trace.c +++ b/contrib/bmake/trace.c @@ -1,4 +1,4 @@ -/* $NetBSD: trace.c,v 1.32 2022/03/26 14:02:40 rillig Exp $ */ +/* $NetBSD: trace.c,v 1.33 2023/03/28 14:39:31 rillig Exp $ */ /* * Copyright (c) 2000 The NetBSD Foundation, Inc. @@ -48,11 +48,11 @@ #include "job.h" #include "trace.h" -MAKE_RCSID("$NetBSD: trace.c,v 1.32 2022/03/26 14:02:40 rillig Exp $"); +MAKE_RCSID("$NetBSD: trace.c,v 1.33 2023/03/28 14:39:31 rillig Exp $"); static FILE *trfile; static pid_t trpid; -const char *trwd; +static const char *trwd; static const char evname[][4] = { "BEG", diff --git a/contrib/bmake/unit-tests/Makefile b/contrib/bmake/unit-tests/Makefile index f4d4425e204c..bcfe853642a5 100644 --- a/contrib/bmake/unit-tests/Makefile +++ b/contrib/bmake/unit-tests/Makefile @@ -1,6 +1,6 @@ -# $Id: Makefile,v 1.191 2023/01/24 06:09:49 sjg Exp $ +# $Id: Makefile,v 1.193 2023/02/25 20:03:25 sjg Exp $ # -# $NetBSD: Makefile,v 1.331 2023/01/24 00:24:02 sjg Exp $ +# $NetBSD: Makefile,v 1.333 2023/02/25 19:30:32 sjg Exp $ # # Unit tests for make(1) # @@ -32,6 +32,21 @@ .MAKE.OS?= ${uname -s:L:sh} .MAKE.UID?= ${id -u:L:sh} +# for many tests we need a TMPDIR that will not collide +# with other users. +.if ${.OBJDIR} != ${.CURDIR} +# easy +TMPDIR:= ${.OBJDIR}/tmp +.elif defined(TMPDIR) +TMPDIR:= ${TMPDIR}/uid${.MAKE.UID} +.else +TMPDIR:= /tmp/uid${.MAKE.UID} +.endif +# make sure it exists +.if !exist(${TMPDIR}) +_!= mkdir -p ${TMPDIR} +.endif + # Each test is in a sub-makefile. # Keep the list sorted. # Any test that is commented out must be ignored in @@ -406,12 +421,16 @@ TESTS+= varname-dot-make-makefiles TESTS+= varname-dot-make-meta-bailiwick TESTS+= varname-dot-make-meta-created TESTS+= varname-dot-make-meta-files +.if ${.MAKE.PATH_FILEMON:Uno:Nktrace:N/dev*} == "" && ${TMPDIR:N/tmp*:N/var/tmp*} != "" +# these tests will not work if TMPDIR is or is a subdir of +# /tmp or /var/tmp TESTS+= varname-dot-make-meta-ignore_filter TESTS+= varname-dot-make-meta-ignore_paths TESTS+= varname-dot-make-meta-ignore_patterns +TESTS+= varname-dot-make-path_filemon +.endif TESTS+= varname-dot-make-meta-prefix TESTS+= varname-dot-make-mode -TESTS+= varname-dot-make-path_filemon TESTS+= varname-dot-make-pid TESTS+= varname-dot-make-ppid TESTS+= varname-dot-make-save_dollars @@ -538,6 +557,9 @@ SED_CMDS.opt-chdir= -e 's,\(nonexistent\).[1-9][0-9]*,\1,' \ -e '/name/s,file,File,' \ -e 's,no such,No such,' \ -e 's,Filename,File name,' + +# meta line numbers can vary based on filemon implementation +SED_CMDS.meta-ignore= -e 's,\(\.meta:\) [1-9][0-9]*:,\1 :,' SED_CMDS.opt-debug-graph1= ${STD_SED_CMDS.dg1} SED_CMDS.opt-debug-graph2= ${STD_SED_CMDS.dg2} SED_CMDS.opt-debug-graph3= ${STD_SED_CMDS.dg3} @@ -571,6 +593,9 @@ SED_CMDS.var-op-shell+= ${STD_SED_CMDS.white-space} SED_CMDS.vardebug+= -e 's,${.SHELL},,' SED_CMDS.varmod-subst-regex+= ${STD_SED_CMDS.regex} SED_CMDS.varparse-errors+= ${STD_SED_CMDS.timestamp} +SED_CMDS.varname-dot-make-meta-ignore_filter+= ${SED_CMDS.meta-ignore} +SED_CMDS.varname-dot-make-meta-ignore_paths+= ${SED_CMDS.meta-ignore} +SED_CMDS.varname-dot-make-meta-ignore_patterns+= ${SED_CMDS.meta-ignore} SED_CMDS.varname-dot-parsedir= -e '/in some cases/ s,^make: "[^"]*,make: ",' SED_CMDS.varname-dot-parsefile= -e '/in some cases/ s,^make: "[^"]*,make: ",' SED_CMDS.varname-dot-shell= -e 's, = /[^ ]*, = (details omitted),g' @@ -713,22 +738,6 @@ LANG= C _MKMSG_TEST= : .endif - -# for many tests we need a TMPDIR that will not collide -# with other users. -.if ${.OBJDIR} != ${.CURDIR} -# easy -TMPDIR:= ${.OBJDIR}/tmp -.elif defined(TMPDIR) -TMPDIR:= ${TMPDIR}/uid${.MAKE.UID} -.else -TMPDIR:= /tmp/uid${.MAKE.UID} -.endif -# make sure it exists -.if !exist(${TMPDIR}) -_!= mkdir -p ${TMPDIR} -.endif - # Some Linux systems such as Fedora have deprecated egrep in favor of grep -E. .if ${.MAKE.OS:NLinux} == "" EGREP= grep -E @@ -768,23 +777,23 @@ LIMIT_RESOURCES?= : # Postprocess the test output to make the output platform-independent. # -# always pretend .MAKE was called 'make' -_SED_CMDS+= -e 's,^${TEST_MAKE:T:S,.,\\.,g}[][0-9]*:,make:,' -_SED_CMDS+= -e 's,${TEST_MAKE:S,.,\\.,g},make,' -_SED_CMDS+= -e 's,^usage: ${TEST_MAKE:T:S,.,\\.,g} ,usage: make ,' -# replace anything after 'stopped in' with unit-tests +# Replace anything after 'stopped in' with unit-tests _SED_CMDS+= -e '/stopped/s, /.*, unit-tests,' # Allow the test files to be placed anywhere. _SED_CMDS+= -e 's,\(\.PARSEDIR}\) = `'"/[^']*'"',\1 = ,' _SED_CMDS+= -e 's,\(\.INCLUDEDFROMDIR}\) = `'"/[^']*'"',\1 = ,' -_SED_CMDS+= -e 's,${TMPDIR},,g' +_SED_CMDS+= -e 's,${TMPDIR},,g' -e 's,${TMPDIR:tA},,g' # canonicalize ${.OBJDIR} and ${.CURDIR} +_SED_CMDS+= -e 's,${.CURDIR},,g' .if ${.OBJDIR} != ${.CURDIR} # yes this is inaccurate but none of the tests expect anywhere # which we get depending on how MAKEOBJDIR is set. -_SED_CMDS+= -e 's,${.OBJDIR},,g' +_SED_CMDS+= -e 's,${.OBJDIR},,g' -e 's,${.OBJDIR:tA},,g' .endif -_SED_CMDS+= -e 's,${.CURDIR},,g' +# always pretend .MAKE was called 'make' +_SED_CMDS+= -e 's,^${TEST_MAKE:T:S,.,\\.,g}[][0-9]*:,make:,' +_SED_CMDS+= -e 's,${TEST_MAKE:S,.,\\.,g},make,' +_SED_CMDS+= -e 's,^usage: ${TEST_MAKE:T:S,.,\\.,g} ,usage: make ,' _SED_CMDS+= -e 's,/,,g' _SED_CMDS+= -e 's,${UNIT_TESTS:S,.,\\.,g}/,,g' _SED_CMDS+= -e '/MAKE_VERSION/d' diff --git a/contrib/bmake/unit-tests/cmd-interrupt.exp b/contrib/bmake/unit-tests/cmd-interrupt.exp index 91f4439e7bea..242db1d9507d 100755 --- a/contrib/bmake/unit-tests/cmd-interrupt.exp +++ b/contrib/bmake/unit-tests/cmd-interrupt.exp @@ -2,7 +2,6 @@ make: *** cmd-interrupt-ordinary removed interrupt-ordinary: ok > cmd-interrupt-phony -make: *** cmd-interrupt-phony removed interrupt-phony: ok > cmd-interrupt-precious interrupt-precious: ok diff --git a/contrib/bmake/unit-tests/cmd-interrupt.mk b/contrib/bmake/unit-tests/cmd-interrupt.mk index fa0d85fc9063..140651b55c62 100755 --- a/contrib/bmake/unit-tests/cmd-interrupt.mk +++ b/contrib/bmake/unit-tests/cmd-interrupt.mk @@ -1,4 +1,4 @@ -# $NetBSD: cmd-interrupt.mk,v 1.3 2020/11/15 14:07:53 rillig Exp $ +# $NetBSD: cmd-interrupt.mk,v 1.4 2023/03/18 22:20:12 sjg Exp $ # # Tests for interrupting a command. # @@ -30,7 +30,7 @@ interrupt-ordinary: interrupt-phony: .PHONY @${.MAKE} ${MAKEFLAGS} -f ${MAKEFILE} cmd-interrupt-phony || true # The ././ is necessary to work around the file cache. - @echo ${.TARGET}: ${exists(././cmd-interrupt-phony) :? error : ok } + @echo ${.TARGET}: ${exists(././cmd-interrupt-phony) :? ok : error } interrupt-precious: .PRECIOUS @${.MAKE} ${MAKEFLAGS} -f ${MAKEFILE} cmd-interrupt-precious || true diff --git a/contrib/bmake/unit-tests/cond-cmp-numeric.exp b/contrib/bmake/unit-tests/cond-cmp-numeric.exp index c03ecd1b311e..69a8a1e4fca0 100644 --- a/contrib/bmake/unit-tests/cond-cmp-numeric.exp +++ b/contrib/bmake/unit-tests/cond-cmp-numeric.exp @@ -1,15 +1,15 @@ CondParser_Eval: !(${:UINF} > 1e100) -make: "cond-cmp-numeric.mk" line 11: Comparison with '>' requires both operands 'INF' and '1e100' to be numeric +make: "cond-cmp-numeric.mk" line 15: Comparison with '>' requires both operands 'INF' and '1e100' to be numeric CondParser_Eval: ${:UNaN} > NaN -make: "cond-cmp-numeric.mk" line 16: Comparison with '>' requires both operands 'NaN' and 'NaN' to be numeric +make: "cond-cmp-numeric.mk" line 21: Comparison with '>' requires both operands 'NaN' and 'NaN' to be numeric CondParser_Eval: !(${:UNaN} == NaN) Comparing "NaN" == "NaN" CondParser_Eval: 123 ! 123 -make: "cond-cmp-numeric.mk" line 34: Malformed conditional (123 ! 123) +make: "cond-cmp-numeric.mk" line 38: Malformed conditional (123 ! 123) CondParser_Eval: ${:U 123} < 124 Comparing 123.000000 < 124.000000 CondParser_Eval: ${:U123 } < 124 -make: "cond-cmp-numeric.mk" line 50: Comparison with '<' requires both operands '123 ' and '124' to be numeric +make: "cond-cmp-numeric.mk" line 54: Comparison with '<' requires both operands '123 ' and '124' to be numeric make: Fatal errors encountered -- cannot continue make: stopped in unit-tests exit status 1 diff --git a/contrib/bmake/unit-tests/cond-cmp-numeric.mk b/contrib/bmake/unit-tests/cond-cmp-numeric.mk index 5386e4a97297..e025b99b27cd 100644 --- a/contrib/bmake/unit-tests/cond-cmp-numeric.mk +++ b/contrib/bmake/unit-tests/cond-cmp-numeric.mk @@ -1,6 +1,9 @@ -# $NetBSD: cond-cmp-numeric.mk,v 1.6 2022/09/04 22:55:00 rillig Exp $ +# $NetBSD: cond-cmp-numeric.mk,v 1.7 2023/03/04 08:07:29 rillig Exp $ # # Tests for numeric comparisons in .if conditions. +# +# See also: +# cond-token-number.mk .MAKEFLAGS: -dc @@ -8,11 +11,13 @@ # Even if strtod(3) parses "INF" as +Infinity, make does not accept this # since it is not really a number; see TryParseNumber. +# expect+1: Comparison with '>' requires both operands 'INF' and '1e100' to be numeric .if !(${:UINF} > 1e100) . error .endif # Neither is NaN a number; see TryParseNumber. +# expect+1: Comparison with '>' requires both operands 'NaN' and 'NaN' to be numeric .if ${:UNaN} > NaN . error .endif @@ -29,8 +34,7 @@ # whether the operator is valid, leaving the rest of the work to the # evaluation functions EvalCompareNum and EvalCompareStr. Ensure that this # parse error is properly reported. -# -# XXX: The warning message does not mention the actual operator. +# expect+1: Malformed conditional (123 ! 123) .if 123 ! 123 . error .else @@ -54,4 +58,3 @@ .endif all: - @:; diff --git a/contrib/bmake/unit-tests/cond-cmp-string.exp b/contrib/bmake/unit-tests/cond-cmp-string.exp index c9c7a0777383..e0aabfdadca4 100644 --- a/contrib/bmake/unit-tests/cond-cmp-string.exp +++ b/contrib/bmake/unit-tests/cond-cmp-string.exp @@ -1,11 +1,11 @@ -make: "cond-cmp-string.mk" line 18: Malformed conditional (str != str) -make: "cond-cmp-string.mk" line 42: Malformed conditional ("string" != "str""ing") -make: "cond-cmp-string.mk" line 49: Malformed conditional (!("value" = "value")) -make: "cond-cmp-string.mk" line 56: Malformed conditional (!("value" === "value")) -make: "cond-cmp-string.mk" line 113: Comparison with '<' requires both operands 'string' and 'string' to be numeric -make: "cond-cmp-string.mk" line 120: Comparison with '<=' requires both operands 'string' and 'string' to be numeric -make: "cond-cmp-string.mk" line 127: Comparison with '>' requires both operands 'string' and 'string' to be numeric -make: "cond-cmp-string.mk" line 134: Comparison with '>=' requires both operands 'string' and 'string' to be numeric +make: "cond-cmp-string.mk" line 19: Malformed conditional (str != str) +make: "cond-cmp-string.mk" line 44: Malformed conditional ("string" != "str""ing") +make: "cond-cmp-string.mk" line 52: Malformed conditional (!("value" = "value")) +make: "cond-cmp-string.mk" line 60: Malformed conditional (!("value" === "value")) +make: "cond-cmp-string.mk" line 118: Comparison with '<' requires both operands 'string' and 'string' to be numeric +make: "cond-cmp-string.mk" line 126: Comparison with '<=' requires both operands 'string' and 'string' to be numeric +make: "cond-cmp-string.mk" line 134: Comparison with '>' requires both operands 'string' and 'string' to be numeric +make: "cond-cmp-string.mk" line 142: Comparison with '>=' requires both operands 'string' and 'string' to be numeric make: Fatal errors encountered -- cannot continue make: stopped in unit-tests exit status 1 diff --git a/contrib/bmake/unit-tests/cond-cmp-string.mk b/contrib/bmake/unit-tests/cond-cmp-string.mk index 8b504ba0c0d6..44d8beceacdd 100644 --- a/contrib/bmake/unit-tests/cond-cmp-string.mk +++ b/contrib/bmake/unit-tests/cond-cmp-string.mk @@ -1,4 +1,4 @@ -# $NetBSD: cond-cmp-string.mk,v 1.16 2022/05/08 06:51:27 rillig Exp $ +# $NetBSD: cond-cmp-string.mk,v 1.17 2023/03/28 14:38:29 rillig Exp $ # # Tests for string comparisons in .if conditions. @@ -15,6 +15,7 @@ # The left-hand side of the comparison must be enclosed in quotes. # This one is not enclosed in quotes and thus generates an error message. +# expect+1: Malformed conditional (str != str) .if str != str . error .endif @@ -39,6 +40,7 @@ # It is not possible to concatenate two string literals to form a single # string. In C, Python and the shell this is possible, but not in make. +# expect+1: Malformed conditional ("string" != "str""ing") .if "string" != "str""ing" . error .else @@ -46,6 +48,7 @@ .endif # There is no = operator for strings. +# expect+1: Malformed conditional (!("value" = "value")) .if !("value" = "value") . error .else @@ -53,6 +56,7 @@ .endif # There is no === operator for strings either. +# expect+1: Malformed conditional (!("value" === "value")) .if !("value" === "value") . error .else @@ -110,6 +114,7 @@ .endif # Strings cannot be compared relationally, only for equality. +# expect+1: Comparison with '<' requires both operands 'string' and 'string' to be numeric .if "string" < "string" . error .else @@ -117,6 +122,7 @@ .endif # Strings cannot be compared relationally, only for equality. +# expect+1: Comparison with '<=' requires both operands 'string' and 'string' to be numeric .if "string" <= "string" . error .else @@ -124,6 +130,7 @@ .endif # Strings cannot be compared relationally, only for equality. +# expect+1: Comparison with '>' requires both operands 'string' and 'string' to be numeric .if "string" > "string" . error .else @@ -131,6 +138,7 @@ .endif # Strings cannot be compared relationally, only for equality. +# expect+1: Comparison with '>=' requires both operands 'string' and 'string' to be numeric .if "string" >= "string" . error .else diff --git a/contrib/bmake/unit-tests/cond-func-empty.exp b/contrib/bmake/unit-tests/cond-func-empty.exp index d1dfda7c03ee..35d83adad5cb 100644 --- a/contrib/bmake/unit-tests/cond-func-empty.exp +++ b/contrib/bmake/unit-tests/cond-func-empty.exp @@ -1,5 +1,5 @@ -make: "cond-func-empty.mk" line 149: Unclosed variable "WORD" -make: "cond-func-empty.mk" line 149: Malformed conditional (empty(WORD) +make: "cond-func-empty.mk" line 153: Unclosed variable "WORD" +make: "cond-func-empty.mk" line 153: Malformed conditional (empty(WORD) make: Fatal errors encountered -- cannot continue make: stopped in unit-tests exit status 1 diff --git a/contrib/bmake/unit-tests/cond-func-empty.mk b/contrib/bmake/unit-tests/cond-func-empty.mk index 24cb7a680b2a..293305281298 100644 --- a/contrib/bmake/unit-tests/cond-func-empty.mk +++ b/contrib/bmake/unit-tests/cond-func-empty.mk @@ -1,4 +1,4 @@ -# $NetBSD: cond-func-empty.mk,v 1.17 2021/12/28 22:13:56 rillig Exp $ +# $NetBSD: cond-func-empty.mk,v 1.18 2023/03/04 21:15:30 rillig Exp $ # # Tests for the empty() function in .if conditions, which tests a variable # expression for emptiness. @@ -24,11 +24,13 @@ WORD= word . error .endif -# The :S modifier replaces the empty value with an actual word. The -# expression is now no longer empty, but it is still based on an undefined -# variable (DEF_UNDEF). There are a few variable modifiers that turn an -# undefined expression into a defined expression, among them :U and :D, but -# not :S. +# The :S modifier replaces the empty value with an actual word. After +# applying the :S modifier to the expression, it value is 'empty', so it is +# no longer empty, but it is still based on an undefined variable. There are +# a few modifiers that turn an undefined expression into a defined expression, +# among them :U and :D, but not :S. Therefore, at the end of evaluating the +# expression, the expression is still undefined, so its final value becomes an +# empty string. # # XXX: This is hard to explain to someone who doesn't know these # implementation details. @@ -45,15 +47,17 @@ WORD= word . error .endif -# And now to the surprising part. Applying the following :S modifier to the -# undefined expression makes it non-empty, but the expression is still in -# state DEF_UNDEF. The :U modifier that follows only looks at the state -# DEF_UNDEF to decide whether the variable is defined or not. This kind of -# makes sense since the :U modifier tests the _variable_, not the +# When an expression is based on an undefined variable, its modifiers interact +# in sometimes surprising ways. Applying the :S modifier to the undefined +# expression makes its value non-empty, but doesn't change that the expression +# is based on an undefined variable. The :U modifier that follows only looks +# at the definedness state to decide whether the variable is defined or not. +# This kind of makes sense since the :U modifier tests the _variable_, not the # _expression_. # -# But since the variable was undefined to begin with, the fallback value from -# the :U modifier is used in this expression. +# Since the variable was undefined to begin with, the fallback value from the +# :U modifier is used in this expression, instead of keeping the 'value' from +# the :S modifier. # .if ${UNDEF:S,^$,value,W:Ufallback} != "fallback" . error @@ -90,8 +94,8 @@ WORD= word # neither leading nor trailing spaces are trimmed in the argument of the # function. If the spaces were trimmed, the variable name would be "" and # that variable is indeed undefined. Since CondParser_FuncCallEmpty calls -# Var_Parse without VARE_UNDEFERR, the value of the undefined variable is -# returned as an empty string. +# Var_Parse without VARE_UNDEFERR, the value of the undefined variable "" +# would be returned as an empty string. ${:U }= space .if empty( ) . error @@ -120,9 +124,9 @@ ${:U }= space . error .endif -# Ensure that variable expressions that appear as part of the argument are -# properly parsed. Typical use cases for this are .for loops, which are -# expanded to exactly these ${:U} expressions. +# Ensure that variable expressions that appear as part of the function call +# argument are properly parsed. Typical use cases for this are .for loops, +# which are expanded to exactly these ${:U} expressions. # # If everything goes well, the argument expands to "WORD", and that variable # is defined at the beginning of this file. The surrounding 'W' and 'D' @@ -159,10 +163,9 @@ ${:U WORD }= variable name with spaces # Since at least 1993, the manual page claimed that irrelevant parts of # conditions were not evaluated, but that was wrong for a long time. The # expressions in irrelevant parts of the condition were actually evaluated, -# they just allowed undefined variables to be used in the conditions, and the -# result of evaluating them was not used further. These unnecessary -# evaluations were fixed in several commits, starting with var.c 1.226 from -# 2020-07-02. +# they just allowed undefined variables to be used in the conditions. These +# unnecessary evaluations were fixed in several commits, starting with var.c +# 1.226 from 2020-07-02. # # In this example, the variable "VARNAME2" is not defined, so evaluation of # the condition should have stopped at this point, and the rest of the diff --git a/contrib/bmake/unit-tests/cond-short.exp b/contrib/bmake/unit-tests/cond-short.exp index 2865dcb6ef33..745d7e912c2b 100644 --- a/contrib/bmake/unit-tests/cond-short.exp +++ b/contrib/bmake/unit-tests/cond-short.exp @@ -7,10 +7,7 @@ expected M pattern expected or expected or exists expected or empty -defined(V42) && ${V42} > 0: Ok -defined(V66) && ( "${iV2}" < ${V42} ): Ok -1 || ${iV1} < ${V42}: Ok -1 || ${iV2:U2} < ${V42}: Ok -0 || ${iV1} <= ${V42}: Ok -0 || ${iV2:U2} < ${V42}: Ok -exit status 0 +make: "cond-short.mk" line 214: Comparison with '<' requires both operands '' and '42' to be numeric +make: Fatal errors encountered -- cannot continue +make: stopped in unit-tests +exit status 1 diff --git a/contrib/bmake/unit-tests/cond-short.mk b/contrib/bmake/unit-tests/cond-short.mk index f4e8f87043b5..525ff7d0f2ab 100644 --- a/contrib/bmake/unit-tests/cond-short.mk +++ b/contrib/bmake/unit-tests/cond-short.mk @@ -1,4 +1,4 @@ -# $NetBSD: cond-short.mk,v 1.19 2021/12/27 18:54:19 rillig Exp $ +# $NetBSD: cond-short.mk,v 1.20 2023/03/04 13:42:36 rillig Exp $ # # Demonstrates that in conditions, the right-hand side of an && or || # is only evaluated if it can actually influence the result. @@ -135,28 +135,32 @@ VAR= # empty again, for the following tests .elif ${echo "unexpected nested or" 1>&2 :L:sh} .endif -# make sure these do not cause complaint -#.MAKEFLAGS: -dc -# TODO: Rewrite this whole section and check all the conditions and variables. -# Several of the assumptions are probably wrong here. -# TODO: replace 'x=' with '.info' or '.error'. -V42= 42 -iV1= ${V42} -iV2= ${V66} +NUMBER= 42 +INDIR_NUMBER= ${NUMBER} +INDIR_UNDEF= ${UNDEF} -.if defined(V42) && ${V42} > 0 -x= Ok +.if defined(NUMBER) && ${NUMBER} > 0 .else -x= Fail +. error .endif -x!= echo 'defined(V42) && $${V42} > 0: $x' >&2; echo -# With cond.c 1.76 from 2020-07-03, the following condition triggered a -# warning: "String comparison operator should be either == or !=". -# This was because the variable expression ${iV2} was defined, but the -# contained variable V66 was undefined. The left-hand side of the comparison -# therefore evaluated to the string "${V66}", which is obviously not a number. +# Starting with var.c 1.226 from from 2020-07-02, the following condition +# triggered a warning: "String comparison operator should be either == or !=". +# +# The left-hand side of the '&&' evaluated to false, which should have made +# the right-hand side irrelevant. +# +# On the right-hand side of the '&&', the expression ${INDIR_UNDEF} was +# defined and had the value '${UNDEF}', but the nested variable UNDEF was +# undefined. The right hand side "${INDIR_UNDEF}" still needed to be parsed, +# and in parse-only mode, the "value" of the parsed expression was the +# uninterpreted variable value, in this case '${UNDEF}'. And even though the +# right hand side of the '&&' should have been irrelevant, the two sides of +# the comparison were still parsed and evaluated. Comparing these two values +# numerically was not possible since the string '${UNDEF}' is not a number, +# so the comparison fell back to string comparison, which then complained +# about the '>' operator. # # This was fixed in cond.c 1.79 from 2020-07-09 by not evaluating irrelevant # comparisons. Instead, they are only parsed and then discarded. @@ -164,59 +168,77 @@ x!= echo 'defined(V42) && $${V42} > 0: $x' >&2; echo # At that time, there was not enough debug logging to see the details in the # -dA log. To actually see it, add debug logging at the beginning and end of # Var_Parse. -.if defined(V66) && ( ${iV2} < ${V42} ) -x= Fail -.else -x= Ok +.if defined(UNDEF) && ${INDIR_UNDEF} < ${NUMBER} +. error .endif -# XXX: This condition doesn't match the one above. The quotes are missing -# above. This is a crucial detail since without quotes, the variable -# expression ${iV2} evaluates to "${V66}", and with quotes, it evaluates to "" -# since undefined variables are allowed and expand to an empty string. -x!= echo 'defined(V66) && ( "$${iV2}" < $${V42} ): $x' >&2; echo - -.if 1 || ${iV1} < ${V42} -x= Ok -.else -x= Fail +# Adding a ':U' modifier to the irrelevant expression didn't help, as that +# expression was only parsed, not evaluated. The resulting literal string +# '${INDIR_UNDEF:U2}' was not numeric either, for the same reason as above. +.if defined(UNDEF) && ${INDIR_UNDEF:U2} < ${NUMBER} +. error .endif -x!= echo '1 || $${iV1} < $${V42}: $x' >&2; echo -# With cond.c 1.76 from 2020-07-03, the following condition triggered a -# warning: "String comparison operator should be either == or !=". -# This was because the variable expression ${iV2} was defined, but the -# contained variable V66 was undefined. The left-hand side of the comparison -# therefore evaluated to the string "${V66}", which is obviously not a number. +# Enclosing the expression in double quotes changes how that expression is +# evaluated. In irrelevant expressions that are enclosed in double quotes, +# expressions based on undefined variables are allowed and evaluate to an +# empty string. # -# This was fixed in cond.c 1.79 from 2020-07-09 by not evaluating irrelevant -# comparisons. Instead, they are only parsed and then discarded. +# The manual page stated from at least 1993 on that irrelevant conditions were +# not evaluated, but that was wrong. These conditions were evaluated, the +# only difference was that undefined variables in them didn't trigger an +# error. Since numeric conditions are quite rare, this subtle difference +# didn't catch much attention, as most other conditions such as pattern +# matches or equality comparisons worked fine and never produced error +# messages. +.if defined(UNDEF) && "${INDIR_UNDEF}" < ${NUMBER} +. error +.endif + +# Since the condition is relevant, the indirect undefined variable is +# evaluated as usual, resolving nested undefined expressions to an empty +# string. # -# At that time, there was not enough debug logging to see the details in the -# -dA log. To actually see it, add debug logging at the beginning and end of -# Var_Parse. -.if 1 || ${iV2:U2} < ${V42} -x= Ok +# Comparing an empty string numerically is not possible, however, make has an +# ugly hack in TryParseNumber that treats an empty string as a valid numerical +# value, thus hiding bugs in the makefile. +.if ${INDIR_UNDEF} < ${NUMBER} +# only due to the ugly hack .else -x= Fail +. error .endif -x!= echo '1 || $${iV2:U2} < $${V42}: $x' >&2; echo -# the same expressions are fine when the lhs is expanded -# ${iV1} expands to 42 -.if 0 || ${iV1} <= ${V42} -x= Ok +# Due to the quotes around the left-hand side of the '<', the operand is +# marked as a string, thus preventing a numerical comparison. +# +# expect+1: Comparison with '<' requires both operands '' and '42' to be numeric +.if "${INDIR_UNDEF}" < ${NUMBER} +. info yes .else -x= Fail +. info no .endif -x!= echo '0 || $${iV1} <= $${V42}: $x' >&2; echo -# ${iV2:U2} expands to 2 -.if 0 || ${iV2:U2} < ${V42} -x= Ok +# The right-hand side of '||' is irrelevant and thus not evaluated. +.if 1 || ${INDIR_NUMBER} < ${NUMBER} .else -x= Fail +. error .endif -x!= echo '0 || $${iV2:U2} < $${V42}: $x' >&2; echo + +# The right-hand side of '||' is relevant and thus evaluated normally. +.if 0 || ${INDIR_NUMBER} < ${NUMBER} +. error +.endif + +# The right-hand side of '||' evaluates to an empty string, as the variable +# 'INDIR_UNDEF' is defined, therefore the modifier ':U2' has no effect. +# Comparing an empty string numerically is not possible, however, make has an +# ugly hack in TryParseNumber that treats an empty string as a valid numerical +# value, thus hiding bugs in the makefile. +.if 0 || ${INDIR_UNDEF:U2} < ${NUMBER} +# only due to the ugly hack +.else +. error +.endif + # The right-hand side of the '&&' is irrelevant since the left-hand side # already evaluates to false. Before cond.c 1.79 from 2020-07-09, it was @@ -229,8 +251,8 @@ x!= echo '0 || $${iV2:U2} < $${V42}: $x' >&2; echo # Ensure that irrelevant conditions do not influence the result of the whole # condition. As of cond.c 1.302 from 2021-12-11, an irrelevant function call -# evaluates to true (see CondParser_FuncCall and CondParser_FuncCallEmpty), an -# irrelevant comparison evaluates to false (see CondParser_Comparison). +# evaluated to true (see CondParser_FuncCall and CondParser_FuncCallEmpty), an +# irrelevant comparison evaluated to false (see CondParser_Comparison). # # An irrelevant true bubbles up to the outermost CondParser_And, where it is # ignored. An irrelevant false bubbles up to the outermost CondParser_Or, diff --git a/contrib/bmake/unit-tests/cond-token-number.exp b/contrib/bmake/unit-tests/cond-token-number.exp index f078cb007323..1d472b63bc77 100644 --- a/contrib/bmake/unit-tests/cond-token-number.exp +++ b/contrib/bmake/unit-tests/cond-token-number.exp @@ -2,7 +2,6 @@ make: "cond-token-number.mk" line 15: Malformed conditional (-0) make: "cond-token-number.mk" line 25: Malformed conditional (+0) make: "cond-token-number.mk" line 35: Malformed conditional (!-1) make: "cond-token-number.mk" line 45: Malformed conditional (!+1) -make: "cond-token-number.mk" line 89: End of the tests. make: Fatal errors encountered -- cannot continue make: stopped in unit-tests exit status 1 diff --git a/contrib/bmake/unit-tests/cond-token-number.mk b/contrib/bmake/unit-tests/cond-token-number.mk index eef528f4b7c6..d1dd7371f447 100644 --- a/contrib/bmake/unit-tests/cond-token-number.mk +++ b/contrib/bmake/unit-tests/cond-token-number.mk @@ -1,4 +1,4 @@ -# $NetBSD: cond-token-number.mk,v 1.7 2022/01/02 02:57:39 rillig Exp $ +# $NetBSD: cond-token-number.mk,v 1.8 2023/03/04 08:07:29 rillig Exp $ # # Tests for number tokens in .if conditions. # @@ -85,7 +85,21 @@ HEX= dead . error .endif -# Ensure that parsing continues until here. -.info End of the tests. +# Very small numbers round to 0. +.if 12345e-400 +. error +.endif +.if 12345e-200 +.else +. error +.endif -all: # nothing +# Very large numbers round up to infinity on IEEE 754 implementations, or to +# the largest representable number (VAX); in particular, make does not fall +# back to checking whether a variable of that name is defined. +.if 12345e400 +.else +. error +.endif + +all: diff --git a/contrib/bmake/unit-tests/cond-token-plain.exp b/contrib/bmake/unit-tests/cond-token-plain.exp index a508bf62a5ea..572e8b3b2c9f 100644 --- a/contrib/bmake/unit-tests/cond-token-plain.exp +++ b/contrib/bmake/unit-tests/cond-token-plain.exp @@ -49,6 +49,7 @@ make: "cond-token-plain.mk" line 172: Now the variable '\\' is defined. CondParser_Eval: "unquoted\"quoted" != unquoted"quoted Comparing "unquoted"quoted" != "unquoted"quoted" CondParser_Eval: $$$$$$$$ != "" +make: "cond-token-plain.mk" line 186: Malformed conditional ($$$$$$$$ != "") CondParser_Eval: left == right make: "cond-token-plain.mk" line 195: Malformed conditional (left == right) CondParser_Eval: ${0:?:} || left == right diff --git a/contrib/bmake/unit-tests/cond-token-plain.mk b/contrib/bmake/unit-tests/cond-token-plain.mk index 5fb4a72b74a5..54bdd4fbf626 100644 --- a/contrib/bmake/unit-tests/cond-token-plain.mk +++ b/contrib/bmake/unit-tests/cond-token-plain.mk @@ -1,4 +1,4 @@ -# $NetBSD: cond-token-plain.mk,v 1.16 2022/09/25 12:51:37 rillig Exp $ +# $NetBSD: cond-token-plain.mk,v 1.17 2023/02/14 20:49:09 rillig Exp $ # # Tests for plain tokens (that is, string literals without quotes) # in .if conditions. These are also called bare words. @@ -89,7 +89,7 @@ # a coincidence that the '!' is both used in the '!=' comparison operator # as well as for negating a comparison result. # -# The boolean operators '&' and '|' don't terminate a comparison operand. +# The characters '&' and '|' are part of the comparison operand. .if ${:Uvar}&&name != "var&&name" . error .endif @@ -97,8 +97,8 @@ . error .endif -# A bare word may appear alone in a condition, without any comparison -# operator. It is implicitly converted into defined(bare). +# A bare word may occur alone in a condition, without any comparison +# operator. It is interpreted as the function call 'defined(bare)'. .if bare . error .else diff --git a/contrib/bmake/unit-tests/cond-undef-lint.exp b/contrib/bmake/unit-tests/cond-undef-lint.exp index 2c4feb0376ff..55073b2116c6 100755 --- a/contrib/bmake/unit-tests/cond-undef-lint.exp +++ b/contrib/bmake/unit-tests/cond-undef-lint.exp @@ -1,7 +1,10 @@ make: "cond-undef-lint.mk" line 23: Variable "UNDEF" is undefined +make: "cond-undef-lint.mk" line 23: Malformed conditional (${UNDEF}) make: "cond-undef-lint.mk" line 38: Variable "UNDEF" is undefined make: "cond-undef-lint.mk" line 38: Variable "VAR." is undefined +make: "cond-undef-lint.mk" line 38: Malformed conditional (${VAR.${UNDEF}}) make: "cond-undef-lint.mk" line 49: Variable "VAR.defined" is undefined +make: "cond-undef-lint.mk" line 49: Malformed conditional (${VAR.${DEF}}) make: Fatal errors encountered -- cannot continue make: stopped in unit-tests exit status 1 diff --git a/contrib/bmake/unit-tests/dep-var.exp b/contrib/bmake/unit-tests/dep-var.exp index d32aca455ceb..4e38057bf6b9 100755 --- a/contrib/bmake/unit-tests/dep-var.exp +++ b/contrib/bmake/unit-tests/dep-var.exp @@ -1,3 +1,27 @@ +Var_Parse: ${UNDEF1} (eval-defined) +Global: .ALLTARGETS = all +Global: .ALLTARGETS = all ${DEF2} +Global: .ALLTARGETS = all ${DEF2} a-${DEF2}-b +Global: .ALLTARGETS = all ${DEF2} a-${DEF2}-b ${UNDEF3} +Global: .ALLTARGETS = all ${DEF2} a-${DEF2}-b ${UNDEF3} 1-${INDIRECT_1}-1 +Global: INDIRECT_1 = 2-$${INDIRECT_2}-2 +Global: INDIRECT_2 = 3-$${INDIRECT_3}-3 +Global: INDIRECT_3 = indirect +Global: UNDEF1 = undef1 +Global: DEF2 = def2 +Global: .ALLTARGETS = all ${DEF2} a-${DEF2}-b ${UNDEF3} 1-${INDIRECT_1}-1 $$) +Var_Parse: ${:U\$)}: (eval-defined) +Evaluating modifier ${:U...} on value "" (eval-defined, undefined) +Result of ${:U\$)} is "$)" (eval-defined, defined) +Global: .ALLTARGETS = all ${DEF2} a-${DEF2}-b ${UNDEF3} 1-${INDIRECT_1}-1 $$) undef1 +Global: .ALLTARGETS = all ${DEF2} a-${DEF2}-b ${UNDEF3} 1-${INDIRECT_1}-1 $$) undef1 def2 +Global: .ALLTARGETS = all ${DEF2} a-${DEF2}-b ${UNDEF3} 1-${INDIRECT_1}-1 $$) undef1 def2 a-def2-b +Var_Parse: $INDIRECT_2-2-1 $): (parse-only) +Global: .ALLTARGETS = all ${DEF2} a-${DEF2}-b ${UNDEF3} 1-${INDIRECT_1}-1 $$) undef1 def2 a-def2-b 1-2-$INDIRECT_2-2-1 +Var_Parse: $): (parse-only) +Global: .ALLTARGETS = all ${DEF2} a-${DEF2}-b ${UNDEF3} 1-${INDIRECT_1}-1 $$) undef1 def2 a-def2-b 1-2-$INDIRECT_2-2-1 $) +Global: .MAKEFLAGS = -r -k -d v -d +Global: .MAKEFLAGS = -r -k -d v -d 0 make: Malformed variable expression at "$)" def2 a-def2-b diff --git a/contrib/bmake/unit-tests/dep-var.mk b/contrib/bmake/unit-tests/dep-var.mk index 4503424e31ab..f4a724f0ce7c 100755 --- a/contrib/bmake/unit-tests/dep-var.mk +++ b/contrib/bmake/unit-tests/dep-var.mk @@ -1,14 +1,16 @@ -# $NetBSD: dep-var.mk,v 1.6 2021/04/04 10:13:09 rillig Exp $ +# $NetBSD: dep-var.mk,v 1.7 2023/02/13 21:01:46 rillig Exp $ # # Tests for variable references in dependency declarations. # # Uh oh, this feels so strange that probably nobody uses it. But it seems to # be the only way to reach the lower half of SuffExpandChildren. -# XXX: The -dv log says: -# Var_Parse: ${UNDEF1} with VARE_UNDEFERR|VARE_WANTRES -# but no error message is generated for this line. -# The variable expression ${UNDEF1} simply expands to an empty string. +.MAKEFLAGS: -dv + +# expect: Var_Parse: ${UNDEF1} (eval-defined) +# Even though undefined expressions should lead to errors, no error message is +# generated for this line. The variable expression ${UNDEF1} simply expands +# to an empty string. all: ${UNDEF1} # Using a double dollar in order to circumvent immediate variable expansion @@ -20,8 +22,8 @@ all: ${UNDEF1} all: $${DEF2} a-$${DEF2}-b # This variable is not defined at all. -# XXX: The -dv log says: -# Var_Parse: ${UNDEF3} with VARE_UNDEFERR|VARE_WANTRES +# XXX: The -dv log says later when expanding the sources of 'all': +# Var_Parse: ${UNDEF3} (eval-defined) # but no error message is generated for this line, just like for UNDEF1. # The variable expression ${UNDEF3} simply expands to an empty string. all: $${UNDEF3} @@ -81,8 +83,13 @@ all: $$$$) # Since 2020-09-13, this generates a parse error in lint mode (-dL), but not # in normal mode since ParseDependency does not handle any errors after # calling Var_Parse. +# expect: Var_Parse: ${:U\$)}: (eval-defined) +# expect: Var_Parse: $INDIRECT_2-2-1 $): (parse-only) +# expect: Var_Parse: $): (parse-only) undef1 def2 a-def2-b 1-2-$$INDIRECT_2-2-1 ${:U\$)}: @echo ${.TARGET:Q} +.MAKEFLAGS: -d0 + # XXX: Why is the exit status still 0, even though Parse_Error is called # with PARSE_FATAL in SuffExpandChildren? diff --git a/contrib/bmake/unit-tests/deptgt-delete_on_error.exp b/contrib/bmake/unit-tests/deptgt-delete_on_error.exp index 9d9f1dc3e5ec..75fbbe12472f 100644 --- a/contrib/bmake/unit-tests/deptgt-delete_on_error.exp +++ b/contrib/bmake/unit-tests/deptgt-delete_on_error.exp @@ -7,10 +7,8 @@ make: *** deptgt-delete_on_error-regular removed make: *** deptgt-delete_on_error-regular-delete removed > deptgt-delete_on_error-phony; false *** Error code 1 (continuing) -make: *** deptgt-delete_on_error-phony removed > deptgt-delete_on_error-phony-delete; false *** Error code 1 (continuing) -make: *** deptgt-delete_on_error-phony-delete removed > deptgt-delete_on_error-precious; false *** Error code 1 (continuing) > deptgt-delete_on_error-precious-delete; false diff --git a/contrib/bmake/unit-tests/meta-ignore.inc b/contrib/bmake/unit-tests/meta-ignore.inc new file mode 100644 index 000000000000..ed74f4d79017 --- /dev/null +++ b/contrib/bmake/unit-tests/meta-ignore.inc @@ -0,0 +1,63 @@ +# $NetBSD: meta-ignore.inc,v 1.2 2023/02/25 19:30:32 sjg Exp $ + +# common logic for testing .MAKE.META.IGNORE_* + +# we want a directory outside of .OBJDIR to drop a file +# that our meta file refers to. +# Note: these tests will not work if TMPDIR is /tmp or /var/tmp +# or a subdir thereof +IGNORE:= ${TMPDIR}/ignore +OBJ:= ${TMPDIR}/obj + +# this is always ignored so make sure it isn't used above +TMPDIR= /tmp/nothanks + +all: one two three + +setup: + @mkdir -p ${IGNORE} ${OBJ} + @echo > ${IGNORE}/check + @rm -f ${OBJ}/check-ignore + +makefile:= ${.INCLUDEDFROMDIR}/${.INCLUDEDFROMFILE} +TEST:= ${.INCLUDEDFROMFILE:R:C,.*meta-,,:S,-,_,g:tu} + +DESC.one= Initialize check-ignore.meta +DESC.two= Use .MAKE.META.${TEST} - check-ignore is up to date +DESC.three= Skip .MAKE.META.${TEST} - check-ignore is out of date + +# just in case someone runs us with -jN +.ORDER: one two three +one two three: .MAKE setup + @echo "${DESC.${.TARGET}}"; \ + ${MAKE} -C ${.CURDIR} -f ${makefile} check-ignore parent=${.TARGET} + +.if make(check-ignore) +.MAKEFLAGS: -dM +.MAKE.MODE = meta verbose silent=yes +.OBJDIR: ${OBJ} +.if ${parent} == "two" +.if ${TEST} == "IGNORE_PATHS" +# this is a prefix list - any path that matches +# one of these prefixes will be ignored +.MAKE.META.IGNORE_PATHS = ${IGNORE} +.elif ${TEST} == "IGNORE_PATTERNS" +# more flexible but more expensive +# this example is equivalent to M*/ignore/* +# a match means ignore +.MAKE.META.IGNORE_PATTERNS = */ignore/* +.elif ${TEST} == "IGNORE_FILTER" +# this is the most flexible, but also most expensive +# if this expands to nothing - ignore the path +.MAKE.META.IGNORE_FILTER = N${IGNORE}/* +.endif +.endif + +# : < just reads from ${IGNORE}/check +# so that our filemon trace will have a reference to it +# we ensure it is always newer than the target. +check-ignore: .META .NOPATH + @: < ${IGNORE}/check > ${.TARGET} + @sleep 1; echo ${.TARGET} > ${IGNORE}/check + +.endif diff --git a/contrib/bmake/unit-tests/opt-debug-lint.exp b/contrib/bmake/unit-tests/opt-debug-lint.exp index 05b341b30dae..83643e9a8772 100644 --- a/contrib/bmake/unit-tests/opt-debug-lint.exp +++ b/contrib/bmake/unit-tests/opt-debug-lint.exp @@ -1,5 +1,7 @@ make: "opt-debug-lint.mk" line 19: Variable "X" is undefined +make: "opt-debug-lint.mk" line 19: Malformed conditional ($X) make: "opt-debug-lint.mk" line 41: Variable "UNDEF" is undefined +make: "opt-debug-lint.mk" line 41: Malformed conditional (${UNDEF}) make: "opt-debug-lint.mk" line 61: Missing delimiter ':' after modifier "L" make: "opt-debug-lint.mk" line 61: Missing delimiter ':' after modifier "P" make: "opt-debug-lint.mk" line 69: Unknown modifier "${" diff --git a/contrib/bmake/unit-tests/opt.mk b/contrib/bmake/unit-tests/opt.mk index 0931a66d3d15..939d5ec35aeb 100644 --- a/contrib/bmake/unit-tests/opt.mk +++ b/contrib/bmake/unit-tests/opt.mk @@ -1,4 +1,4 @@ -# $NetBSD: opt.mk,v 1.6 2020/11/18 01:06:59 sjg Exp $ +# $NetBSD: opt.mk,v 1.7 2023/02/25 00:07:08 rillig Exp $ # # Tests for the command line options. @@ -7,7 +7,7 @@ all: .IGNORE # The options from the top-level make are passed to the sub-makes via # the environment variable MAKEFLAGS. This is where the " -r -k -d 0" - # comes from. See MainParseArg. + # comes from. See MainParseOption. ${MAKE} -r -f /dev/null -V MAKEFLAGS @echo diff --git a/contrib/bmake/unit-tests/parse-var.exp b/contrib/bmake/unit-tests/parse-var.exp index bae925e8c869..39a9383953dd 100644 --- a/contrib/bmake/unit-tests/parse-var.exp +++ b/contrib/bmake/unit-tests/parse-var.exp @@ -1,5 +1 @@ -make: Unfinished modifier for "BRACE_GROUP" (',' missing) -make: "parse-var.mk" line 130: Malformed conditional (0 && ${BRACE_GROUP:S,${BRACE_PAIR:S,{,{{,},,}) -make: Fatal errors encountered -- cannot continue -make: stopped in unit-tests -exit status 1 +exit status 0 diff --git a/contrib/bmake/unit-tests/parse-var.mk b/contrib/bmake/unit-tests/parse-var.mk index cca6931d14a1..6205664c558e 100644 --- a/contrib/bmake/unit-tests/parse-var.mk +++ b/contrib/bmake/unit-tests/parse-var.mk @@ -1,4 +1,4 @@ -# $NetBSD: parse-var.mk,v 1.6 2022/09/25 21:26:23 rillig Exp $ +# $NetBSD: parse-var.mk,v 1.8 2023/02/18 11:16:09 rillig Exp $ # # Tests for parsing variable expressions. # @@ -68,8 +68,7 @@ # # Effects: # How much does the parsing position advance (pp)? -# What's the value of the expression (out_val)? -# What's the status after parsing the expression (VarParseResult)? +# What's the value of the expression (return value)? # What error messages are printed (Parse_Error)? # What no-effect error messages are printed (Error)? # What error messages should be printed but aren't? @@ -86,12 +85,9 @@ VAR.${:U param }= value . error .endif -# XXX: The following paragraph already uses past tense, in the hope that the -# parsing behavior can be cleaned up soon. - -# Since var.c 1.323 from 2020-07-26 18:11 and except for var.c 1.1028 from -# 2022-08-08, the exact way of parsing an expression depended on whether the -# expression was actually evaluated or merely parsed. +# Since var.c 1.323 from 2020-07-26 18:11 and until var.c 1.1047 from +# 2023-02-18, the exact way of parsing an expression with subexpressions +# depended on whether the expression was actually evaluated or merely parsed. # # If it was evaluated, nested expressions were parsed correctly, parsing each # modifier according to its exact definition (see varmod.mk). @@ -103,30 +99,28 @@ VAR.${:U param }= value # expression was not parsed correctly. Instead, make only counted the opening # and closing delimiters, which failed for nested modifiers with unbalanced # braces. -# -# This naive brace counting was implemented in ParseModifierPartDollar. As of -# var.c 1.1029, there are still several other places that merely count braces -# instead of properly parsing subexpressions. #.MAKEFLAGS: -dcpv # Keep these braces outside the conditions below, to keep them simple to -# understand. If the BRACE_PAIR had been replaced with ':U{}', the '}' would -# have to be escaped, but not the '{'. This asymmetry would have made the -# example even more complicated to understand. +# understand. If the expression ${BRACE_PAIR:...} had been replaced with the +# literal ${:U{}}, the '}' would have to be escaped, but not the '{'. This +# asymmetry would have made the example even more complicated to understand. BRACE_PAIR= {} -# In this test word, the '{{}' in the middle will be replaced. +# In this test word, the below conditions will replace the '{{}' in the middle +# with the string ''. BRACE_GROUP= {{{{}}}} # The inner ':S' modifier turns the word '{}' into '{{}'. # The outer ':S' modifier then replaces '{{}' with ''. -# In the first case, the outer expression is relevant and is parsed correctly. +# Due to the always-true condition '1', the outer expression is relevant and +# is parsed correctly. .if 1 && ${BRACE_GROUP:S,${BRACE_PAIR:S,{,{{,},,} .endif -# In the second case, the outer expression was irrelevant. In this case, in -# the parts of the outer ':S' modifier, make only counted the braces, and since -# the inner expression '${BRACE_PAIR:...}' contains more '{' than '}', parsing -# failed with the error message 'Unfinished modifier for "BRACE_GROUP"'. Fixed -# in var.c 1.1028 from 2022-08-08, reverted in var.c 1.1029 from 2022-08-23. +# Due to the always-false condition '0', the outer expression is irrelevant. +# In this case, in the parts of the outer ':S' modifier, the expression parser +# only counted the braces, and since the inner expression '${BRACE_PAIR:...}' +# contains more '{' than '}', parsing failed with the error message 'Unfinished +# modifier for "BRACE_GROUP"'. Fixed in var.c 1.1047 from 2023-02-18. .if 0 && ${BRACE_GROUP:S,${BRACE_PAIR:S,{,{{,},,} .endif #.MAKEFLAGS: -d0 diff --git a/contrib/bmake/unit-tests/var-eval-short.exp b/contrib/bmake/unit-tests/var-eval-short.exp index f574a6444e1b..34380ec61c41 100644 --- a/contrib/bmake/unit-tests/var-eval-short.exp +++ b/contrib/bmake/unit-tests/var-eval-short.exp @@ -7,7 +7,9 @@ make: "var-eval-short.mk" line 98: Malformed conditional (0 && ${:Uword:localtim CondParser_Eval: 0 && ${0:?${FAIL}then:${FAIL}else} Var_Parse: ${0:?${FAIL}then:${FAIL}else} (parse-only) Parsing modifier ${0:?...} +Var_Parse: ${FAIL}then:${FAIL}else} (parse-only) Modifier part: "${FAIL}then" +Var_Parse: ${FAIL}else} (parse-only) Modifier part: "${FAIL}else" Result of ${0:?${FAIL}then:${FAIL}else} is "" (parse-only, defined) Parsing line 163: DEFINED= defined @@ -17,7 +19,9 @@ Var_Parse: ${DEFINED:L:?${FAIL}then:${FAIL}else} (parse-only) Parsing modifier ${DEFINED:L} Result of ${DEFINED:L} is "defined" (parse-only, regular) Parsing modifier ${DEFINED:?...} +Var_Parse: ${FAIL}then:${FAIL}else} (parse-only) Modifier part: "${FAIL}then" +Var_Parse: ${FAIL}else} (parse-only) Modifier part: "${FAIL}else" Result of ${DEFINED:?${FAIL}then:${FAIL}else} is "defined" (parse-only, regular) Parsing line 166: .MAKEFLAGS: -d0 diff --git a/contrib/bmake/unit-tests/var-scope-cmdline.exp b/contrib/bmake/unit-tests/var-scope-cmdline.exp index a1227a1dd1f2..281b5af291ca 100644 --- a/contrib/bmake/unit-tests/var-scope-cmdline.exp +++ b/contrib/bmake/unit-tests/var-scope-cmdline.exp @@ -1,4 +1,4 @@ -make: "var-scope-cmdline.mk" line 67: global -make: "var-scope-cmdline.mk" line 76: makeflags +make: "var-scope-cmdline.mk" line 71: global +make: "var-scope-cmdline.mk" line 80: makeflags makeflags exit status 0 diff --git a/contrib/bmake/unit-tests/var-scope-cmdline.mk b/contrib/bmake/unit-tests/var-scope-cmdline.mk index 1f4a3e700253..fbfb2d0290a4 100644 --- a/contrib/bmake/unit-tests/var-scope-cmdline.mk +++ b/contrib/bmake/unit-tests/var-scope-cmdline.mk @@ -1,4 +1,4 @@ -# $NetBSD: var-scope-cmdline.mk,v 1.1 2022/01/23 16:25:54 rillig Exp $ +# $NetBSD: var-scope-cmdline.mk,v 1.2 2023/04/07 05:54:16 rillig Exp $ # # Tests for variables specified on the command line. # @@ -61,6 +61,10 @@ # Most cmdline variables are set at the very beginning, when parsing the # command line arguments. Using the special target '.MAKEFLAGS', it is # possible to set cmdline variables at any later time. +# +# See also: +# varcmd.mk +# varname-makeflags.mk # A normal global variable, without any cmdline variable nearby. VAR= global diff --git a/contrib/bmake/unit-tests/varcmd.mk b/contrib/bmake/unit-tests/varcmd.mk index 12739df30926..ec0cf96ed75c 100644 --- a/contrib/bmake/unit-tests/varcmd.mk +++ b/contrib/bmake/unit-tests/varcmd.mk @@ -1,4 +1,4 @@ -# $NetBSD: varcmd.mk,v 1.6 2021/02/16 19:43:09 rillig Exp $ +# $NetBSD: varcmd.mk,v 1.7 2023/04/07 05:54:16 rillig Exp $ # # Test behaviour of recursive make and vars set on command line. # @@ -12,6 +12,10 @@ # be rewritten to make it clear why there is a difference and why this is # actually intended. Removing that large block of code makes only this test # and vardebug.mk fail, which is not enough. +# +# See also: +# var-scope-cmdline.mk +# varname-makeflags.mk FU= fu FOO?= foo diff --git a/contrib/bmake/unit-tests/varmod-ifelse.exp b/contrib/bmake/unit-tests/varmod-ifelse.exp index 80361ebf6d61..94cbcbdeae82 100644 --- a/contrib/bmake/unit-tests/varmod-ifelse.exp +++ b/contrib/bmake/unit-tests/varmod-ifelse.exp @@ -27,6 +27,13 @@ make: "varmod-ifelse.mk" line 167: true make: "varmod-ifelse.mk" line 169: false make: Bad conditional expression ' ' in ' ?true:false' make: "varmod-ifelse.mk" line 171: +CondParser_Eval: 0 && ${1:?${:Uthen0:S,}},,}:${:Uelse0:S,}},,}} != "not evaluated" +CondParser_Eval: 1 && ${0:?${:Uthen1:S,}},,}:${:Uelse1:S,}},,}} != "else1" +CondParser_Eval: 0 +Comparing "else1" != "else1" +CondParser_Eval: 2 && ${1:?${:Uthen2:S,}},,}:${:Uelse2:S,}},,}} != "then2" +CondParser_Eval: 1 +Comparing "then2" != "then2" make: Fatal errors encountered -- cannot continue make: stopped in unit-tests exit status 1 diff --git a/contrib/bmake/unit-tests/varmod-ifelse.mk b/contrib/bmake/unit-tests/varmod-ifelse.mk index 2d1c54943ca1..0df45cae6870 100644 --- a/contrib/bmake/unit-tests/varmod-ifelse.mk +++ b/contrib/bmake/unit-tests/varmod-ifelse.mk @@ -1,4 +1,4 @@ -# $NetBSD: varmod-ifelse.mk,v 1.20 2022/09/25 12:51:37 rillig Exp $ +# $NetBSD: varmod-ifelse.mk,v 1.21 2023/02/18 18:23:58 rillig Exp $ # # Tests for the ${cond:?then:else} variable modifier, which evaluates either # the then-expression or the else-expression, depending on the condition. @@ -182,3 +182,67 @@ PRIMES= 2 3 5 7 11 "1:not_prime 2:prime 3:prime 4:not_prime 5:prime" . error .endif + +# When parsing the modifier ':?', there are 3 possible cases: +# +# 1. The whole expression is only parsed. +# 2. The expression is parsed and the 'then' branch is evaluated. +# 3. The expression is parsed and the 'else' branch is evaluated. +# +# In all of these cases, the expression must be parsed in the same way, +# especially when one of the branches contains unbalanced '{}' braces. +# +# At 2020-01-01, the expressions from the 'then' and 'else' branches were +# parsed differently, depending on whether the branch was taken or not. When +# the branch was taken, the parser recognized that in the modifier ':S,}},,', +# the '}}' were ordinary characters. When the branch was not taken, the +# parser only counted balanced '{' and '}', ignoring any escaping or other +# changes in the interpretation. +# +# In var.c 1.285 from 2020-07-20, the parsing of the expressions changed so +# that in both cases the expression is parsed in the same way, taking the +# unbalanced braces in the ':S' modifiers into account. This change was not +# on purpose, the commit message mentioned 'has the same effect', which was a +# wrong assumption. +# +# In var.c 1.323 from 2020-07-26, the unintended fix from var.c 1.285 was +# reverted, still not knowing about the difference between regular parsing and +# balanced-mode parsing. +# +# In var.c 1.1028 from 2022-08-08, there was another attempt at fixing this +# inconsistency in parsing, but since that broke parsing of the modifier ':@', +# it was reverted in var.c 1.1029 from 2022-08-23. +# +# In var.c 1.1047 from 2023-02-18, the inconsistency in parsing was finally +# fixed. The modifier ':@' now parses the body in balanced mode, while +# everywhere else the modifier parts have their subexpressions parsed in the +# same way, no matter whether they are evaluated or not. +# +# The modifiers ':@' and ':?' are similar in that they conceptually contain +# text to be evaluated later or conditionally, still they parse that text +# differently. The crucial difference is that the body of the modifier ':@' +# is always parsed using balanced mode. The modifier ':?', on the other hand, +# must parse both of its branches in the same way, no matter whether they are +# evaluated or not. Since balanced mode and standard mode are incompatible, +# it's impossible to use balanced mode in the modifier ':?'. +.MAKEFLAGS: -dc +.if 0 && ${1:?${:Uthen0:S,}},,}:${:Uelse0:S,}},,}} != "not evaluated" +# At 2020-01-07, the expression evaluated to 'then0,,}}', even though it was +# irrelevant as the '0' had already been evaluated to 'false'. +. error +.endif +.if 1 && ${0:?${:Uthen1:S,}},,}:${:Uelse1:S,}},,}} != "else1" +. error +.endif +.if 2 && ${1:?${:Uthen2:S,}},,}:${:Uelse2:S,}},,}} != "then2" +# At 2020-01-07, the whole expression evaluated to 'then2,,}}' instead of the +# expected 'then2'. The 'then' branch of the ':?' modifier was parsed +# normally, parsing and evaluating the ':S' modifier, thereby treating the +# '}}' as ordinary characters and resulting in 'then2'. The 'else' branch was +# parsed in balanced mode, ignoring that the inner '}}' were ordinary +# characters. The '}}' were thus interpreted as the end of the 'else' branch +# and the whole expression. This left the trailing ',,}}', which together +# with the 'then2' formed the result 'then2,,}}'. +. error +.endif +.MAKEFLAGS: -d0 diff --git a/contrib/bmake/unit-tests/varmod-loop.exp b/contrib/bmake/unit-tests/varmod-loop.exp index 9b432c806885..356946f63a9b 100644 --- a/contrib/bmake/unit-tests/varmod-loop.exp +++ b/contrib/bmake/unit-tests/varmod-loop.exp @@ -1,10 +1,10 @@ -Parsing line 78: USE_8_DOLLARS= ${:U1:@var@${8_DOLLARS}@} ${8_DOLLARS} $$$$$$$$ +Parsing line 91: USE_8_DOLLARS= ${:U1:@var@${8_DOLLARS}@} ${8_DOLLARS} $$$$$$$$ CondParser_Eval: ${USE_8_DOLLARS} != "\$\$\$\$ \$\$\$\$ \$\$\$\$" Comparing "$$$$ $$$$ $$$$" != "$$$$ $$$$ $$$$" -Parsing line 83: SUBST_CONTAINING_LOOP:= ${USE_8_DOLLARS} +Parsing line 96: SUBST_CONTAINING_LOOP:= ${USE_8_DOLLARS} CondParser_Eval: ${SUBST_CONTAINING_LOOP} != "\$\$ \$\$\$\$ \$\$\$\$" Comparing "$$ $$$$ $$$$" != "$$ $$$$ $$$$" -Parsing line 108: .MAKEFLAGS: -d0 +Parsing line 121: .MAKEFLAGS: -d0 ParseDependency(.MAKEFLAGS: -d0) :varname-overwriting-target: :x1y x2y x3y: :: mod-loop-dollar:1: diff --git a/contrib/bmake/unit-tests/varmod-loop.mk b/contrib/bmake/unit-tests/varmod-loop.mk index d3cc0228efd9..d09e49a6d842 100644 --- a/contrib/bmake/unit-tests/varmod-loop.mk +++ b/contrib/bmake/unit-tests/varmod-loop.mk @@ -1,6 +1,20 @@ -# $NetBSD: varmod-loop.mk,v 1.21 2022/08/23 21:13:46 rillig Exp $ +# $NetBSD: varmod-loop.mk,v 1.23 2023/02/18 11:55:20 rillig Exp $ # -# Tests for the :@var@...${var}...@ variable modifier. +# Tests for the expression modifier ':@var@body@', which replaces each word of +# the expression with the expanded body, which may contain references to the +# variable 'var'. For example, '${1 2 3:L:@word@<${word}>@}' encloses each +# word in angle quotes, resulting in '<1> <2> <3>'. +# +# The variable name can be chosen freely, except that it must not contain a +# '$'. For simplicity and readability, variable names should only use the +# characters 'A-Za-z0-9'. +# +# The body may contain subexpressions in the form '${...}' or '$(...)'. These +# subexpressions differ from everywhere else in makefiles in that the parser +# only scans '${...}' for balanced '{' and '}', likewise for '$(...)'. Any +# other '$' is left as-is during parsing. Later, when the body is expanded +# for each word, each '$$' is interpreted as a single '$', and the remaining +# '$' are interpreted as expressions, like when evaluating a regular variable. # Force the test results to be independent of the default value of this # setting, which is 'yes' for NetBSD's usr.bin/make but 'no' for the bmake @@ -19,7 +33,6 @@ varname-overwriting-target: @echo :$@: :${:U1 2 3:@\@@x${@}y@}: :$@: - # Demonstrate that it is possible to generate dollar signs using the # :@ modifier. # @@ -192,15 +205,14 @@ CMDLINE= global # needed for deleting the environment # except for '$i', which is replaced with the then-current value '1' of the # iteration variable. # -# XXX: was broken in var.c 1.1028 from 2022-08-08, reverted in var.c 1.1029 -# from 2022-08-23; see parse-var.mk, keyword 'BRACE_GROUP'. +# See parse-var.mk, keyword 'BRACE_GROUP'. all: varmod-loop-literal-dollar varmod-loop-literal-dollar: .PHONY : ${:U1:@i@ t=$$(( $${t:-0} + $i ))@} # When parsing the loop body, each '\$', '\@' and '\\' is unescaped to '$', -# '@' and '\'; all other backslashes are retained. +# '@' and '\', respectively; all other backslashes are retained. # # In practice, the '$' is not escaped as '\$', as there is a second round of # unescaping '$$' to '$' later when the loop body is expanded after setting the diff --git a/contrib/bmake/unit-tests/varmod-no-match.mk b/contrib/bmake/unit-tests/varmod-no-match.mk index 2acb27e2e727..c03b4bf94e70 100644 --- a/contrib/bmake/unit-tests/varmod-no-match.mk +++ b/contrib/bmake/unit-tests/varmod-no-match.mk @@ -1,9 +1,97 @@ -# $NetBSD: varmod-no-match.mk,v 1.2 2020/08/16 14:25:16 rillig Exp $ +# $NetBSD: varmod-no-match.mk,v 1.3 2023/02/26 06:08:06 rillig Exp $ # -# Tests for the :N variable modifier, which filters words that do not match -# the given pattern. +# Tests for the expression modifier ':N', which filters words that do not +# match the given pattern. + + +# Keep all words except for 'two'. +.if ${:U one two three :Ntwo} != "one three" +. error +.endif + +# Keep all words except those starting with 't'. +# See varmod-match.mk for the details of pattern matching. +.if ${:U one two three four six :Nt*} != "one four six" +. error +.endif + + +# Idiom: normalize whitespace +# +# The modifier ':N' can be used with an empty pattern. As that pattern never +# matches a word, the only effect is that the string is split into words and +# then joined again, thereby normalizing whitespace around and between the +# words. And even though the 'N' in ':N' might serve as a mnemonic for +# "normalize whitespace", this idiom is not used in practice, resorting to the +# much more common ':M*' to "select all words" instead. +.if ${:U :N} != "" +. error +.endif +.if ${:U one two three :N} != "one two three" +. error +.endif +.if ${:U one two three :M*} != "one two three" +. error +.endif + + +# Idiom: single-word expression equals any of several words or patterns +# +# If an expression is guaranteed to consist of a single word, the modifier +# ':N' can be chained to compare the expression to several words or even +# patterns in a sequence. If one of the patterns matches, the final +# expression will be the empty string. +# +.if ${:U word :None:Ntwo:Nthree} != "" +# good +.else +. error +.endif +.if ${:U two :None:Ntwo:Nthree} != "" +. error +.else +# good +.endif +# +# The modifier ':N' is seldom used in general since positive matches with ':M' +# are easier to grasp. Chaining the ':N' modifier is even more difficult to +# grasp due to the many negations involved. +# +# The final '!= ""' adds to the confusion because at first glance, the +# condition may look like '${VAR} != ""', which for a single-word variable is +# always true. +# +# The '!= ""' can be omitted if the expression cannot have the numeric value +# 0, which is common in practice. In that form, each ':N' can be pronounced +# as 'neither' or 'nor', which makes the expression sound more natural. +# +.if ${:U word :None:Ntwo:Nthree} +# good +.else +. error +.endif +.if ${:U two :None:Ntwo:Nthree} +. error +.else +# good +.endif +# +# Replacing the '${...} != ""' with '!empty(...)' doesn't improve the +# situation as the '!' adds another level of negations, and the word 'empty' +# is a negation on its own, thereby creating a triple negation. Furthermore, +# due to the '!empty', the expression to be evaluated no longer starts with +# '$' and is thus more difficult to spot quickly. +# +.if !empty(:U word :None:Ntwo:Nthree) +# good +.else +. error +.endif +.if !empty(:U two :None:Ntwo:Nthree) +. error +.else +# good +.endif -# TODO: Implementation all: - @:; diff --git a/contrib/bmake/unit-tests/varmod-order-shuffle.mk b/contrib/bmake/unit-tests/varmod-order-shuffle.mk index 16121d7e498f..e9898600355a 100644 --- a/contrib/bmake/unit-tests/varmod-order-shuffle.mk +++ b/contrib/bmake/unit-tests/varmod-order-shuffle.mk @@ -1,4 +1,4 @@ -# $NetBSD: varmod-order-shuffle.mk,v 1.7 2021/08/03 04:46:49 rillig Exp $ +# $NetBSD: varmod-order-shuffle.mk,v 1.8 2023/02/26 06:08:06 rillig Exp $ # # Tests for the :Ox variable modifier, which returns the words of the # variable, shuffled. @@ -6,8 +6,9 @@ # The variable modifier :Ox is available since 2005-06-01. # # As of 2020-08-16, make uses random(3) seeded by the current time in seconds. -# This makes the random numbers completely predictable since there is no other -# part of make that uses random numbers. +# This makes the random numbers completely predictable since the only other +# part of make that uses random numbers is the 'randomize-targets' mode, which +# is off by default. # # Tags: probabilistic diff --git a/contrib/bmake/unit-tests/varmod-order.exp b/contrib/bmake/unit-tests/varmod-order.exp index 46dc45e9f6d6..e5d03f887fc7 100644 --- a/contrib/bmake/unit-tests/varmod-order.exp +++ b/contrib/bmake/unit-tests/varmod-order.exp @@ -19,6 +19,8 @@ make: Bad modifier ":Onrr" for variable "NUMBERS" make: "varmod-order.mk" line 77: Malformed conditional (${NUMBERS:Onrr}) make: Bad modifier ":Orrn" for variable "NUMBERS" make: "varmod-order.mk" line 86: Malformed conditional (${NUMBERS:Orrn}) +make: Bad modifier ":On=Off" for variable "SWITCH" +make: "varmod-order.mk" line 100: Malformed conditional (${SWITCH:On=Off} != "Off") make: Fatal errors encountered -- cannot continue make: stopped in unit-tests exit status 1 diff --git a/contrib/bmake/unit-tests/varmod-order.mk b/contrib/bmake/unit-tests/varmod-order.mk index c6028fc10abd..b4d5452263c7 100644 --- a/contrib/bmake/unit-tests/varmod-order.mk +++ b/contrib/bmake/unit-tests/varmod-order.mk @@ -1,4 +1,4 @@ -# $NetBSD: varmod-order.mk,v 1.8 2022/01/15 12:35:18 rillig Exp $ +# $NetBSD: varmod-order.mk,v 1.10 2023/02/27 08:29:36 rillig Exp $ # # Tests for the :O variable modifier and its variants, which either sort the # words of the value or shuffle them. @@ -89,4 +89,18 @@ _:= ${NUMBERS:Onr . error .endif + +# If a modifier that starts with ':O' is not one of the known sort or shuffle +# forms, it is a parse error. Several other modifiers such as ':H' or ':u' +# fall back to the SysV modifier, for example, ':H=new' is not the standard +# ':H' modifier but instead replaces a trailing 'H' with 'new' in each word. +# There is no such fallback for the ':O' modifiers. +SWITCH= On +# expect: make: Bad modifier ":On=Off" for variable "SWITCH" +.if ${SWITCH:On=Off} != "Off" +. error +.else +. error +.endif + all: diff --git a/contrib/bmake/unit-tests/varname-dot-make-meta-ignore_filter.exp b/contrib/bmake/unit-tests/varname-dot-make-meta-ignore_filter.exp index 39a9383953dd..045d26dc080e 100644 --- a/contrib/bmake/unit-tests/varname-dot-make-meta-ignore_filter.exp +++ b/contrib/bmake/unit-tests/varname-dot-make-meta-ignore_filter.exp @@ -1 +1,11 @@ +Initialize check-ignore.meta +Building /obj/check-ignore +Skipping meta for .END: .SPECIAL +Use .MAKE.META.IGNORE_FILTER - check-ignore is up to date +`check-ignore' is up to date. +Skipping meta for .END: .SPECIAL +Skip .MAKE.META.IGNORE_FILTER - check-ignore is out of date +/obj/check-ignore.meta: : file '/ignore/check' is newer than the target... +Building /obj/check-ignore +Skipping meta for .END: .SPECIAL exit status 0 diff --git a/contrib/bmake/unit-tests/varname-dot-make-meta-ignore_filter.mk b/contrib/bmake/unit-tests/varname-dot-make-meta-ignore_filter.mk index c41aec4acdf8..0adf6a202857 100644 --- a/contrib/bmake/unit-tests/varname-dot-make-meta-ignore_filter.mk +++ b/contrib/bmake/unit-tests/varname-dot-make-meta-ignore_filter.mk @@ -1,8 +1,5 @@ -# $NetBSD: varname-dot-make-meta-ignore_filter.mk,v 1.2 2020/08/16 14:25:16 rillig Exp $ +# $NetBSD: varname-dot-make-meta-ignore_filter.mk,v 1.3 2023/02/23 05:20:45 sjg Exp $ # # Tests for the special .MAKE.META.IGNORE_FILTER variable. -# TODO: Implementation - -all: - @:; +.include "meta-ignore.inc" diff --git a/contrib/bmake/unit-tests/varname-dot-make-meta-ignore_paths.exp b/contrib/bmake/unit-tests/varname-dot-make-meta-ignore_paths.exp index 39a9383953dd..161d09c2eff4 100644 --- a/contrib/bmake/unit-tests/varname-dot-make-meta-ignore_paths.exp +++ b/contrib/bmake/unit-tests/varname-dot-make-meta-ignore_paths.exp @@ -1 +1,11 @@ +Initialize check-ignore.meta +Building /obj/check-ignore +Skipping meta for .END: .SPECIAL +Use .MAKE.META.IGNORE_PATHS - check-ignore is up to date +`check-ignore' is up to date. +Skipping meta for .END: .SPECIAL +Skip .MAKE.META.IGNORE_PATHS - check-ignore is out of date +/obj/check-ignore.meta: : file '/ignore/check' is newer than the target... +Building /obj/check-ignore +Skipping meta for .END: .SPECIAL exit status 0 diff --git a/contrib/bmake/unit-tests/varname-dot-make-meta-ignore_paths.mk b/contrib/bmake/unit-tests/varname-dot-make-meta-ignore_paths.mk index 4ae34f51608b..2c58849af0be 100644 --- a/contrib/bmake/unit-tests/varname-dot-make-meta-ignore_paths.mk +++ b/contrib/bmake/unit-tests/varname-dot-make-meta-ignore_paths.mk @@ -1,8 +1,5 @@ -# $NetBSD: varname-dot-make-meta-ignore_paths.mk,v 1.2 2020/08/16 14:25:16 rillig Exp $ +# $NetBSD: varname-dot-make-meta-ignore_paths.mk,v 1.3 2023/02/23 05:20:45 sjg Exp $ # # Tests for the special .MAKE.META.IGNORE_PATHS variable. -# TODO: Implementation - -all: - @:; +.include "meta-ignore.inc" diff --git a/contrib/bmake/unit-tests/varname-dot-make-meta-ignore_patterns.exp b/contrib/bmake/unit-tests/varname-dot-make-meta-ignore_patterns.exp index 39a9383953dd..ebc1c0c6261c 100644 --- a/contrib/bmake/unit-tests/varname-dot-make-meta-ignore_patterns.exp +++ b/contrib/bmake/unit-tests/varname-dot-make-meta-ignore_patterns.exp @@ -1 +1,11 @@ +Initialize check-ignore.meta +Building /obj/check-ignore +Skipping meta for .END: .SPECIAL +Use .MAKE.META.IGNORE_PATTERNS - check-ignore is up to date +`check-ignore' is up to date. +Skipping meta for .END: .SPECIAL +Skip .MAKE.META.IGNORE_PATTERNS - check-ignore is out of date +/obj/check-ignore.meta: : file '/ignore/check' is newer than the target... +Building /obj/check-ignore +Skipping meta for .END: .SPECIAL exit status 0 diff --git a/contrib/bmake/unit-tests/varname-dot-make-meta-ignore_patterns.mk b/contrib/bmake/unit-tests/varname-dot-make-meta-ignore_patterns.mk index ea9fc49f1718..d3d6e065857d 100644 --- a/contrib/bmake/unit-tests/varname-dot-make-meta-ignore_patterns.mk +++ b/contrib/bmake/unit-tests/varname-dot-make-meta-ignore_patterns.mk @@ -1,8 +1,5 @@ -# $NetBSD: varname-dot-make-meta-ignore_patterns.mk,v 1.2 2020/08/16 14:25:16 rillig Exp $ +# $NetBSD: varname-dot-make-meta-ignore_patterns.mk,v 1.3 2023/02/23 05:20:45 sjg Exp $ # # Tests for the special .MAKE.META.IGNORE_PATTERNS variable. -# TODO: Implementation - -all: - @:; +.include "meta-ignore.inc" diff --git a/contrib/bmake/unit-tests/varname-dot-makeflags.exp b/contrib/bmake/unit-tests/varname-dot-makeflags.exp index dbf96469f86b..28cc64fd66c8 100644 --- a/contrib/bmake/unit-tests/varname-dot-makeflags.exp +++ b/contrib/bmake/unit-tests/varname-dot-makeflags.exp @@ -1,3 +1,10 @@ -echo "$MAKEFLAGS" - -r -k -d 00000 -D VARNAME WITH SPACES +make: "varname-dot-makeflags.mk" line 10: MAKEFLAGS= +make: "varname-dot-makeflags.mk" line 11: .MAKEFLAGS=< -r -k> +make: "varname-dot-makeflags.mk" line 12: .MAKEOVERRIDES=<> +make: "varname-dot-makeflags.mk" line 18: MAKEFLAGS= +make: "varname-dot-makeflags.mk" line 20: .MAKEFLAGS=< -r -k -D VARNAME -r> +make: "varname-dot-makeflags.mk" line 22: .MAKEOVERRIDES=< VAR> +runtime: MAKEFLAGS=< -r -k -D VARNAME -r VAR=value> +runtime: .MAKEFLAGS=< -r -k -D VARNAME -r> +runtime: .MAKEOVERRIDES=< VAR> exit status 0 diff --git a/contrib/bmake/unit-tests/varname-dot-makeflags.mk b/contrib/bmake/unit-tests/varname-dot-makeflags.mk index 10d1903022cb..cca285f93013 100644 --- a/contrib/bmake/unit-tests/varname-dot-makeflags.mk +++ b/contrib/bmake/unit-tests/varname-dot-makeflags.mk @@ -1,15 +1,36 @@ -# $NetBSD: varname-dot-makeflags.mk,v 1.1 2020/12/01 20:37:30 rillig Exp $ +# $NetBSD: varname-dot-makeflags.mk,v 1.7 2023/02/25 19:24:07 rillig Exp $ # # Tests for the special .MAKEFLAGS variable, which collects almost all # command line arguments and passes them on to any child processes via # the environment variable MAKEFLAGS (without leading '.'). +# +# See also: +# varname-dot-makeoverrides.mk -# When options are parsed, the option and its argument are appended as -# separate words to .MAKEFLAGS. Special characters in the option argument -# are not quoted though. It seems to have not been necessary at least from -# 1993 until 2020. -.MAKEFLAGS: -d00000 -D"VARNAME WITH SPACES" +.info MAKEFLAGS=<${MAKEFLAGS:Uundefined}> +.info .MAKEFLAGS=<${.MAKEFLAGS}> +.info .MAKEOVERRIDES=<${.MAKEOVERRIDES:Uundefined}> -all: - echo "$$MAKEFLAGS" - @:; +# Append an option with argument, a plain option and a variable assignment. +.MAKEFLAGS: -DVARNAME -r VAR=value + +# expect+1: MAKEFLAGS= +.info MAKEFLAGS=<${MAKEFLAGS:Uundefined}> +# expect+1: .MAKEFLAGS=< -r -k -D VARNAME -r> +.info .MAKEFLAGS=<${.MAKEFLAGS}> +# expect+1: .MAKEOVERRIDES=< VAR> +.info .MAKEOVERRIDES=<${.MAKEOVERRIDES}> + +# The environment variable 'MAKEFLAGS' is not available to child processes +# when parsing the makefiles. This is different from exported variables, +# which are already available during parse time. +.if ${:!echo "\${MAKEFLAGS-undef}"!} != "undef" +. error +.endif + +# After parsing, the environment variable 'MAKEFLAGS' is set based on the +# special variables '.MAKEFLAGS' and '.MAKEOVERRIDES'. +runtime: + @echo '$@: MAKEFLAGS=<'${MAKEFLAGS:Q}'>' + @echo '$@: .MAKEFLAGS=<'${.MAKEFLAGS:Q}'>' + @echo '$@: .MAKEOVERRIDES=<'${.MAKEOVERRIDES:Q}'>' diff --git a/contrib/bmake/unit-tests/varname-dot-makeoverrides.exp b/contrib/bmake/unit-tests/varname-dot-makeoverrides.exp index 39a9383953dd..78c0296f8d76 100644 --- a/contrib/bmake/unit-tests/varname-dot-makeoverrides.exp +++ b/contrib/bmake/unit-tests/varname-dot-makeoverrides.exp @@ -1 +1,8 @@ +all: overrides=<> +make -f varname-dot-makeoverrides.mk stage_1 VAR=value +stage_1: overrides=< VAR> +make -f varname-dot-makeoverrides.mk stage_2 +stage_2: overrides=< VAR> +make -f varname-dot-makeoverrides.mk stage_3 +stage_3: overrides=< VAR> exit status 0 diff --git a/contrib/bmake/unit-tests/varname-dot-makeoverrides.mk b/contrib/bmake/unit-tests/varname-dot-makeoverrides.mk index a897f4667175..f3f3897f8aa4 100644 --- a/contrib/bmake/unit-tests/varname-dot-makeoverrides.mk +++ b/contrib/bmake/unit-tests/varname-dot-makeoverrides.mk @@ -1,8 +1,23 @@ -# $NetBSD: varname-dot-makeoverrides.mk,v 1.2 2020/08/16 14:25:16 rillig Exp $ +# $NetBSD: varname-dot-makeoverrides.mk,v 1.5 2023/02/25 06:54:08 rillig Exp $ # -# Tests for the special .MAKE.MAKEOVERRIDES variable. - -# TODO: Implementation +# Tests for the special .MAKEOVERRIDES variable, which lists the names of the +# variables that are passed on to child processes via the MAKEFLAGS +# environment variable. +# +# See also: +# varname-dot-makeflags.mk all: - @:; + @echo '$@: overrides=<'${.MAKEOVERRIDES:Uundefined:Q}'>' + ${MAKE} -f ${MAKEFILE} stage_1 VAR=value + +stage_1: + @echo '$@: overrides=<'${.MAKEOVERRIDES:Q}'>' + ${MAKE} -f ${MAKEFILE} stage_2 + +stage_2: + @echo '$@: overrides=<'${.MAKEOVERRIDES:Q}'>' + ${MAKE} -f ${MAKEFILE} stage_3 + +stage_3: + @echo '$@: overrides=<'${.MAKEOVERRIDES:Q}'>' diff --git a/contrib/bmake/unit-tests/varname-makeflags.exp b/contrib/bmake/unit-tests/varname-makeflags.exp index 39a9383953dd..c1354177ca47 100644 --- a/contrib/bmake/unit-tests/varname-makeflags.exp +++ b/contrib/bmake/unit-tests/varname-makeflags.exp @@ -1 +1,21 @@ +spaces_stage_0: MAKEFLAGS=< -r -k > +spaces_stage_0: env MAKEFLAGS=< -r -k > +spaces_stage_1: MAKEFLAGS=< -r -k -d 00000 -D VARNAME WITH SPACES > +spaces_stage_1: env MAKEFLAGS=< -r -k -d 00000 -D VARNAME WITH SPACES > +dollars_stage_0: MAKEFLAGS=< -r -k > +dollars_stage_1: env MAKEFLAGS=< -r -k DOLLARS=\$\{varname\}> +dollars_stage_1: MAKEFLAGS=< -r -k DOLLARS=\{varname\}> +dollars_stage_1: MAKEFLAGS:q=< -r -k DOLLARS=\{varname\}> +dollars_stage_2: env MAKEFLAGS=< -r -k DOLLARS=> +dollars_stage_2: dollars=<> +dollars_stage_2: MAKEFLAGS=< -r -k DOLLARS=> +dollars_stage_3: env MAKEFLAGS=< -r -k DOLLARS=> +dollars_stage_3: dollars=<> +dollars_stage_3: MAKEFLAGS=< -r -k DOLLARS=> +append_stage_0: MAKEFLAGS=< -r -k > +append_stage_1: MAKEFLAGS=< -r -k -D before-0 -D after-0 VAR0=value> +append_stage_2: MAKEFLAGS=< -r -k -D before-0 -D after-0 -D before-1 -D after-1 VAR0=value VAR1=value> +append_stage_3: MAKEFLAGS=< -r -k -D before-0 -D after-0 -D before-1 -D after-1 -D before-2 -D after-2 VAR0=value VAR1=value VAR2=value> +override_stage_1: run MAKEFLAGS=< -r -k STAGE=1 VAR=value> +override_stage_2: STAGE=<2> VAR= exit status 0 diff --git a/contrib/bmake/unit-tests/varname-makeflags.mk b/contrib/bmake/unit-tests/varname-makeflags.mk index f7840c2eb7a5..da339ba9c5e2 100644 --- a/contrib/bmake/unit-tests/varname-makeflags.mk +++ b/contrib/bmake/unit-tests/varname-makeflags.mk @@ -1,44 +1,182 @@ -# $NetBSD: varname-makeflags.mk,v 1.5 2022/01/16 18:16:06 sjg Exp $ +# $NetBSD: varname-makeflags.mk,v 1.7 2023/02/25 19:24:07 rillig Exp $ # -# Tests for the special MAKEFLAGS variable, which is basically just a normal -# environment variable. It is closely related to .MAKEFLAGS but captures the -# state of .MAKEFLAGS at the very beginning of make, before any makefiles are -# read. +# Tests for the environment variable 'MAKEFLAGS', from which additional +# command line arguments are read before the actual command line arguments. +# +# After reading the makefiles and before making the targets, the arguments +# that were collected in '.MAKEFLAGS' and '.MAKEOVERRIDES' are written back to +# the environment variable 'MAKEFLAGS'. -# TODO: Implementation +all: spaces_stage_0 dollars_stage_0 append_stage_0 override_stage_0 -.MAKEFLAGS: -d0 + +.if !make(*stage*) # The unit tests are run with an almost empty environment. In particular, -# the variable MAKEFLAGS is not set. The '.MAKEFLAGS:' above also doesn't -# influence the environment variable MAKEFLAGS, therefore it is still -# undefined at this point. -.if ${MAKEFLAGS:Uundefined} != "undefined" -. error -.endif +# the variable MAKEFLAGS is not set. +. if ${MAKEFLAGS:Uundefined} != "undefined" +. error +. endif # The special variable .MAKEFLAGS is influenced though. # See varname-dot-makeflags.mk for more details. -.if ${.MAKEFLAGS} != " -r -k -d 0" -. error -.endif +. if ${.MAKEFLAGS} != " -r -k" +. error +. endif # In POSIX mode, the environment variable MAKEFLAGS can contain letters only, # for compatibility. These letters are exploded to form regular options. OUTPUT!= env MAKEFLAGS=ikrs ${MAKE} -f /dev/null -v .MAKEFLAGS -.if ${OUTPUT} != " -i -k -r -s -V .MAKEFLAGS" -. error -.endif +. if ${OUTPUT} != " -i -k -r -s -V .MAKEFLAGS" +. error +. endif # As soon as there is a single non-alphabetic character in the environment # variable MAKEFLAGS, it is no longer split. In this example, the word # "d0ikrs" is treated as a target, but the option '-v' prevents any targets # from being built. OUTPUT!= env MAKEFLAGS=d0ikrs ${MAKE} -r -f /dev/null -v .MAKEFLAGS -.if ${OUTPUT} != " -r -V .MAKEFLAGS" -. error ${OUTPUT} +. if ${OUTPUT} != " -r -V .MAKEFLAGS" +. error ${OUTPUT} +. endif + .endif -all: +# When options are parsed, the option and its argument are appended as +# separate words to the MAKEFLAGS for the child processes. Special characters +# in the option arguments are not quoted though. +spaces_stage_0: + @echo '$@: MAKEFLAGS=<'${MAKEFLAGS:Q}'>' + @echo "$@: env MAKEFLAGS=<$$MAKEFLAGS>" + @${MAKE} -f ${MAKEFILE} spaces_stage_1 -d00000 -D"VARNAME WITH SPACES" + +# At this point, the 'VARNAME WITH SPACES' is no longer recognizable as a +# single command line argument. In practice, variable names don't contain +# spaces. +spaces_stage_1: + @echo '$@: MAKEFLAGS=<'${MAKEFLAGS:Q}'>' + @echo "$@: env MAKEFLAGS=<$$MAKEFLAGS>" + + +# Demonstrate that '$' characters are altered when they are passed on to child +# make processes via MAKEFLAGS. +dollars_stage_0: + @echo '$@: MAKEFLAGS=<'${MAKEFLAGS:Q}'>' + + # The '$$$$' becomes a literal '$$' when building the '${MAKE}' + # command line, making the actual argument 'DOLLARS=$${varname}'. + # At this stage, MAKEFLAGS is not yet involved. + @${MAKE} -f ${MAKEFILE} dollars_stage_1 DOLLARS='$$$${varname}' + +.if make(dollars_stage_1) +# At this point, the variable 'DOLLARS' contains '$${varname}', which +# evaluates to a literal '$' followed by '{varname}'. +. if ${DOLLARS} != "\${varname}" +. error +. endif +.endif +dollars_stage_1: + # At this point, the stage 1 make provides the environment variable + # 'MAKEFLAGS' to its child processes, even if the child process is not + # another make. + # + # expect: dollars_stage_1: env MAKEFLAGS=< -r -k DOLLARS=\$\{varname\}> + # + # The 'DOLLARS=\$\{varname\}' assignment is escaped so that the stage + # 2 make will see it as a single word. + @echo "$@: env MAKEFLAGS=<$$MAKEFLAGS>" + + # At this point, evaluating the environment variable 'MAKEFLAGS' leads + # to strange side effects as the string '\$\{varname\}' is interpreted + # as: + # + # \ a literal string of a single backslash + # $\ the value of the variable named '\' + # {varname\} a literal string + # + # Since the variable name '\' is not defined, the resulting value is + # '\{varname\}'. Make doesn't handle isolated '$' characters in + # strings well, instead each '$' has to be part of a '$$' or be part + # of a subexpression like '${VAR}'. + @echo '$@: MAKEFLAGS=<'${MAKEFLAGS:Q}'>' + + # The modifier ':q' preserves a '$$' in an expression value instead of + # expanding it to a single '$', but it's already too late, as that + # modifier applies after the expression has been evaluated. Except + # for debug logging, there is no way to process strings that contain + # isolated '$'. + @echo '$@: MAKEFLAGS:q=<'${MAKEFLAGS:q}'>' + + @${MAKE} -f ${MAKEFILE} dollars_stage_2 + +.if make(dollars_stage_2) +# At this point, the variable 'DOLLARS' contains '${varname}', and since +# 'varname' is undefined, that expression evaluates to an empty string. +. if ${DOLLARS} != "" +. error +. endif +varname= varvalue +. if ${DOLLARS} != "varvalue" +. error +. endif +. undef varname +.endif +dollars_stage_2: + @echo "$@: env MAKEFLAGS=<$$MAKEFLAGS>" + @echo '$@: dollars=<'${DOLLARS:Q}'>' + @echo '$@: MAKEFLAGS=<'${MAKEFLAGS:Q}'>' + @${MAKE} -f ${MAKEFILE} dollars_stage_3 + +dollars_stage_3: + @echo "$@: env MAKEFLAGS=<$$MAKEFLAGS>" + @echo '$@: dollars=<'${DOLLARS:Uundefined:Q}'>' + @echo '$@: MAKEFLAGS=<'${MAKEFLAGS:Q}'>' + + +# Demonstrates in which exact order the MAKEFLAGS are built together from the +# parent MAKEFLAGS and the flags from the command line, in particular that +# variable assignments are passed at the end, after the options. +append_stage_0: + @echo '$@: MAKEFLAGS=<'${MAKEFLAGS:Q}'>' + @${MAKE} -Dbefore-0 -f ${MAKEFILE} append_stage_1 VAR0=value -Dafter-0 + +append_stage_1: + @echo '$@: MAKEFLAGS=<'${MAKEFLAGS:Q}'>' + @${MAKE} -Dbefore-1 -f ${MAKEFILE} append_stage_2 VAR1=value -Dafter-1 + +append_stage_2: + @echo '$@: MAKEFLAGS=<'${MAKEFLAGS:Q}'>' + @${MAKE} -Dbefore-2 -f ${MAKEFILE} append_stage_3 VAR2=value -Dafter-2 + +append_stage_3: + @echo '$@: MAKEFLAGS=<'${MAKEFLAGS:Q}'>' + + +# Demonstrates the implementation details of 'MAKEFLAGS', in particular that +# it is an environment variable rather than a global variable. +override_stage_0: + @${MAKE} -f ${MAKEFILE} STAGE=1 VAR=value override_stage_1 + +.if make(override_stage_1) +# While parsing the makefiles, 'MAKEFLAGS' is the value of the environment +# variable, in this case provided by stage 0. +. if ${MAKEFLAGS:M*} != "-r -k" +. error +. endif +MAKEFLAGS= overridden # temporarily override it +. if ${MAKEFLAGS} != "overridden" +. error +. endif +.undef MAKEFLAGS # make the environment variable visible again +. if ${MAKEFLAGS:M*} != "-r -k" +. error +. endif +.endif +override_stage_1: + @echo '$@: run MAKEFLAGS=<'${MAKEFLAGS:Q}'>' + @${MAKE} -f ${MAKEFILE} STAGE=2 override_stage_2 + +override_stage_2: + @echo '$@: STAGE=<${STAGE}> VAR=<${VAR}>' diff --git a/contrib/bmake/unit-tests/varparse-errors.exp b/contrib/bmake/unit-tests/varparse-errors.exp index 2c3568e468ca..fc20e427296a 100644 --- a/contrib/bmake/unit-tests/varparse-errors.exp +++ b/contrib/bmake/unit-tests/varparse-errors.exp @@ -1,10 +1,10 @@ -make: "varparse-errors.mk" line 38: Unknown modifier "Z" -make: "varparse-errors.mk" line 46: Unknown modifier "Z" +make: "varparse-errors.mk" line 37: Unknown modifier "Z" +make: "varparse-errors.mk" line 45: Unknown modifier "Z" make: Bad modifier ":OX" for variable "" -make: "varparse-errors.mk" line 68: Undefined variable "${:U:OX" +make: "varparse-errors.mk" line 67: Undefined variable "${:U:OX" make: Bad modifier ":OX" for variable "" make: Bad modifier ":OX" for variable "" -make: "varparse-errors.mk" line 68: Undefined variable "${:U:OX" +make: "varparse-errors.mk" line 67: Undefined variable "${:U:OX" make: Bad modifier ":OX" for variable "" make: Unclosed variable expression, expecting '}' for modifier "Q" of variable "" with value "" make: Unclosed variable expression, expecting '}' for modifier "sh" of variable "" with value "" diff --git a/contrib/bmake/unit-tests/varparse-errors.mk b/contrib/bmake/unit-tests/varparse-errors.mk index 9174d264db0f..9ce41cc3be9a 100644 --- a/contrib/bmake/unit-tests/varparse-errors.mk +++ b/contrib/bmake/unit-tests/varparse-errors.mk @@ -1,4 +1,4 @@ -# $NetBSD: varparse-errors.mk,v 1.7 2022/08/24 22:09:41 rillig Exp $ +# $NetBSD: varparse-errors.mk,v 1.8 2023/02/14 21:56:48 rillig Exp $ # Tests for parsing and evaluating all kinds of variable expressions. # @@ -6,7 +6,6 @@ # Var_Subst, collecting typical and not so typical use cases. # # See also: -# VarParseResult # Var_Parse # Var_Subst diff --git a/contrib/bmake/var.c b/contrib/bmake/var.c index a938cefcfd1b..965080bbcddd 100644 --- a/contrib/bmake/var.c +++ b/contrib/bmake/var.c @@ -1,4 +1,4 @@ -/* $NetBSD: var.c,v 1.1040 2023/02/09 07:34:15 sjg Exp $ */ +/* $NetBSD: var.c,v 1.1049 2023/03/28 14:39:31 rillig Exp $ */ /* * Copyright (c) 1988, 1989, 1990, 1993 @@ -147,7 +147,7 @@ #include "metachar.h" /* "@(#)var.c 8.3 (Berkeley) 3/19/94" */ -MAKE_RCSID("$NetBSD: var.c,v 1.1040 2023/02/09 07:34:15 sjg Exp $"); +MAKE_RCSID("$NetBSD: var.c,v 1.1049 2023/03/28 14:39:31 rillig Exp $"); /* * Variables are defined using one of the VAR=value assignments. Their @@ -336,6 +336,7 @@ static VarExportedMode var_exportedVars = VAR_EXPORTED_NONE; static const char VarEvalMode_Name[][32] = { "parse-only", + "parse-balanced", "eval", "eval-defined", "eval-keep-dollar", @@ -529,7 +530,7 @@ Var_Delete(GNode *scope, const char *varname) if (v->exported) unsetenv(v->name.str); - if (strcmp(v->name.str, MAKE_EXPORTED) == 0) + if (strcmp(v->name.str, ".MAKE.EXPORTED") == 0) var_exportedVars = VAR_EXPORTED_NONE; assert(v->name.freeIt == NULL); @@ -545,7 +546,6 @@ Var_Delete(GNode *scope, const char *varname) void Var_Undef(const char *arg) { - VarParseResult vpr; char *expanded; Words varnames; size_t i; @@ -556,8 +556,9 @@ Var_Undef(const char *arg) return; } - vpr = Var_Subst(arg, SCOPE_GLOBAL, VARE_WANTRES, &expanded); - if (vpr != VPR_OK) { + expanded = Var_Subst(arg, SCOPE_GLOBAL, VARE_WANTRES); + if (expanded == var_Error) { + /* TODO: Make this part of the code reachable. */ Parse_Error(PARSE_FATAL, "Error in variable names to be undefined"); return; @@ -627,7 +628,7 @@ ExportVarEnv(Var *v) /* XXX: name is injected without escaping it */ expr = str_concat3("${", name, "}"); - (void)Var_Subst(expr, SCOPE_GLOBAL, VARE_WANTRES, &val); + val = Var_Subst(expr, SCOPE_GLOBAL, VARE_WANTRES); /* TODO: handle errors */ setenv(name, val, 1); free(val); @@ -727,8 +728,8 @@ Var_ReexportVars(void) return; } - (void)Var_Subst("${" MAKE_EXPORTED ":O:u}", SCOPE_GLOBAL, VARE_WANTRES, - &xvarnames); + xvarnames = Var_Subst("${.MAKE.EXPORTED:O:u}", SCOPE_GLOBAL, + VARE_WANTRES); /* TODO: handle errors */ if (xvarnames[0] != '\0') { Words varnames = Str_Words(xvarnames, false); @@ -760,7 +761,7 @@ ExportVars(const char *varnames, bool isExport, VarExportMode mode) var_exportedVars = VAR_EXPORTED_SOME; if (isExport && mode == VEM_PLAIN) - Global_Append(MAKE_EXPORTED, varname); + Global_Append(".MAKE.EXPORTED", varname); } Words_Free(words); } @@ -768,9 +769,7 @@ ExportVars(const char *varnames, bool isExport, VarExportMode mode) static void ExportVarsExpand(const char *uvarnames, bool isExport, VarExportMode mode) { - char *xvarnames; - - (void)Var_Subst(uvarnames, SCOPE_GLOBAL, VARE_WANTRES, &xvarnames); + char *xvarnames = Var_Subst(uvarnames, SCOPE_GLOBAL, VARE_WANTRES); /* TODO: handle errors */ ExportVars(xvarnames, isExport, mode); free(xvarnames); @@ -795,8 +794,6 @@ Var_ExportVars(const char *varnames) } -extern char **environ; - static void ClearEnv(void) { @@ -846,10 +843,8 @@ GetVarnamesToUnexport(bool isEnv, const char *arg, } if (what != UNEXPORT_NAMED) { - char *expanded; - /* Using .MAKE.EXPORTED */ - (void)Var_Subst("${" MAKE_EXPORTED ":O:u}", SCOPE_GLOBAL, - VARE_WANTRES, &expanded); + char *expanded = Var_Subst("${.MAKE.EXPORTED:O:u}", + SCOPE_GLOBAL, VARE_WANTRES); /* TODO: handle errors */ varnames = FStr_InitOwn(expanded); } @@ -878,12 +873,11 @@ UnexportVar(Substring varname, UnexportWhat what) if (what == UNEXPORT_NAMED) { /* Remove the variable names from .MAKE.EXPORTED. */ /* XXX: v->name is injected without escaping it */ - char *expr = str_concat3("${" MAKE_EXPORTED ":N", + char *expr = str_concat3("${.MAKE.EXPORTED:N", v->name.str, "}"); - char *cp; - (void)Var_Subst(expr, SCOPE_GLOBAL, VARE_WANTRES, &cp); + char *cp = Var_Subst(expr, SCOPE_GLOBAL, VARE_WANTRES); /* TODO: handle errors */ - Global_Set(MAKE_EXPORTED, cp); + Global_Set(".MAKE.EXPORTED", cp); free(cp); free(expr); } @@ -904,7 +898,7 @@ UnexportVars(FStr *varnames, UnexportWhat what) SubstringWords_Free(words); if (what != UNEXPORT_NAMED) - Global_Delete(MAKE_EXPORTED); + Global_Delete(".MAKE.EXPORTED"); } /* @@ -1014,7 +1008,7 @@ Var_SetWithFlags(GNode *scope, const char *name, const char *val, /* * If requested, don't export these in the environment - * individually. We still put them in MAKEOVERRIDES so + * individually. We still put them in .MAKEOVERRIDES so * that the command-line settings continue to override * Makefile settings. */ @@ -1026,7 +1020,7 @@ Var_SetWithFlags(GNode *scope, const char *name, const char *val, * in ExportVarPlain? */ - Global_Append(MAKEOVERRIDES, name); + Global_Append(".MAKEOVERRIDES", name); } if (name[0] == '.' && strcmp(name, MAKE_SAVE_DOLLARS) == 0) @@ -1706,7 +1700,7 @@ ModifyWord_Loop(Substring word, SepBuf *buf, void *data) assert(word.end[0] == '\0'); /* assume null-terminated word */ Var_SetWithFlags(args->scope, args->var, word.start, VAR_SET_NO_EXPORT); - (void)Var_Subst(args->body, args->scope, args->emode, &s); + s = Var_Subst(args->body, args->scope, args->emode); /* TODO: handle errors */ assert(word.end[0] == '\0'); /* assume null-terminated word */ @@ -2153,36 +2147,26 @@ ParseModifierPartExpr(const char **pp, LazyBuf *part, const ModChain *ch, VarEvalMode emode) { const char *p = *pp; - FStr nested_val; - - (void)Var_Parse(&p, ch->expr->scope, - VarEvalMode_WithoutKeepDollar(emode), &nested_val); + FStr nested_val = Var_Parse(&p, ch->expr->scope, + VarEvalMode_WithoutKeepDollar(emode)); /* TODO: handle errors */ - LazyBuf_AddStr(part, nested_val.str); + if (VarEvalMode_ShouldEval(emode)) + LazyBuf_AddStr(part, nested_val.str); + else + LazyBuf_AddSubstring(part, Substring_Init(*pp, p)); FStr_Done(&nested_val); *pp = p; } /* - * In a part of a modifier, parse a subexpression but don't evaluate it. - * - * XXX: This whole block is very similar to Var_Parse with VARE_PARSE_ONLY. - * There may be subtle edge cases though that are not yet covered in the unit - * tests and that are parsed differently, depending on whether they are - * evaluated or not. - * - * This subtle difference is not documented in the manual page, neither is - * the difference between parsing ':D' and ':M' documented. No code should - * ever depend on these details, but who knows. - * - * TODO: Before trying to replace this code with Var_Parse, there need to be - * more unit tests in varmod-loop.mk. The modifier ':@' uses Var_Subst - * internally, in which a '$' is escaped as '$$', not as '\$' like in other - * modifiers. When parsing the body text '$${var}', skipping over the first - * '$' would treat '${var}' as a make expression, not as a shell variable. + * In a part of a modifier, parse some text that looks like a subexpression. + * If the text starts with '$(', any '(' and ')' must be balanced. + * If the text starts with '${', any '{' and '}' must be balanced. + * If the text starts with '$', that '$' is copied, it is not parsed as a + * short-name variable expression. */ static void -ParseModifierPartDollar(const char **pp, LazyBuf *part) +ParseModifierPartBalanced(const char **pp, LazyBuf *part) { const char *p = *pp; const char *start = *pp; @@ -2209,7 +2193,7 @@ ParseModifierPartDollar(const char **pp, LazyBuf *part) } /* See ParseModifierPart for the documentation. */ -static VarParseResult +static bool ParseModifierPartSubst( const char **pp, char delim, @@ -2249,10 +2233,10 @@ ParseModifierPartSubst( else LazyBuf_Add(part, *p); p++; - } else if (VarEvalMode_ShouldEval(emode)) - ParseModifierPartExpr(&p, part, ch, emode); + } else if (emode == VARE_PARSE_BALANCED) + ParseModifierPartBalanced(&p, part); else - ParseModifierPartDollar(&p, part); + ParseModifierPartExpr(&p, part, ch, emode); } if (*p != delim) { @@ -2260,7 +2244,7 @@ ParseModifierPartSubst( Error("Unfinished modifier for \"%s\" ('%c' missing)", ch->expr->name, delim); LazyBuf_Done(part); - return VPR_ERR; + return false; } *pp = p + 1; @@ -2271,7 +2255,7 @@ ParseModifierPartSubst( (int)Substring_Length(sub), sub.start); } - return VPR_OK; + return true; } /* @@ -2280,11 +2264,11 @@ ParseModifierPartSubst( * including the next unescaped delimiter. The delimiter, as well as the * backslash or the dollar, can be escaped with a backslash. * - * Return VPR_OK if parsing succeeded, together with the parsed (and possibly + * Return true if parsing succeeded, together with the parsed (and possibly * expanded) part. In that case, pp points right after the delimiter. The * delimiter is not included in the part though. */ -static VarParseResult +static bool ParseModifierPart( /* The parsing position, updated upon return */ const char **pp, @@ -2434,15 +2418,13 @@ ApplyModifier_Loop(const char **pp, ModChain *ch) Expr *expr = ch->expr; struct ModifyWord_LoopArgs args; char prev_sep; - VarParseResult res; LazyBuf tvarBuf, strBuf; FStr tvar, str; args.scope = expr->scope; (*pp)++; /* Skip the first '@' */ - res = ParseModifierPart(pp, '@', VARE_PARSE_ONLY, ch, &tvarBuf); - if (res != VPR_OK) + if (!ParseModifierPart(pp, '@', VARE_PARSE_ONLY, ch, &tvarBuf)) return AMR_CLEANUP; tvar = LazyBuf_DoneGet(&tvarBuf); args.var = tvar.str; @@ -2454,8 +2436,7 @@ ApplyModifier_Loop(const char **pp, ModChain *ch) return AMR_CLEANUP; } - res = ParseModifierPart(pp, '@', VARE_PARSE_ONLY, ch, &strBuf); - if (res != VPR_OK) + if (!ParseModifierPart(pp, '@', VARE_PARSE_BALANCED, ch, &strBuf)) return AMR_CLEANUP; str = LazyBuf_DoneGet(&strBuf); args.body = str.str; @@ -2508,11 +2489,8 @@ ParseModifier_Defined(const char **pp, ModChain *ch, bool shouldEval, /* Nested variable expression */ if (*p == '$') { - FStr val; - - (void)Var_Parse(&p, ch->expr->scope, - shouldEval ? ch->expr->emode : VARE_PARSE_ONLY, - &val); + FStr val = Var_Parse(&p, ch->expr->scope, + shouldEval ? ch->expr->emode : VARE_PARSE_ONLY); /* TODO: handle errors */ if (shouldEval) LazyBuf_AddStr(buf, val.str); @@ -2666,13 +2644,11 @@ static ApplyModifierResult ApplyModifier_ShellCommand(const char **pp, ModChain *ch) { Expr *expr = ch->expr; - VarParseResult res; LazyBuf cmdBuf; FStr cmd; (*pp)++; - res = ParseModifierPart(pp, '!', expr->emode, ch, &cmdBuf); - if (res != VPR_OK) + if (!ParseModifierPart(pp, '!', expr->emode, ch, &cmdBuf)) return AMR_CLEANUP; cmd = LazyBuf_DoneGet(&cmdBuf); @@ -2818,7 +2794,7 @@ ParseModifier_Match(const char **pp, const ModChain *ch) * XXX: Contrary to ParseModifierPart, a dollar in a ':M' or * ':N' modifier must be escaped as '$$', not as '\$'. */ - (void)Var_Subst(pattern, expr->scope, expr->emode, &pattern); + pattern = Var_Subst(pattern, expr->scope, expr->emode); /* TODO: handle errors */ free(old_pattern); } @@ -2875,7 +2851,6 @@ ApplyModifier_Subst(const char **pp, ModChain *ch) { struct ModifyWord_SubstArgs args; bool oneBigWord; - VarParseResult res; LazyBuf lhsBuf, rhsBuf; char delim = (*pp)[1]; @@ -2895,15 +2870,13 @@ ApplyModifier_Subst(const char **pp, ModChain *ch) (*pp)++; } - res = ParseModifierPartSubst(pp, delim, ch->expr->emode, ch, &lhsBuf, - &args.pflags, NULL); - if (res != VPR_OK) + if (!ParseModifierPartSubst(pp, delim, ch->expr->emode, ch, &lhsBuf, + &args.pflags, NULL)) return AMR_CLEANUP; args.lhs = LazyBuf_Get(&lhsBuf); - res = ParseModifierPartSubst(pp, delim, ch->expr->emode, ch, &rhsBuf, - NULL, &args); - if (res != VPR_OK) { + if (!ParseModifierPartSubst(pp, delim, ch->expr->emode, ch, &rhsBuf, + NULL, &args)) { LazyBuf_Done(&lhsBuf); return AMR_CLEANUP; } @@ -2928,7 +2901,6 @@ ApplyModifier_Regex(const char **pp, ModChain *ch) struct ModifyWord_SubstRegexArgs args; bool oneBigWord; int error; - VarParseResult res; LazyBuf reBuf, replaceBuf; FStr re; @@ -2941,13 +2913,11 @@ ApplyModifier_Regex(const char **pp, ModChain *ch) *pp += 2; - res = ParseModifierPart(pp, delim, ch->expr->emode, ch, &reBuf); - if (res != VPR_OK) + if (!ParseModifierPart(pp, delim, ch->expr->emode, ch, &reBuf)) return AMR_CLEANUP; re = LazyBuf_DoneGet(&reBuf); - res = ParseModifierPart(pp, delim, ch->expr->emode, ch, &replaceBuf); - if (res != VPR_OK) { + if (!ParseModifierPart(pp, delim, ch->expr->emode, ch, &replaceBuf)) { FStr_Done(&re); return AMR_CLEANUP; } @@ -3180,14 +3150,12 @@ ApplyModifier_Words(const char **pp, ModChain *ch) Expr *expr = ch->expr; const char *estr; int first, last; - VarParseResult res; const char *p; LazyBuf estrBuf; FStr festr; (*pp)++; /* skip the '[' */ - res = ParseModifierPart(pp, ']', expr->emode, ch, &estrBuf); - if (res != VPR_OK) + if (!ParseModifierPart(pp, ']', expr->emode, ch, &estrBuf)) return AMR_CLEANUP; festr = LazyBuf_DoneGet(&estrBuf); estr = festr.str; @@ -3412,7 +3380,6 @@ static ApplyModifierResult ApplyModifier_IfElse(const char **pp, ModChain *ch) { Expr *expr = ch->expr; - VarParseResult res; LazyBuf thenBuf; LazyBuf elseBuf; @@ -3429,12 +3396,10 @@ ApplyModifier_IfElse(const char **pp, ModChain *ch) } (*pp)++; /* skip past the '?' */ - res = ParseModifierPart(pp, ':', then_emode, ch, &thenBuf); - if (res != VPR_OK) + if (!ParseModifierPart(pp, ':', then_emode, ch, &thenBuf)) return AMR_CLEANUP; - res = ParseModifierPart(pp, ch->endc, else_emode, ch, &elseBuf); - if (res != VPR_OK) { + if (!ParseModifierPart(pp, ch->endc, else_emode, ch, &elseBuf)) { LazyBuf_Done(&thenBuf); return AMR_CLEANUP; } @@ -3495,7 +3460,6 @@ ApplyModifier_Assign(const char **pp, ModChain *ch) Expr *expr = ch->expr; GNode *scope; FStr val; - VarParseResult res; LazyBuf buf; const char *mod = *pp; @@ -3515,8 +3479,7 @@ ApplyModifier_Assign(const char **pp, ModChain *ch) *pp = mod + (op[0] == '+' || op[0] == '?' || op[0] == '!' ? 3 : 2); - res = ParseModifierPart(pp, ch->endc, expr->emode, ch, &buf); - if (res != VPR_OK) + if (!ParseModifierPart(pp, ch->endc, expr->emode, ch, &buf)) return AMR_CLEANUP; val = LazyBuf_DoneGet(&buf); @@ -3650,7 +3613,6 @@ static ApplyModifierResult ApplyModifier_SysV(const char **pp, ModChain *ch) { Expr *expr = ch->expr; - VarParseResult res; LazyBuf lhsBuf, rhsBuf; FStr rhs; struct ModifyWord_SysVSubstArgs args; @@ -3680,15 +3642,13 @@ ApplyModifier_SysV(const char **pp, ModChain *ch) if (*p != ch->endc || !eqFound) return AMR_UNKNOWN; - res = ParseModifierPart(pp, '=', expr->emode, ch, &lhsBuf); - if (res != VPR_OK) + if (!ParseModifierPart(pp, '=', expr->emode, ch, &lhsBuf)) return AMR_CLEANUP; /* * The SysV modifier lasts until the end of the variable expression. */ - res = ParseModifierPart(pp, ch->endc, expr->emode, ch, &rhsBuf); - if (res != VPR_OK) { + if (!ParseModifierPart(pp, ch->endc, expr->emode, ch, &rhsBuf)) { LazyBuf_Done(&lhsBuf); return AMR_CLEANUP; } @@ -3714,6 +3674,7 @@ ApplyModifier_SysV(const char **pp, ModChain *ch) done: LazyBuf_Done(&lhsBuf); + FStr_Done(&rhs); return AMR_OK; } #endif @@ -3743,6 +3704,18 @@ ApplyModifier_SunShell(const char **pp, ModChain *ch) } #endif +/* + * In cases where the evaluation mode and the definedness are the "standard" + * ones, don't log them, to keep the logs readable. + */ +static bool +ShouldLogInSimpleFormat(const Expr *expr) +{ + return (expr->emode == VARE_WANTRES || + expr->emode == VARE_UNDEFERR) && + expr->defined == DEF_REGULAR; +} + static void LogBeforeApply(const ModChain *ch, const char *mod) { @@ -3760,8 +3733,7 @@ LogBeforeApply(const ModChain *ch, const char *mod) return; } - if ((expr->emode == VARE_WANTRES || expr->emode == VARE_UNDEFERR) && - expr->defined == DEF_REGULAR) { + if (ShouldLogInSimpleFormat(expr)) { debug_printf( "Evaluating modifier ${%s:%c%s} on value \"%s\"\n", expr->name, mod[0], is_single_char ? "" : "...", @@ -3782,9 +3754,7 @@ LogAfterApply(const ModChain *ch, const char *p, const char *mod) const char *value = Expr_Str(expr); const char *quot = value == var_Error ? "" : "\""; - if ((expr->emode == VARE_WANTRES || expr->emode == VARE_UNDEFERR) && - expr->defined == DEF_REGULAR) { - + if (ShouldLogInSimpleFormat(expr)) { debug_printf("Result of ${%s:%.*s} is %s%s%s\n", expr->name, (int)(p - mod), mod, quot, value == var_Error ? "error" : value, quot); @@ -3892,9 +3862,7 @@ ApplyModifiersIndirect(ModChain *ch, const char **pp) { Expr *expr = ch->expr; const char *p = *pp; - FStr mods; - - (void)Var_Parse(&p, expr->scope, expr->emode, &mods); + FStr mods = Var_Parse(&p, expr->scope, expr->emode); /* TODO: handle errors */ if (mods.str[0] != '\0' && !IsDelimiter(*p, ch)) { @@ -4079,7 +4047,7 @@ ApplyModifiers( * commands with evaluation errors should not be run at all. * * To make that happen, Var_Subst must report the actual errors - * instead of returning VPR_OK unconditionally. + * instead of returning the resulting string unconditionally. */ *pp = p; Expr_SetValueRefer(expr, var_Error); @@ -4169,8 +4137,7 @@ ParseVarname(const char **pp, char startc, char endc, /* A variable inside a variable, expand. */ if (*p == '$') { - FStr nested_val; - (void)Var_Parse(&p, scope, emode, &nested_val); + FStr nested_val = Var_Parse(&p, scope, emode); /* TODO: handle errors */ LazyBuf_AddStr(buf, nested_val.str); FStr_Done(&nested_val); @@ -4211,7 +4178,7 @@ IsShortVarnameValid(char varname, const char *start) static bool ParseVarnameShort(char varname, const char **pp, GNode *scope, VarEvalMode emode, - VarParseResult *out_false_res, const char **out_false_val, + const char **out_false_val, Var **out_true_var) { char name[2]; @@ -4220,7 +4187,6 @@ ParseVarnameShort(char varname, const char **pp, GNode *scope, if (!IsShortVarnameValid(varname, *pp)) { (*pp)++; /* only skip the '$' */ - *out_false_res = VPR_ERR; *out_false_val = var_Error; return false; } @@ -4243,22 +4209,8 @@ ParseVarnameShort(char varname, const char **pp, GNode *scope, if (opts.strict && val == var_Error) { Parse_Error(PARSE_FATAL, "Variable \"%s\" is undefined", name); - *out_false_res = VPR_ERR; - *out_false_val = val; - return false; } - /* - * XXX: This looks completely wrong. - * - * If undefined expressions are not allowed, this should - * rather be VPR_ERR instead of VPR_UNDEF, together with an - * error message. - * - * If undefined expressions are allowed, this should rather - * be VPR_UNDEF instead of VPR_OK. - */ - *out_false_res = emode == VARE_UNDEFERR ? VPR_UNDEF : VPR_OK; *out_false_val = val; return false; } @@ -4289,30 +4241,22 @@ FindLocalLegacyVar(Substring varname, GNode *scope, return v; } -static VarParseResult +static FStr EvalUndefined(bool dynamic, const char *start, const char *p, - Substring varname, VarEvalMode emode, FStr *out_val) + Substring varname, VarEvalMode emode) { - if (dynamic) { - *out_val = FStr_InitOwn(bmake_strsedup(start, p)); - return VPR_OK; - } + if (dynamic) + return FStr_InitOwn(bmake_strsedup(start, p)); if (emode == VARE_UNDEFERR && opts.strict) { Parse_Error(PARSE_FATAL, "Variable \"%.*s\" is undefined", (int)Substring_Length(varname), varname.start); - *out_val = FStr_InitRefer(var_Error); - return VPR_ERR; + return FStr_InitRefer(var_Error); } - if (emode == VARE_UNDEFERR) { - *out_val = FStr_InitRefer(var_Error); - return VPR_UNDEF; /* XXX: Should be VPR_ERR instead. */ - } - - *out_val = FStr_InitRefer(varUndefined); - return VPR_OK; + return FStr_InitRefer( + emode == VARE_UNDEFERR ? var_Error : varUndefined); } /* @@ -4329,7 +4273,6 @@ ParseVarnameLong( VarEvalMode emode, const char **out_false_pp, - VarParseResult *out_false_res, FStr *out_false_val, char *out_true_endc, @@ -4364,7 +4307,6 @@ ParseVarnameLong( LazyBuf_Done(&varname); *out_false_pp = p; *out_false_val = FStr_InitRefer(var_Error); - *out_false_res = VPR_ERR; return false; } @@ -4394,8 +4336,8 @@ ParseVarnameLong( if (!haveModifier) { p++; /* skip endc */ *out_false_pp = p; - *out_false_res = EvalUndefined(dynamic, start, p, - name, emode, out_false_val); + *out_false_val = EvalUndefined(dynamic, start, p, + name, emode); LazyBuf_Done(&varname); return false; } @@ -4497,23 +4439,23 @@ Var_Parse_FastLane(const char **pp, VarEvalMode emode, FStr *out_value) * point to some random character in the string, to the * location of the parse error, or at the end of the * string. - * *out_val The value of the variable expression, never NULL. - * *out_val var_Error if there was a parse error. - * *out_val var_Error if the base variable of the expression was + * return The value of the variable expression, never NULL. + * return var_Error if there was a parse error. + * return var_Error if the base variable of the expression was * undefined, emode is VARE_UNDEFERR, and none of * the modifiers turned the undefined expression into a * defined expression. * XXX: It is not guaranteed that an error message has * been printed. - * *out_val varUndefined if the base variable of the expression + * return varUndefined if the base variable of the expression * was undefined, emode was not VARE_UNDEFERR, * and none of the modifiers turned the undefined * expression into a defined expression. * XXX: It is not guaranteed that an error message has * been printed. */ -VarParseResult -Var_Parse(const char **pp, GNode *scope, VarEvalMode emode, FStr *out_val) +FStr +Var_Parse(const char **pp, GNode *scope, VarEvalMode emode) { const char *p = *pp; const char *const start = p; @@ -4531,15 +4473,16 @@ Var_Parse(const char **pp, GNode *scope, VarEvalMode emode, FStr *out_val) Var *v; Expr expr = Expr_Literal(NULL, FStr_InitRefer(NULL), emode, scope, DEF_REGULAR); + FStr val; - if (Var_Parse_FastLane(pp, emode, out_val)) - return VPR_OK; + if (Var_Parse_FastLane(pp, emode, &val)) + return val; /* TODO: Reduce computations in parse-only mode. */ DEBUG2(VAR, "Var_Parse: %s (%s)\n", start, VarEvalMode_Name[emode]); - *out_val = FStr_InitRefer(NULL); + val = FStr_InitRefer(NULL); extramodifiers = NULL; /* extra modifiers to apply first */ dynamic = false; @@ -4547,19 +4490,16 @@ Var_Parse(const char **pp, GNode *scope, VarEvalMode emode, FStr *out_val) startc = p[1]; if (startc != '(' && startc != '{') { - VarParseResult res; - if (!ParseVarnameShort(startc, pp, scope, emode, &res, - &out_val->str, &v)) - return res; + if (!ParseVarnameShort(startc, pp, scope, emode, &val.str, &v)) + return val; haveModifier = false; p++; } else { - VarParseResult res; if (!ParseVarnameLong(&p, startc, scope, emode, - pp, &res, out_val, + pp, &val, &endc, &v, &haveModifier, &extramodifiers, &dynamic, &expr.defined)) - return res; + return val; } expr.name = v->name.str; @@ -4595,8 +4535,7 @@ Var_Parse(const char **pp, GNode *scope, VarEvalMode emode, FStr *out_val) if (opts.strict) nested_emode = VarEvalMode_UndefOk(nested_emode); v->inUse = true; - (void)Var_Subst(Expr_Str(&expr), scope, nested_emode, - &expanded); + expanded = Var_Subst(Expr_Str(&expr), scope, nested_emode); v->inUse = false; /* TODO: handle errors */ Expr_SetValueOwn(&expr, expanded); @@ -4641,8 +4580,7 @@ Var_Parse(const char **pp, GNode *scope, VarEvalMode emode, FStr *out_val) VarFreeShortLived(v); } - *out_val = expr.value; - return VPR_OK; /* XXX: Is not correct in all cases */ + return expr.value; } static void @@ -4661,9 +4599,7 @@ VarSubstExpr(const char **pp, Buffer *buf, GNode *scope, { const char *p = *pp; const char *nested_p = p; - FStr val; - - (void)Var_Parse(&nested_p, scope, emode, &val); + FStr val = Var_Parse(&nested_p, scope, emode); /* TODO: handle errors */ if (val.str == var_Error || val.str == varUndefined) { @@ -4737,8 +4673,8 @@ VarSubstPlain(const char **pp, Buffer *res) * variables. The other scopes are searched as well. * emode The mode for parsing or evaluating subexpressions. */ -VarParseResult -Var_Subst(const char *str, GNode *scope, VarEvalMode emode, char **out_res) +char * +Var_Subst(const char *str, GNode *scope, VarEvalMode emode) { const char *p = str; Buffer res; @@ -4762,8 +4698,7 @@ Var_Subst(const char *str, GNode *scope, VarEvalMode emode, char **out_res) VarSubstPlain(&p, &res); } - *out_res = Buf_DoneDataCompact(&res); - return VPR_OK; + return Buf_DoneDataCompact(&res); } void @@ -4773,7 +4708,7 @@ Var_Expand(FStr *str, GNode *scope, VarEvalMode emode) if (strchr(str->str, '$') == NULL) return; - (void)Var_Subst(str->str, scope, emode, &expanded); + expanded = Var_Subst(str->str, scope, emode); /* TODO: handle errors */ FStr_Done(str); *str = FStr_InitOwn(expanded); diff --git a/usr.bin/bmake/Makefile b/usr.bin/bmake/Makefile index f94c7d3d2914..ed2f5b3d5e2f 100644 --- a/usr.bin/bmake/Makefile +++ b/usr.bin/bmake/Makefile @@ -12,7 +12,7 @@ CFLAGS+= -I${.CURDIR} CLEANDIRS+= FreeBSD CLEANFILES+= bootstrap -# $Id: Makefile,v 1.123 2023/01/28 02:49:20 sjg Exp $ +# $Id: Makefile,v 1.124 2023/02/25 20:27:44 sjg Exp $ PROG?= ${.CURDIR:T} @@ -140,9 +140,7 @@ SHAREDIR= ${SHAREDIR.bmake:U${prefix}/share} BINDIR= ${BINDIR.bmake:U${prefix}/bin} MANDIR= ${MANDIR.bmake:U${SHAREDIR}/man} -.if !exists(.depend) ${OBJS}: config.h -.endif # A simple unit-test driver to help catch regressions diff --git a/usr.bin/bmake/Makefile.config b/usr.bin/bmake/Makefile.config index a0310f91a5f8..60e86b185246 100644 --- a/usr.bin/bmake/Makefile.config +++ b/usr.bin/bmake/Makefile.config @@ -7,7 +7,7 @@ SRCTOP?= ${.CURDIR:H:H} # things set by configure -_MAKE_VERSION?=20230208 +_MAKE_VERSION?=20230414 prefix?= /usr srcdir= ${SRCTOP}/contrib/bmake diff --git a/usr.bin/bmake/unit-tests/Makefile b/usr.bin/bmake/unit-tests/Makefile index 3214dacda5fc..6594bdd5cd81 100644 --- a/usr.bin/bmake/unit-tests/Makefile +++ b/usr.bin/bmake/unit-tests/Makefile @@ -2,9 +2,9 @@ # See contrib/bmake/bsd.after-import.mk # # $FreeBSD$ -# $Id: Makefile,v 1.191 2023/01/24 06:09:49 sjg Exp $ +# $Id: Makefile,v 1.193 2023/02/25 20:03:25 sjg Exp $ # -# $NetBSD: Makefile,v 1.331 2023/01/24 00:24:02 sjg Exp $ +# $NetBSD: Makefile,v 1.333 2023/02/25 19:30:32 sjg Exp $ # # Unit tests for make(1) # @@ -36,6 +36,21 @@ .MAKE.OS?= ${uname -s:L:sh} .MAKE.UID?= ${id -u:L:sh} +# for many tests we need a TMPDIR that will not collide +# with other users. +.if ${.OBJDIR} != ${.CURDIR} +# easy +TMPDIR:= ${.OBJDIR}/tmp +.elif defined(TMPDIR) +TMPDIR:= ${TMPDIR}/uid${.MAKE.UID} +.else +TMPDIR:= /tmp/uid${.MAKE.UID} +.endif +# make sure it exists +.if !exist(${TMPDIR}) +_!= mkdir -p ${TMPDIR} +.endif + # Each test is in a sub-makefile. # Keep the list sorted. # Any test that is commented out must be ignored in @@ -410,12 +425,16 @@ TESTS+= varname-dot-make-makefiles TESTS+= varname-dot-make-meta-bailiwick TESTS+= varname-dot-make-meta-created TESTS+= varname-dot-make-meta-files +.if ${.MAKE.PATH_FILEMON:Uno:Nktrace:N/dev*} == "" && ${TMPDIR:N/tmp*:N/var/tmp*} != "" +# these tests will not work if TMPDIR is or is a subdir of +# /tmp or /var/tmp TESTS+= varname-dot-make-meta-ignore_filter TESTS+= varname-dot-make-meta-ignore_paths TESTS+= varname-dot-make-meta-ignore_patterns +TESTS+= varname-dot-make-path_filemon +.endif TESTS+= varname-dot-make-meta-prefix TESTS+= varname-dot-make-mode -TESTS+= varname-dot-make-path_filemon TESTS+= varname-dot-make-pid TESTS+= varname-dot-make-ppid TESTS+= varname-dot-make-save_dollars @@ -542,6 +561,9 @@ SED_CMDS.opt-chdir= -e 's,\(nonexistent\).[1-9][0-9]*,\1,' \ -e '/name/s,file,File,' \ -e 's,no such,No such,' \ -e 's,Filename,File name,' + +# meta line numbers can vary based on filemon implementation +SED_CMDS.meta-ignore= -e 's,\(\.meta:\) [1-9][0-9]*:,\1 :,' SED_CMDS.opt-debug-graph1= ${STD_SED_CMDS.dg1} SED_CMDS.opt-debug-graph2= ${STD_SED_CMDS.dg2} SED_CMDS.opt-debug-graph3= ${STD_SED_CMDS.dg3} @@ -575,6 +597,9 @@ SED_CMDS.var-op-shell+= ${STD_SED_CMDS.white-space} SED_CMDS.vardebug+= -e 's,${.SHELL},,' SED_CMDS.varmod-subst-regex+= ${STD_SED_CMDS.regex} SED_CMDS.varparse-errors+= ${STD_SED_CMDS.timestamp} +SED_CMDS.varname-dot-make-meta-ignore_filter+= ${SED_CMDS.meta-ignore} +SED_CMDS.varname-dot-make-meta-ignore_paths+= ${SED_CMDS.meta-ignore} +SED_CMDS.varname-dot-make-meta-ignore_patterns+= ${SED_CMDS.meta-ignore} SED_CMDS.varname-dot-parsedir= -e '/in some cases/ s,^make: "[^"]*,make: ",' SED_CMDS.varname-dot-parsefile= -e '/in some cases/ s,^make: "[^"]*,make: ",' SED_CMDS.varname-dot-shell= -e 's, = /[^ ]*, = (details omitted),g' @@ -717,22 +742,6 @@ LANG= C _MKMSG_TEST= : .endif - -# for many tests we need a TMPDIR that will not collide -# with other users. -.if ${.OBJDIR} != ${.CURDIR} -# easy -TMPDIR:= ${.OBJDIR}/tmp -.elif defined(TMPDIR) -TMPDIR:= ${TMPDIR}/uid${.MAKE.UID} -.else -TMPDIR:= /tmp/uid${.MAKE.UID} -.endif -# make sure it exists -.if !exist(${TMPDIR}) -_!= mkdir -p ${TMPDIR} -.endif - # Some Linux systems such as Fedora have deprecated egrep in favor of grep -E. .if ${.MAKE.OS:NLinux} == "" EGREP= grep -E @@ -772,23 +781,23 @@ LIMIT_RESOURCES?= : # Postprocess the test output to make the output platform-independent. # -# always pretend .MAKE was called 'make' -_SED_CMDS+= -e 's,^${TEST_MAKE:T:S,.,\\.,g}[][0-9]*:,make:,' -_SED_CMDS+= -e 's,${TEST_MAKE:S,.,\\.,g},make,' -_SED_CMDS+= -e 's,^usage: ${TEST_MAKE:T:S,.,\\.,g} ,usage: make ,' -# replace anything after 'stopped in' with unit-tests +# Replace anything after 'stopped in' with unit-tests _SED_CMDS+= -e '/stopped/s, /.*, unit-tests,' # Allow the test files to be placed anywhere. _SED_CMDS+= -e 's,\(\.PARSEDIR}\) = `'"/[^']*'"',\1 = ,' _SED_CMDS+= -e 's,\(\.INCLUDEDFROMDIR}\) = `'"/[^']*'"',\1 = ,' -_SED_CMDS+= -e 's,${TMPDIR},,g' +_SED_CMDS+= -e 's,${TMPDIR},,g' -e 's,${TMPDIR:tA},,g' # canonicalize ${.OBJDIR} and ${.CURDIR} +_SED_CMDS+= -e 's,${.CURDIR},,g' .if ${.OBJDIR} != ${.CURDIR} # yes this is inaccurate but none of the tests expect anywhere # which we get depending on how MAKEOBJDIR is set. -_SED_CMDS+= -e 's,${.OBJDIR},,g' +_SED_CMDS+= -e 's,${.OBJDIR},,g' -e 's,${.OBJDIR:tA},,g' .endif -_SED_CMDS+= -e 's,${.CURDIR},,g' +# always pretend .MAKE was called 'make' +_SED_CMDS+= -e 's,^${TEST_MAKE:T:S,.,\\.,g}[][0-9]*:,make:,' +_SED_CMDS+= -e 's,${TEST_MAKE:S,.,\\.,g},make,' +_SED_CMDS+= -e 's,^usage: ${TEST_MAKE:T:S,.,\\.,g} ,usage: make ,' _SED_CMDS+= -e 's,/,,g' _SED_CMDS+= -e 's,${UNIT_TESTS:S,.,\\.,g}/,,g' _SED_CMDS+= -e '/MAKE_VERSION/d'