Merge bmake-20230414

Merge commit '51d8a8b4ac1dd7265e891149e470a803906de2a7'
This commit is contained in:
Simon J. Gerraty 2023-04-24 16:46:44 -07:00
commit 8c973ee23d
88 changed files with 1595 additions and 754 deletions

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -1,2 +1,2 @@
# keep this compatible with sh and make
_MAKE_VERSION=20230208
_MAKE_VERSION=20230414

View File

@ -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);

View File

@ -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

View File

@ -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

Before

Width:  |  Height:  |  Size: 84 KiB

After

Width:  |  Height:  |  Size: 85 KiB

View File

@ -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') {

View File

@ -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)

View File

@ -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;
}

View File

@ -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 */
}

View File

@ -1,4 +1,4 @@
/* $NetBSD: main.c,v 1.589 2023/01/26 20:48:17 sjg Exp $ */
/* $NetBSD: main.c,v 1.593 2023/03/28 14:39:31 rillig Exp $ */
/*
* Copyright (c) 1988, 1989, 1990, 1993
@ -111,7 +111,7 @@
#include "trace.h"
/* "@(#)main.c 8.3 (Berkeley) 3/19/94" */
MAKE_RCSID("$NetBSD: main.c,v 1.589 2023/01/26 20:48:17 sjg Exp $");
MAKE_RCSID("$NetBSD: main.c,v 1.593 2023/03/28 14:39:31 rillig Exp $");
#if defined(MAKE_NATIVE) && !defined(lint)
__COPYRIGHT("@(#) Copyright (c) 1988, 1989, 1990, 1993 "
"The Regents of the University of California. "
@ -129,7 +129,7 @@ bool allPrecious; /* .PRECIOUS given on line by itself */
bool deleteOnError; /* .DELETE_ON_ERROR: set */
static int maxJobTokens; /* -j argument */
bool enterFlagObj; /* -w and objdir != srcdir */
static bool enterFlagObj; /* -w and objdir != srcdir */
static int jp_0 = -1, jp_1 = -1; /* ends of parent job pipe */
bool doing_depend; /* Set while reading .depend */
@ -436,7 +436,7 @@ MainParseArgSysInc(const char *argvalue)
}
static bool
MainParseArg(char c, const char *argvalue)
MainParseOption(char c, const char *argvalue)
{
switch (c) {
case '\0':
@ -444,7 +444,7 @@ MainParseArg(char c, const char *argvalue)
case 'B':
opts.compatMake = true;
Global_Append(MAKEFLAGS, "-B");
Global_Set(MAKE_MODE, "compat");
Global_Set(".MAKE.MODE", "compat");
break;
case 'C':
MainParseArgChdir(argvalue);
@ -628,7 +628,7 @@ MainParseArgs(int argc, char **argv)
dashDash = true;
break;
default:
if (!MainParseArg(c, argvalue))
if (!MainParseOption(c, argvalue))
goto noarg;
}
argv += arginc;
@ -806,9 +806,8 @@ siginfo(int signo MAKE_ATTR_UNUSED)
static void
MakeMode(void)
{
char *mode;
(void)Var_Subst("${" MAKE_MODE ":tl}", SCOPE_GLOBAL, VARE_WANTRES, &mode);
char *mode = Var_Subst("${.MAKE.MODE:tl}",
SCOPE_GLOBAL, VARE_WANTRES);
/* TODO: handle errors */
if (mode[0] != '\0') {
@ -831,16 +830,14 @@ static void
PrintVar(const char *varname, bool expandVars)
{
if (strchr(varname, '$') != NULL) {
char *evalue;
(void)Var_Subst(varname, SCOPE_GLOBAL, VARE_WANTRES, &evalue);
char *evalue = Var_Subst(varname, SCOPE_GLOBAL, VARE_WANTRES);
/* TODO: handle errors */
printf("%s\n", evalue);
free(evalue);
} else if (expandVars) {
char *expr = str_concat3("${", varname, "}");
char *evalue;
(void)Var_Subst(expr, SCOPE_GLOBAL, VARE_WANTRES, &evalue);
char *evalue = Var_Subst(expr, SCOPE_GLOBAL, VARE_WANTRES);
/* TODO: handle errors */
free(expr);
printf("%s\n", evalue);
@ -866,7 +863,7 @@ GetBooleanExpr(const char *expr, bool fallback)
char *value;
bool res;
(void)Var_Subst(expr, SCOPE_GLOBAL, VARE_WANTRES, &value);
value = Var_Subst(expr, SCOPE_GLOBAL, VARE_WANTRES);
/* TODO: handle errors */
res = ParseBoolean(value, fallback);
free(value);
@ -1098,6 +1095,11 @@ UnlimitFiles(void)
struct rlimit rl;
if (getrlimit(RLIMIT_NOFILE, &rl) != -1 &&
rl.rlim_cur != rl.rlim_max) {
#ifdef BMAKE_NOFILE_MAX
if (BMAKE_NOFILE_MAX < rl.rlim_max)
rl.rlim_cur = BMAKE_NOFILE_MAX;
else
#endif
rl.rlim_cur = rl.rlim_max;
(void)setrlimit(RLIMIT_NOFILE, &rl);
}
@ -1232,7 +1234,7 @@ InitMaxJobs(void)
!Var_Exists(SCOPE_GLOBAL, ".MAKE.JOBS"))
return;
(void)Var_Subst("${.MAKE.JOBS}", SCOPE_GLOBAL, VARE_WANTRES, &value);
value = Var_Subst("${.MAKE.JOBS}", SCOPE_GLOBAL, VARE_WANTRES);
/* TODO: handle errors */
n = (int)strtol(value, NULL, 0);
if (n < 1) {
@ -1267,7 +1269,7 @@ InitVpath(void)
if (!Var_Exists(SCOPE_CMDLINE, "VPATH"))
return;
(void)Var_Subst("${VPATH}", SCOPE_CMDLINE, VARE_WANTRES, &vpath);
vpath = Var_Subst("${VPATH}", SCOPE_CMDLINE, VARE_WANTRES);
/* TODO: handle errors */
path = vpath;
do {
@ -1303,10 +1305,8 @@ ReadFirstDefaultMakefile(void)
{
StringList makefiles = LST_INIT;
StringListNode *ln;
char *prefs;
(void)Var_Subst("${" MAKE_MAKEFILE_PREFERENCE "}",
SCOPE_CMDLINE, VARE_WANTRES, &prefs);
char *prefs = Var_Subst("${.MAKE.MAKEFILE_PREFERENCE}",
SCOPE_CMDLINE, VARE_WANTRES);
/* TODO: handle errors */
(void)str2Lst_Append(&makefiles, prefs);
@ -1384,7 +1384,7 @@ main_Init(int argc, char **argv)
/* This is the traditional preference for makefiles. */
# define MAKEFILE_PREFERENCE_LIST "makefile Makefile"
#endif
Global_Set(MAKE_MAKEFILE_PREFERENCE, MAKEFILE_PREFERENCE_LIST);
Global_Set(".MAKE.MAKEFILE_PREFERENCE", MAKEFILE_PREFERENCE_LIST);
Global_Set(".MAKE.DEPENDFILE", ".depend");
CmdOpts_Init();
@ -1410,7 +1410,7 @@ main_Init(int argc, char **argv)
Parse_Init();
InitVarMake(argv[0]);
Global_Set(MAKEFLAGS, "");
Global_Set(MAKEOVERRIDES, "");
Global_Set(".MAKEOVERRIDES", "");
Global_Set("MFLAGS", "");
Global_Set(".ALLTARGETS", "");
Var_Set(SCOPE_CMDLINE, ".MAKE.LEVEL.ENV", MAKE_LEVEL_ENV);
@ -1423,7 +1423,7 @@ main_Init(int argc, char **argv)
if (makelevel < 0)
makelevel = 0;
snprintf(buf, sizeof buf, "%d", makelevel);
Global_Set(MAKE_LEVEL, buf);
Global_Set(".MAKE.LEVEL", buf);
snprintf(buf, sizeof buf, "%u", myPid);
Global_Set_ReadOnly(".MAKE.PID", buf);
snprintf(buf, sizeof buf, "%u", getppid());
@ -1525,8 +1525,8 @@ main_PrepareMaking(void)
{
/* In particular suppress .depend for '-r -V .OBJDIR -f /dev/null' */
if (!opts.noBuiltins || opts.printVars == PVM_NONE) {
(void)Var_Subst("${.MAKE.DEPENDFILE}",
SCOPE_CMDLINE, VARE_WANTRES, &makeDependfile);
makeDependfile = Var_Subst("${.MAKE.DEPENDFILE}",
SCOPE_CMDLINE, VARE_WANTRES);
if (makeDependfile[0] != '\0') {
/* TODO: handle errors */
doing_depend = true;
@ -2088,9 +2088,9 @@ PrintOnError(GNode *gn, const char *msg)
SetErrorVars(gn);
{
char *errorVarsValues;
(void)Var_Subst("${MAKE_PRINT_VAR_ON_ERROR:@v@$v='${$v}'\n@}",
SCOPE_GLOBAL, VARE_WANTRES, &errorVarsValues);
char *errorVarsValues = Var_Subst(
"${MAKE_PRINT_VAR_ON_ERROR:@v@$v='${$v}'\n@}",
SCOPE_GLOBAL, VARE_WANTRES);
/* TODO: handle errors */
printf("%s", errorVarsValues);
free(errorVarsValues);
@ -2118,9 +2118,9 @@ Main_ExportMAKEFLAGS(bool first)
return;
once = false;
(void)Var_Subst(
flags = Var_Subst(
"${.MAKEFLAGS} ${.MAKEOVERRIDES:O:u:@v@$v=${$v:Q}@}",
SCOPE_CMDLINE, VARE_WANTRES, &flags);
SCOPE_CMDLINE, VARE_WANTRES);
/* TODO: handle errors */
if (flags[0] != '\0') {
#ifdef POSIX
@ -2141,8 +2141,8 @@ getTmpdir(void)
return tmpdir;
/* Honor $TMPDIR if it is valid, strip a trailing '/'. */
(void)Var_Subst("${TMPDIR:tA:U" _PATH_TMP ":S,/$,,W}/",
SCOPE_GLOBAL, VARE_WANTRES, &tmpdir);
tmpdir = Var_Subst("${TMPDIR:tA:U" _PATH_TMP ":S,/$,,W}/",
SCOPE_GLOBAL, VARE_WANTRES);
/* TODO: handle errors */
if (stat(tmpdir, &st) < 0 || !S_ISDIR(st.st_mode)) {

View File

@ -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

View File

@ -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. */

View File

@ -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>

View File

@ -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) {

View File

@ -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.

View File

@ -20,6 +20,7 @@ inc.mk
init.mk
install-mk
java.mk
jobs.mk
ldorder.mk
lib.mk
libnames.mk

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

88
contrib/bmake/mk/jobs.mk Normal file
View File

@ -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}`"

View File

@ -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)

View File

@ -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

View File

@ -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>

View File

@ -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

View File

@ -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}

View File

@ -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:}@

View File

@ -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

0
contrib/bmake/os.sh Normal file → Executable file
View File

View File

@ -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 */

View File

@ -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 */
{

View File

@ -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",

View File

@ -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'

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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:
@:;

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -1,4 +1,4 @@
# $NetBSD: cond-short.mk,v 1.19 2021/12/27 18:54:19 rillig Exp $
# $NetBSD: cond-short.mk,v 1.20 2023/03/04 13:42:36 rillig Exp $
#
# Demonstrates that in conditions, the right-hand side of an && or ||
# is only evaluated if it can actually influence the result.
@ -135,28 +135,32 @@ VAR= # empty again, for the following tests
.elif ${echo "unexpected nested or" 1>&2 :L:sh}
.endif
# make sure these do not cause complaint
#.MAKEFLAGS: -dc
# TODO: Rewrite this whole section and check all the conditions and variables.
# Several of the assumptions are probably wrong here.
# TODO: replace 'x=' with '.info' or '.error'.
V42= 42
iV1= ${V42}
iV2= ${V66}
NUMBER= 42
INDIR_NUMBER= ${NUMBER}
INDIR_UNDEF= ${UNDEF}
.if defined(V42) && ${V42} > 0
x= Ok
.if defined(NUMBER) && ${NUMBER} > 0
.else
x= Fail
. error
.endif
x!= echo 'defined(V42) && $${V42} > 0: $x' >&2; echo
# With cond.c 1.76 from 2020-07-03, the following condition triggered a
# warning: "String comparison operator should be either == or !=".
# This was because the variable expression ${iV2} was defined, but the
# contained variable V66 was undefined. The left-hand side of the comparison
# therefore evaluated to the string "${V66}", which is obviously not a number.
# Starting with var.c 1.226 from from 2020-07-02, the following condition
# triggered a warning: "String comparison operator should be either == or !=".
#
# The left-hand side of the '&&' evaluated to false, which should have made
# the right-hand side irrelevant.
#
# On the right-hand side of the '&&', the expression ${INDIR_UNDEF} was
# defined and had the value '${UNDEF}', but the nested variable UNDEF was
# undefined. The right hand side "${INDIR_UNDEF}" still needed to be parsed,
# and in parse-only mode, the "value" of the parsed expression was the
# uninterpreted variable value, in this case '${UNDEF}'. And even though the
# right hand side of the '&&' should have been irrelevant, the two sides of
# the comparison were still parsed and evaluated. Comparing these two values
# numerically was not possible since the string '${UNDEF}' is not a number,
# so the comparison fell back to string comparison, which then complained
# about the '>' operator.
#
# This was fixed in cond.c 1.79 from 2020-07-09 by not evaluating irrelevant
# comparisons. Instead, they are only parsed and then discarded.
@ -164,59 +168,77 @@ x!= echo 'defined(V42) && $${V42} > 0: $x' >&2; echo
# At that time, there was not enough debug logging to see the details in the
# -dA log. To actually see it, add debug logging at the beginning and end of
# Var_Parse.
.if defined(V66) && ( ${iV2} < ${V42} )
x= Fail
.else
x= Ok
.if defined(UNDEF) && ${INDIR_UNDEF} < ${NUMBER}
. error
.endif
# XXX: This condition doesn't match the one above. The quotes are missing
# above. This is a crucial detail since without quotes, the variable
# expression ${iV2} evaluates to "${V66}", and with quotes, it evaluates to ""
# since undefined variables are allowed and expand to an empty string.
x!= echo 'defined(V66) && ( "$${iV2}" < $${V42} ): $x' >&2; echo
.if 1 || ${iV1} < ${V42}
x= Ok
.else
x= Fail
# Adding a ':U' modifier to the irrelevant expression didn't help, as that
# expression was only parsed, not evaluated. The resulting literal string
# '${INDIR_UNDEF:U2}' was not numeric either, for the same reason as above.
.if defined(UNDEF) && ${INDIR_UNDEF:U2} < ${NUMBER}
. error
.endif
x!= echo '1 || $${iV1} < $${V42}: $x' >&2; echo
# With cond.c 1.76 from 2020-07-03, the following condition triggered a
# warning: "String comparison operator should be either == or !=".
# This was because the variable expression ${iV2} was defined, but the
# contained variable V66 was undefined. The left-hand side of the comparison
# therefore evaluated to the string "${V66}", which is obviously not a number.
# Enclosing the expression in double quotes changes how that expression is
# evaluated. In irrelevant expressions that are enclosed in double quotes,
# expressions based on undefined variables are allowed and evaluate to an
# empty string.
#
# This was fixed in cond.c 1.79 from 2020-07-09 by not evaluating irrelevant
# comparisons. Instead, they are only parsed and then discarded.
# The manual page stated from at least 1993 on that irrelevant conditions were
# not evaluated, but that was wrong. These conditions were evaluated, the
# only difference was that undefined variables in them didn't trigger an
# error. Since numeric conditions are quite rare, this subtle difference
# didn't catch much attention, as most other conditions such as pattern
# matches or equality comparisons worked fine and never produced error
# messages.
.if defined(UNDEF) && "${INDIR_UNDEF}" < ${NUMBER}
. error
.endif
# Since the condition is relevant, the indirect undefined variable is
# evaluated as usual, resolving nested undefined expressions to an empty
# string.
#
# At that time, there was not enough debug logging to see the details in the
# -dA log. To actually see it, add debug logging at the beginning and end of
# Var_Parse.
.if 1 || ${iV2:U2} < ${V42}
x= Ok
# Comparing an empty string numerically is not possible, however, make has an
# ugly hack in TryParseNumber that treats an empty string as a valid numerical
# value, thus hiding bugs in the makefile.
.if ${INDIR_UNDEF} < ${NUMBER}
# only due to the ugly hack
.else
x= Fail
. error
.endif
x!= echo '1 || $${iV2:U2} < $${V42}: $x' >&2; echo
# the same expressions are fine when the lhs is expanded
# ${iV1} expands to 42
.if 0 || ${iV1} <= ${V42}
x= Ok
# Due to the quotes around the left-hand side of the '<', the operand is
# marked as a string, thus preventing a numerical comparison.
#
# expect+1: Comparison with '<' requires both operands '' and '42' to be numeric
.if "${INDIR_UNDEF}" < ${NUMBER}
. info yes
.else
x= Fail
. info no
.endif
x!= echo '0 || $${iV1} <= $${V42}: $x' >&2; echo
# ${iV2:U2} expands to 2
.if 0 || ${iV2:U2} < ${V42}
x= Ok
# The right-hand side of '||' is irrelevant and thus not evaluated.
.if 1 || ${INDIR_NUMBER} < ${NUMBER}
.else
x= Fail
. error
.endif
x!= echo '0 || $${iV2:U2} < $${V42}: $x' >&2; echo
# The right-hand side of '||' is relevant and thus evaluated normally.
.if 0 || ${INDIR_NUMBER} < ${NUMBER}
. error
.endif
# The right-hand side of '||' evaluates to an empty string, as the variable
# 'INDIR_UNDEF' is defined, therefore the modifier ':U2' has no effect.
# Comparing an empty string numerically is not possible, however, make has an
# ugly hack in TryParseNumber that treats an empty string as a valid numerical
# value, thus hiding bugs in the makefile.
.if 0 || ${INDIR_UNDEF:U2} < ${NUMBER}
# only due to the ugly hack
.else
. error
.endif
# The right-hand side of the '&&' is irrelevant since the left-hand side
# already evaluates to false. Before cond.c 1.79 from 2020-07-09, it was
@ -229,8 +251,8 @@ x!= echo '0 || $${iV2:U2} < $${V42}: $x' >&2; echo
# Ensure that irrelevant conditions do not influence the result of the whole
# condition. As of cond.c 1.302 from 2021-12-11, an irrelevant function call
# evaluates to true (see CondParser_FuncCall and CondParser_FuncCallEmpty), an
# irrelevant comparison evaluates to false (see CondParser_Comparison).
# evaluated to true (see CondParser_FuncCall and CondParser_FuncCallEmpty), an
# irrelevant comparison evaluated to false (see CondParser_Comparison).
#
# An irrelevant true bubbles up to the outermost CondParser_And, where it is
# ignored. An irrelevant false bubbles up to the outermost CondParser_Or,

View File

@ -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

View File

@ -1,4 +1,4 @@
# $NetBSD: cond-token-number.mk,v 1.7 2022/01/02 02:57:39 rillig Exp $
# $NetBSD: cond-token-number.mk,v 1.8 2023/03/04 08:07:29 rillig Exp $
#
# Tests for number tokens in .if conditions.
#
@ -85,7 +85,21 @@ HEX= dead
. error
.endif
# Ensure that parsing continues until here.
.info End of the tests.
# Very small numbers round to 0.
.if 12345e-400
. error
.endif
.if 12345e-200
.else
. error
.endif
all: # nothing
# Very large numbers round up to infinity on IEEE 754 implementations, or to
# the largest representable number (VAX); in particular, make does not fall
# back to checking whether a variable of that name is defined.
.if 12345e400
.else
. error
.endif
all:

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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?

View File

@ -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

View File

@ -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

View File

@ -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 "${"

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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:

View File

@ -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

View File

@ -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:
@:;

View File

@ -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

View File

@ -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

View File

@ -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:

View File

@ -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

View File

@ -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"

View File

@ -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

View File

@ -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"

View File

@ -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

View File

@ -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"

View File

@ -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

View File

@ -1,15 +1,36 @@
# $NetBSD: varname-dot-makeflags.mk,v 1.1 2020/12/01 20:37:30 rillig Exp $
# $NetBSD: varname-dot-makeflags.mk,v 1.7 2023/02/25 19:24:07 rillig Exp $
#
# Tests for the special .MAKEFLAGS variable, which collects almost all
# command line arguments and passes them on to any child processes via
# the environment variable MAKEFLAGS (without leading '.').
#
# See also:
# varname-dot-makeoverrides.mk
# When options are parsed, the option and its argument are appended as
# separate words to .MAKEFLAGS. Special characters in the option argument
# are not quoted though. It seems to have not been necessary at least from
# 1993 until 2020.
.MAKEFLAGS: -d00000 -D"VARNAME WITH SPACES"
.info MAKEFLAGS=<${MAKEFLAGS:Uundefined}>
.info .MAKEFLAGS=<${.MAKEFLAGS}>
.info .MAKEOVERRIDES=<${.MAKEOVERRIDES:Uundefined}>
all:
echo "$$MAKEFLAGS"
@:;
# Append an option with argument, a plain option and a variable assignment.
.MAKEFLAGS: -DVARNAME -r VAR=value
# expect+1: MAKEFLAGS=<undefined>
.info MAKEFLAGS=<${MAKEFLAGS:Uundefined}>
# expect+1: .MAKEFLAGS=< -r -k -D VARNAME -r>
.info .MAKEFLAGS=<${.MAKEFLAGS}>
# expect+1: .MAKEOVERRIDES=< VAR>
.info .MAKEOVERRIDES=<${.MAKEOVERRIDES}>
# The environment variable 'MAKEFLAGS' is not available to child processes
# when parsing the makefiles. This is different from exported variables,
# which are already available during parse time.
.if ${:!echo "\${MAKEFLAGS-undef}"!} != "undef"
. error
.endif
# After parsing, the environment variable 'MAKEFLAGS' is set based on the
# special variables '.MAKEFLAGS' and '.MAKEOVERRIDES'.
runtime:
@echo '$@: MAKEFLAGS=<'${MAKEFLAGS:Q}'>'
@echo '$@: .MAKEFLAGS=<'${.MAKEFLAGS:Q}'>'
@echo '$@: .MAKEOVERRIDES=<'${.MAKEOVERRIDES:Q}'>'

View File

@ -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

View File

@ -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}'>'

View File

@ -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

View File

@ -1,44 +1,182 @@
# $NetBSD: varname-makeflags.mk,v 1.5 2022/01/16 18:16:06 sjg Exp $
# $NetBSD: varname-makeflags.mk,v 1.7 2023/02/25 19:24:07 rillig Exp $
#
# Tests for the special MAKEFLAGS variable, which is basically just a normal
# environment variable. It is closely related to .MAKEFLAGS but captures the
# state of .MAKEFLAGS at the very beginning of make, before any makefiles are
# read.
# Tests for the environment variable 'MAKEFLAGS', from which additional
# command line arguments are read before the actual command line arguments.
#
# After reading the makefiles and before making the targets, the arguments
# that were collected in '.MAKEFLAGS' and '.MAKEOVERRIDES' are written back to
# the environment variable 'MAKEFLAGS'.
# TODO: Implementation
all: spaces_stage_0 dollars_stage_0 append_stage_0 override_stage_0
.MAKEFLAGS: -d0
.if !make(*stage*)
# The unit tests are run with an almost empty environment. In particular,
# the variable MAKEFLAGS is not set. The '.MAKEFLAGS:' above also doesn't
# influence the environment variable MAKEFLAGS, therefore it is still
# undefined at this point.
.if ${MAKEFLAGS:Uundefined} != "undefined"
. error
.endif
# the variable MAKEFLAGS is not set.
. if ${MAKEFLAGS:Uundefined} != "undefined"
. error
. endif
# The special variable .MAKEFLAGS is influenced though.
# See varname-dot-makeflags.mk for more details.
.if ${.MAKEFLAGS} != " -r -k -d 0"
. error
.endif
. if ${.MAKEFLAGS} != " -r -k"
. error
. endif
# In POSIX mode, the environment variable MAKEFLAGS can contain letters only,
# for compatibility. These letters are exploded to form regular options.
OUTPUT!= env MAKEFLAGS=ikrs ${MAKE} -f /dev/null -v .MAKEFLAGS
.if ${OUTPUT} != " -i -k -r -s -V .MAKEFLAGS"
. error
.endif
. if ${OUTPUT} != " -i -k -r -s -V .MAKEFLAGS"
. error
. endif
# As soon as there is a single non-alphabetic character in the environment
# variable MAKEFLAGS, it is no longer split. In this example, the word
# "d0ikrs" is treated as a target, but the option '-v' prevents any targets
# from being built.
OUTPUT!= env MAKEFLAGS=d0ikrs ${MAKE} -r -f /dev/null -v .MAKEFLAGS
.if ${OUTPUT} != " -r -V .MAKEFLAGS"
. error ${OUTPUT}
. if ${OUTPUT} != " -r -V .MAKEFLAGS"
. error ${OUTPUT}
. endif
.endif
all:
# When options are parsed, the option and its argument are appended as
# separate words to the MAKEFLAGS for the child processes. Special characters
# in the option arguments are not quoted though.
spaces_stage_0:
@echo '$@: MAKEFLAGS=<'${MAKEFLAGS:Q}'>'
@echo "$@: env MAKEFLAGS=<$$MAKEFLAGS>"
@${MAKE} -f ${MAKEFILE} spaces_stage_1 -d00000 -D"VARNAME WITH SPACES"
# At this point, the 'VARNAME WITH SPACES' is no longer recognizable as a
# single command line argument. In practice, variable names don't contain
# spaces.
spaces_stage_1:
@echo '$@: MAKEFLAGS=<'${MAKEFLAGS:Q}'>'
@echo "$@: env MAKEFLAGS=<$$MAKEFLAGS>"
# Demonstrate that '$' characters are altered when they are passed on to child
# make processes via MAKEFLAGS.
dollars_stage_0:
@echo '$@: MAKEFLAGS=<'${MAKEFLAGS:Q}'>'
# The '$$$$' becomes a literal '$$' when building the '${MAKE}'
# command line, making the actual argument 'DOLLARS=$${varname}'.
# At this stage, MAKEFLAGS is not yet involved.
@${MAKE} -f ${MAKEFILE} dollars_stage_1 DOLLARS='$$$${varname}'
.if make(dollars_stage_1)
# At this point, the variable 'DOLLARS' contains '$${varname}', which
# evaluates to a literal '$' followed by '{varname}'.
. if ${DOLLARS} != "\${varname}"
. error
. endif
.endif
dollars_stage_1:
# At this point, the stage 1 make provides the environment variable
# 'MAKEFLAGS' to its child processes, even if the child process is not
# another make.
#
# expect: dollars_stage_1: env MAKEFLAGS=< -r -k DOLLARS=\$\{varname\}>
#
# The 'DOLLARS=\$\{varname\}' assignment is escaped so that the stage
# 2 make will see it as a single word.
@echo "$@: env MAKEFLAGS=<$$MAKEFLAGS>"
# At this point, evaluating the environment variable 'MAKEFLAGS' leads
# to strange side effects as the string '\$\{varname\}' is interpreted
# as:
#
# \ a literal string of a single backslash
# $\ the value of the variable named '\'
# {varname\} a literal string
#
# Since the variable name '\' is not defined, the resulting value is
# '\{varname\}'. Make doesn't handle isolated '$' characters in
# strings well, instead each '$' has to be part of a '$$' or be part
# of a subexpression like '${VAR}'.
@echo '$@: MAKEFLAGS=<'${MAKEFLAGS:Q}'>'
# The modifier ':q' preserves a '$$' in an expression value instead of
# expanding it to a single '$', but it's already too late, as that
# modifier applies after the expression has been evaluated. Except
# for debug logging, there is no way to process strings that contain
# isolated '$'.
@echo '$@: MAKEFLAGS:q=<'${MAKEFLAGS:q}'>'
@${MAKE} -f ${MAKEFILE} dollars_stage_2
.if make(dollars_stage_2)
# At this point, the variable 'DOLLARS' contains '${varname}', and since
# 'varname' is undefined, that expression evaluates to an empty string.
. if ${DOLLARS} != ""
. error
. endif
varname= varvalue
. if ${DOLLARS} != "varvalue"
. error
. endif
. undef varname
.endif
dollars_stage_2:
@echo "$@: env MAKEFLAGS=<$$MAKEFLAGS>"
@echo '$@: dollars=<'${DOLLARS:Q}'>'
@echo '$@: MAKEFLAGS=<'${MAKEFLAGS:Q}'>'
@${MAKE} -f ${MAKEFILE} dollars_stage_3
dollars_stage_3:
@echo "$@: env MAKEFLAGS=<$$MAKEFLAGS>"
@echo '$@: dollars=<'${DOLLARS:Uundefined:Q}'>'
@echo '$@: MAKEFLAGS=<'${MAKEFLAGS:Q}'>'
# Demonstrates in which exact order the MAKEFLAGS are built together from the
# parent MAKEFLAGS and the flags from the command line, in particular that
# variable assignments are passed at the end, after the options.
append_stage_0:
@echo '$@: MAKEFLAGS=<'${MAKEFLAGS:Q}'>'
@${MAKE} -Dbefore-0 -f ${MAKEFILE} append_stage_1 VAR0=value -Dafter-0
append_stage_1:
@echo '$@: MAKEFLAGS=<'${MAKEFLAGS:Q}'>'
@${MAKE} -Dbefore-1 -f ${MAKEFILE} append_stage_2 VAR1=value -Dafter-1
append_stage_2:
@echo '$@: MAKEFLAGS=<'${MAKEFLAGS:Q}'>'
@${MAKE} -Dbefore-2 -f ${MAKEFILE} append_stage_3 VAR2=value -Dafter-2
append_stage_3:
@echo '$@: MAKEFLAGS=<'${MAKEFLAGS:Q}'>'
# Demonstrates the implementation details of 'MAKEFLAGS', in particular that
# it is an environment variable rather than a global variable.
override_stage_0:
@${MAKE} -f ${MAKEFILE} STAGE=1 VAR=value override_stage_1
.if make(override_stage_1)
# While parsing the makefiles, 'MAKEFLAGS' is the value of the environment
# variable, in this case provided by stage 0.
. if ${MAKEFLAGS:M*} != "-r -k"
. error
. endif
MAKEFLAGS= overridden # temporarily override it
. if ${MAKEFLAGS} != "overridden"
. error
. endif
.undef MAKEFLAGS # make the environment variable visible again
. if ${MAKEFLAGS:M*} != "-r -k"
. error
. endif
.endif
override_stage_1:
@echo '$@: run MAKEFLAGS=<'${MAKEFLAGS:Q}'>'
@${MAKE} -f ${MAKEFILE} STAGE=2 override_stage_2
override_stage_2:
@echo '$@: STAGE=<${STAGE}> VAR=<${VAR}>'

View File

@ -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 ""

View File

@ -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

View File

@ -1,4 +1,4 @@
/* $NetBSD: var.c,v 1.1040 2023/02/09 07:34:15 sjg Exp $ */
/* $NetBSD: var.c,v 1.1049 2023/03/28 14:39:31 rillig Exp $ */
/*
* Copyright (c) 1988, 1989, 1990, 1993
@ -147,7 +147,7 @@
#include "metachar.h"
/* "@(#)var.c 8.3 (Berkeley) 3/19/94" */
MAKE_RCSID("$NetBSD: var.c,v 1.1040 2023/02/09 07:34:15 sjg Exp $");
MAKE_RCSID("$NetBSD: var.c,v 1.1049 2023/03/28 14:39:31 rillig Exp $");
/*
* Variables are defined using one of the VAR=value assignments. Their
@ -336,6 +336,7 @@ static VarExportedMode var_exportedVars = VAR_EXPORTED_NONE;
static const char VarEvalMode_Name[][32] = {
"parse-only",
"parse-balanced",
"eval",
"eval-defined",
"eval-keep-dollar",
@ -529,7 +530,7 @@ Var_Delete(GNode *scope, const char *varname)
if (v->exported)
unsetenv(v->name.str);
if (strcmp(v->name.str, MAKE_EXPORTED) == 0)
if (strcmp(v->name.str, ".MAKE.EXPORTED") == 0)
var_exportedVars = VAR_EXPORTED_NONE;
assert(v->name.freeIt == NULL);
@ -545,7 +546,6 @@ Var_Delete(GNode *scope, const char *varname)
void
Var_Undef(const char *arg)
{
VarParseResult vpr;
char *expanded;
Words varnames;
size_t i;
@ -556,8 +556,9 @@ Var_Undef(const char *arg)
return;
}
vpr = Var_Subst(arg, SCOPE_GLOBAL, VARE_WANTRES, &expanded);
if (vpr != VPR_OK) {
expanded = Var_Subst(arg, SCOPE_GLOBAL, VARE_WANTRES);
if (expanded == var_Error) {
/* TODO: Make this part of the code reachable. */
Parse_Error(PARSE_FATAL,
"Error in variable names to be undefined");
return;
@ -627,7 +628,7 @@ ExportVarEnv(Var *v)
/* XXX: name is injected without escaping it */
expr = str_concat3("${", name, "}");
(void)Var_Subst(expr, SCOPE_GLOBAL, VARE_WANTRES, &val);
val = Var_Subst(expr, SCOPE_GLOBAL, VARE_WANTRES);
/* TODO: handle errors */
setenv(name, val, 1);
free(val);
@ -727,8 +728,8 @@ Var_ReexportVars(void)
return;
}
(void)Var_Subst("${" MAKE_EXPORTED ":O:u}", SCOPE_GLOBAL, VARE_WANTRES,
&xvarnames);
xvarnames = Var_Subst("${.MAKE.EXPORTED:O:u}", SCOPE_GLOBAL,
VARE_WANTRES);
/* TODO: handle errors */
if (xvarnames[0] != '\0') {
Words varnames = Str_Words(xvarnames, false);
@ -760,7 +761,7 @@ ExportVars(const char *varnames, bool isExport, VarExportMode mode)
var_exportedVars = VAR_EXPORTED_SOME;
if (isExport && mode == VEM_PLAIN)
Global_Append(MAKE_EXPORTED, varname);
Global_Append(".MAKE.EXPORTED", varname);
}
Words_Free(words);
}
@ -768,9 +769,7 @@ ExportVars(const char *varnames, bool isExport, VarExportMode mode)
static void
ExportVarsExpand(const char *uvarnames, bool isExport, VarExportMode mode)
{
char *xvarnames;
(void)Var_Subst(uvarnames, SCOPE_GLOBAL, VARE_WANTRES, &xvarnames);
char *xvarnames = Var_Subst(uvarnames, SCOPE_GLOBAL, VARE_WANTRES);
/* TODO: handle errors */
ExportVars(xvarnames, isExport, mode);
free(xvarnames);
@ -795,8 +794,6 @@ Var_ExportVars(const char *varnames)
}
extern char **environ;
static void
ClearEnv(void)
{
@ -846,10 +843,8 @@ GetVarnamesToUnexport(bool isEnv, const char *arg,
}
if (what != UNEXPORT_NAMED) {
char *expanded;
/* Using .MAKE.EXPORTED */
(void)Var_Subst("${" MAKE_EXPORTED ":O:u}", SCOPE_GLOBAL,
VARE_WANTRES, &expanded);
char *expanded = Var_Subst("${.MAKE.EXPORTED:O:u}",
SCOPE_GLOBAL, VARE_WANTRES);
/* TODO: handle errors */
varnames = FStr_InitOwn(expanded);
}
@ -878,12 +873,11 @@ UnexportVar(Substring varname, UnexportWhat what)
if (what == UNEXPORT_NAMED) {
/* Remove the variable names from .MAKE.EXPORTED. */
/* XXX: v->name is injected without escaping it */
char *expr = str_concat3("${" MAKE_EXPORTED ":N",
char *expr = str_concat3("${.MAKE.EXPORTED:N",
v->name.str, "}");
char *cp;
(void)Var_Subst(expr, SCOPE_GLOBAL, VARE_WANTRES, &cp);
char *cp = Var_Subst(expr, SCOPE_GLOBAL, VARE_WANTRES);
/* TODO: handle errors */
Global_Set(MAKE_EXPORTED, cp);
Global_Set(".MAKE.EXPORTED", cp);
free(cp);
free(expr);
}
@ -904,7 +898,7 @@ UnexportVars(FStr *varnames, UnexportWhat what)
SubstringWords_Free(words);
if (what != UNEXPORT_NAMED)
Global_Delete(MAKE_EXPORTED);
Global_Delete(".MAKE.EXPORTED");
}
/*
@ -1014,7 +1008,7 @@ Var_SetWithFlags(GNode *scope, const char *name, const char *val,
/*
* If requested, don't export these in the environment
* individually. We still put them in MAKEOVERRIDES so
* individually. We still put them in .MAKEOVERRIDES so
* that the command-line settings continue to override
* Makefile settings.
*/
@ -1026,7 +1020,7 @@ Var_SetWithFlags(GNode *scope, const char *name, const char *val,
* in ExportVarPlain?
*/
Global_Append(MAKEOVERRIDES, name);
Global_Append(".MAKEOVERRIDES", name);
}
if (name[0] == '.' && strcmp(name, MAKE_SAVE_DOLLARS) == 0)
@ -1706,7 +1700,7 @@ ModifyWord_Loop(Substring word, SepBuf *buf, void *data)
assert(word.end[0] == '\0'); /* assume null-terminated word */
Var_SetWithFlags(args->scope, args->var, word.start,
VAR_SET_NO_EXPORT);
(void)Var_Subst(args->body, args->scope, args->emode, &s);
s = Var_Subst(args->body, args->scope, args->emode);
/* TODO: handle errors */
assert(word.end[0] == '\0'); /* assume null-terminated word */
@ -2153,36 +2147,26 @@ ParseModifierPartExpr(const char **pp, LazyBuf *part, const ModChain *ch,
VarEvalMode emode)
{
const char *p = *pp;
FStr nested_val;
(void)Var_Parse(&p, ch->expr->scope,
VarEvalMode_WithoutKeepDollar(emode), &nested_val);
FStr nested_val = Var_Parse(&p, ch->expr->scope,
VarEvalMode_WithoutKeepDollar(emode));
/* TODO: handle errors */
LazyBuf_AddStr(part, nested_val.str);
if (VarEvalMode_ShouldEval(emode))
LazyBuf_AddStr(part, nested_val.str);
else
LazyBuf_AddSubstring(part, Substring_Init(*pp, p));
FStr_Done(&nested_val);
*pp = p;
}
/*
* In a part of a modifier, parse a subexpression but don't evaluate it.
*
* XXX: This whole block is very similar to Var_Parse with VARE_PARSE_ONLY.
* There may be subtle edge cases though that are not yet covered in the unit
* tests and that are parsed differently, depending on whether they are
* evaluated or not.
*
* This subtle difference is not documented in the manual page, neither is
* the difference between parsing ':D' and ':M' documented. No code should
* ever depend on these details, but who knows.
*
* TODO: Before trying to replace this code with Var_Parse, there need to be
* more unit tests in varmod-loop.mk. The modifier ':@' uses Var_Subst
* internally, in which a '$' is escaped as '$$', not as '\$' like in other
* modifiers. When parsing the body text '$${var}', skipping over the first
* '$' would treat '${var}' as a make expression, not as a shell variable.
* In a part of a modifier, parse some text that looks like a subexpression.
* If the text starts with '$(', any '(' and ')' must be balanced.
* If the text starts with '${', any '{' and '}' must be balanced.
* If the text starts with '$', that '$' is copied, it is not parsed as a
* short-name variable expression.
*/
static void
ParseModifierPartDollar(const char **pp, LazyBuf *part)
ParseModifierPartBalanced(const char **pp, LazyBuf *part)
{
const char *p = *pp;
const char *start = *pp;
@ -2209,7 +2193,7 @@ ParseModifierPartDollar(const char **pp, LazyBuf *part)
}
/* See ParseModifierPart for the documentation. */
static VarParseResult
static bool
ParseModifierPartSubst(
const char **pp,
char delim,
@ -2249,10 +2233,10 @@ ParseModifierPartSubst(
else
LazyBuf_Add(part, *p);
p++;
} else if (VarEvalMode_ShouldEval(emode))
ParseModifierPartExpr(&p, part, ch, emode);
} else if (emode == VARE_PARSE_BALANCED)
ParseModifierPartBalanced(&p, part);
else
ParseModifierPartDollar(&p, part);
ParseModifierPartExpr(&p, part, ch, emode);
}
if (*p != delim) {
@ -2260,7 +2244,7 @@ ParseModifierPartSubst(
Error("Unfinished modifier for \"%s\" ('%c' missing)",
ch->expr->name, delim);
LazyBuf_Done(part);
return VPR_ERR;
return false;
}
*pp = p + 1;
@ -2271,7 +2255,7 @@ ParseModifierPartSubst(
(int)Substring_Length(sub), sub.start);
}
return VPR_OK;
return true;
}
/*
@ -2280,11 +2264,11 @@ ParseModifierPartSubst(
* including the next unescaped delimiter. The delimiter, as well as the
* backslash or the dollar, can be escaped with a backslash.
*
* Return VPR_OK if parsing succeeded, together with the parsed (and possibly
* Return true if parsing succeeded, together with the parsed (and possibly
* expanded) part. In that case, pp points right after the delimiter. The
* delimiter is not included in the part though.
*/
static VarParseResult
static bool
ParseModifierPart(
/* The parsing position, updated upon return */
const char **pp,
@ -2434,15 +2418,13 @@ ApplyModifier_Loop(const char **pp, ModChain *ch)
Expr *expr = ch->expr;
struct ModifyWord_LoopArgs args;
char prev_sep;
VarParseResult res;
LazyBuf tvarBuf, strBuf;
FStr tvar, str;
args.scope = expr->scope;
(*pp)++; /* Skip the first '@' */
res = ParseModifierPart(pp, '@', VARE_PARSE_ONLY, ch, &tvarBuf);
if (res != VPR_OK)
if (!ParseModifierPart(pp, '@', VARE_PARSE_ONLY, ch, &tvarBuf))
return AMR_CLEANUP;
tvar = LazyBuf_DoneGet(&tvarBuf);
args.var = tvar.str;
@ -2454,8 +2436,7 @@ ApplyModifier_Loop(const char **pp, ModChain *ch)
return AMR_CLEANUP;
}
res = ParseModifierPart(pp, '@', VARE_PARSE_ONLY, ch, &strBuf);
if (res != VPR_OK)
if (!ParseModifierPart(pp, '@', VARE_PARSE_BALANCED, ch, &strBuf))
return AMR_CLEANUP;
str = LazyBuf_DoneGet(&strBuf);
args.body = str.str;
@ -2508,11 +2489,8 @@ ParseModifier_Defined(const char **pp, ModChain *ch, bool shouldEval,
/* Nested variable expression */
if (*p == '$') {
FStr val;
(void)Var_Parse(&p, ch->expr->scope,
shouldEval ? ch->expr->emode : VARE_PARSE_ONLY,
&val);
FStr val = Var_Parse(&p, ch->expr->scope,
shouldEval ? ch->expr->emode : VARE_PARSE_ONLY);
/* TODO: handle errors */
if (shouldEval)
LazyBuf_AddStr(buf, val.str);
@ -2666,13 +2644,11 @@ static ApplyModifierResult
ApplyModifier_ShellCommand(const char **pp, ModChain *ch)
{
Expr *expr = ch->expr;
VarParseResult res;
LazyBuf cmdBuf;
FStr cmd;
(*pp)++;
res = ParseModifierPart(pp, '!', expr->emode, ch, &cmdBuf);
if (res != VPR_OK)
if (!ParseModifierPart(pp, '!', expr->emode, ch, &cmdBuf))
return AMR_CLEANUP;
cmd = LazyBuf_DoneGet(&cmdBuf);
@ -2818,7 +2794,7 @@ ParseModifier_Match(const char **pp, const ModChain *ch)
* XXX: Contrary to ParseModifierPart, a dollar in a ':M' or
* ':N' modifier must be escaped as '$$', not as '\$'.
*/
(void)Var_Subst(pattern, expr->scope, expr->emode, &pattern);
pattern = Var_Subst(pattern, expr->scope, expr->emode);
/* TODO: handle errors */
free(old_pattern);
}
@ -2875,7 +2851,6 @@ ApplyModifier_Subst(const char **pp, ModChain *ch)
{
struct ModifyWord_SubstArgs args;
bool oneBigWord;
VarParseResult res;
LazyBuf lhsBuf, rhsBuf;
char delim = (*pp)[1];
@ -2895,15 +2870,13 @@ ApplyModifier_Subst(const char **pp, ModChain *ch)
(*pp)++;
}
res = ParseModifierPartSubst(pp, delim, ch->expr->emode, ch, &lhsBuf,
&args.pflags, NULL);
if (res != VPR_OK)
if (!ParseModifierPartSubst(pp, delim, ch->expr->emode, ch, &lhsBuf,
&args.pflags, NULL))
return AMR_CLEANUP;
args.lhs = LazyBuf_Get(&lhsBuf);
res = ParseModifierPartSubst(pp, delim, ch->expr->emode, ch, &rhsBuf,
NULL, &args);
if (res != VPR_OK) {
if (!ParseModifierPartSubst(pp, delim, ch->expr->emode, ch, &rhsBuf,
NULL, &args)) {
LazyBuf_Done(&lhsBuf);
return AMR_CLEANUP;
}
@ -2928,7 +2901,6 @@ ApplyModifier_Regex(const char **pp, ModChain *ch)
struct ModifyWord_SubstRegexArgs args;
bool oneBigWord;
int error;
VarParseResult res;
LazyBuf reBuf, replaceBuf;
FStr re;
@ -2941,13 +2913,11 @@ ApplyModifier_Regex(const char **pp, ModChain *ch)
*pp += 2;
res = ParseModifierPart(pp, delim, ch->expr->emode, ch, &reBuf);
if (res != VPR_OK)
if (!ParseModifierPart(pp, delim, ch->expr->emode, ch, &reBuf))
return AMR_CLEANUP;
re = LazyBuf_DoneGet(&reBuf);
res = ParseModifierPart(pp, delim, ch->expr->emode, ch, &replaceBuf);
if (res != VPR_OK) {
if (!ParseModifierPart(pp, delim, ch->expr->emode, ch, &replaceBuf)) {
FStr_Done(&re);
return AMR_CLEANUP;
}
@ -3180,14 +3150,12 @@ ApplyModifier_Words(const char **pp, ModChain *ch)
Expr *expr = ch->expr;
const char *estr;
int first, last;
VarParseResult res;
const char *p;
LazyBuf estrBuf;
FStr festr;
(*pp)++; /* skip the '[' */
res = ParseModifierPart(pp, ']', expr->emode, ch, &estrBuf);
if (res != VPR_OK)
if (!ParseModifierPart(pp, ']', expr->emode, ch, &estrBuf))
return AMR_CLEANUP;
festr = LazyBuf_DoneGet(&estrBuf);
estr = festr.str;
@ -3412,7 +3380,6 @@ static ApplyModifierResult
ApplyModifier_IfElse(const char **pp, ModChain *ch)
{
Expr *expr = ch->expr;
VarParseResult res;
LazyBuf thenBuf;
LazyBuf elseBuf;
@ -3429,12 +3396,10 @@ ApplyModifier_IfElse(const char **pp, ModChain *ch)
}
(*pp)++; /* skip past the '?' */
res = ParseModifierPart(pp, ':', then_emode, ch, &thenBuf);
if (res != VPR_OK)
if (!ParseModifierPart(pp, ':', then_emode, ch, &thenBuf))
return AMR_CLEANUP;
res = ParseModifierPart(pp, ch->endc, else_emode, ch, &elseBuf);
if (res != VPR_OK) {
if (!ParseModifierPart(pp, ch->endc, else_emode, ch, &elseBuf)) {
LazyBuf_Done(&thenBuf);
return AMR_CLEANUP;
}
@ -3495,7 +3460,6 @@ ApplyModifier_Assign(const char **pp, ModChain *ch)
Expr *expr = ch->expr;
GNode *scope;
FStr val;
VarParseResult res;
LazyBuf buf;
const char *mod = *pp;
@ -3515,8 +3479,7 @@ ApplyModifier_Assign(const char **pp, ModChain *ch)
*pp = mod + (op[0] == '+' || op[0] == '?' || op[0] == '!' ? 3 : 2);
res = ParseModifierPart(pp, ch->endc, expr->emode, ch, &buf);
if (res != VPR_OK)
if (!ParseModifierPart(pp, ch->endc, expr->emode, ch, &buf))
return AMR_CLEANUP;
val = LazyBuf_DoneGet(&buf);
@ -3650,7 +3613,6 @@ static ApplyModifierResult
ApplyModifier_SysV(const char **pp, ModChain *ch)
{
Expr *expr = ch->expr;
VarParseResult res;
LazyBuf lhsBuf, rhsBuf;
FStr rhs;
struct ModifyWord_SysVSubstArgs args;
@ -3680,15 +3642,13 @@ ApplyModifier_SysV(const char **pp, ModChain *ch)
if (*p != ch->endc || !eqFound)
return AMR_UNKNOWN;
res = ParseModifierPart(pp, '=', expr->emode, ch, &lhsBuf);
if (res != VPR_OK)
if (!ParseModifierPart(pp, '=', expr->emode, ch, &lhsBuf))
return AMR_CLEANUP;
/*
* The SysV modifier lasts until the end of the variable expression.
*/
res = ParseModifierPart(pp, ch->endc, expr->emode, ch, &rhsBuf);
if (res != VPR_OK) {
if (!ParseModifierPart(pp, ch->endc, expr->emode, ch, &rhsBuf)) {
LazyBuf_Done(&lhsBuf);
return AMR_CLEANUP;
}
@ -3714,6 +3674,7 @@ ApplyModifier_SysV(const char **pp, ModChain *ch)
done:
LazyBuf_Done(&lhsBuf);
FStr_Done(&rhs);
return AMR_OK;
}
#endif
@ -3743,6 +3704,18 @@ ApplyModifier_SunShell(const char **pp, ModChain *ch)
}
#endif
/*
* In cases where the evaluation mode and the definedness are the "standard"
* ones, don't log them, to keep the logs readable.
*/
static bool
ShouldLogInSimpleFormat(const Expr *expr)
{
return (expr->emode == VARE_WANTRES ||
expr->emode == VARE_UNDEFERR) &&
expr->defined == DEF_REGULAR;
}
static void
LogBeforeApply(const ModChain *ch, const char *mod)
{
@ -3760,8 +3733,7 @@ LogBeforeApply(const ModChain *ch, const char *mod)
return;
}
if ((expr->emode == VARE_WANTRES || expr->emode == VARE_UNDEFERR) &&
expr->defined == DEF_REGULAR) {
if (ShouldLogInSimpleFormat(expr)) {
debug_printf(
"Evaluating modifier ${%s:%c%s} on value \"%s\"\n",
expr->name, mod[0], is_single_char ? "" : "...",
@ -3782,9 +3754,7 @@ LogAfterApply(const ModChain *ch, const char *p, const char *mod)
const char *value = Expr_Str(expr);
const char *quot = value == var_Error ? "" : "\"";
if ((expr->emode == VARE_WANTRES || expr->emode == VARE_UNDEFERR) &&
expr->defined == DEF_REGULAR) {
if (ShouldLogInSimpleFormat(expr)) {
debug_printf("Result of ${%s:%.*s} is %s%s%s\n",
expr->name, (int)(p - mod), mod,
quot, value == var_Error ? "error" : value, quot);
@ -3892,9 +3862,7 @@ ApplyModifiersIndirect(ModChain *ch, const char **pp)
{
Expr *expr = ch->expr;
const char *p = *pp;
FStr mods;
(void)Var_Parse(&p, expr->scope, expr->emode, &mods);
FStr mods = Var_Parse(&p, expr->scope, expr->emode);
/* TODO: handle errors */
if (mods.str[0] != '\0' && !IsDelimiter(*p, ch)) {
@ -4079,7 +4047,7 @@ ApplyModifiers(
* commands with evaluation errors should not be run at all.
*
* To make that happen, Var_Subst must report the actual errors
* instead of returning VPR_OK unconditionally.
* instead of returning the resulting string unconditionally.
*/
*pp = p;
Expr_SetValueRefer(expr, var_Error);
@ -4169,8 +4137,7 @@ ParseVarname(const char **pp, char startc, char endc,
/* A variable inside a variable, expand. */
if (*p == '$') {
FStr nested_val;
(void)Var_Parse(&p, scope, emode, &nested_val);
FStr nested_val = Var_Parse(&p, scope, emode);
/* TODO: handle errors */
LazyBuf_AddStr(buf, nested_val.str);
FStr_Done(&nested_val);
@ -4211,7 +4178,7 @@ IsShortVarnameValid(char varname, const char *start)
static bool
ParseVarnameShort(char varname, const char **pp, GNode *scope,
VarEvalMode emode,
VarParseResult *out_false_res, const char **out_false_val,
const char **out_false_val,
Var **out_true_var)
{
char name[2];
@ -4220,7 +4187,6 @@ ParseVarnameShort(char varname, const char **pp, GNode *scope,
if (!IsShortVarnameValid(varname, *pp)) {
(*pp)++; /* only skip the '$' */
*out_false_res = VPR_ERR;
*out_false_val = var_Error;
return false;
}
@ -4243,22 +4209,8 @@ ParseVarnameShort(char varname, const char **pp, GNode *scope,
if (opts.strict && val == var_Error) {
Parse_Error(PARSE_FATAL,
"Variable \"%s\" is undefined", name);
*out_false_res = VPR_ERR;
*out_false_val = val;
return false;
}
/*
* XXX: This looks completely wrong.
*
* If undefined expressions are not allowed, this should
* rather be VPR_ERR instead of VPR_UNDEF, together with an
* error message.
*
* If undefined expressions are allowed, this should rather
* be VPR_UNDEF instead of VPR_OK.
*/
*out_false_res = emode == VARE_UNDEFERR ? VPR_UNDEF : VPR_OK;
*out_false_val = val;
return false;
}
@ -4289,30 +4241,22 @@ FindLocalLegacyVar(Substring varname, GNode *scope,
return v;
}
static VarParseResult
static FStr
EvalUndefined(bool dynamic, const char *start, const char *p,
Substring varname, VarEvalMode emode, FStr *out_val)
Substring varname, VarEvalMode emode)
{
if (dynamic) {
*out_val = FStr_InitOwn(bmake_strsedup(start, p));
return VPR_OK;
}
if (dynamic)
return FStr_InitOwn(bmake_strsedup(start, p));
if (emode == VARE_UNDEFERR && opts.strict) {
Parse_Error(PARSE_FATAL,
"Variable \"%.*s\" is undefined",
(int)Substring_Length(varname), varname.start);
*out_val = FStr_InitRefer(var_Error);
return VPR_ERR;
return FStr_InitRefer(var_Error);
}
if (emode == VARE_UNDEFERR) {
*out_val = FStr_InitRefer(var_Error);
return VPR_UNDEF; /* XXX: Should be VPR_ERR instead. */
}
*out_val = FStr_InitRefer(varUndefined);
return VPR_OK;
return FStr_InitRefer(
emode == VARE_UNDEFERR ? var_Error : varUndefined);
}
/*
@ -4329,7 +4273,6 @@ ParseVarnameLong(
VarEvalMode emode,
const char **out_false_pp,
VarParseResult *out_false_res,
FStr *out_false_val,
char *out_true_endc,
@ -4364,7 +4307,6 @@ ParseVarnameLong(
LazyBuf_Done(&varname);
*out_false_pp = p;
*out_false_val = FStr_InitRefer(var_Error);
*out_false_res = VPR_ERR;
return false;
}
@ -4394,8 +4336,8 @@ ParseVarnameLong(
if (!haveModifier) {
p++; /* skip endc */
*out_false_pp = p;
*out_false_res = EvalUndefined(dynamic, start, p,
name, emode, out_false_val);
*out_false_val = EvalUndefined(dynamic, start, p,
name, emode);
LazyBuf_Done(&varname);
return false;
}
@ -4497,23 +4439,23 @@ Var_Parse_FastLane(const char **pp, VarEvalMode emode, FStr *out_value)
* point to some random character in the string, to the
* location of the parse error, or at the end of the
* string.
* *out_val The value of the variable expression, never NULL.
* *out_val var_Error if there was a parse error.
* *out_val var_Error if the base variable of the expression was
* return The value of the variable expression, never NULL.
* return var_Error if there was a parse error.
* return var_Error if the base variable of the expression was
* undefined, emode is VARE_UNDEFERR, and none of
* the modifiers turned the undefined expression into a
* defined expression.
* XXX: It is not guaranteed that an error message has
* been printed.
* *out_val varUndefined if the base variable of the expression
* return varUndefined if the base variable of the expression
* was undefined, emode was not VARE_UNDEFERR,
* and none of the modifiers turned the undefined
* expression into a defined expression.
* XXX: It is not guaranteed that an error message has
* been printed.
*/
VarParseResult
Var_Parse(const char **pp, GNode *scope, VarEvalMode emode, FStr *out_val)
FStr
Var_Parse(const char **pp, GNode *scope, VarEvalMode emode)
{
const char *p = *pp;
const char *const start = p;
@ -4531,15 +4473,16 @@ Var_Parse(const char **pp, GNode *scope, VarEvalMode emode, FStr *out_val)
Var *v;
Expr expr = Expr_Literal(NULL, FStr_InitRefer(NULL), emode,
scope, DEF_REGULAR);
FStr val;
if (Var_Parse_FastLane(pp, emode, out_val))
return VPR_OK;
if (Var_Parse_FastLane(pp, emode, &val))
return val;
/* TODO: Reduce computations in parse-only mode. */
DEBUG2(VAR, "Var_Parse: %s (%s)\n", start, VarEvalMode_Name[emode]);
*out_val = FStr_InitRefer(NULL);
val = FStr_InitRefer(NULL);
extramodifiers = NULL; /* extra modifiers to apply first */
dynamic = false;
@ -4547,19 +4490,16 @@ Var_Parse(const char **pp, GNode *scope, VarEvalMode emode, FStr *out_val)
startc = p[1];
if (startc != '(' && startc != '{') {
VarParseResult res;
if (!ParseVarnameShort(startc, pp, scope, emode, &res,
&out_val->str, &v))
return res;
if (!ParseVarnameShort(startc, pp, scope, emode, &val.str, &v))
return val;
haveModifier = false;
p++;
} else {
VarParseResult res;
if (!ParseVarnameLong(&p, startc, scope, emode,
pp, &res, out_val,
pp, &val,
&endc, &v, &haveModifier, &extramodifiers,
&dynamic, &expr.defined))
return res;
return val;
}
expr.name = v->name.str;
@ -4595,8 +4535,7 @@ Var_Parse(const char **pp, GNode *scope, VarEvalMode emode, FStr *out_val)
if (opts.strict)
nested_emode = VarEvalMode_UndefOk(nested_emode);
v->inUse = true;
(void)Var_Subst(Expr_Str(&expr), scope, nested_emode,
&expanded);
expanded = Var_Subst(Expr_Str(&expr), scope, nested_emode);
v->inUse = false;
/* TODO: handle errors */
Expr_SetValueOwn(&expr, expanded);
@ -4641,8 +4580,7 @@ Var_Parse(const char **pp, GNode *scope, VarEvalMode emode, FStr *out_val)
VarFreeShortLived(v);
}
*out_val = expr.value;
return VPR_OK; /* XXX: Is not correct in all cases */
return expr.value;
}
static void
@ -4661,9 +4599,7 @@ VarSubstExpr(const char **pp, Buffer *buf, GNode *scope,
{
const char *p = *pp;
const char *nested_p = p;
FStr val;
(void)Var_Parse(&nested_p, scope, emode, &val);
FStr val = Var_Parse(&nested_p, scope, emode);
/* TODO: handle errors */
if (val.str == var_Error || val.str == varUndefined) {
@ -4737,8 +4673,8 @@ VarSubstPlain(const char **pp, Buffer *res)
* variables. The other scopes are searched as well.
* emode The mode for parsing or evaluating subexpressions.
*/
VarParseResult
Var_Subst(const char *str, GNode *scope, VarEvalMode emode, char **out_res)
char *
Var_Subst(const char *str, GNode *scope, VarEvalMode emode)
{
const char *p = str;
Buffer res;
@ -4762,8 +4698,7 @@ Var_Subst(const char *str, GNode *scope, VarEvalMode emode, char **out_res)
VarSubstPlain(&p, &res);
}
*out_res = Buf_DoneDataCompact(&res);
return VPR_OK;
return Buf_DoneDataCompact(&res);
}
void
@ -4773,7 +4708,7 @@ Var_Expand(FStr *str, GNode *scope, VarEvalMode emode)
if (strchr(str->str, '$') == NULL)
return;
(void)Var_Subst(str->str, scope, emode, &expanded);
expanded = Var_Subst(str->str, scope, emode);
/* TODO: handle errors */
FStr_Done(str);
*str = FStr_InitOwn(expanded);

View File

@ -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

View File

@ -7,7 +7,7 @@ SRCTOP?= ${.CURDIR:H:H}
# things set by configure
_MAKE_VERSION?=20230208
_MAKE_VERSION?=20230414
prefix?= /usr
srcdir= ${SRCTOP}/contrib/bmake

View File

@ -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'