aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSimon J. Gerraty <sjg@FreeBSD.org>2023-04-24 23:46:44 +0000
committerSimon J. Gerraty <sjg@FreeBSD.org>2023-04-24 23:50:16 +0000
commit8c973ee23d647bbdebd2c12cb51460d80101e11a (patch)
treed5d8ea65136bef5248fefd2ec8c6e91930ab80fb
parent1f782fcc0cf1042c6a08148cde0a81b4c6245e29 (diff)
parent51d8a8b4ac1dd7265e891149e470a803906de2a7 (diff)
downloadsrc-8c973ee23d647bbdebd2c12cb51460d80101e11a.tar.gz
src-8c973ee23d647bbdebd2c12cb51460d80101e11a.zip
Merge bmake-20230414
Merge commit '51d8a8b4ac1dd7265e891149e470a803906de2a7'
-rw-r--r--contrib/bmake/ChangeLog52
-rw-r--r--contrib/bmake/FILES1
-rw-r--r--contrib/bmake/Makefile4
-rw-r--r--contrib/bmake/VERSION2
-rw-r--r--contrib/bmake/arch.c11
-rw-r--r--contrib/bmake/bmake.127
-rw-r--r--contrib/bmake/bmake.cat132
-rw-r--r--contrib/bmake/compat.c9
-rw-r--r--contrib/bmake/cond.c39
-rw-r--r--contrib/bmake/for.c8
-rw-r--r--contrib/bmake/job.c19
-rw-r--r--contrib/bmake/main.c64
-rw-r--r--contrib/bmake/make.127
-rw-r--r--contrib/bmake/make.c6
-rw-r--r--contrib/bmake/make.h52
-rw-r--r--contrib/bmake/meta.c89
-rw-r--r--contrib/bmake/mk/ChangeLog59
-rw-r--r--contrib/bmake/mk/FILES1
-rw-r--r--contrib/bmake/mk/autoconf.mk4
-rw-r--r--contrib/bmake/mk/dirdeps.mk29
-rw-r--r--contrib/bmake/mk/gendirdeps.mk35
-rw-r--r--contrib/bmake/mk/install-mk4
-rw-r--r--contrib/bmake/mk/jobs.mk88
-rw-r--r--contrib/bmake/mk/lib.mk17
-rw-r--r--contrib/bmake/mk/meta.stage.mk6
-rw-r--r--contrib/bmake/mk/meta.sys.mk43
-rw-r--r--contrib/bmake/mk/mk-files.txt29
-rw-r--r--contrib/bmake/mk/prog.mk4
-rw-r--r--contrib/bmake/mk/sys.vars.mk10
-rw-r--r--contrib/bmake/mk/warnings.mk70
-rwxr-xr-x[-rw-r--r--]contrib/bmake/os.sh0
-rw-r--r--contrib/bmake/parse.c36
-rw-r--r--contrib/bmake/suff.c10
-rw-r--r--contrib/bmake/trace.c6
-rw-r--r--contrib/bmake/unit-tests/Makefile63
-rwxr-xr-xcontrib/bmake/unit-tests/cmd-interrupt.exp1
-rwxr-xr-xcontrib/bmake/unit-tests/cmd-interrupt.mk4
-rw-r--r--contrib/bmake/unit-tests/cond-cmp-numeric.exp8
-rw-r--r--contrib/bmake/unit-tests/cond-cmp-numeric.mk11
-rw-r--r--contrib/bmake/unit-tests/cond-cmp-string.exp16
-rw-r--r--contrib/bmake/unit-tests/cond-cmp-string.mk10
-rw-r--r--contrib/bmake/unit-tests/cond-func-empty.exp4
-rw-r--r--contrib/bmake/unit-tests/cond-func-empty.mk47
-rw-r--r--contrib/bmake/unit-tests/cond-short.exp11
-rw-r--r--contrib/bmake/unit-tests/cond-short.mk140
-rw-r--r--contrib/bmake/unit-tests/cond-token-number.exp1
-rw-r--r--contrib/bmake/unit-tests/cond-token-number.mk22
-rw-r--r--contrib/bmake/unit-tests/cond-token-plain.exp1
-rw-r--r--contrib/bmake/unit-tests/cond-token-plain.mk8
-rwxr-xr-xcontrib/bmake/unit-tests/cond-undef-lint.exp3
-rwxr-xr-xcontrib/bmake/unit-tests/dep-var.exp24
-rwxr-xr-xcontrib/bmake/unit-tests/dep-var.mk21
-rw-r--r--contrib/bmake/unit-tests/deptgt-delete_on_error.exp2
-rw-r--r--contrib/bmake/unit-tests/meta-ignore.inc63
-rw-r--r--contrib/bmake/unit-tests/opt-debug-lint.exp2
-rw-r--r--contrib/bmake/unit-tests/opt.mk4
-rw-r--r--contrib/bmake/unit-tests/parse-var.exp6
-rw-r--r--contrib/bmake/unit-tests/parse-var.mk40
-rw-r--r--contrib/bmake/unit-tests/var-eval-short.exp4
-rw-r--r--contrib/bmake/unit-tests/var-scope-cmdline.exp4
-rw-r--r--contrib/bmake/unit-tests/var-scope-cmdline.mk6
-rw-r--r--contrib/bmake/unit-tests/varcmd.mk6
-rw-r--r--contrib/bmake/unit-tests/varmod-ifelse.exp7
-rw-r--r--contrib/bmake/unit-tests/varmod-ifelse.mk66
-rw-r--r--contrib/bmake/unit-tests/varmod-loop.exp6
-rw-r--r--contrib/bmake/unit-tests/varmod-loop.mk24
-rw-r--r--contrib/bmake/unit-tests/varmod-no-match.mk98
-rw-r--r--contrib/bmake/unit-tests/varmod-order-shuffle.mk7
-rw-r--r--contrib/bmake/unit-tests/varmod-order.exp2
-rw-r--r--contrib/bmake/unit-tests/varmod-order.mk16
-rw-r--r--contrib/bmake/unit-tests/varname-dot-make-meta-ignore_filter.exp10
-rw-r--r--contrib/bmake/unit-tests/varname-dot-make-meta-ignore_filter.mk7
-rw-r--r--contrib/bmake/unit-tests/varname-dot-make-meta-ignore_paths.exp10
-rw-r--r--contrib/bmake/unit-tests/varname-dot-make-meta-ignore_paths.mk7
-rw-r--r--contrib/bmake/unit-tests/varname-dot-make-meta-ignore_patterns.exp10
-rw-r--r--contrib/bmake/unit-tests/varname-dot-make-meta-ignore_patterns.mk7
-rw-r--r--contrib/bmake/unit-tests/varname-dot-makeflags.exp11
-rw-r--r--contrib/bmake/unit-tests/varname-dot-makeflags.mk39
-rw-r--r--contrib/bmake/unit-tests/varname-dot-makeoverrides.exp7
-rw-r--r--contrib/bmake/unit-tests/varname-dot-makeoverrides.mk25
-rw-r--r--contrib/bmake/unit-tests/varname-makeflags.exp20
-rw-r--r--contrib/bmake/unit-tests/varname-makeflags.mk182
-rw-r--r--contrib/bmake/unit-tests/varparse-errors.exp8
-rw-r--r--contrib/bmake/unit-tests/varparse-errors.mk3
-rw-r--r--contrib/bmake/var.c281
-rw-r--r--usr.bin/bmake/Makefile4
-rw-r--r--usr.bin/bmake/Makefile.config2
-rw-r--r--usr.bin/bmake/unit-tests/Makefile63
88 files changed, 1594 insertions, 753 deletions
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 <sjg@beast.crufty.net>
+
+ * VERSION (_MAKE_VERSION): 20230414
+ Merge with NetBSD make, pick up
+ o minor cleanup
+
+2023-03-25 Simon J Gerraty <sjg@beast.crufty.net>
+
+ * 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 <sjg@beast.crufty.net>
+
+ * VERSION (_MAKE_VERSION): 20230321
+ Merge with NetBSD make, pick up
+ * make.1: document seemingly unexplained Error code 6.
+
+2023-03-18 Simon J Gerraty <sjg@beast.crufty.net>
+
+ * 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 <sjg@beast.crufty.net>
+
+ * VERSION (_MAKE_VERSION): 20230303
+ Merge with NetBSD make, pick up
+ o several updated unit-tests
+
+2023-02-22 Simon J Gerraty <sjg@beast.crufty.net>
+
+ * 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 <sjg@beast.crufty.net>
+
+ * 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 <sjg@beast.crufty.net>
+
+ * 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 <sjg@beast.crufty.net>
* 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 @@ rearg:
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 <sys/cdefs.h>
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 <sjg@beast.crufty.net>
+
+ * 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 <sjg@beast.crufty.net>
+
+ * dirdeps.mk: check we were not included by
+ Makefile.depend.options as the result is bad.
+
+2023-04-14 Simon J Gerraty <sjg@beast.crufty.net>
+
+ * 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 <sjg@beast.crufty.net>
+
+ * Add jobs.mk
+
+2023-03-21 Simon J Gerraty <sjg@beast.crufty.net>
+
+ * 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 <sjg@beast.crufty.net>
+
+ * sys.vars.mk: add M_Index to report the index of a word in a list.
+
+2023-02-15 Simon J Gerraty <sjg@beast.crufty.net>
+
+ * 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 <sjg@beast.crufty.net>
* 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 <local.dirdeps-missing.mk>
.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 <sjg@crufty.net>
# 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 <jobs.mk>
+# .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 <local.meta.sys.mk>
+.-include <local.meta.sys.env.mk>
+
+# 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 <local.meta.sys.mk>
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 <warnings-sets.mk>
+# This is more in keeping with our current practice
+.-include <local.warnings.mk>
# 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
index 6bf52420c90f..6bf52420c90f 100644..100755
--- a/contrib/bmake/os.sh
+++ b/contrib/bmake/os.sh
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 <line>:,'
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},</path/to/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: "<normalized>,'
SED_CMDS.varname-dot-parsefile= -e '/in some cases/ s,^make: "[^"]*,make: "<normalized>,'
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 = <some-dir>,'
_SED_CMDS+= -e 's,\(\.INCLUDEDFROMDIR}\) = `'"/[^']*'"',\1 = <some-dir>,'
-_SED_CMDS+= -e 's,${TMPDIR},<tmpdir>,g'
+_SED_CMDS+= -e 's,${TMPDIR},<tmpdir>,g' -e 's,${TMPDIR:tA},<tmpdir>,g'
# canonicalize ${.OBJDIR} and ${.CURDIR}
+_SED_CMDS+= -e 's,${.CURDIR},<curdir>,g'
.if ${.OBJDIR} != ${.CURDIR}
# yes this is inaccurate but none of the tests expect <objdir> anywhere
# which we get depending on how MAKEOBJDIR is set.
-_SED_CMDS+= -e 's,${.OBJDIR},<curdir>,g'
+_SED_CMDS+= -e 's,${.OBJDIR},<curdir>,g' -e 's,${.OBJDIR:tA},<curdir>,g'
.endif
-_SED_CMDS+= -e 's,${.CURDIR},<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,<curdir>/,,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
+# 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
-# 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
+# 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.
+#
+# 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
-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.
+# Since the condition is relevant, the indirect undefined variable is
+# evaluated as usual, resolving nested undefined expressions 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.
+# 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
+. error
+.endif
+
+# Due to the quotes around the left-hand side of the '<', the operand is
+# marked as a string, thus preventing a numerical comparison.
#
-# 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
+# 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 '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
+# The right-hand side of '||' is irrelevant and thus not evaluated.
+.if 1 || ${INDIR_NUMBER} < ${NUMBER}
.else
-x= Fail
+. error
+.endif
+
+# The right-hand side of '||' is relevant and thus evaluated normally.
+.if 0 || ${INDIR_NUMBER} < ${NUMBER}
+. error
.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 '||' 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
-x= Fail
+. error
.endif
-x!= echo '0 || $${iV2:U2} < $${V42}: $x' >&2; echo
+
# 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
+
+# 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: # nothing
+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,{,{{,},<lbraces>,})
-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 '<lbraces>'.
BRACE_GROUP= {{{{}}}}
# The inner ':S' modifier turns the word '{}' into '{{}'.
# The outer ':S' modifier then replaces '{{}' with '<lbraces>'.
-# 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,{,{{,},<lbraces>,}
.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,{,{{,},<lbraces>,}
.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 <tmpdir>/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
+<tmpdir>/obj/check-ignore.meta: <line>: file '<tmpdir>/ignore/check' is newer than the target...
+Building <tmpdir>/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 <tmpdir>/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
+<tmpdir>/obj/check-ignore.meta: <line>: file '<tmpdir>/ignore/check' is newer than the target...
+Building <tmpdir>/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 <tmpdir>/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
+<tmpdir>/obj/check-ignore.meta: <line>: file '<tmpdir>/ignore/check' is newer than the target...
+Building <tmpdir>/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=<undefined>
+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=<undefined>
+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
+
+.info MAKEFLAGS=<${MAKEFLAGS:Uundefined}>
+.info .MAKEFLAGS=<${.MAKEFLAGS}>
+.info .MAKEOVERRIDES=<${.MAKEOVERRIDES:Uundefined}>
+
+# Append an option with argument, a plain option and a variable assignment.
+.MAKEFLAGS: -DVARNAME -r VAR=value
+
+# expect+1: MAKEFLAGS=<undefined>
+.info MAKEFLAGS=<${MAKEFLAGS:Uundefined}>
+# expect+1: .MAKEFLAGS=< -r -k -D VARNAME -r>
+.info .MAKEFLAGS=<${.MAKEFLAGS}>
+# expect+1: .MAKEOVERRIDES=< VAR>
+.info .MAKEOVERRIDES=<${.MAKEOVERRIDES}>
-# 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"
+# 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
-all:
- echo "$$MAKEFLAGS"
- @:;
+# 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=<value>
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'.
+
+all: spaces_stage_0 dollars_stage_0 append_stage_0 override_stage_0
-# TODO: Implementation
-.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
+
+
+# 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
-all:
+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 @@ found_op:
*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 @@ cleanup:
* 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;
- }
-
- if (emode == VARE_UNDEFERR) {
- *out_val = FStr_InitRefer(var_Error);
- return VPR_UNDEF; /* XXX: Should be VPR_ERR instead. */
+ return FStr_InitRefer(var_Error);
}
- *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 <line>:,'
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},</path/to/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: "<normalized>,'
SED_CMDS.varname-dot-parsefile= -e '/in some cases/ s,^make: "[^"]*,make: "<normalized>,'
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 = <some-dir>,'
_SED_CMDS+= -e 's,\(\.INCLUDEDFROMDIR}\) = `'"/[^']*'"',\1 = <some-dir>,'
-_SED_CMDS+= -e 's,${TMPDIR},<tmpdir>,g'
+_SED_CMDS+= -e 's,${TMPDIR},<tmpdir>,g' -e 's,${TMPDIR:tA},<tmpdir>,g'
# canonicalize ${.OBJDIR} and ${.CURDIR}
+_SED_CMDS+= -e 's,${.CURDIR},<curdir>,g'
.if ${.OBJDIR} != ${.CURDIR}
# yes this is inaccurate but none of the tests expect <objdir> anywhere
# which we get depending on how MAKEOBJDIR is set.
-_SED_CMDS+= -e 's,${.OBJDIR},<curdir>,g'
+_SED_CMDS+= -e 's,${.OBJDIR},<curdir>,g' -e 's,${.OBJDIR:tA},<curdir>,g'
.endif
-_SED_CMDS+= -e 's,${.CURDIR},<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,<curdir>/,,g'
_SED_CMDS+= -e 's,${UNIT_TESTS:S,.,\\.,g}/,,g'
_SED_CMDS+= -e '/MAKE_VERSION/d'