mirror of
https://github.com/freebsd/freebsd-src
synced 2024-10-02 22:54:52 +00:00
Import bmake-20240625
Intersting/relevant changes since bmake-20240520 ChangeLog since bmake-20240520 2024-06-25 Simon J Gerraty <sjg@beast.crufty.net> * VERSION (_MAKE_VERSION): 20240625 Merge with NetBSD make, pick up o job.c: ensure shellPath is always duped, avoid upsetting free() 2024-06-16 Simon J Gerraty <sjg@beast.crufty.net> * VERSION (_MAKE_VERSION): 20240616 Merge with NetBSD make, pick up o clean up collection of context information for error messages o in warnings, move the word "warning" to the front o var.c: throw an error on attempt to override an internal read-only variable 2024-06-10 Simon J Gerraty <sjg@beast.crufty.net> * VERSION (_MAKE_VERSION): 20240610 Merge with NetBSD make, pick up o for.c: remove redundant shortcut for building the .for loop body 2024-06-02 Simon J Gerraty <sjg@beast.crufty.net> * VERSION (_MAKE_VERSION): 20240602 Merge with NetBSD make, pick up o rename some VarEvalMode constants to better match debug names. o var.c: avoid out-of-bounds read when parsing indirect modifiers. 2024-06-01 Simon J Gerraty <sjg@beast.crufty.net> * VERSION (_MAKE_VERSION): 20240601 Merge with NetBSD make, pick up o add .export-all rather than allow .export with no argument which can happen accidentally. o if lua is available, run check-expect.lua after unit-tests o main.c: use snprintf rather than strncpy fix memory leak when purging realpath cache. 2024-05-28 Simon J Gerraty <sjg@beast.crufty.net> * VERSION (_MAKE_VERSION): 20240528 Merge with NetBSD make, pick up o fix a number of memory leaks o replace magic numbers with POSIX FILENO constants o hash.c: remove dead code from HashTable_DeleteEntry o main.c: when complaining about unusable .OBJDIR call PrintOnError if MAKE_DEBUG_OBJDIR_CHECK_WRITABLE is true. o parse.c: use fewer technical terms in debug message for dependency mk/ChangeLog since bmake-20240520 2024-06-22 Simon J Gerraty <sjg@beast.crufty.net> * install-mk (MK_VERSION): 20240616 * dirdeps.mk: apply DEP_DIRDEPS_BUILD_DIR_FILTER after we have computed build dirs, since some filters cannot be easily expressed via DEP_DIRDEPS_FILTER. 2024-05-31 Simon J Gerraty <sjg@beast.crufty.net> * dirdeps.mk: move reset of DIRDEPS_EXPORT_VARS until after we a finished with it if building a cache.
This commit is contained in:
parent
29efb3dcae
commit
dbb5be7f07
49
ChangeLog
49
ChangeLog
|
@ -1,3 +1,52 @@
|
||||||
|
2024-06-25 Simon J Gerraty <sjg@beast.crufty.net>
|
||||||
|
|
||||||
|
* VERSION (_MAKE_VERSION): 20240625
|
||||||
|
Merge with NetBSD make, pick up
|
||||||
|
o job.c: ensure shellPath is always duped, avoid upsetting free()
|
||||||
|
|
||||||
|
2024-06-16 Simon J Gerraty <sjg@beast.crufty.net>
|
||||||
|
|
||||||
|
* VERSION (_MAKE_VERSION): 20240616
|
||||||
|
Merge with NetBSD make, pick up
|
||||||
|
o clean up collection of context information for error messages
|
||||||
|
o in warnings, move the word "warning" to the front
|
||||||
|
o var.c: throw an error on attempt to override an internal
|
||||||
|
read-only variable
|
||||||
|
|
||||||
|
2024-06-10 Simon J Gerraty <sjg@beast.crufty.net>
|
||||||
|
|
||||||
|
* VERSION (_MAKE_VERSION): 20240610
|
||||||
|
Merge with NetBSD make, pick up
|
||||||
|
o for.c: remove redundant shortcut for building the .for loop body
|
||||||
|
|
||||||
|
2024-06-02 Simon J Gerraty <sjg@beast.crufty.net>
|
||||||
|
|
||||||
|
* VERSION (_MAKE_VERSION): 20240602
|
||||||
|
Merge with NetBSD make, pick up
|
||||||
|
o rename some VarEvalMode constants to better match debug names.
|
||||||
|
o var.c: avoid out-of-bounds read when parsing indirect modifiers.
|
||||||
|
|
||||||
|
2024-06-01 Simon J Gerraty <sjg@beast.crufty.net>
|
||||||
|
|
||||||
|
* VERSION (_MAKE_VERSION): 20240601
|
||||||
|
Merge with NetBSD make, pick up
|
||||||
|
o add .export-all rather than allow .export with no argument
|
||||||
|
which can happen accidentally.
|
||||||
|
o if lua is available, run check-expect.lua after unit-tests
|
||||||
|
o main.c: use snprintf rather than strncpy
|
||||||
|
fix memory leak when purging realpath cache.
|
||||||
|
|
||||||
|
2024-05-28 Simon J Gerraty <sjg@beast.crufty.net>
|
||||||
|
|
||||||
|
* VERSION (_MAKE_VERSION): 20240528
|
||||||
|
Merge with NetBSD make, pick up
|
||||||
|
o fix a number of memory leaks
|
||||||
|
o replace magic numbers with POSIX FILENO constants
|
||||||
|
o hash.c: remove dead code from HashTable_DeleteEntry
|
||||||
|
o main.c: when complaining about unusable .OBJDIR
|
||||||
|
call PrintOnError if MAKE_DEBUG_OBJDIR_CHECK_WRITABLE is true.
|
||||||
|
o parse.c: use fewer technical terms in debug message for dependency
|
||||||
|
|
||||||
2024-05-20 Simon J Gerraty <sjg@beast.crufty.net>
|
2024-05-20 Simon J Gerraty <sjg@beast.crufty.net>
|
||||||
|
|
||||||
* VERSION (_MAKE_VERSION):
|
* VERSION (_MAKE_VERSION):
|
||||||
|
|
2
VERSION
2
VERSION
|
@ -1,2 +1,2 @@
|
||||||
# keep this compatible with sh and make
|
# keep this compatible with sh and make
|
||||||
_MAKE_VERSION=20240520
|
_MAKE_VERSION=20240625
|
||||||
|
|
15
arch.c
15
arch.c
|
@ -1,4 +1,4 @@
|
||||||
/* $NetBSD: arch.c,v 1.217 2024/04/27 20:41:32 rillig Exp $ */
|
/* $NetBSD: arch.c,v 1.219 2024/06/02 15:31:25 rillig Exp $ */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 1988, 1989, 1990, 1993
|
* Copyright (c) 1988, 1989, 1990, 1993
|
||||||
|
@ -147,7 +147,7 @@ struct ar_hdr {
|
||||||
#include "dir.h"
|
#include "dir.h"
|
||||||
|
|
||||||
/* "@(#)arch.c 8.2 (Berkeley) 1/2/94" */
|
/* "@(#)arch.c 8.2 (Berkeley) 1/2/94" */
|
||||||
MAKE_RCSID("$NetBSD: arch.c,v 1.217 2024/04/27 20:41:32 rillig Exp $");
|
MAKE_RCSID("$NetBSD: arch.c,v 1.219 2024/06/02 15:31:25 rillig Exp $");
|
||||||
|
|
||||||
typedef struct List ArchList;
|
typedef struct List ArchList;
|
||||||
typedef struct ListNode ArchListNode;
|
typedef struct ListNode ArchListNode;
|
||||||
|
@ -204,7 +204,7 @@ ArchFree(Arch *a)
|
||||||
HashIter hi;
|
HashIter hi;
|
||||||
|
|
||||||
HashIter_Init(&hi, &a->members);
|
HashIter_Init(&hi, &a->members);
|
||||||
while (HashIter_Next(&hi) != NULL)
|
while (HashIter_Next(&hi))
|
||||||
free(hi.entry->value);
|
free(hi.entry->value);
|
||||||
|
|
||||||
free(a->name);
|
free(a->name);
|
||||||
|
@ -257,7 +257,8 @@ Arch_ParseArchive(char **pp, GNodeList *gns, GNode *scope)
|
||||||
bool isError;
|
bool isError;
|
||||||
|
|
||||||
/* XXX: is expanded twice: once here and once below */
|
/* XXX: is expanded twice: once here and once below */
|
||||||
result = Var_Parse(&nested_p, scope, VARE_UNDEFERR);
|
result = Var_Parse(&nested_p, scope,
|
||||||
|
VARE_EVAL_DEFINED);
|
||||||
/* TODO: handle errors */
|
/* TODO: handle errors */
|
||||||
isError = result.str == var_Error;
|
isError = result.str == var_Error;
|
||||||
FStr_Done(&result);
|
FStr_Done(&result);
|
||||||
|
@ -272,7 +273,7 @@ Arch_ParseArchive(char **pp, GNodeList *gns, GNode *scope)
|
||||||
|
|
||||||
spec[cp++ - spec] = '\0';
|
spec[cp++ - spec] = '\0';
|
||||||
if (expandLib)
|
if (expandLib)
|
||||||
Var_Expand(&lib, scope, VARE_UNDEFERR);
|
Var_Expand(&lib, scope, VARE_EVAL_DEFINED);
|
||||||
|
|
||||||
for (;;) {
|
for (;;) {
|
||||||
/*
|
/*
|
||||||
|
@ -296,7 +297,7 @@ Arch_ParseArchive(char **pp, GNodeList *gns, GNode *scope)
|
||||||
const char *nested_p = cp;
|
const char *nested_p = cp;
|
||||||
|
|
||||||
result = Var_Parse(&nested_p, scope,
|
result = Var_Parse(&nested_p, scope,
|
||||||
VARE_UNDEFERR);
|
VARE_EVAL_DEFINED);
|
||||||
/* TODO: handle errors */
|
/* TODO: handle errors */
|
||||||
isError = result.str == var_Error;
|
isError = result.str == var_Error;
|
||||||
FStr_Done(&result);
|
FStr_Done(&result);
|
||||||
|
@ -341,7 +342,7 @@ Arch_ParseArchive(char **pp, GNodeList *gns, GNode *scope)
|
||||||
char *p;
|
char *p;
|
||||||
const char *unexpandedMem = mem.str;
|
const char *unexpandedMem = mem.str;
|
||||||
|
|
||||||
Var_Expand(&mem, scope, VARE_UNDEFERR);
|
Var_Expand(&mem, scope, VARE_EVAL_DEFINED);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Now form an archive spec and recurse to deal with
|
* Now form an archive spec and recurse to deal with
|
||||||
|
|
33
bmake.1
33
bmake.1
|
@ -1,4 +1,4 @@
|
||||||
.\" $NetBSD: make.1,v 1.375 2024/03/10 02:53:37 sjg Exp $
|
.\" $NetBSD: make.1,v 1.377 2024/06/01 06:26:36 sjg Exp $
|
||||||
.\"
|
.\"
|
||||||
.\" Copyright (c) 1990, 1993
|
.\" Copyright (c) 1990, 1993
|
||||||
.\" The Regents of the University of California. All rights reserved.
|
.\" The Regents of the University of California. All rights reserved.
|
||||||
|
@ -29,7 +29,7 @@
|
||||||
.\"
|
.\"
|
||||||
.\" from: @(#)make.1 8.4 (Berkeley) 3/19/94
|
.\" from: @(#)make.1 8.4 (Berkeley) 3/19/94
|
||||||
.\"
|
.\"
|
||||||
.Dd March 9, 2024
|
.Dd June 1, 2024
|
||||||
.Dt BMAKE 1
|
.Dt BMAKE 1
|
||||||
.Os
|
.Os
|
||||||
.Sh NAME
|
.Sh NAME
|
||||||
|
@ -1143,9 +1143,19 @@ This mode can be used to detect undeclared dependencies between files.
|
||||||
Used to create files in a separate directory, see
|
Used to create files in a separate directory, see
|
||||||
.Va .OBJDIR .
|
.Va .OBJDIR .
|
||||||
.It Va MAKE_OBJDIR_CHECK_WRITABLE
|
.It Va MAKE_OBJDIR_CHECK_WRITABLE
|
||||||
Used to force a separate directory for the created files,
|
When true,
|
||||||
even if that directory is not writable, see
|
.Nm
|
||||||
.Va .OBJDIR .
|
will check that
|
||||||
|
.Va .OBJDIR
|
||||||
|
is writable, and issue a warning if not.
|
||||||
|
.It Va MAKE_DEBUG_OBJDIR_CHECK_WRITABLE
|
||||||
|
When true and
|
||||||
|
.Nm
|
||||||
|
is warning about an unwritable
|
||||||
|
.Va .OBJDIR ,
|
||||||
|
report the variables listed in
|
||||||
|
.Va MAKE_PRINT_VAR_ON_ERROR
|
||||||
|
to help debug.
|
||||||
.It Va MAKEOBJDIRPREFIX
|
.It Va MAKEOBJDIRPREFIX
|
||||||
Used to create files in a separate directory, see
|
Used to create files in a separate directory, see
|
||||||
.Va .OBJDIR .
|
.Va .OBJDIR .
|
||||||
|
@ -1951,12 +1961,7 @@ The directives for exporting and unexporting variables are:
|
||||||
.Bl -tag -width Ds
|
.Bl -tag -width Ds
|
||||||
.It Ic .export Ar variable No ...
|
.It Ic .export Ar variable No ...
|
||||||
Export the specified global variable.
|
Export the specified global variable.
|
||||||
If no variable list is provided, all globals are exported
|
.Pp
|
||||||
except for internal variables (those that start with
|
|
||||||
.Ql \&. ) .
|
|
||||||
This is not affected by the
|
|
||||||
.Fl X
|
|
||||||
flag, so should be used with caution.
|
|
||||||
For compatibility with other make programs,
|
For compatibility with other make programs,
|
||||||
.Cm export Ar variable\| Ns Cm \&= Ns Ar value
|
.Cm export Ar variable\| Ns Cm \&= Ns Ar value
|
||||||
(without leading dot) is also accepted.
|
(without leading dot) is also accepted.
|
||||||
|
@ -1964,6 +1969,12 @@ For compatibility with other make programs,
|
||||||
Appending a variable name to
|
Appending a variable name to
|
||||||
.Va .MAKE.EXPORTED
|
.Va .MAKE.EXPORTED
|
||||||
is equivalent to exporting a variable.
|
is equivalent to exporting a variable.
|
||||||
|
.It Ic .export-all
|
||||||
|
Export all globals except for internal variables (those that start with
|
||||||
|
.Ql \&. ) .
|
||||||
|
This is not affected by the
|
||||||
|
.Fl X
|
||||||
|
flag, so should be used with caution.
|
||||||
.It Ic .export-env Ar variable No ...
|
.It Ic .export-env Ar variable No ...
|
||||||
The same as
|
The same as
|
||||||
.Ql .export ,
|
.Ql .export ,
|
||||||
|
|
26
bmake.cat1
26
bmake.cat1
|
@ -756,8 +756,13 @@ VVAARRIIAABBLLEE AASSSSIIGGNNMMEENNTTSS
|
||||||
Used to create files in a separate directory, see _._O_B_J_D_I_R.
|
Used to create files in a separate directory, see _._O_B_J_D_I_R.
|
||||||
|
|
||||||
_M_A_K_E___O_B_J_D_I_R___C_H_E_C_K___W_R_I_T_A_B_L_E
|
_M_A_K_E___O_B_J_D_I_R___C_H_E_C_K___W_R_I_T_A_B_L_E
|
||||||
Used to force a separate directory for the created files, even if
|
When true, bbmmaakkee will check that _._O_B_J_D_I_R is writable, and issue a
|
||||||
that directory is not writable, see _._O_B_J_D_I_R.
|
warning if not.
|
||||||
|
|
||||||
|
_M_A_K_E___D_E_B_U_G___O_B_J_D_I_R___C_H_E_C_K___W_R_I_T_A_B_L_E
|
||||||
|
When true and bbmmaakkee is warning about an unwritable _._O_B_J_D_I_R,
|
||||||
|
report the variables listed in _M_A_K_E___P_R_I_N_T___V_A_R___O_N___E_R_R_O_R to help
|
||||||
|
debug.
|
||||||
|
|
||||||
_M_A_K_E_O_B_J_D_I_R_P_R_E_F_I_X
|
_M_A_K_E_O_B_J_D_I_R_P_R_E_F_I_X
|
||||||
Used to create files in a separate directory, see _._O_B_J_D_I_R.
|
Used to create files in a separate directory, see _._O_B_J_D_I_R.
|
||||||
|
@ -1230,16 +1235,19 @@ DDIIRREECCTTIIVVEESS
|
||||||
The directives for exporting and unexporting variables are:
|
The directives for exporting and unexporting variables are:
|
||||||
|
|
||||||
..eexxppoorrtt _v_a_r_i_a_b_l_e ...
|
..eexxppoorrtt _v_a_r_i_a_b_l_e ...
|
||||||
Export the specified global variable. If no variable list is
|
Export the specified global variable.
|
||||||
provided, all globals are exported except for internal variables
|
|
||||||
(those that start with `.'). This is not affected by the --XX
|
For compatibility with other make programs, eexxppoorrtt _v_a_r_i_a_b_l_e==_v_a_l_u_e
|
||||||
flag, so should be used with caution. For compatibility with
|
(without leading dot) is also accepted.
|
||||||
other make programs, eexxppoorrtt _v_a_r_i_a_b_l_e==_v_a_l_u_e (without leading dot)
|
|
||||||
is also accepted.
|
|
||||||
|
|
||||||
Appending a variable name to _._M_A_K_E_._E_X_P_O_R_T_E_D is equivalent to
|
Appending a variable name to _._M_A_K_E_._E_X_P_O_R_T_E_D is equivalent to
|
||||||
exporting a variable.
|
exporting a variable.
|
||||||
|
|
||||||
|
..eexxppoorrtt--aallll
|
||||||
|
Export all globals except for internal variables (those that
|
||||||
|
start with `.'). This is not affected by the --XX flag, so should
|
||||||
|
be used with caution.
|
||||||
|
|
||||||
..eexxppoorrtt--eennvv _v_a_r_i_a_b_l_e ...
|
..eexxppoorrtt--eennvv _v_a_r_i_a_b_l_e ...
|
||||||
The same as `.export', except that the variable is not appended
|
The same as `.export', except that the variable is not appended
|
||||||
to _._M_A_K_E_._E_X_P_O_R_T_E_D. This allows exporting a value to the
|
to _._M_A_K_E_._E_X_P_O_R_T_E_D. This allows exporting a value to the
|
||||||
|
@ -1780,4 +1788,4 @@ BBUUGGSS
|
||||||
attempt to suppress a cascade of unnecessary errors, can result in a
|
attempt to suppress a cascade of unnecessary errors, can result in a
|
||||||
seemingly unexplained `*** Error code 6'
|
seemingly unexplained `*** Error code 6'
|
||||||
|
|
||||||
FreeBSD 13.2-RELEASE-p10 March 9, 2024 FreeBSD 13.2-RELEASE-p10
|
FreeBSD 13.2-RELEASE-p11 June 1, 2024 FreeBSD 13.2-RELEASE-p11
|
||||||
|
|
Before Width: | Height: | Size: 89 KiB After Width: | Height: | Size: 90 KiB |
57
compat.c
57
compat.c
|
@ -1,4 +1,4 @@
|
||||||
/* $NetBSD: compat.c,v 1.255 2024/04/20 10:18:55 rillig Exp $ */
|
/* $NetBSD: compat.c,v 1.259 2024/06/15 20:02:45 rillig Exp $ */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 1988, 1989, 1990 The Regents of the University of California.
|
* Copyright (c) 1988, 1989, 1990 The Regents of the University of California.
|
||||||
|
@ -94,7 +94,7 @@
|
||||||
#include "pathnames.h"
|
#include "pathnames.h"
|
||||||
|
|
||||||
/* "@(#)compat.c 8.2 (Berkeley) 3/19/94" */
|
/* "@(#)compat.c 8.2 (Berkeley) 3/19/94" */
|
||||||
MAKE_RCSID("$NetBSD: compat.c,v 1.255 2024/04/20 10:18:55 rillig Exp $");
|
MAKE_RCSID("$NetBSD: compat.c,v 1.259 2024/06/15 20:02:45 rillig Exp $");
|
||||||
|
|
||||||
static GNode *curTarg = NULL;
|
static GNode *curTarg = NULL;
|
||||||
static pid_t compatChild;
|
static pid_t compatChild;
|
||||||
|
@ -203,6 +203,24 @@ UseShell(const char *cmd MAKE_ATTR_UNUSED)
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
Compat_Spawn(const char **av)
|
||||||
|
{
|
||||||
|
int pid = vfork();
|
||||||
|
if (pid < 0)
|
||||||
|
Fatal("Could not fork");
|
||||||
|
|
||||||
|
if (pid == 0) {
|
||||||
|
#ifdef USE_META
|
||||||
|
if (useMeta)
|
||||||
|
meta_compat_child();
|
||||||
|
#endif
|
||||||
|
(void)execvp(av[0], (char *const *)UNCONST(av));
|
||||||
|
execDie("exec", av[0]);
|
||||||
|
}
|
||||||
|
return pid;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Execute the next command for a target. If the command returns an error,
|
* Execute the next command for a target. If the command returns an error,
|
||||||
* the node's made field is set to ERROR and creation stops.
|
* the node's made field is set to ERROR and creation stops.
|
||||||
|
@ -225,21 +243,18 @@ Compat_RunCommand(const char *cmdp, GNode *gn, StringListNode *ln)
|
||||||
volatile bool errCheck; /* Check errors */
|
volatile bool errCheck; /* Check errors */
|
||||||
WAIT_T reason; /* Reason for child's death */
|
WAIT_T reason; /* Reason for child's death */
|
||||||
WAIT_T status; /* Description of child's death */
|
WAIT_T status; /* Description of child's death */
|
||||||
pid_t cpid; /* Child actually found */
|
|
||||||
pid_t retstat; /* Result of wait */
|
pid_t retstat; /* Result of wait */
|
||||||
const char **volatile av; /* Argument vector for thing to exec */
|
const char **av; /* Arguments for the child process */
|
||||||
char **volatile mav; /* Copy of the argument vector for freeing */
|
char **volatile mav; /* Copy of the argument vector for freeing */
|
||||||
bool useShell; /* True if command should be executed using a
|
bool useShell; /* True if command should be executed using a
|
||||||
* shell */
|
* shell */
|
||||||
const char *volatile cmd = cmdp;
|
const char *cmd = cmdp;
|
||||||
|
|
||||||
silent = (gn->type & OP_SILENT) != OP_NONE;
|
silent = (gn->type & OP_SILENT) != OP_NONE;
|
||||||
errCheck = !(gn->type & OP_IGNORE);
|
errCheck = !(gn->type & OP_IGNORE);
|
||||||
doIt = false;
|
doIt = false;
|
||||||
|
|
||||||
EvalStack_Push(gn->name, NULL, NULL);
|
cmdStart = Var_SubstInTarget(cmd, gn);
|
||||||
cmdStart = Var_Subst(cmd, gn, VARE_WANTRES);
|
|
||||||
EvalStack_Pop();
|
|
||||||
/* TODO: handle errors */
|
/* TODO: handle errors */
|
||||||
|
|
||||||
if (cmdStart[0] == '\0') {
|
if (cmdStart[0] == '\0') {
|
||||||
|
@ -264,11 +279,13 @@ Compat_RunCommand(const char *cmdp, GNode *gn, StringListNode *ln)
|
||||||
* usual '$$'.
|
* usual '$$'.
|
||||||
*/
|
*/
|
||||||
Lst_Append(&endNode->commands, cmdStart);
|
Lst_Append(&endNode->commands, cmdStart);
|
||||||
return true;
|
goto register_command;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (strcmp(cmdStart, "...") == 0) {
|
if (strcmp(cmdStart, "...") == 0) {
|
||||||
gn->type |= OP_SAVE_CMDS;
|
gn->type |= OP_SAVE_CMDS;
|
||||||
|
register_command:
|
||||||
|
Parse_RegisterCommand(cmdStart);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -288,7 +305,7 @@ Compat_RunCommand(const char *cmdp, GNode *gn, StringListNode *ln)
|
||||||
while (ch_isspace(*cmd))
|
while (ch_isspace(*cmd))
|
||||||
cmd++;
|
cmd++;
|
||||||
if (cmd[0] == '\0')
|
if (cmd[0] == '\0')
|
||||||
return true;
|
goto register_command;
|
||||||
|
|
||||||
useShell = UseShell(cmd);
|
useShell = UseShell(cmd);
|
||||||
|
|
||||||
|
@ -298,7 +315,7 @@ Compat_RunCommand(const char *cmdp, GNode *gn, StringListNode *ln)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!doIt && !GNode_ShouldExecute(gn))
|
if (!doIt && !GNode_ShouldExecute(gn))
|
||||||
return true;
|
goto register_command;
|
||||||
|
|
||||||
DEBUG1(JOB, "Execute: '%s'\n", cmd);
|
DEBUG1(JOB, "Execute: '%s'\n", cmd);
|
||||||
|
|
||||||
|
@ -333,19 +350,7 @@ Compat_RunCommand(const char *cmdp, GNode *gn, StringListNode *ln)
|
||||||
|
|
||||||
Var_ReexportVars(gn);
|
Var_ReexportVars(gn);
|
||||||
|
|
||||||
compatChild = cpid = vfork();
|
compatChild = Compat_Spawn(av);
|
||||||
if (cpid < 0)
|
|
||||||
Fatal("Could not fork");
|
|
||||||
|
|
||||||
if (cpid == 0) {
|
|
||||||
#ifdef USE_META
|
|
||||||
if (useMeta)
|
|
||||||
meta_compat_child();
|
|
||||||
#endif
|
|
||||||
(void)execvp(av[0], (char *const *)UNCONST(av));
|
|
||||||
execDie("exec", av[0]);
|
|
||||||
}
|
|
||||||
|
|
||||||
free(mav);
|
free(mav);
|
||||||
free(bp);
|
free(bp);
|
||||||
|
|
||||||
|
@ -355,11 +360,11 @@ Compat_RunCommand(const char *cmdp, GNode *gn, StringListNode *ln)
|
||||||
|
|
||||||
#ifdef USE_META
|
#ifdef USE_META
|
||||||
if (useMeta)
|
if (useMeta)
|
||||||
meta_compat_parent(cpid);
|
meta_compat_parent(compatChild);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* The child is off and running. Now all we can do is wait... */
|
/* The child is off and running. Now all we can do is wait... */
|
||||||
while ((retstat = wait(&reason)) != cpid) {
|
while ((retstat = wait(&reason)) != compatChild) {
|
||||||
if (retstat > 0)
|
if (retstat > 0)
|
||||||
JobReapChild(retstat, reason, false); /* not ours? */
|
JobReapChild(retstat, reason, false); /* not ours? */
|
||||||
if (retstat == -1 && errno != EINTR)
|
if (retstat == -1 && errno != EINTR)
|
||||||
|
|
21
cond.c
21
cond.c
|
@ -1,4 +1,4 @@
|
||||||
/* $NetBSD: cond.c,v 1.363 2024/04/23 22:51:28 rillig Exp $ */
|
/* $NetBSD: cond.c,v 1.365 2024/06/02 15:31:25 rillig Exp $ */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 1988, 1989, 1990 The Regents of the University of California.
|
* Copyright (c) 1988, 1989, 1990 The Regents of the University of California.
|
||||||
|
@ -91,7 +91,7 @@
|
||||||
#include "dir.h"
|
#include "dir.h"
|
||||||
|
|
||||||
/* "@(#)cond.c 8.2 (Berkeley) 1/2/94" */
|
/* "@(#)cond.c 8.2 (Berkeley) 1/2/94" */
|
||||||
MAKE_RCSID("$NetBSD: cond.c,v 1.363 2024/04/23 22:51:28 rillig Exp $");
|
MAKE_RCSID("$NetBSD: cond.c,v 1.365 2024/06/02 15:31:25 rillig Exp $");
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Conditional expressions conform to this grammar:
|
* Conditional expressions conform to this grammar:
|
||||||
|
@ -222,8 +222,8 @@ ParseWord(const char **pp, bool doEval)
|
||||||
break;
|
break;
|
||||||
if (ch == '$') {
|
if (ch == '$') {
|
||||||
VarEvalMode emode = doEval
|
VarEvalMode emode = doEval
|
||||||
? VARE_UNDEFERR
|
? VARE_EVAL_DEFINED
|
||||||
: VARE_PARSE_ONLY;
|
: VARE_PARSE;
|
||||||
/*
|
/*
|
||||||
* TODO: make Var_Parse complain about undefined
|
* TODO: make Var_Parse complain about undefined
|
||||||
* variables.
|
* variables.
|
||||||
|
@ -396,9 +396,9 @@ CondParser_StringExpr(CondParser *par, const char *start,
|
||||||
const char *p;
|
const char *p;
|
||||||
bool atStart; /* true means an expression outside quotes */
|
bool atStart; /* true means an expression outside quotes */
|
||||||
|
|
||||||
emode = doEval && quoted ? VARE_WANTRES
|
emode = doEval && quoted ? VARE_EVAL
|
||||||
: doEval ? VARE_UNDEFERR
|
: doEval ? VARE_EVAL_DEFINED
|
||||||
: VARE_PARSE_ONLY;
|
: VARE_PARSE;
|
||||||
|
|
||||||
p = par->p;
|
p = par->p;
|
||||||
atStart = p == start;
|
atStart = p == start;
|
||||||
|
@ -651,8 +651,7 @@ CondParser_FuncCallEmpty(CondParser *par, bool doEval, Token *out_token)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
p--; /* Make p[1] point to the '('. */
|
p--; /* Make p[1] point to the '('. */
|
||||||
val = Var_Parse(&p, SCOPE_CMDLINE,
|
val = Var_Parse(&p, SCOPE_CMDLINE, doEval ? VARE_EVAL : VARE_PARSE);
|
||||||
doEval ? VARE_WANTRES : VARE_PARSE_ONLY);
|
|
||||||
/* TODO: handle errors */
|
/* TODO: handle errors */
|
||||||
|
|
||||||
if (val.str == var_Error)
|
if (val.str == var_Error)
|
||||||
|
@ -736,8 +735,10 @@ CondParser_ComparisonOrLeaf(CondParser *par, bool doEval)
|
||||||
arg = ParseWord(&p, doEval);
|
arg = ParseWord(&p, doEval);
|
||||||
assert(arg[0] != '\0');
|
assert(arg[0] != '\0');
|
||||||
|
|
||||||
if (*p == '=' || *p == '!' || *p == '<' || *p == '>')
|
if (*p == '=' || *p == '!' || *p == '<' || *p == '>') {
|
||||||
|
free(arg);
|
||||||
return CondParser_Comparison(par, doEval);
|
return CondParser_Comparison(par, doEval);
|
||||||
|
}
|
||||||
par->p = p;
|
par->p = p;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
23
dir.c
23
dir.c
|
@ -1,4 +1,4 @@
|
||||||
/* $NetBSD: dir.c,v 1.290 2024/05/20 19:14:12 sjg Exp $ */
|
/* $NetBSD: dir.c,v 1.294 2024/05/31 05:50:11 rillig Exp $ */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 1988, 1989, 1990 The Regents of the University of California.
|
* Copyright (c) 1988, 1989, 1990 The Regents of the University of California.
|
||||||
|
@ -132,7 +132,7 @@
|
||||||
#include "job.h"
|
#include "job.h"
|
||||||
|
|
||||||
/* "@(#)dir.c 8.2 (Berkeley) 1/2/94" */
|
/* "@(#)dir.c 8.2 (Berkeley) 1/2/94" */
|
||||||
MAKE_RCSID("$NetBSD: dir.c,v 1.290 2024/05/20 19:14:12 sjg Exp $");
|
MAKE_RCSID("$NetBSD: dir.c,v 1.294 2024/05/31 05:50:11 rillig Exp $");
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* A search path is a list of CachedDir structures. A CachedDir has in it the
|
* A search path is a list of CachedDir structures. A CachedDir has in it the
|
||||||
|
@ -501,6 +501,18 @@ Dir_InitDot(void)
|
||||||
Dir_SetPATH(); /* initialize */
|
Dir_SetPATH(); /* initialize */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef CLEANUP
|
||||||
|
static void
|
||||||
|
FreeCachedTable(HashTable *tbl)
|
||||||
|
{
|
||||||
|
HashIter hi;
|
||||||
|
HashIter_Init(&hi, tbl);
|
||||||
|
while (HashIter_Next(&hi))
|
||||||
|
free(hi.entry->value);
|
||||||
|
HashTable_Done(tbl);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
/* Clean up the directories module. */
|
/* Clean up the directories module. */
|
||||||
void
|
void
|
||||||
Dir_End(void)
|
Dir_End(void)
|
||||||
|
@ -511,8 +523,8 @@ Dir_End(void)
|
||||||
CachedDir_Assign(&dotLast, NULL);
|
CachedDir_Assign(&dotLast, NULL);
|
||||||
SearchPath_Clear(&dirSearchPath);
|
SearchPath_Clear(&dirSearchPath);
|
||||||
OpenDirs_Done(&openDirs);
|
OpenDirs_Done(&openDirs);
|
||||||
HashTable_Done(&mtimes);
|
FreeCachedTable(&mtimes);
|
||||||
HashTable_Done(&lmtimes);
|
FreeCachedTable(&lmtimes);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -644,7 +656,7 @@ DirMatchFiles(const char *pattern, CachedDir *dir, StringList *expansions)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
HashIter_InitSet(&hi, &dir->files);
|
HashIter_InitSet(&hi, &dir->files);
|
||||||
while (HashIter_Next(&hi) != NULL) {
|
while (HashIter_Next(&hi)) {
|
||||||
const char *base = hi.entry->key;
|
const char *base = hi.entry->key;
|
||||||
StrMatchResult res = Str_Match(base, pattern);
|
StrMatchResult res = Str_Match(base, pattern);
|
||||||
/* TODO: handle errors from res.error */
|
/* TODO: handle errors from res.error */
|
||||||
|
@ -864,6 +876,7 @@ SearchPath_ExpandMiddle(SearchPath *path, const char *pattern,
|
||||||
(void)SearchPath_Add(partPath, dirpath);
|
(void)SearchPath_Add(partPath, dirpath);
|
||||||
DirExpandPath(wildcardComponent + 1, partPath, expansions);
|
DirExpandPath(wildcardComponent + 1, partPath, expansions);
|
||||||
SearchPath_Free(partPath);
|
SearchPath_Free(partPath);
|
||||||
|
free(dirpath);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
34
for.c
34
for.c
|
@ -1,4 +1,4 @@
|
||||||
/* $NetBSD: for.c,v 1.179 2024/04/01 12:33:27 rillig Exp $ */
|
/* $NetBSD: for.c,v 1.182 2024/06/07 18:57:30 rillig Exp $ */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 1992, The Regents of the University of California.
|
* Copyright (c) 1992, The Regents of the University of California.
|
||||||
|
@ -58,7 +58,7 @@
|
||||||
#include "make.h"
|
#include "make.h"
|
||||||
|
|
||||||
/* "@(#)for.c 8.1 (Berkeley) 6/6/93" */
|
/* "@(#)for.c 8.1 (Berkeley) 6/6/93" */
|
||||||
MAKE_RCSID("$NetBSD: for.c,v 1.179 2024/04/01 12:33:27 rillig Exp $");
|
MAKE_RCSID("$NetBSD: for.c,v 1.182 2024/06/07 18:57:30 rillig Exp $");
|
||||||
|
|
||||||
|
|
||||||
typedef struct ForLoop {
|
typedef struct ForLoop {
|
||||||
|
@ -156,7 +156,8 @@ ForLoop_ParseVarnames(ForLoop *f, const char **pp)
|
||||||
cpp_skip_whitespace(&p);
|
cpp_skip_whitespace(&p);
|
||||||
if (*p == '\0') {
|
if (*p == '\0') {
|
||||||
Parse_Error(PARSE_FATAL, "missing `in' in for");
|
Parse_Error(PARSE_FATAL, "missing `in' in for");
|
||||||
f->vars.len = 0;
|
while (f->vars.len > 0)
|
||||||
|
free(*(char **)Vector_Pop(&f->vars));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -166,7 +167,8 @@ ForLoop_ParseVarnames(ForLoop *f, const char **pp)
|
||||||
"invalid character '%c' "
|
"invalid character '%c' "
|
||||||
"in .for loop variable name",
|
"in .for loop variable name",
|
||||||
p[len]);
|
p[len]);
|
||||||
f->vars.len = 0;
|
while (f->vars.len > 0)
|
||||||
|
free(*(char **)Vector_Pop(&f->vars));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -195,7 +197,7 @@ ForLoop_ParseItems(ForLoop *f, const char *p)
|
||||||
|
|
||||||
cpp_skip_whitespace(&p);
|
cpp_skip_whitespace(&p);
|
||||||
|
|
||||||
items = Var_Subst(p, SCOPE_GLOBAL, VARE_WANTRES);
|
items = Var_Subst(p, SCOPE_GLOBAL, VARE_EVAL);
|
||||||
/* TODO: handle errors */
|
/* TODO: handle errors */
|
||||||
|
|
||||||
f->items = Substring_Words(items, false);
|
f->items = Substring_Words(items, false);
|
||||||
|
@ -329,23 +331,6 @@ ExprLen(const char *s, const char *e)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* The .for loop substitutes the items as ${:U<value>...}, which means
|
|
||||||
* that characters that break this syntax must be backslash-escaped.
|
|
||||||
*/
|
|
||||||
static bool
|
|
||||||
NeedsEscapes(Substring value, char endc)
|
|
||||||
{
|
|
||||||
const char *p;
|
|
||||||
|
|
||||||
for (p = value.start; p != value.end; p++) {
|
|
||||||
if (*p == ':' || *p == '$' || *p == '\\' || *p == endc ||
|
|
||||||
*p == '\n')
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* While expanding the body of a .for loop, write the item as a ${:U...}
|
* While expanding the body of a .for loop, write the item as a ${:U...}
|
||||||
* expression, escaping characters as needed. The result is later unescaped
|
* expression, escaping characters as needed. The result is later unescaped
|
||||||
|
@ -357,11 +342,6 @@ AddEscaped(Buffer *cmds, Substring item, char endc)
|
||||||
const char *p;
|
const char *p;
|
||||||
char ch;
|
char ch;
|
||||||
|
|
||||||
if (!NeedsEscapes(item, endc)) {
|
|
||||||
Buf_AddRange(cmds, item.start, item.end);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (p = item.start; p != item.end;) {
|
for (p = item.start; p != item.end;) {
|
||||||
ch = *p;
|
ch = *p;
|
||||||
if (ch == '$') {
|
if (ch == '$') {
|
||||||
|
|
27
hash.c
27
hash.c
|
@ -1,4 +1,4 @@
|
||||||
/* $NetBSD: hash.c,v 1.74 2023/12/19 19:33:39 rillig Exp $ */
|
/* $NetBSD: hash.c,v 1.78 2024/06/05 22:06:53 rillig Exp $ */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 1988, 1989, 1990 The Regents of the University of California.
|
* Copyright (c) 1988, 1989, 1990 The Regents of the University of California.
|
||||||
|
@ -74,7 +74,7 @@
|
||||||
#include "make.h"
|
#include "make.h"
|
||||||
|
|
||||||
/* "@(#)hash.c 8.1 (Berkeley) 6/6/93" */
|
/* "@(#)hash.c 8.1 (Berkeley) 6/6/93" */
|
||||||
MAKE_RCSID("$NetBSD: hash.c,v 1.74 2023/12/19 19:33:39 rillig Exp $");
|
MAKE_RCSID("$NetBSD: hash.c,v 1.78 2024/06/05 22:06:53 rillig Exp $");
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The ratio of # entries to # buckets at which we rebuild the table to
|
* The ratio of # entries to # buckets at which we rebuild the table to
|
||||||
|
@ -288,24 +288,19 @@ void
|
||||||
HashTable_DeleteEntry(HashTable *t, HashEntry *he)
|
HashTable_DeleteEntry(HashTable *t, HashEntry *he)
|
||||||
{
|
{
|
||||||
HashEntry **ref = &t->buckets[he->hash & t->bucketsMask];
|
HashEntry **ref = &t->buckets[he->hash & t->bucketsMask];
|
||||||
HashEntry *p;
|
|
||||||
|
|
||||||
for (; (p = *ref) != NULL; ref = &p->next) {
|
for (; *ref != he; ref = &(*ref)->next)
|
||||||
if (p == he) {
|
continue;
|
||||||
*ref = p->next;
|
*ref = he->next;
|
||||||
free(p);
|
free(he);
|
||||||
t->numEntries--;
|
t->numEntries--;
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
abort();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Return the next entry in the hash table, or NULL if the end of the table
|
* Place the next entry from the hash table in hi->entry, or return false if
|
||||||
* is reached.
|
* the end of the table is reached.
|
||||||
*/
|
*/
|
||||||
HashEntry *
|
bool
|
||||||
HashIter_Next(HashIter *hi)
|
HashIter_Next(HashIter *hi)
|
||||||
{
|
{
|
||||||
HashTable *t = hi->table;
|
HashTable *t = hi->table;
|
||||||
|
@ -318,11 +313,11 @@ HashIter_Next(HashIter *hi)
|
||||||
|
|
||||||
while (he == NULL) { /* find the next nonempty chain */
|
while (he == NULL) { /* find the next nonempty chain */
|
||||||
if (hi->nextBucket >= bucketsSize)
|
if (hi->nextBucket >= bucketsSize)
|
||||||
return NULL;
|
return false;
|
||||||
he = buckets[hi->nextBucket++];
|
he = buckets[hi->nextBucket++];
|
||||||
}
|
}
|
||||||
hi->entry = he;
|
hi->entry = he;
|
||||||
return he;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
|
4
hash.h
4
hash.h
|
@ -1,4 +1,4 @@
|
||||||
/* $NetBSD: hash.h,v 1.48 2023/12/19 19:33:39 rillig Exp $ */
|
/* $NetBSD: hash.h,v 1.50 2024/06/01 10:10:50 rillig Exp $ */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 1988, 1989, 1990 The Regents of the University of California.
|
* Copyright (c) 1988, 1989, 1990 The Regents of the University of California.
|
||||||
|
@ -140,7 +140,7 @@ void HashTable_Set(HashTable *, const char *, void *);
|
||||||
void HashTable_DeleteEntry(HashTable *, HashEntry *);
|
void HashTable_DeleteEntry(HashTable *, HashEntry *);
|
||||||
void HashTable_DebugStats(HashTable *, const char *);
|
void HashTable_DebugStats(HashTable *, const char *);
|
||||||
|
|
||||||
HashEntry *HashIter_Next(HashIter *);
|
bool HashIter_Next(HashIter *) MAKE_ATTR_USE;
|
||||||
|
|
||||||
MAKE_INLINE void
|
MAKE_INLINE void
|
||||||
HashSet_Init(HashSet *set)
|
HashSet_Init(HashSet *set)
|
||||||
|
|
36
job.c
36
job.c
|
@ -1,4 +1,4 @@
|
||||||
/* $NetBSD: job.c,v 1.471 2024/05/07 18:26:22 sjg Exp $ */
|
/* $NetBSD: job.c,v 1.477 2024/06/25 05:18:38 rillig Exp $ */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 1988, 1989, 1990 The Regents of the University of California.
|
* Copyright (c) 1988, 1989, 1990 The Regents of the University of California.
|
||||||
|
@ -154,7 +154,7 @@
|
||||||
#include "trace.h"
|
#include "trace.h"
|
||||||
|
|
||||||
/* "@(#)job.c 8.2 (Berkeley) 3/19/94" */
|
/* "@(#)job.c 8.2 (Berkeley) 3/19/94" */
|
||||||
MAKE_RCSID("$NetBSD: job.c,v 1.471 2024/05/07 18:26:22 sjg Exp $");
|
MAKE_RCSID("$NetBSD: job.c,v 1.477 2024/06/25 05:18:38 rillig Exp $");
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* A shell defines how the commands are run. All commands for a target are
|
* A shell defines how the commands are run. All commands for a target are
|
||||||
|
@ -914,9 +914,7 @@ JobWriteCommand(Job *job, ShellWriter *wr, StringListNode *ln, const char *ucmd)
|
||||||
|
|
||||||
run = GNode_ShouldExecute(job->node);
|
run = GNode_ShouldExecute(job->node);
|
||||||
|
|
||||||
EvalStack_Push(job->node->name, NULL, NULL);
|
xcmd = Var_SubstInTarget(ucmd, job->node);
|
||||||
xcmd = Var_Subst(ucmd, job->node, VARE_WANTRES);
|
|
||||||
EvalStack_Pop();
|
|
||||||
/* TODO: handle errors */
|
/* TODO: handle errors */
|
||||||
xcmdStart = xcmd;
|
xcmdStart = xcmd;
|
||||||
|
|
||||||
|
@ -1043,11 +1041,10 @@ JobSaveCommands(Job *job)
|
||||||
* variables such as .TARGET, .IMPSRC. It is not intended to
|
* variables such as .TARGET, .IMPSRC. It is not intended to
|
||||||
* expand the other variables as well; see deptgt-end.mk.
|
* expand the other variables as well; see deptgt-end.mk.
|
||||||
*/
|
*/
|
||||||
EvalStack_Push(job->node->name, NULL, NULL);
|
expanded_cmd = Var_SubstInTarget(cmd, job->node);
|
||||||
expanded_cmd = Var_Subst(cmd, job->node, VARE_WANTRES);
|
|
||||||
EvalStack_Pop();
|
|
||||||
/* TODO: handle errors */
|
/* TODO: handle errors */
|
||||||
Lst_Append(&Targ_GetEndNode()->commands, expanded_cmd);
|
Lst_Append(&Targ_GetEndNode()->commands, expanded_cmd);
|
||||||
|
Parse_RegisterCommand(expanded_cmd);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1082,7 +1079,7 @@ DebugFailedJob(const Job *job)
|
||||||
debug_printf("\t%s\n", cmd);
|
debug_printf("\t%s\n", cmd);
|
||||||
|
|
||||||
if (strchr(cmd, '$') != NULL) {
|
if (strchr(cmd, '$') != NULL) {
|
||||||
char *xcmd = Var_Subst(cmd, job->node, VARE_WANTRES);
|
char *xcmd = Var_Subst(cmd, job->node, VARE_EVAL);
|
||||||
debug_printf("\t=> %s\n", xcmd);
|
debug_printf("\t=> %s\n", xcmd);
|
||||||
free(xcmd);
|
free(xcmd);
|
||||||
}
|
}
|
||||||
|
@ -1468,11 +1465,11 @@ JobExec(Job *job, char **argv)
|
||||||
* was marked close-on-exec, we must clear that bit in the
|
* was marked close-on-exec, we must clear that bit in the
|
||||||
* new input.
|
* new input.
|
||||||
*/
|
*/
|
||||||
if (dup2(fileno(job->cmdFILE), 0) == -1)
|
if (dup2(fileno(job->cmdFILE), STDIN_FILENO) == -1)
|
||||||
execDie("dup2", "job->cmdFILE");
|
execDie("dup2", "job->cmdFILE");
|
||||||
if (fcntl(0, F_SETFD, 0) == -1)
|
if (fcntl(STDIN_FILENO, F_SETFD, 0) == -1)
|
||||||
execDie("fcntl clear close-on-exec", "stdin");
|
execDie("fcntl clear close-on-exec", "stdin");
|
||||||
if (lseek(0, 0, SEEK_SET) == -1)
|
if (lseek(STDIN_FILENO, 0, SEEK_SET) == -1)
|
||||||
execDie("lseek to 0", "stdin");
|
execDie("lseek to 0", "stdin");
|
||||||
|
|
||||||
if (job->node->type & (OP_MAKE | OP_SUBMAKE)) {
|
if (job->node->type & (OP_MAKE | OP_SUBMAKE)) {
|
||||||
|
@ -1489,18 +1486,18 @@ JobExec(Job *job, char **argv)
|
||||||
* Set up the child's output to be routed through the pipe
|
* Set up the child's output to be routed through the pipe
|
||||||
* we've created for it.
|
* we've created for it.
|
||||||
*/
|
*/
|
||||||
if (dup2(job->outPipe, 1) == -1)
|
if (dup2(job->outPipe, STDOUT_FILENO) == -1)
|
||||||
execDie("dup2", "job->outPipe");
|
execDie("dup2", "job->outPipe");
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The output channels are marked close on exec. This bit
|
* The output channels are marked close on exec. This bit
|
||||||
* was duplicated by the dup2(on some systems), so we have
|
* was duplicated by dup2 (on some systems), so we have
|
||||||
* to clear it before routing the shell's error output to
|
* to clear it before routing the shell's error output to
|
||||||
* the same place as its standard output.
|
* the same place as its standard output.
|
||||||
*/
|
*/
|
||||||
if (fcntl(1, F_SETFD, 0) == -1)
|
if (fcntl(STDOUT_FILENO, F_SETFD, 0) == -1)
|
||||||
execDie("clear close-on-exec", "stdout");
|
execDie("clear close-on-exec", "stdout");
|
||||||
if (dup2(1, 2) == -1)
|
if (dup2(STDOUT_FILENO, STDERR_FILENO) == -1)
|
||||||
execDie("dup2", "1, 2");
|
execDie("dup2", "1, 2");
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -2155,7 +2152,7 @@ InitShellNameAndPath(void)
|
||||||
|
|
||||||
#ifdef DEFSHELL_CUSTOM
|
#ifdef DEFSHELL_CUSTOM
|
||||||
if (shellName[0] == '/') {
|
if (shellName[0] == '/') {
|
||||||
shellPath = shellName;
|
shellPath = bmake_strdup(shellName);
|
||||||
shellName = str_basename(shellPath);
|
shellName = str_basename(shellPath);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -2212,7 +2209,7 @@ Job_SetPrefix(void)
|
||||||
Global_Set(".MAKE.JOB.PREFIX", "---");
|
Global_Set(".MAKE.JOB.PREFIX", "---");
|
||||||
|
|
||||||
targPrefix = Var_Subst("${.MAKE.JOB.PREFIX}",
|
targPrefix = Var_Subst("${.MAKE.JOB.PREFIX}",
|
||||||
SCOPE_GLOBAL, VARE_WANTRES);
|
SCOPE_GLOBAL, VARE_EVAL);
|
||||||
/* TODO: handle errors */
|
/* TODO: handle errors */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2502,7 +2499,8 @@ Job_ParseShell(char *line)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
shellPath = path;
|
free(UNCONST(shellPath));
|
||||||
|
shellPath = bmake_strdup(path);
|
||||||
shellName = newShell.name != NULL ? newShell.name
|
shellName = newShell.name != NULL ? newShell.name
|
||||||
: str_basename(path);
|
: str_basename(path);
|
||||||
if (!fullSpec) {
|
if (!fullSpec) {
|
||||||
|
|
61
main.c
61
main.c
|
@ -1,4 +1,4 @@
|
||||||
/* $NetBSD: main.c,v 1.616 2024/05/19 17:55:54 sjg Exp $ */
|
/* $NetBSD: main.c,v 1.624 2024/06/02 15:31:26 rillig Exp $ */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 1988, 1989, 1990, 1993
|
* Copyright (c) 1988, 1989, 1990, 1993
|
||||||
|
@ -111,7 +111,7 @@
|
||||||
#include "trace.h"
|
#include "trace.h"
|
||||||
|
|
||||||
/* "@(#)main.c 8.3 (Berkeley) 3/19/94" */
|
/* "@(#)main.c 8.3 (Berkeley) 3/19/94" */
|
||||||
MAKE_RCSID("$NetBSD: main.c,v 1.616 2024/05/19 17:55:54 sjg Exp $");
|
MAKE_RCSID("$NetBSD: main.c,v 1.624 2024/06/02 15:31:26 rillig Exp $");
|
||||||
#if defined(MAKE_NATIVE)
|
#if defined(MAKE_NATIVE)
|
||||||
__COPYRIGHT("@(#) Copyright (c) 1988, 1989, 1990, 1993 "
|
__COPYRIGHT("@(#) Copyright (c) 1988, 1989, 1990, 1993 "
|
||||||
"The Regents of the University of California. "
|
"The Regents of the University of California. "
|
||||||
|
@ -372,7 +372,7 @@ MainParseArgChdir(const char *argvalue)
|
||||||
stat(curdir, &sb) != -1 &&
|
stat(curdir, &sb) != -1 &&
|
||||||
sa.st_ino == sb.st_ino &&
|
sa.st_ino == sb.st_ino &&
|
||||||
sa.st_dev == sb.st_dev)
|
sa.st_dev == sb.st_dev)
|
||||||
strncpy(curdir, argvalue, MAXPATHLEN);
|
snprintf(curdir, MAXPATHLEN, "%s", argvalue);
|
||||||
ignorePWD = true;
|
ignorePWD = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -743,6 +743,10 @@ Main_SetObjdir(bool writable, const char *fmt, ...)
|
||||||
if ((writable && access(path, W_OK) != 0) || chdir(path) != 0) {
|
if ((writable && access(path, W_OK) != 0) || chdir(path) != 0) {
|
||||||
(void)fprintf(stderr, "%s: warning: %s: %s.\n",
|
(void)fprintf(stderr, "%s: warning: %s: %s.\n",
|
||||||
progname, path, strerror(errno));
|
progname, path, strerror(errno));
|
||||||
|
/* Allow debugging how we got here - not always obvious */
|
||||||
|
if (GetBooleanExpr("${MAKE_DEBUG_OBJDIR_CHECK_WRITABLE}",
|
||||||
|
false))
|
||||||
|
PrintOnError(NULL, "");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -766,7 +770,7 @@ SetVarObjdir(bool writable, const char *var, const char *suffix)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
Var_Expand(&path, SCOPE_GLOBAL, VARE_WANTRES);
|
Var_Expand(&path, SCOPE_GLOBAL, VARE_EVAL);
|
||||||
|
|
||||||
(void)Main_SetObjdir(writable, "%s%s", path.str, suffix);
|
(void)Main_SetObjdir(writable, "%s%s", path.str, suffix);
|
||||||
|
|
||||||
|
@ -808,8 +812,7 @@ siginfo(int signo MAKE_ATTR_UNUSED)
|
||||||
static void
|
static void
|
||||||
MakeMode(void)
|
MakeMode(void)
|
||||||
{
|
{
|
||||||
char *mode = Var_Subst("${.MAKE.MODE:tl}",
|
char *mode = Var_Subst("${.MAKE.MODE:tl}", SCOPE_GLOBAL, VARE_EVAL);
|
||||||
SCOPE_GLOBAL, VARE_WANTRES);
|
|
||||||
/* TODO: handle errors */
|
/* TODO: handle errors */
|
||||||
|
|
||||||
if (mode[0] != '\0') {
|
if (mode[0] != '\0') {
|
||||||
|
@ -832,14 +835,14 @@ static void
|
||||||
PrintVar(const char *varname, bool expandVars)
|
PrintVar(const char *varname, bool expandVars)
|
||||||
{
|
{
|
||||||
if (strchr(varname, '$') != NULL) {
|
if (strchr(varname, '$') != NULL) {
|
||||||
char *evalue = Var_Subst(varname, SCOPE_GLOBAL, VARE_WANTRES);
|
char *evalue = Var_Subst(varname, SCOPE_GLOBAL, VARE_EVAL);
|
||||||
/* TODO: handle errors */
|
/* TODO: handle errors */
|
||||||
printf("%s\n", evalue);
|
printf("%s\n", evalue);
|
||||||
free(evalue);
|
free(evalue);
|
||||||
|
|
||||||
} else if (expandVars) {
|
} else if (expandVars) {
|
||||||
char *expr = str_concat3("${", varname, "}");
|
char *expr = str_concat3("${", varname, "}");
|
||||||
char *evalue = Var_Subst(expr, SCOPE_GLOBAL, VARE_WANTRES);
|
char *evalue = Var_Subst(expr, SCOPE_GLOBAL, VARE_EVAL);
|
||||||
/* TODO: handle errors */
|
/* TODO: handle errors */
|
||||||
free(expr);
|
free(expr);
|
||||||
printf("%s\n", evalue);
|
printf("%s\n", evalue);
|
||||||
|
@ -865,7 +868,7 @@ GetBooleanExpr(const char *expr, bool fallback)
|
||||||
char *value;
|
char *value;
|
||||||
bool res;
|
bool res;
|
||||||
|
|
||||||
value = Var_Subst(expr, SCOPE_GLOBAL, VARE_WANTRES);
|
value = Var_Subst(expr, SCOPE_GLOBAL, VARE_EVAL);
|
||||||
/* TODO: handle errors */
|
/* TODO: handle errors */
|
||||||
res = ParseBoolean(value, fallback);
|
res = ParseBoolean(value, fallback);
|
||||||
free(value);
|
free(value);
|
||||||
|
@ -1050,7 +1053,7 @@ HandlePWD(const struct stat *curdir_st)
|
||||||
if (stat(pwd, &pwd_st) == 0 &&
|
if (stat(pwd, &pwd_st) == 0 &&
|
||||||
curdir_st->st_ino == pwd_st.st_ino &&
|
curdir_st->st_ino == pwd_st.st_ino &&
|
||||||
curdir_st->st_dev == pwd_st.st_dev)
|
curdir_st->st_dev == pwd_st.st_dev)
|
||||||
(void)strncpy(curdir, pwd, MAXPATHLEN);
|
snprintf(curdir, MAXPATHLEN, "%s", pwd);
|
||||||
|
|
||||||
ignore_pwd:
|
ignore_pwd:
|
||||||
FStr_Done(&makeobjdir);
|
FStr_Done(&makeobjdir);
|
||||||
|
@ -1140,9 +1143,9 @@ static void
|
||||||
InitVarMake(const char *argv0)
|
InitVarMake(const char *argv0)
|
||||||
{
|
{
|
||||||
const char *make = argv0;
|
const char *make = argv0;
|
||||||
|
char pathbuf[MAXPATHLEN];
|
||||||
|
|
||||||
if (argv0[0] != '/' && strchr(argv0, '/') != NULL) {
|
if (argv0[0] != '/' && strchr(argv0, '/') != NULL) {
|
||||||
char pathbuf[MAXPATHLEN];
|
|
||||||
const char *abspath = cached_realpath(argv0, pathbuf);
|
const char *abspath = cached_realpath(argv0, pathbuf);
|
||||||
struct stat st;
|
struct stat st;
|
||||||
if (abspath != NULL && abspath[0] == '/' &&
|
if (abspath != NULL && abspath[0] == '/' &&
|
||||||
|
@ -1230,7 +1233,7 @@ InitMaxJobs(void)
|
||||||
!Var_Exists(SCOPE_GLOBAL, ".MAKE.JOBS"))
|
!Var_Exists(SCOPE_GLOBAL, ".MAKE.JOBS"))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
value = Var_Subst("${.MAKE.JOBS}", SCOPE_GLOBAL, VARE_WANTRES);
|
value = Var_Subst("${.MAKE.JOBS}", SCOPE_GLOBAL, VARE_EVAL);
|
||||||
/* TODO: handle errors */
|
/* TODO: handle errors */
|
||||||
n = (int)strtol(value, NULL, 0);
|
n = (int)strtol(value, NULL, 0);
|
||||||
if (n < 1) {
|
if (n < 1) {
|
||||||
|
@ -1265,7 +1268,7 @@ InitVpath(void)
|
||||||
if (!Var_Exists(SCOPE_CMDLINE, "VPATH"))
|
if (!Var_Exists(SCOPE_CMDLINE, "VPATH"))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
vpath = Var_Subst("${VPATH}", SCOPE_CMDLINE, VARE_WANTRES);
|
vpath = Var_Subst("${VPATH}", SCOPE_CMDLINE, VARE_EVAL);
|
||||||
/* TODO: handle errors */
|
/* TODO: handle errors */
|
||||||
path = vpath;
|
path = vpath;
|
||||||
do {
|
do {
|
||||||
|
@ -1302,7 +1305,7 @@ ReadFirstDefaultMakefile(void)
|
||||||
StringList makefiles = LST_INIT;
|
StringList makefiles = LST_INIT;
|
||||||
StringListNode *ln;
|
StringListNode *ln;
|
||||||
char *prefs = Var_Subst("${.MAKE.MAKEFILE_PREFERENCE}",
|
char *prefs = Var_Subst("${.MAKE.MAKEFILE_PREFERENCE}",
|
||||||
SCOPE_CMDLINE, VARE_WANTRES);
|
SCOPE_CMDLINE, VARE_EVAL);
|
||||||
/* TODO: handle errors */
|
/* TODO: handle errors */
|
||||||
|
|
||||||
AppendWords(&makefiles, prefs);
|
AppendWords(&makefiles, prefs);
|
||||||
|
@ -1513,7 +1516,7 @@ main_PrepareMaking(void)
|
||||||
/* In particular suppress .depend for '-r -V .OBJDIR -f /dev/null' */
|
/* In particular suppress .depend for '-r -V .OBJDIR -f /dev/null' */
|
||||||
if (!opts.noBuiltins || opts.printVars == PVM_NONE) {
|
if (!opts.noBuiltins || opts.printVars == PVM_NONE) {
|
||||||
makeDependfile = Var_Subst("${.MAKE.DEPENDFILE}",
|
makeDependfile = Var_Subst("${.MAKE.DEPENDFILE}",
|
||||||
SCOPE_CMDLINE, VARE_WANTRES);
|
SCOPE_CMDLINE, VARE_EVAL);
|
||||||
if (makeDependfile[0] != '\0') {
|
if (makeDependfile[0] != '\0') {
|
||||||
/* TODO: handle errors */
|
/* TODO: handle errors */
|
||||||
doing_depend = true;
|
doing_depend = true;
|
||||||
|
@ -1605,9 +1608,9 @@ main_CleanUp(void)
|
||||||
meta_finish();
|
meta_finish();
|
||||||
#endif
|
#endif
|
||||||
Suff_End();
|
Suff_End();
|
||||||
|
Var_End();
|
||||||
Targ_End();
|
Targ_End();
|
||||||
Arch_End();
|
Arch_End();
|
||||||
Var_End();
|
|
||||||
Parse_End();
|
Parse_End();
|
||||||
Dir_End();
|
Dir_End();
|
||||||
Job_End();
|
Job_End();
|
||||||
|
@ -1988,22 +1991,19 @@ execDie(const char *af, const char *av)
|
||||||
static void
|
static void
|
||||||
purge_relative_cached_realpaths(void)
|
purge_relative_cached_realpaths(void)
|
||||||
{
|
{
|
||||||
HashEntry *he, *next;
|
|
||||||
HashIter hi;
|
HashIter hi;
|
||||||
|
bool more;
|
||||||
|
|
||||||
HashIter_Init(&hi, &cached_realpaths);
|
HashIter_Init(&hi, &cached_realpaths);
|
||||||
he = HashIter_Next(&hi);
|
more = HashIter_Next(&hi);
|
||||||
while (he != NULL) {
|
while (more) {
|
||||||
next = HashIter_Next(&hi);
|
HashEntry *he = hi.entry;
|
||||||
|
more = HashIter_Next(&hi);
|
||||||
if (he->key[0] != '/') {
|
if (he->key[0] != '/') {
|
||||||
DEBUG1(DIR, "cached_realpath: purging %s\n", he->key);
|
DEBUG1(DIR, "cached_realpath: purging %s\n", he->key);
|
||||||
|
free(he->value);
|
||||||
HashTable_DeleteEntry(&cached_realpaths, he);
|
HashTable_DeleteEntry(&cached_realpaths, he);
|
||||||
/*
|
|
||||||
* XXX: What about the allocated he->value? Either
|
|
||||||
* free them or document why they cannot be freed.
|
|
||||||
*/
|
|
||||||
}
|
}
|
||||||
he = next;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2017,9 +2017,7 @@ cached_realpath(const char *pathname, char *resolved)
|
||||||
|
|
||||||
rp = HashTable_FindValue(&cached_realpaths, pathname);
|
rp = HashTable_FindValue(&cached_realpaths, pathname);
|
||||||
if (rp != NULL) {
|
if (rp != NULL) {
|
||||||
/* a hit */
|
snprintf(resolved, MAXPATHLEN, "%s", rp);
|
||||||
strncpy(resolved, rp, MAXPATHLEN);
|
|
||||||
resolved[MAXPATHLEN - 1] = '\0';
|
|
||||||
return resolved;
|
return resolved;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2107,7 +2105,7 @@ PrintOnError(GNode *gn, const char *msg)
|
||||||
{
|
{
|
||||||
char *errorVarsValues = Var_Subst(
|
char *errorVarsValues = Var_Subst(
|
||||||
"${MAKE_PRINT_VAR_ON_ERROR:@v@$v='${$v}'\n@}",
|
"${MAKE_PRINT_VAR_ON_ERROR:@v@$v='${$v}'\n@}",
|
||||||
SCOPE_GLOBAL, VARE_WANTRES);
|
SCOPE_GLOBAL, VARE_EVAL);
|
||||||
/* TODO: handle errors */
|
/* TODO: handle errors */
|
||||||
printf("%s", errorVarsValues);
|
printf("%s", errorVarsValues);
|
||||||
free(errorVarsValues);
|
free(errorVarsValues);
|
||||||
|
@ -2137,10 +2135,11 @@ Main_ExportMAKEFLAGS(bool first)
|
||||||
|
|
||||||
flags = Var_Subst(
|
flags = Var_Subst(
|
||||||
"${.MAKEFLAGS} ${.MAKEOVERRIDES:O:u:@v@$v=${$v:Q}@}",
|
"${.MAKEFLAGS} ${.MAKEOVERRIDES:O:u:@v@$v=${$v:Q}@}",
|
||||||
SCOPE_CMDLINE, VARE_WANTRES);
|
SCOPE_CMDLINE, VARE_EVAL);
|
||||||
/* TODO: handle errors */
|
/* TODO: handle errors */
|
||||||
if (flags[0] != '\0')
|
if (flags[0] != '\0')
|
||||||
setenv("MAKEFLAGS", flags, 1);
|
setenv("MAKEFLAGS", flags, 1);
|
||||||
|
free(flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
char *
|
char *
|
||||||
|
@ -2154,7 +2153,7 @@ getTmpdir(void)
|
||||||
|
|
||||||
/* Honor $TMPDIR if it is valid, strip a trailing '/'. */
|
/* Honor $TMPDIR if it is valid, strip a trailing '/'. */
|
||||||
tmpdir = Var_Subst("${TMPDIR:tA:U" _PATH_TMP ":S,/$,,W}/",
|
tmpdir = Var_Subst("${TMPDIR:tA:U" _PATH_TMP ":S,/$,,W}/",
|
||||||
SCOPE_GLOBAL, VARE_WANTRES);
|
SCOPE_GLOBAL, VARE_EVAL);
|
||||||
/* TODO: handle errors */
|
/* TODO: handle errors */
|
||||||
|
|
||||||
if (stat(tmpdir, &st) < 0 || !S_ISDIR(st.st_mode)) {
|
if (stat(tmpdir, &st) < 0 || !S_ISDIR(st.st_mode)) {
|
||||||
|
|
33
make.1
33
make.1
|
@ -1,4 +1,4 @@
|
||||||
.\" $NetBSD: make.1,v 1.375 2024/03/10 02:53:37 sjg Exp $
|
.\" $NetBSD: make.1,v 1.377 2024/06/01 06:26:36 sjg Exp $
|
||||||
.\"
|
.\"
|
||||||
.\" Copyright (c) 1990, 1993
|
.\" Copyright (c) 1990, 1993
|
||||||
.\" The Regents of the University of California. All rights reserved.
|
.\" The Regents of the University of California. All rights reserved.
|
||||||
|
@ -29,7 +29,7 @@
|
||||||
.\"
|
.\"
|
||||||
.\" from: @(#)make.1 8.4 (Berkeley) 3/19/94
|
.\" from: @(#)make.1 8.4 (Berkeley) 3/19/94
|
||||||
.\"
|
.\"
|
||||||
.Dd March 9, 2024
|
.Dd June 1, 2024
|
||||||
.Dt MAKE 1
|
.Dt MAKE 1
|
||||||
.Os
|
.Os
|
||||||
.Sh NAME
|
.Sh NAME
|
||||||
|
@ -1143,9 +1143,19 @@ This mode can be used to detect undeclared dependencies between files.
|
||||||
Used to create files in a separate directory, see
|
Used to create files in a separate directory, see
|
||||||
.Va .OBJDIR .
|
.Va .OBJDIR .
|
||||||
.It Va MAKE_OBJDIR_CHECK_WRITABLE
|
.It Va MAKE_OBJDIR_CHECK_WRITABLE
|
||||||
Used to force a separate directory for the created files,
|
When true,
|
||||||
even if that directory is not writable, see
|
.Nm
|
||||||
.Va .OBJDIR .
|
will check that
|
||||||
|
.Va .OBJDIR
|
||||||
|
is writable, and issue a warning if not.
|
||||||
|
.It Va MAKE_DEBUG_OBJDIR_CHECK_WRITABLE
|
||||||
|
When true and
|
||||||
|
.Nm
|
||||||
|
is warning about an unwritable
|
||||||
|
.Va .OBJDIR ,
|
||||||
|
report the variables listed in
|
||||||
|
.Va MAKE_PRINT_VAR_ON_ERROR
|
||||||
|
to help debug.
|
||||||
.It Va MAKEOBJDIRPREFIX
|
.It Va MAKEOBJDIRPREFIX
|
||||||
Used to create files in a separate directory, see
|
Used to create files in a separate directory, see
|
||||||
.Va .OBJDIR .
|
.Va .OBJDIR .
|
||||||
|
@ -1951,12 +1961,7 @@ The directives for exporting and unexporting variables are:
|
||||||
.Bl -tag -width Ds
|
.Bl -tag -width Ds
|
||||||
.It Ic .export Ar variable No ...
|
.It Ic .export Ar variable No ...
|
||||||
Export the specified global variable.
|
Export the specified global variable.
|
||||||
If no variable list is provided, all globals are exported
|
.Pp
|
||||||
except for internal variables (those that start with
|
|
||||||
.Ql \&. ) .
|
|
||||||
This is not affected by the
|
|
||||||
.Fl X
|
|
||||||
flag, so should be used with caution.
|
|
||||||
For compatibility with other make programs,
|
For compatibility with other make programs,
|
||||||
.Cm export Ar variable\| Ns Cm \&= Ns Ar value
|
.Cm export Ar variable\| Ns Cm \&= Ns Ar value
|
||||||
(without leading dot) is also accepted.
|
(without leading dot) is also accepted.
|
||||||
|
@ -1964,6 +1969,12 @@ For compatibility with other make programs,
|
||||||
Appending a variable name to
|
Appending a variable name to
|
||||||
.Va .MAKE.EXPORTED
|
.Va .MAKE.EXPORTED
|
||||||
is equivalent to exporting a variable.
|
is equivalent to exporting a variable.
|
||||||
|
.It Ic .export-all
|
||||||
|
Export all globals except for internal variables (those that start with
|
||||||
|
.Ql \&. ) .
|
||||||
|
This is not affected by the
|
||||||
|
.Fl X
|
||||||
|
flag, so should be used with caution.
|
||||||
.It Ic .export-env Ar variable No ...
|
.It Ic .export-env Ar variable No ...
|
||||||
The same as
|
The same as
|
||||||
.Ql .export ,
|
.Ql .export ,
|
||||||
|
|
36
make.c
36
make.c
|
@ -1,4 +1,4 @@
|
||||||
/* $NetBSD: make.c,v 1.262 2024/01/05 23:22:06 rillig Exp $ */
|
/* $NetBSD: make.c,v 1.264 2024/06/02 15:31:26 rillig Exp $ */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 1988, 1989, 1990, 1993
|
* Copyright (c) 1988, 1989, 1990, 1993
|
||||||
|
@ -104,7 +104,7 @@
|
||||||
#include "job.h"
|
#include "job.h"
|
||||||
|
|
||||||
/* "@(#)make.c 8.1 (Berkeley) 6/6/93" */
|
/* "@(#)make.c 8.1 (Berkeley) 6/6/93" */
|
||||||
MAKE_RCSID("$NetBSD: make.c,v 1.262 2024/01/05 23:22:06 rillig Exp $");
|
MAKE_RCSID("$NetBSD: make.c,v 1.264 2024/06/02 15:31:26 rillig Exp $");
|
||||||
|
|
||||||
/* Sequence # to detect recursion. */
|
/* Sequence # to detect recursion. */
|
||||||
static unsigned int checked_seqno = 1;
|
static unsigned int checked_seqno = 1;
|
||||||
|
@ -127,8 +127,8 @@ debug_printf(const char *fmt, ...)
|
||||||
va_end(ap);
|
va_end(ap);
|
||||||
}
|
}
|
||||||
|
|
||||||
static const char *
|
static char *
|
||||||
GNodeType_ToString(GNodeType type, void **freeIt)
|
GNodeType_ToString(GNodeType type)
|
||||||
{
|
{
|
||||||
Buffer buf;
|
Buffer buf;
|
||||||
|
|
||||||
|
@ -166,11 +166,13 @@ GNodeType_ToString(GNodeType type, void **freeIt)
|
||||||
ADD(OP_DEPS_FOUND);
|
ADD(OP_DEPS_FOUND);
|
||||||
ADD(OP_MARK);
|
ADD(OP_MARK);
|
||||||
#undef ADD
|
#undef ADD
|
||||||
return buf.len == 0 ? "none" : (*freeIt = Buf_DoneData(&buf));
|
if (buf.len == 0)
|
||||||
|
Buf_AddStr(&buf, "none");
|
||||||
|
return Buf_DoneData(&buf);
|
||||||
}
|
}
|
||||||
|
|
||||||
static const char *
|
static char *
|
||||||
GNodeFlags_ToString(GNodeFlags flags, void **freeIt)
|
GNodeFlags_ToString(GNodeFlags flags)
|
||||||
{
|
{
|
||||||
Buffer buf;
|
Buffer buf;
|
||||||
|
|
||||||
|
@ -184,24 +186,22 @@ GNodeFlags_ToString(GNodeFlags flags, void **freeIt)
|
||||||
Buf_AddFlag(&buf, flags.doneAllsrc, "DONE_ALLSRC");
|
Buf_AddFlag(&buf, flags.doneAllsrc, "DONE_ALLSRC");
|
||||||
Buf_AddFlag(&buf, flags.cycle, "CYCLE");
|
Buf_AddFlag(&buf, flags.cycle, "CYCLE");
|
||||||
Buf_AddFlag(&buf, flags.doneCycle, "DONECYCLE");
|
Buf_AddFlag(&buf, flags.doneCycle, "DONECYCLE");
|
||||||
return buf.len == 0 ? "none" : (*freeIt = Buf_DoneData(&buf));
|
if (buf.len == 0)
|
||||||
|
Buf_AddStr(&buf, "none");
|
||||||
|
return Buf_DoneData(&buf);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
GNode_FprintDetails(FILE *f, const char *prefix, const GNode *gn,
|
GNode_FprintDetails(FILE *f, const char *prefix, const GNode *gn,
|
||||||
const char *suffix)
|
const char *suffix)
|
||||||
{
|
{
|
||||||
void *type_freeIt = NULL;
|
char *type = GNodeType_ToString(gn->type);
|
||||||
void *flags_freeIt = NULL;
|
char *flags = GNodeFlags_ToString(gn->flags);
|
||||||
|
|
||||||
fprintf(f, "%s%s, type %s, flags %s%s",
|
fprintf(f, "%s%s, type %s, flags %s%s",
|
||||||
prefix,
|
prefix, GNodeMade_Name(gn->made), type, flags, suffix);
|
||||||
GNodeMade_Name(gn->made),
|
free(type);
|
||||||
GNodeType_ToString(gn->type, &type_freeIt),
|
free(flags);
|
||||||
GNodeFlags_ToString(gn->flags, &flags_freeIt),
|
|
||||||
suffix);
|
|
||||||
free(type_freeIt);
|
|
||||||
free(flags_freeIt);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
|
@ -443,7 +443,7 @@ Make_HandleUse(GNode *cgn, GNode *pgn)
|
||||||
gn->uname = gn->name;
|
gn->uname = gn->name;
|
||||||
else
|
else
|
||||||
free(gn->name);
|
free(gn->name);
|
||||||
gn->name = Var_Subst(gn->uname, pgn, VARE_WANTRES);
|
gn->name = Var_Subst(gn->uname, pgn, VARE_EVAL);
|
||||||
/* TODO: handle errors */
|
/* TODO: handle errors */
|
||||||
if (gn->uname != NULL && strcmp(gn->name, gn->uname) != 0) {
|
if (gn->uname != NULL && strcmp(gn->name, gn->uname) != 0) {
|
||||||
/* See if we have a target for this node. */
|
/* See if we have a target for this node. */
|
||||||
|
|
41
make.h
41
make.h
|
@ -1,4 +1,4 @@
|
||||||
/* $NetBSD: make.h,v 1.333 2024/05/07 18:26:22 sjg Exp $ */
|
/* $NetBSD: make.h,v 1.339 2024/06/15 20:02:45 rillig Exp $ */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 1988, 1989, 1990, 1993
|
* Copyright (c) 1988, 1989, 1990, 1993
|
||||||
|
@ -938,6 +938,15 @@ void Targ_PrintType(GNodeType);
|
||||||
void Targ_PrintGraph(int);
|
void Targ_PrintGraph(int);
|
||||||
void Targ_Propagate(void);
|
void Targ_Propagate(void);
|
||||||
const char *GNodeMade_Name(GNodeMade) MAKE_ATTR_USE;
|
const char *GNodeMade_Name(GNodeMade) MAKE_ATTR_USE;
|
||||||
|
#ifdef CLEANUP
|
||||||
|
void Parse_RegisterCommand(char *);
|
||||||
|
#else
|
||||||
|
/* ARGSUSED */
|
||||||
|
MAKE_INLINE
|
||||||
|
void Parse_RegisterCommand(char *cmd MAKE_ATTR_UNUSED)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
/* var.c */
|
/* var.c */
|
||||||
void Var_Init(void);
|
void Var_Init(void);
|
||||||
|
@ -951,7 +960,7 @@ typedef enum VarEvalMode {
|
||||||
* TODO: Document what Var_Parse and Var_Subst return in this mode.
|
* TODO: Document what Var_Parse and Var_Subst return in this mode.
|
||||||
* As of 2021-03-15, they return unspecified, inconsistent results.
|
* As of 2021-03-15, they return unspecified, inconsistent results.
|
||||||
*/
|
*/
|
||||||
VARE_PARSE_ONLY,
|
VARE_PARSE,
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Parse text in which '${...}' and '$(...)' are not parsed as
|
* Parse text in which '${...}' and '$(...)' are not parsed as
|
||||||
|
@ -962,25 +971,13 @@ typedef enum VarEvalMode {
|
||||||
VARE_PARSE_BALANCED,
|
VARE_PARSE_BALANCED,
|
||||||
|
|
||||||
/* Parse and evaluate the expression. */
|
/* Parse and evaluate the expression. */
|
||||||
VARE_WANTRES,
|
VARE_EVAL,
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Parse and evaluate the expression. It is an error if a
|
* Parse and evaluate the expression. It is an error if a
|
||||||
* subexpression evaluates to undefined.
|
* subexpression evaluates to undefined.
|
||||||
*/
|
*/
|
||||||
VARE_UNDEFERR,
|
VARE_EVAL_DEFINED,
|
||||||
|
|
||||||
/*
|
|
||||||
* Parse and evaluate the expression. Keep '$$' as '$$' instead of
|
|
||||||
* reducing it to a single '$'. Subexpressions that evaluate to
|
|
||||||
* undefined expand to an empty string.
|
|
||||||
*
|
|
||||||
* Used in variable assignments using the ':=' operator. It allows
|
|
||||||
* multiple such assignments to be chained without accidentally
|
|
||||||
* expanding '$$file' to '$file' in the first assignment and
|
|
||||||
* interpreting it as '${f}' followed by 'ile' in the next assignment.
|
|
||||||
*/
|
|
||||||
VARE_EVAL_KEEP_DOLLAR,
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Parse and evaluate the expression. Keep undefined variables as-is
|
* Parse and evaluate the expression. Keep undefined variables as-is
|
||||||
|
@ -993,13 +990,13 @@ typedef enum VarEvalMode {
|
||||||
* # way) is still undefined, the updated CFLAGS becomes
|
* # way) is still undefined, the updated CFLAGS becomes
|
||||||
* # "-I.. $(.INCLUDES)".
|
* # "-I.. $(.INCLUDES)".
|
||||||
*/
|
*/
|
||||||
VARE_EVAL_KEEP_UNDEF,
|
VARE_EVAL_KEEP_UNDEFINED,
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Parse and evaluate the expression. Keep '$$' as '$$' and preserve
|
* Parse and evaluate the expression. Keep '$$' as '$$' and preserve
|
||||||
* undefined subexpressions.
|
* undefined subexpressions.
|
||||||
*/
|
*/
|
||||||
VARE_KEEP_DOLLAR_UNDEF
|
VARE_EVAL_KEEP_DOLLAR_AND_UNDEFINED
|
||||||
} VarEvalMode;
|
} VarEvalMode;
|
||||||
|
|
||||||
typedef enum VarSetFlags {
|
typedef enum VarSetFlags {
|
||||||
|
@ -1018,6 +1015,8 @@ typedef enum VarSetFlags {
|
||||||
} VarSetFlags;
|
} VarSetFlags;
|
||||||
|
|
||||||
typedef enum VarExportMode {
|
typedef enum VarExportMode {
|
||||||
|
/* .export-all */
|
||||||
|
VEM_ALL,
|
||||||
/* .export-env */
|
/* .export-env */
|
||||||
VEM_ENV,
|
VEM_ENV,
|
||||||
/* .export: Initial export or update an already exported variable. */
|
/* .export: Initial export or update an already exported variable. */
|
||||||
|
@ -1027,6 +1026,9 @@ typedef enum VarExportMode {
|
||||||
} VarExportMode;
|
} VarExportMode;
|
||||||
|
|
||||||
void Var_Delete(GNode *, const char *);
|
void Var_Delete(GNode *, const char *);
|
||||||
|
#ifdef CLEANUP
|
||||||
|
void Var_DeleteAll(GNode *scope);
|
||||||
|
#endif
|
||||||
void Var_Undef(const char *);
|
void Var_Undef(const char *);
|
||||||
void Var_Set(GNode *, const char *, const char *);
|
void Var_Set(GNode *, const char *, const char *);
|
||||||
void Var_SetExpand(GNode *, const char *, const char *);
|
void Var_SetExpand(GNode *, const char *, const char *);
|
||||||
|
@ -1039,6 +1041,7 @@ FStr Var_Value(GNode *, const char *) MAKE_ATTR_USE;
|
||||||
const char *GNode_ValueDirect(GNode *, const char *) MAKE_ATTR_USE;
|
const char *GNode_ValueDirect(GNode *, const char *) MAKE_ATTR_USE;
|
||||||
FStr Var_Parse(const char **, GNode *, VarEvalMode);
|
FStr Var_Parse(const char **, GNode *, VarEvalMode);
|
||||||
char *Var_Subst(const char *, GNode *, VarEvalMode);
|
char *Var_Subst(const char *, GNode *, VarEvalMode);
|
||||||
|
char *Var_SubstInTarget(const char *, GNode *);
|
||||||
void Var_Expand(FStr *, GNode *, VarEvalMode);
|
void Var_Expand(FStr *, GNode *, VarEvalMode);
|
||||||
void Var_Stats(void);
|
void Var_Stats(void);
|
||||||
void Var_Dump(GNode *);
|
void Var_Dump(GNode *);
|
||||||
|
@ -1053,8 +1056,6 @@ void Global_Append(const char *, const char *);
|
||||||
void Global_Delete(const char *);
|
void Global_Delete(const char *);
|
||||||
void Global_Set_ReadOnly(const char *, const char *);
|
void Global_Set_ReadOnly(const char *, const char *);
|
||||||
|
|
||||||
void EvalStack_Push(const char *, const char *, const char *);
|
|
||||||
void EvalStack_Pop(void);
|
|
||||||
const char *EvalStack_Details(void);
|
const char *EvalStack_Details(void);
|
||||||
|
|
||||||
/* util.c */
|
/* util.c */
|
||||||
|
|
25
meta.c
25
meta.c
|
@ -1,4 +1,4 @@
|
||||||
/* $NetBSD: meta.c,v 1.208 2024/04/27 17:33:46 rillig Exp $ */
|
/* $NetBSD: meta.c,v 1.210 2024/06/02 15:31:26 rillig Exp $ */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Implement 'meta' mode.
|
* Implement 'meta' mode.
|
||||||
|
@ -326,7 +326,7 @@ is_submake(const char *cmd, GNode *gn)
|
||||||
p_len = strlen(p_make);
|
p_len = strlen(p_make);
|
||||||
}
|
}
|
||||||
if (strchr(cmd, '$') != NULL) {
|
if (strchr(cmd, '$') != NULL) {
|
||||||
mp = Var_Subst(cmd, gn, VARE_WANTRES);
|
mp = Var_Subst(cmd, gn, VARE_EVAL);
|
||||||
/* TODO: handle errors */
|
/* TODO: handle errors */
|
||||||
cmd = mp;
|
cmd = mp;
|
||||||
}
|
}
|
||||||
|
@ -372,7 +372,7 @@ printCMD(const char *ucmd, FILE *fp, GNode *gn)
|
||||||
{
|
{
|
||||||
FStr xcmd = FStr_InitRefer(ucmd);
|
FStr xcmd = FStr_InitRefer(ucmd);
|
||||||
|
|
||||||
Var_Expand(&xcmd, gn, VARE_WANTRES);
|
Var_Expand(&xcmd, gn, VARE_EVAL);
|
||||||
fprintf(fp, "CMD %s\n", xcmd.str);
|
fprintf(fp, "CMD %s\n", xcmd.str);
|
||||||
FStr_Done(&xcmd);
|
FStr_Done(&xcmd);
|
||||||
}
|
}
|
||||||
|
@ -481,7 +481,7 @@ meta_create(BuildMon *pbm, GNode *gn)
|
||||||
|
|
||||||
if (metaVerbose) {
|
if (metaVerbose) {
|
||||||
/* Describe the target we are building */
|
/* Describe the target we are building */
|
||||||
char *mp = Var_Subst("${" MAKE_META_PREFIX "}", gn, VARE_WANTRES);
|
char *mp = Var_Subst("${" MAKE_META_PREFIX "}", gn, VARE_EVAL);
|
||||||
/* TODO: handle errors */
|
/* TODO: handle errors */
|
||||||
if (mp[0] != '\0')
|
if (mp[0] != '\0')
|
||||||
fprintf(stdout, "%s\n", mp);
|
fprintf(stdout, "%s\n", mp);
|
||||||
|
@ -618,7 +618,7 @@ meta_mode_init(const char *make_mode)
|
||||||
* We consider ourselves master of all within ${.MAKE.META.BAILIWICK}
|
* We consider ourselves master of all within ${.MAKE.META.BAILIWICK}
|
||||||
*/
|
*/
|
||||||
metaBailiwickStr = Var_Subst("${.MAKE.META.BAILIWICK:O:u:tA}",
|
metaBailiwickStr = Var_Subst("${.MAKE.META.BAILIWICK:O:u:tA}",
|
||||||
SCOPE_GLOBAL, VARE_WANTRES);
|
SCOPE_GLOBAL, VARE_EVAL);
|
||||||
/* TODO: handle errors */
|
/* TODO: handle errors */
|
||||||
AppendWords(&metaBailiwick, metaBailiwickStr);
|
AppendWords(&metaBailiwick, metaBailiwickStr);
|
||||||
/*
|
/*
|
||||||
|
@ -627,7 +627,7 @@ meta_mode_init(const char *make_mode)
|
||||||
Global_Append(MAKE_META_IGNORE_PATHS,
|
Global_Append(MAKE_META_IGNORE_PATHS,
|
||||||
"/dev /etc /proc /tmp /var/run /var/tmp ${TMPDIR}");
|
"/dev /etc /proc /tmp /var/run /var/tmp ${TMPDIR}");
|
||||||
metaIgnorePathsStr = Var_Subst("${" MAKE_META_IGNORE_PATHS ":O:u:tA}",
|
metaIgnorePathsStr = Var_Subst("${" MAKE_META_IGNORE_PATHS ":O:u:tA}",
|
||||||
SCOPE_GLOBAL, VARE_WANTRES);
|
SCOPE_GLOBAL, VARE_EVAL);
|
||||||
/* TODO: handle errors */
|
/* TODO: handle errors */
|
||||||
AppendWords(&metaIgnorePaths, metaIgnorePathsStr);
|
AppendWords(&metaIgnorePaths, metaIgnorePathsStr);
|
||||||
|
|
||||||
|
@ -777,7 +777,7 @@ meta_job_output(Job *job, char *cp, const char *nl)
|
||||||
char *cp2;
|
char *cp2;
|
||||||
|
|
||||||
meta_prefix = Var_Subst("${" MAKE_META_PREFIX "}",
|
meta_prefix = Var_Subst("${" MAKE_META_PREFIX "}",
|
||||||
SCOPE_GLOBAL, VARE_WANTRES);
|
SCOPE_GLOBAL, VARE_EVAL);
|
||||||
/* TODO: handle errors */
|
/* TODO: handle errors */
|
||||||
if ((cp2 = strchr(meta_prefix, '$')) != NULL)
|
if ((cp2 = strchr(meta_prefix, '$')) != NULL)
|
||||||
meta_prefix_len = (size_t)(cp2 - meta_prefix);
|
meta_prefix_len = (size_t)(cp2 - meta_prefix);
|
||||||
|
@ -967,7 +967,7 @@ meta_ignore(GNode *gn, const char *p)
|
||||||
*/
|
*/
|
||||||
Var_Set(gn, ".p.", p);
|
Var_Set(gn, ".p.", p);
|
||||||
expr = "${" MAKE_META_IGNORE_PATTERNS ":@m@${.p.:M$m}@}";
|
expr = "${" MAKE_META_IGNORE_PATTERNS ":@m@${.p.:M$m}@}";
|
||||||
pm = Var_Subst(expr, gn, VARE_WANTRES);
|
pm = Var_Subst(expr, gn, VARE_EVAL);
|
||||||
/* TODO: handle errors */
|
/* TODO: handle errors */
|
||||||
if (pm[0] != '\0') {
|
if (pm[0] != '\0') {
|
||||||
#ifdef DEBUG_META_MODE
|
#ifdef DEBUG_META_MODE
|
||||||
|
@ -986,7 +986,7 @@ meta_ignore(GNode *gn, const char *p)
|
||||||
snprintf(fname, sizeof fname,
|
snprintf(fname, sizeof fname,
|
||||||
"${%s:L:${%s:ts:}}",
|
"${%s:L:${%s:ts:}}",
|
||||||
p, MAKE_META_IGNORE_FILTER);
|
p, MAKE_META_IGNORE_FILTER);
|
||||||
fm = Var_Subst(fname, gn, VARE_WANTRES);
|
fm = Var_Subst(fname, gn, VARE_EVAL);
|
||||||
/* TODO: handle errors */
|
/* TODO: handle errors */
|
||||||
if (*fm == '\0') {
|
if (*fm == '\0') {
|
||||||
#ifdef DEBUG_META_MODE
|
#ifdef DEBUG_META_MODE
|
||||||
|
@ -1046,7 +1046,7 @@ meta_filter_cmd(GNode *gn, char *s)
|
||||||
Var_Set(gn, META_CMD_FILTER_VAR, s);
|
Var_Set(gn, META_CMD_FILTER_VAR, s);
|
||||||
s = Var_Subst(
|
s = Var_Subst(
|
||||||
"${" META_CMD_FILTER_VAR ":${" MAKE_META_CMP_FILTER ":ts:}}",
|
"${" META_CMD_FILTER_VAR ":${" MAKE_META_CMP_FILTER ":ts:}}",
|
||||||
gn, VARE_WANTRES);
|
gn, VARE_EVAL);
|
||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1514,7 +1514,7 @@ meta_oodate(GNode *gn, bool oodate)
|
||||||
DEBUG2(META, "%s: %u: cannot compare command using .OODATE\n",
|
DEBUG2(META, "%s: %u: cannot compare command using .OODATE\n",
|
||||||
fname, lineno);
|
fname, lineno);
|
||||||
}
|
}
|
||||||
cmd = Var_Subst(cmd, gn, VARE_UNDEFERR);
|
cmd = Var_Subst(cmd, gn, VARE_EVAL_DEFINED);
|
||||||
/* TODO: handle errors */
|
/* TODO: handle errors */
|
||||||
|
|
||||||
if ((cp = strchr(cmd, '\n')) != NULL) {
|
if ((cp = strchr(cmd, '\n')) != NULL) {
|
||||||
|
@ -1650,7 +1650,8 @@ void
|
||||||
meta_compat_child(void)
|
meta_compat_child(void)
|
||||||
{
|
{
|
||||||
meta_job_child(NULL);
|
meta_job_child(NULL);
|
||||||
if (dup2(childPipe[1], 1) < 0 || dup2(1, 2) < 0)
|
if (dup2(childPipe[1], STDOUT_FILENO) < 0
|
||||||
|
|| dup2(STDOUT_FILENO, STDERR_FILENO) < 0)
|
||||||
execDie("dup2", "pipe");
|
execDie("dup2", "pipe");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
13
mk/ChangeLog
13
mk/ChangeLog
|
@ -1,3 +1,16 @@
|
||||||
|
2024-06-22 Simon J Gerraty <sjg@beast.crufty.net>
|
||||||
|
|
||||||
|
* install-mk (MK_VERSION): 20240616
|
||||||
|
|
||||||
|
* dirdeps.mk: apply DEP_DIRDEPS_BUILD_DIR_FILTER after we have
|
||||||
|
computed build dirs, since some filters cannot be easily expressed via
|
||||||
|
DEP_DIRDEPS_FILTER.
|
||||||
|
|
||||||
|
2024-05-31 Simon J Gerraty <sjg@beast.crufty.net>
|
||||||
|
|
||||||
|
* dirdeps.mk: move reset of DIRDEPS_EXPORT_VARS
|
||||||
|
until after we a finished with it if building a cache.
|
||||||
|
|
||||||
2024-05-04 Simon J Gerraty <sjg@beast.crufty.net>
|
2024-05-04 Simon J Gerraty <sjg@beast.crufty.net>
|
||||||
|
|
||||||
* install-mk (MK_VERSION): 20240504
|
* install-mk (MK_VERSION): 20240504
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
# $Id: dirdeps.mk,v 1.167 2024/05/06 20:41:08 sjg Exp $
|
# $Id: dirdeps.mk,v 1.170 2024/06/24 02:21:00 sjg Exp $
|
||||||
|
|
||||||
# SPDX-License-Identifier: BSD-2-Clause
|
# SPDX-License-Identifier: BSD-2-Clause
|
||||||
#
|
#
|
||||||
|
@ -139,7 +139,7 @@
|
||||||
# DIRDEPS_EXPORT_VARS (DEP_EXPORT_VARS)
|
# DIRDEPS_EXPORT_VARS (DEP_EXPORT_VARS)
|
||||||
# It is discouraged, but sometimes necessary for a
|
# It is discouraged, but sometimes necessary for a
|
||||||
# Makefile.depend file to influence the environment.
|
# Makefile.depend file to influence the environment.
|
||||||
# Doing this is correctly (especially if using DIRDEPS_CACHE) is
|
# Doing this correctly (especially if using DIRDEPS_CACHE) is
|
||||||
# tricky so a Makefile.depend file can set DIRDEPS_EXPORT_VARS
|
# tricky so a Makefile.depend file can set DIRDEPS_EXPORT_VARS
|
||||||
# and dirdeps.mk will do the deed:
|
# and dirdeps.mk will do the deed:
|
||||||
#
|
#
|
||||||
|
@ -695,9 +695,22 @@ DEP_DIRDEPS_FILTER = \
|
||||||
${DIRDEPS_FILTER.${DEP_TARGET_SPEC}:U} \
|
${DIRDEPS_FILTER.${DEP_TARGET_SPEC}:U} \
|
||||||
${TARGET_SPEC_VARS:@v@${DIRDEPS_FILTER.${DEP_$v}:U}@} \
|
${TARGET_SPEC_VARS:@v@${DIRDEPS_FILTER.${DEP_$v}:U}@} \
|
||||||
${DIRDEPS_FILTER:U}
|
${DIRDEPS_FILTER:U}
|
||||||
|
|
||||||
.if empty(DEP_DIRDEPS_FILTER)
|
.if empty(DEP_DIRDEPS_FILTER)
|
||||||
# something harmless
|
# something harmless
|
||||||
DEP_DIRDEPS_FILTER = U
|
DEP_DIRDEPS_FILTER = u
|
||||||
|
.endif
|
||||||
|
|
||||||
|
# this is applied after we have computed build dirs
|
||||||
|
# so everything is fully qualified and starts with ${SRCTOP}/
|
||||||
|
DEP_DIRDEPS_BUILD_DIR_FILTER = \
|
||||||
|
${DIRDEPS_BUILD_DIR_FILTER.${DEP_TARGET_SPEC}:U} \
|
||||||
|
${TARGET_SPEC_VARS:@v@${DIRDEPS_BUILD_DIR_FILTER.${DEP_$v}:U}@} \
|
||||||
|
${DIRDEPS_BUILD_DIR_FILTER:U}
|
||||||
|
|
||||||
|
.if empty(DEP_DIRDEPS_BUILD_DIR_FILTER)
|
||||||
|
# something harmless
|
||||||
|
DEP_DIRDEPS_BUILD_DIR_FILTER = u
|
||||||
.endif
|
.endif
|
||||||
|
|
||||||
# this is what we start with
|
# this is what we start with
|
||||||
|
@ -717,6 +730,7 @@ __qual_depdirs += ${__hostdpadd}
|
||||||
|
|
||||||
.if ${_debug_reldir}
|
.if ${_debug_reldir}
|
||||||
.info DEP_DIRDEPS_FILTER=${DEP_DIRDEPS_FILTER:ts:}
|
.info DEP_DIRDEPS_FILTER=${DEP_DIRDEPS_FILTER:ts:}
|
||||||
|
.info DEP_DIRDEPS_BUILD_DIR_FILTER=${DEP_DIRDEPS_BUILD_DIR_FILTER:ts:}
|
||||||
.info depdirs=${__depdirs:S,^${SRCTOP}/,,:${DEBUG_DIRDEPS_LIST_FILTER:U:N/:ts:}}
|
.info depdirs=${__depdirs:S,^${SRCTOP}/,,:${DEBUG_DIRDEPS_LIST_FILTER:U:N/:ts:}}
|
||||||
.info qualified=${__qual_depdirs:S,^${SRCTOP}/,,:${DEBUG_DIRDEPS_LIST_FILTER:U:N/:ts:}}
|
.info qualified=${__qual_depdirs:S,^${SRCTOP}/,,:${DEBUG_DIRDEPS_LIST_FILTER:U:N/:ts:}}
|
||||||
.info unqualified=${__unqual_depdirs:S,^${SRCTOP}/,,:${DEBUG_DIRDEPS_LIST_FILTER:U:N/:ts:}}
|
.info unqualified=${__unqual_depdirs:S,^${SRCTOP}/,,:${DEBUG_DIRDEPS_LIST_FILTER:U:N/:ts:}}
|
||||||
|
@ -736,7 +750,8 @@ _build_dirs += \
|
||||||
# make sure we do not mess with qualifying "host" entries
|
# make sure we do not mess with qualifying "host" entries
|
||||||
_build_dirs := ${_build_dirs:M*.host*:${M_dep_qual_fixes.host:ts:}} \
|
_build_dirs := ${_build_dirs:M*.host*:${M_dep_qual_fixes.host:ts:}} \
|
||||||
${_build_dirs:N*.host*:${M_dep_qual_fixes:ts:}}
|
${_build_dirs:N*.host*:${M_dep_qual_fixes:ts:}}
|
||||||
_build_dirs := ${_build_dirs:O:u}
|
# some filters can only be applied now
|
||||||
|
_build_dirs := ${_build_dirs:${DEP_DIRDEPS_BUILD_DIR_FILTER:ts:}:O:u}
|
||||||
.if ${_debug_reldir}
|
.if ${_debug_reldir}
|
||||||
.info _build_dirs=${_build_dirs:${DEBUG_DIRDEPS_LIST_FILTER:U:N/:ts:}}
|
.info _build_dirs=${_build_dirs:${DEBUG_DIRDEPS_LIST_FILTER:U:N/:ts:}}
|
||||||
.endif
|
.endif
|
||||||
|
@ -746,6 +761,11 @@ _build_dirs := ${_build_dirs:O:u}
|
||||||
_build_all_dirs += ${_build_dirs} ${_build_xtra_dirs}
|
_build_all_dirs += ${_build_dirs} ${_build_xtra_dirs}
|
||||||
_build_all_dirs := ${_build_all_dirs:O:u}
|
_build_all_dirs := ${_build_all_dirs:O:u}
|
||||||
|
|
||||||
|
# we prefer DIRDEPS_EXPORT_VARS
|
||||||
|
.if empty(DIRDEPS_EXPORT_VARS) && !empty(DEP_EXPORT_VARS)
|
||||||
|
DIRDEPS_EXPORT_VARS = ${DEP_EXPORT_VARS}
|
||||||
|
.endif
|
||||||
|
|
||||||
# Normally if doing make -V something,
|
# Normally if doing make -V something,
|
||||||
# we do not want to waste time chasing DIRDEPS
|
# we do not want to waste time chasing DIRDEPS
|
||||||
# but if we want to count the number of Makefile.depend* read, we do.
|
# but if we want to count the number of Makefile.depend* read, we do.
|
||||||
|
@ -757,10 +777,9 @@ _cache_script = echo '\# ${DEP_RELDIR}.${DEP_TARGET_SPEC}';
|
||||||
# guard against _new_dirdeps being too big for a single command line
|
# guard against _new_dirdeps being too big for a single command line
|
||||||
_new_dirdeps := ${_build_all_dirs:@x@${target($x):?:$x}@:S,^${SRCTOP}/,,}
|
_new_dirdeps := ${_build_all_dirs:@x@${target($x):?:$x}@:S,^${SRCTOP}/,,}
|
||||||
_cache_xtra_deps := ${_build_xtra_dirs:S,^${SRCTOP}/,,}
|
_cache_xtra_deps := ${_build_xtra_dirs:S,^${SRCTOP}/,,}
|
||||||
.if !empty(DIRDEPS_EXPORT_VARS) || !empty(DEP_EXPORT_VARS)
|
.if !empty(DIRDEPS_EXPORT_VARS)
|
||||||
# Discouraged, but there are always exceptions.
|
# Discouraged, but there are always exceptions.
|
||||||
# Handle it here rather than explain how.
|
# Handle it here rather than explain how.
|
||||||
DIRDEPS_EXPORT_VARS ?= ${DEP_EXPORT_VARS}
|
|
||||||
_cache_xvars := echo; ${DIRDEPS_EXPORT_VARS:@v@echo '$v = ${$v}';@} echo '.export ${DIRDEPS_EXPORT_VARS}'; echo;
|
_cache_xvars := echo; ${DIRDEPS_EXPORT_VARS:@v@echo '$v = ${$v}';@} echo '.export ${DIRDEPS_EXPORT_VARS}'; echo;
|
||||||
_cache_script += ${_cache_xvars}
|
_cache_script += ${_cache_xvars}
|
||||||
.endif
|
.endif
|
||||||
|
@ -774,12 +793,6 @@ ${_build_all_dirs}: _DIRDEP_USE
|
||||||
.info ${DEP_RELDIR}.${DEP_TARGET_SPEC}: needs: ${_build_dirs:S,^${SRCTOP}/,,:${DEBUG_DIRDEPS_LIST_FILTER:U:N/:ts:}}
|
.info ${DEP_RELDIR}.${DEP_TARGET_SPEC}: needs: ${_build_dirs:S,^${SRCTOP}/,,:${DEBUG_DIRDEPS_LIST_FILTER:U:N/:ts:}}
|
||||||
.endif
|
.endif
|
||||||
|
|
||||||
.if !empty(DIRDEPS_EXPORT_VARS) || !empty(DEP_EXPORT_VARS)
|
|
||||||
.export ${DIRDEPS_EXPORT_VARS} ${DEP_EXPORT_VARS}
|
|
||||||
DIRDEPS_EXPORT_VARS =
|
|
||||||
DEP_EXPORT_VARS =
|
|
||||||
.endif
|
|
||||||
|
|
||||||
# this builds the dependency graph
|
# this builds the dependency graph
|
||||||
.for m in ${_machines}
|
.for m in ${_machines}
|
||||||
.if ${BUILD_DIRDEPS_CACHE} == "yes" && !empty(_build_dirs)
|
.if ${BUILD_DIRDEPS_CACHE} == "yes" && !empty(_build_dirs)
|
||||||
|
@ -835,6 +848,15 @@ ${_this_dir}.$m: ${_build_dirs:M*.$m:N${_this_dir}.$m}
|
||||||
|
|
||||||
.endif
|
.endif
|
||||||
|
|
||||||
|
.if !empty(DIRDEPS_EXPORT_VARS)
|
||||||
|
.if ${BUILD_DIRDEPS_CACHE} == "no"
|
||||||
|
.export ${DIRDEPS_EXPORT_VARS}
|
||||||
|
.endif
|
||||||
|
# Reset these, we are done with them for this iteration.
|
||||||
|
DIRDEPS_EXPORT_VARS =
|
||||||
|
DEP_EXPORT_VARS =
|
||||||
|
.endif
|
||||||
|
|
||||||
# Now find more dependencies - and recurse.
|
# Now find more dependencies - and recurse.
|
||||||
.for d in ${_build_all_dirs}
|
.for d in ${_build_all_dirs}
|
||||||
.if !target(_dirdeps_checked.$d)
|
.if !target(_dirdeps_checked.$d)
|
||||||
|
|
|
@ -59,7 +59,7 @@
|
||||||
# Simon J. Gerraty <sjg@crufty.net>
|
# Simon J. Gerraty <sjg@crufty.net>
|
||||||
|
|
||||||
# RCSid:
|
# RCSid:
|
||||||
# $Id: install-mk,v 1.254 2024/05/06 20:41:08 sjg Exp $
|
# $Id: install-mk,v 1.255 2024/06/24 02:21:00 sjg Exp $
|
||||||
#
|
#
|
||||||
# @(#) Copyright (c) 1994-2024 Simon J. Gerraty
|
# @(#) Copyright (c) 1994-2024 Simon J. Gerraty
|
||||||
#
|
#
|
||||||
|
@ -74,7 +74,7 @@
|
||||||
# sjg@crufty.net
|
# sjg@crufty.net
|
||||||
#
|
#
|
||||||
|
|
||||||
MK_VERSION=20240504
|
MK_VERSION=20240616
|
||||||
OWNER=
|
OWNER=
|
||||||
GROUP=
|
GROUP=
|
||||||
MODE=444
|
MODE=444
|
||||||
|
|
67
parse.c
67
parse.c
|
@ -1,4 +1,4 @@
|
||||||
/* $NetBSD: parse.c,v 1.723 2024/05/19 20:09:40 sjg Exp $ */
|
/* $NetBSD: parse.c,v 1.731 2024/06/15 19:43:56 rillig Exp $ */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 1988, 1989, 1990, 1993
|
* Copyright (c) 1988, 1989, 1990, 1993
|
||||||
|
@ -121,7 +121,7 @@
|
||||||
#include "pathnames.h"
|
#include "pathnames.h"
|
||||||
|
|
||||||
/* "@(#)parse.c 8.3 (Berkeley) 3/19/94" */
|
/* "@(#)parse.c 8.3 (Berkeley) 3/19/94" */
|
||||||
MAKE_RCSID("$NetBSD: parse.c,v 1.723 2024/05/19 20:09:40 sjg Exp $");
|
MAKE_RCSID("$NetBSD: parse.c,v 1.731 2024/06/15 19:43:56 rillig Exp $");
|
||||||
|
|
||||||
/* Detects a multiple-inclusion guard in a makefile. */
|
/* Detects a multiple-inclusion guard in a makefile. */
|
||||||
typedef enum {
|
typedef enum {
|
||||||
|
@ -234,9 +234,9 @@ static GNodeList *targets;
|
||||||
#ifdef CLEANUP
|
#ifdef CLEANUP
|
||||||
/*
|
/*
|
||||||
* All shell commands for all targets, in no particular order and possibly
|
* All shell commands for all targets, in no particular order and possibly
|
||||||
* with duplicates. Kept in a separate list since the commands from .USE or
|
* with duplicate values. Kept in a separate list since the commands from
|
||||||
* .USEBEFORE nodes are shared with other GNodes, thereby giving up the
|
* .USE or .USEBEFORE nodes are shared with other GNodes, thereby giving up
|
||||||
* easily understandable ownership over the allocated strings.
|
* the easily understandable ownership over the allocated strings.
|
||||||
*/
|
*/
|
||||||
static StringList targCmds = LST_INIT;
|
static StringList targCmds = LST_INIT;
|
||||||
#endif
|
#endif
|
||||||
|
@ -537,9 +537,9 @@ ParseVErrorInternal(FILE *f, bool useVars, const GNode *gn,
|
||||||
(void)fprintf(f, "%s: ", progname);
|
(void)fprintf(f, "%s: ", progname);
|
||||||
|
|
||||||
PrintLocation(f, useVars, gn);
|
PrintLocation(f, useVars, gn);
|
||||||
fprintf(f, "%s", EvalStack_Details());
|
|
||||||
if (level == PARSE_WARNING)
|
if (level == PARSE_WARNING)
|
||||||
(void)fprintf(f, "warning: ");
|
(void)fprintf(f, "warning: ");
|
||||||
|
fprintf(f, "%s", EvalStack_Details());
|
||||||
(void)vfprintf(f, fmt, ap);
|
(void)vfprintf(f, fmt, ap);
|
||||||
(void)fprintf(f, "\n");
|
(void)fprintf(f, "\n");
|
||||||
(void)fflush(f);
|
(void)fflush(f);
|
||||||
|
@ -619,7 +619,7 @@ HandleMessage(ParseErrorLevel level, const char *levelName, const char *umsg)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
xmsg = Var_Subst(umsg, SCOPE_CMDLINE, VARE_WANTRES);
|
xmsg = Var_Subst(umsg, SCOPE_CMDLINE, VARE_EVAL);
|
||||||
/* TODO: handle errors */
|
/* TODO: handle errors */
|
||||||
|
|
||||||
Parse_Error(level, "%s", xmsg);
|
Parse_Error(level, "%s", xmsg);
|
||||||
|
@ -652,7 +652,7 @@ LinkSource(GNode *pgn, GNode *cgn, bool isSpecial)
|
||||||
Lst_Append(&cgn->parents, pgn);
|
Lst_Append(&cgn->parents, pgn);
|
||||||
|
|
||||||
if (DEBUG(PARSE)) {
|
if (DEBUG(PARSE)) {
|
||||||
debug_printf("# LinkSource: added child %s - %s\n",
|
debug_printf("Target \"%s\" depends on \"%s\"\n",
|
||||||
pgn->name, cgn->name);
|
pgn->name, cgn->name);
|
||||||
Targ_PrintNode(pgn, 0);
|
Targ_PrintNode(pgn, 0);
|
||||||
Targ_PrintNode(cgn, 0);
|
Targ_PrintNode(cgn, 0);
|
||||||
|
@ -925,8 +925,7 @@ ParseDependencyTargetWord(char **pp, const char *lstart)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
if (*p == '$') {
|
if (*p == '$') {
|
||||||
FStr val = Var_Parse(&p, SCOPE_CMDLINE,
|
FStr val = Var_Parse(&p, SCOPE_CMDLINE, VARE_PARSE);
|
||||||
VARE_PARSE_ONLY);
|
|
||||||
/* TODO: handle errors */
|
/* TODO: handle errors */
|
||||||
FStr_Done(&val);
|
FStr_Done(&val);
|
||||||
} else
|
} else
|
||||||
|
@ -1279,13 +1278,12 @@ IncludeFile(const char *file, bool isSystem, bool depinc, bool silent)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (SkipGuarded(fullname))
|
if (SkipGuarded(fullname))
|
||||||
return;
|
goto done;
|
||||||
|
|
||||||
if ((fd = open(fullname, O_RDONLY)) == -1) {
|
if ((fd = open(fullname, O_RDONLY)) == -1) {
|
||||||
if (!silent)
|
if (!silent)
|
||||||
Parse_Error(PARSE_FATAL, "Cannot open %s", fullname);
|
Parse_Error(PARSE_FATAL, "Cannot open %s", fullname);
|
||||||
free(fullname);
|
goto done;
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
buf = LoadFile(fullname, fd);
|
buf = LoadFile(fullname, fd);
|
||||||
|
@ -1294,6 +1292,7 @@ IncludeFile(const char *file, bool isSystem, bool depinc, bool silent)
|
||||||
Parse_PushInput(fullname, 1, 0, buf, NULL);
|
Parse_PushInput(fullname, 1, 0, buf, NULL);
|
||||||
if (depinc)
|
if (depinc)
|
||||||
doing_depend = depinc; /* only turn it on */
|
doing_depend = depinc; /* only turn it on */
|
||||||
|
done:
|
||||||
free(fullname);
|
free(fullname);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1811,7 +1810,7 @@ VarCheckSyntax(VarAssignOp op, const char *uvalue, GNode *scope)
|
||||||
if (opts.strict) {
|
if (opts.strict) {
|
||||||
if (op != VAR_SUBST && strchr(uvalue, '$') != NULL) {
|
if (op != VAR_SUBST && strchr(uvalue, '$') != NULL) {
|
||||||
char *parsedValue = Var_Subst(uvalue,
|
char *parsedValue = Var_Subst(uvalue,
|
||||||
scope, VARE_PARSE_ONLY);
|
scope, VARE_PARSE);
|
||||||
/* TODO: handle errors */
|
/* TODO: handle errors */
|
||||||
free(parsedValue);
|
free(parsedValue);
|
||||||
}
|
}
|
||||||
|
@ -1837,7 +1836,8 @@ VarAssign_EvalSubst(GNode *scope, const char *name, const char *uvalue,
|
||||||
if (!Var_ExistsExpand(scope, name))
|
if (!Var_ExistsExpand(scope, name))
|
||||||
Var_SetExpand(scope, name, "");
|
Var_SetExpand(scope, name, "");
|
||||||
|
|
||||||
evalue = Var_Subst(uvalue, scope, VARE_KEEP_DOLLAR_UNDEF);
|
evalue = Var_Subst(uvalue, scope,
|
||||||
|
VARE_EVAL_KEEP_DOLLAR_AND_UNDEFINED);
|
||||||
/* TODO: handle errors */
|
/* TODO: handle errors */
|
||||||
|
|
||||||
Var_SetExpand(scope, name, evalue);
|
Var_SetExpand(scope, name, evalue);
|
||||||
|
@ -1854,7 +1854,7 @@ VarAssign_EvalShell(const char *name, const char *uvalue, GNode *scope,
|
||||||
char *output, *error;
|
char *output, *error;
|
||||||
|
|
||||||
cmd = FStr_InitRefer(uvalue);
|
cmd = FStr_InitRefer(uvalue);
|
||||||
Var_Expand(&cmd, SCOPE_CMDLINE, VARE_UNDEFERR);
|
Var_Expand(&cmd, SCOPE_CMDLINE, VARE_EVAL_DEFINED);
|
||||||
|
|
||||||
output = Cmd_Exec(cmd.str, &error);
|
output = Cmd_Exec(cmd.str, &error);
|
||||||
Var_SetExpand(scope, name, output);
|
Var_SetExpand(scope, name, output);
|
||||||
|
@ -2036,7 +2036,7 @@ ParseInclude(char *directive)
|
||||||
|
|
||||||
*p = '\0';
|
*p = '\0';
|
||||||
|
|
||||||
Var_Expand(&file, SCOPE_CMDLINE, VARE_WANTRES);
|
Var_Expand(&file, SCOPE_CMDLINE, VARE_EVAL);
|
||||||
IncludeFile(file.str, endc == '>', directive[0] == 'd', silent);
|
IncludeFile(file.str, endc == '>', directive[0] == 'd', silent);
|
||||||
FStr_Done(&file);
|
FStr_Done(&file);
|
||||||
}
|
}
|
||||||
|
@ -2245,7 +2245,7 @@ ParseTraditionalInclude(char *line)
|
||||||
|
|
||||||
pp_skip_whitespace(&file);
|
pp_skip_whitespace(&file);
|
||||||
|
|
||||||
all_files = Var_Subst(file, SCOPE_CMDLINE, VARE_WANTRES);
|
all_files = Var_Subst(file, SCOPE_CMDLINE, VARE_EVAL);
|
||||||
/* TODO: handle errors */
|
/* TODO: handle errors */
|
||||||
|
|
||||||
for (file = all_files; !done; file = p + 1) {
|
for (file = all_files; !done; file = p + 1) {
|
||||||
|
@ -2288,7 +2288,7 @@ ParseGmakeExport(char *line)
|
||||||
/*
|
/*
|
||||||
* Expand the value before putting it in the environment.
|
* Expand the value before putting it in the environment.
|
||||||
*/
|
*/
|
||||||
value = Var_Subst(value, SCOPE_CMDLINE, VARE_WANTRES);
|
value = Var_Subst(value, SCOPE_CMDLINE, VARE_EVAL);
|
||||||
/* TODO: handle errors */
|
/* TODO: handle errors */
|
||||||
|
|
||||||
setenv(variable, value, 1);
|
setenv(variable, value, 1);
|
||||||
|
@ -2319,9 +2319,15 @@ ParseEOF(void)
|
||||||
|
|
||||||
Cond_EndFile();
|
Cond_EndFile();
|
||||||
|
|
||||||
if (curFile->guardState == GS_DONE)
|
if (curFile->guardState == GS_DONE) {
|
||||||
HashTable_Set(&guards, curFile->name.str, curFile->guard);
|
HashEntry *he = HashTable_CreateEntry(&guards,
|
||||||
else if (curFile->guard != NULL) {
|
curFile->name.str, NULL);
|
||||||
|
if (he->value != NULL) {
|
||||||
|
free(((Guard *)he->value)->name);
|
||||||
|
free(he->value);
|
||||||
|
}
|
||||||
|
HashEntry_Set(he, curFile->guard);
|
||||||
|
} else if (curFile->guard != NULL) {
|
||||||
free(curFile->guard->name);
|
free(curFile->guard->name);
|
||||||
free(curFile->guard);
|
free(curFile->guard);
|
||||||
}
|
}
|
||||||
|
@ -2684,6 +2690,13 @@ FinishDependencyGroup(void)
|
||||||
targets = NULL;
|
targets = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef CLEANUP
|
||||||
|
void Parse_RegisterCommand(char *cmd)
|
||||||
|
{
|
||||||
|
Lst_Append(&targCmds, cmd);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
/* Add the command to each target from the current dependency spec. */
|
/* Add the command to each target from the current dependency spec. */
|
||||||
static void
|
static void
|
||||||
ParseLine_ShellCommand(const char *p)
|
ParseLine_ShellCommand(const char *p)
|
||||||
|
@ -2706,9 +2719,7 @@ ParseLine_ShellCommand(const char *p)
|
||||||
GNode *gn = ln->datum;
|
GNode *gn = ln->datum;
|
||||||
GNode_AddCommand(gn, cmd);
|
GNode_AddCommand(gn, cmd);
|
||||||
}
|
}
|
||||||
#ifdef CLEANUP
|
Parse_RegisterCommand(cmd);
|
||||||
Lst_Append(&targCmds, cmd);
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2764,6 +2775,8 @@ ParseDirective(char *line)
|
||||||
Var_Undef(arg);
|
Var_Undef(arg);
|
||||||
else if (Substring_Equals(dir, "export"))
|
else if (Substring_Equals(dir, "export"))
|
||||||
Var_Export(VEM_PLAIN, arg);
|
Var_Export(VEM_PLAIN, arg);
|
||||||
|
else if (Substring_Equals(dir, "export-all"))
|
||||||
|
Var_Export(VEM_ALL, arg);
|
||||||
else if (Substring_Equals(dir, "export-env"))
|
else if (Substring_Equals(dir, "export-env"))
|
||||||
Var_Export(VEM_ENV, arg);
|
Var_Export(VEM_ENV, arg);
|
||||||
else if (Substring_Equals(dir, "export-literal"))
|
else if (Substring_Equals(dir, "export-literal"))
|
||||||
|
@ -2884,7 +2897,7 @@ ParseDependencyLine(char *line)
|
||||||
* empty string var_Error, which cannot be detected in the result of
|
* empty string var_Error, which cannot be detected in the result of
|
||||||
* Var_Subst.
|
* Var_Subst.
|
||||||
*/
|
*/
|
||||||
emode = opts.strict ? VARE_WANTRES : VARE_UNDEFERR;
|
emode = opts.strict ? VARE_EVAL : VARE_EVAL_DEFINED;
|
||||||
expanded_line = Var_Subst(line, SCOPE_CMDLINE, emode);
|
expanded_line = Var_Subst(line, SCOPE_CMDLINE, emode);
|
||||||
/* TODO: handle errors */
|
/* TODO: handle errors */
|
||||||
|
|
||||||
|
@ -2990,7 +3003,7 @@ Parse_End(void)
|
||||||
assert(includes.len == 0);
|
assert(includes.len == 0);
|
||||||
Vector_Done(&includes);
|
Vector_Done(&includes);
|
||||||
HashIter_Init(&hi, &guards);
|
HashIter_Init(&hi, &guards);
|
||||||
while (HashIter_Next(&hi) != NULL) {
|
while (HashIter_Next(&hi)) {
|
||||||
Guard *guard = hi.entry->value;
|
Guard *guard = hi.entry->value;
|
||||||
free(guard->name);
|
free(guard->name);
|
||||||
free(guard);
|
free(guard);
|
||||||
|
|
9
suff.c
9
suff.c
|
@ -1,4 +1,4 @@
|
||||||
/* $NetBSD: suff.c,v 1.378 2024/02/07 06:43:02 rillig Exp $ */
|
/* $NetBSD: suff.c,v 1.380 2024/06/02 15:31:26 rillig Exp $ */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 1988, 1989, 1990, 1993
|
* Copyright (c) 1988, 1989, 1990, 1993
|
||||||
|
@ -115,7 +115,7 @@
|
||||||
#include "dir.h"
|
#include "dir.h"
|
||||||
|
|
||||||
/* "@(#)suff.c 8.4 (Berkeley) 3/21/94" */
|
/* "@(#)suff.c 8.4 (Berkeley) 3/21/94" */
|
||||||
MAKE_RCSID("$NetBSD: suff.c,v 1.378 2024/02/07 06:43:02 rillig Exp $");
|
MAKE_RCSID("$NetBSD: suff.c,v 1.380 2024/06/02 15:31:26 rillig Exp $");
|
||||||
|
|
||||||
typedef List SuffixList;
|
typedef List SuffixList;
|
||||||
typedef ListNode SuffixListNode;
|
typedef ListNode SuffixListNode;
|
||||||
|
@ -1223,6 +1223,7 @@ ExpandWildcards(GNodeListNode *cln, GNode *pgn)
|
||||||
|
|
||||||
DEBUG1(SUFF, "%s...", name);
|
DEBUG1(SUFF, "%s...", name);
|
||||||
gn = Targ_GetNode(name);
|
gn = Targ_GetNode(name);
|
||||||
|
free(name);
|
||||||
|
|
||||||
/* Insert gn before the original child. */
|
/* Insert gn before the original child. */
|
||||||
Lst_InsertBefore(&pgn->children, cln, gn);
|
Lst_InsertBefore(&pgn->children, cln, gn);
|
||||||
|
@ -1273,7 +1274,7 @@ ExpandChildrenRegular(char *p, GNode *pgn, GNodeList *members)
|
||||||
} else if (*p == '$') {
|
} else if (*p == '$') {
|
||||||
/* Skip over the expression. */
|
/* Skip over the expression. */
|
||||||
const char *nested_p = p;
|
const char *nested_p = p;
|
||||||
FStr junk = Var_Parse(&nested_p, pgn, VARE_PARSE_ONLY);
|
FStr junk = Var_Parse(&nested_p, pgn, VARE_PARSE);
|
||||||
/* TODO: handle errors */
|
/* TODO: handle errors */
|
||||||
if (junk.str == var_Error) {
|
if (junk.str == var_Error) {
|
||||||
Parse_Error(PARSE_FATAL,
|
Parse_Error(PARSE_FATAL,
|
||||||
|
@ -1343,7 +1344,7 @@ ExpandChildren(GNodeListNode *cln, GNode *pgn)
|
||||||
}
|
}
|
||||||
|
|
||||||
DEBUG1(SUFF, "Expanding \"%s\"...", cgn->name);
|
DEBUG1(SUFF, "Expanding \"%s\"...", cgn->name);
|
||||||
expanded = Var_Subst(cgn->name, pgn, VARE_UNDEFERR);
|
expanded = Var_Subst(cgn->name, pgn, VARE_EVAL_DEFINED);
|
||||||
/* TODO: handle errors */
|
/* TODO: handle errors */
|
||||||
|
|
||||||
{
|
{
|
||||||
|
|
20
targ.c
20
targ.c
|
@ -1,4 +1,4 @@
|
||||||
/* $NetBSD: targ.c,v 1.181 2024/04/27 17:33:47 rillig Exp $ */
|
/* $NetBSD: targ.c,v 1.183 2024/05/25 21:07:48 rillig Exp $ */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 1988, 1989, 1990, 1993
|
* Copyright (c) 1988, 1989, 1990, 1993
|
||||||
|
@ -107,7 +107,7 @@
|
||||||
#include "dir.h"
|
#include "dir.h"
|
||||||
|
|
||||||
/* "@(#)targ.c 8.2 (Berkeley) 3/19/94" */
|
/* "@(#)targ.c 8.2 (Berkeley) 3/19/94" */
|
||||||
MAKE_RCSID("$NetBSD: targ.c,v 1.181 2024/04/27 17:33:47 rillig Exp $");
|
MAKE_RCSID("$NetBSD: targ.c,v 1.183 2024/05/25 21:07:48 rillig Exp $");
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* All target nodes that appeared on the left-hand side of one of the
|
* All target nodes that appeared on the left-hand side of one of the
|
||||||
|
@ -219,6 +219,8 @@ GNode_New(const char *name)
|
||||||
static void
|
static void
|
||||||
GNode_Free(GNode *gn)
|
GNode_Free(GNode *gn)
|
||||||
{
|
{
|
||||||
|
Var_DeleteAll(gn);
|
||||||
|
|
||||||
free(gn->name);
|
free(gn->name);
|
||||||
free(gn->uname);
|
free(gn->uname);
|
||||||
free(gn->path);
|
free(gn->path);
|
||||||
|
@ -236,20 +238,6 @@ GNode_Free(GNode *gn)
|
||||||
Lst_Done(&gn->order_succ);
|
Lst_Done(&gn->order_succ);
|
||||||
Lst_Done(&gn->cohorts);
|
Lst_Done(&gn->cohorts);
|
||||||
|
|
||||||
/*
|
|
||||||
* Do not free the variables themselves, even though they are owned
|
|
||||||
* by this node.
|
|
||||||
*
|
|
||||||
* XXX: For the nodes that represent targets or sources (and not
|
|
||||||
* SCOPE_GLOBAL), it should be safe to free the variables as well,
|
|
||||||
* since each node manages the memory for all its variables itself.
|
|
||||||
*
|
|
||||||
* XXX: The GNodes that are only used as variable scopes (SCOPE_CMD,
|
|
||||||
* SCOPE_GLOBAL, SCOPE_INTERNAL) are not freed at all (see Var_End,
|
|
||||||
* where they are not mentioned). These may be freed if their
|
|
||||||
* variable values are indeed not used anywhere else (see Trace_Init
|
|
||||||
* for the only suspicious use).
|
|
||||||
*/
|
|
||||||
HashTable_Done(&gn->vars);
|
HashTable_Done(&gn->vars);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
# $Id: Makefile,v 1.216 2024/04/30 16:42:50 sjg Exp $
|
# $Id: Makefile,v 1.219 2024/06/01 16:14:47 sjg Exp $
|
||||||
#
|
#
|
||||||
# $NetBSD: Makefile,v 1.344 2024/04/30 16:41:32 sjg Exp $
|
# $NetBSD: Makefile,v 1.347 2024/06/01 15:54:40 sjg Exp $
|
||||||
#
|
#
|
||||||
# Unit tests for make(1)
|
# Unit tests for make(1)
|
||||||
#
|
#
|
||||||
|
@ -745,11 +745,11 @@ all: ${OUTFILES}
|
||||||
CLEANFILES= *.rawout *.out *.status *.tmp *.core *.tmp
|
CLEANFILES= *.rawout *.out *.status *.tmp *.core *.tmp
|
||||||
CLEANFILES+= obj*.[och] lib*.a # posix1.mk
|
CLEANFILES+= obj*.[och] lib*.a # posix1.mk
|
||||||
CLEANFILES+= issue* .[ab]* # suffixes.mk
|
CLEANFILES+= issue* .[ab]* # suffixes.mk
|
||||||
CLEANDIRS= dir dummy # posix1.mk
|
CLEANDIRS= dir dummy *.tmp # posix1.mk
|
||||||
|
|
||||||
clean:
|
clean:
|
||||||
rm -f ${CLEANFILES}
|
|
||||||
rm -rf ${CLEANDIRS}
|
rm -rf ${CLEANDIRS}
|
||||||
|
rm -f ${CLEANFILES}
|
||||||
|
|
||||||
TEST_MAKE?= ${.MAKE}
|
TEST_MAKE?= ${.MAKE}
|
||||||
TOOL_SED?= sed
|
TOOL_SED?= sed
|
||||||
|
@ -864,6 +864,11 @@ test: ${OUTFILES} .PHONY
|
||||||
echo "Failed tests: $${failed}" ; false ; \
|
echo "Failed tests: $${failed}" ; false ; \
|
||||||
else \
|
else \
|
||||||
echo "All tests passed" ; \
|
echo "All tests passed" ; \
|
||||||
|
lua=${LUA:Ulua} ; \
|
||||||
|
have_lua=$$("$$lua" -e 'print "yes"' 2>&1) ; \
|
||||||
|
if [ "$$have_lua" = "yes" -a -s ${.CURDIR}/check-expect.lua ]; then \
|
||||||
|
(cd ${.CURDIR} && "$$lua" ./check-expect.lua *.mk); \
|
||||||
|
fi; \
|
||||||
fi
|
fi
|
||||||
|
|
||||||
accept:
|
accept:
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
# $NetBSD: cond-func-empty.mk,v 1.24 2023/12/19 19:33:40 rillig Exp $
|
# $NetBSD: cond-func-empty.mk,v 1.25 2024/06/02 15:31:26 rillig Exp $
|
||||||
#
|
#
|
||||||
# Tests for the empty() function in .if conditions, which tests an
|
# Tests for the empty() function in .if conditions, which tests an
|
||||||
# expression for emptiness.
|
# expression for emptiness.
|
||||||
|
@ -104,10 +104,10 @@ WORD= word
|
||||||
|
|
||||||
# Now the variable named " " gets a non-empty value, which demonstrates that
|
# Now the variable named " " gets a non-empty value, which demonstrates that
|
||||||
# neither leading nor trailing spaces are trimmed in the argument of the
|
# neither leading nor trailing spaces are trimmed in the argument of the
|
||||||
# function. If the spaces were trimmed, the variable name would be "" and
|
# function. If the spaces were trimmed, the variable name would be "", and
|
||||||
# that variable is indeed undefined. Since CondParser_FuncCallEmpty calls
|
# that variable is indeed undefined. Since CondParser_FuncCallEmpty allows
|
||||||
# Var_Parse without VARE_UNDEFERR, the value of the undefined variable ""
|
# subexpressions to be based on undefined variables, the value of the
|
||||||
# would be returned as an empty string.
|
# undefined variable "" would be returned as an empty string.
|
||||||
${:U }= space
|
${:U }= space
|
||||||
.if empty( )
|
.if empty( )
|
||||||
. error
|
. error
|
||||||
|
@ -194,15 +194,15 @@ ${:U WORD }= variable name with spaces
|
||||||
# wrong variable name should have been discarded quickly after parsing it, to
|
# wrong variable name should have been discarded quickly after parsing it, to
|
||||||
# prevent it from doing any harm.
|
# prevent it from doing any harm.
|
||||||
#
|
#
|
||||||
# The expression was expanded, and this was wrong. The
|
# The expression was evaluated, and this was wrong. The evaluation was done
|
||||||
# expansion was done without VARE_WANTRES (called VARF_WANTRES back then)
|
# without VARE_EVAL (called VARF_WANTRES back then) though. This had the
|
||||||
# though. This had the effect that the ${:U1} from the value of VARNAME
|
# effect that the ${:U1} from the value of VARNAME evaluated to an empty
|
||||||
# expanded to an empty string. This in turn created the seemingly recursive
|
# string. This in turn created the seemingly recursive definition
|
||||||
# definition VARNAME=${VARNAME}, and that definition was never meant to be
|
# VARNAME=${VARNAME}, and that definition was evaluated even though it was
|
||||||
# expanded.
|
# never meant to be evaluated.
|
||||||
#
|
#
|
||||||
# This was fixed by expanding nested expressions in the variable name
|
# This was fixed by evaluating nested expressions in the variable name only
|
||||||
# only if the flag VARE_WANTRES is given.
|
# when the whole expression was evaluated as well.
|
||||||
VARNAME= ${VARNAME${:U1}}
|
VARNAME= ${VARNAME${:U1}}
|
||||||
.if defined(VARNAME${:U2}) && !empty(VARNAME${:U2})
|
.if defined(VARNAME${:U2}) && !empty(VARNAME${:U2})
|
||||||
.endif
|
.endif
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
make: "dep-duplicate.inc" line 1: warning: duplicate script for target "all" ignored
|
make: "dep-duplicate.tmp" line 1: warning: duplicate script for target "all" ignored
|
||||||
make: "dep-duplicate.main" line 3: warning: using previous script for "all" defined here
|
make: "dep-duplicate.main" line 3: warning: using previous script for "all" defined here
|
||||||
main-output
|
main-output
|
||||||
exit status 0
|
exit status 0
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
# $NetBSD: dep-duplicate.mk,v 1.3 2022/01/20 19:24:53 rillig Exp $
|
# $NetBSD: dep-duplicate.mk,v 1.4 2024/05/25 21:11:30 rillig Exp $
|
||||||
#
|
#
|
||||||
# Test for a target whose commands are defined twice. This generates a
|
# Test for a target whose commands are defined twice. This generates a
|
||||||
# warning, not an error, so ensure that the correct commands are kept.
|
# warning, not an error, so ensure that the correct commands are kept.
|
||||||
|
@ -13,9 +13,9 @@ all: .PHONY
|
||||||
echo '# empty line 1'; \
|
echo '# empty line 1'; \
|
||||||
echo '# empty line 2'; \
|
echo '# empty line 2'; \
|
||||||
echo 'all:; @echo main-output'; \
|
echo 'all:; @echo main-output'; \
|
||||||
echo '.include "dep-duplicate.inc"'
|
echo '.include "dep-duplicate.tmp"'
|
||||||
|
|
||||||
@exec > dep-duplicate.inc; \
|
@exec > dep-duplicate.tmp; \
|
||||||
echo 'all:; @echo inc-output'
|
echo 'all:; @echo inc-output'
|
||||||
|
|
||||||
# The main file must be specified using a relative path, just like the
|
# The main file must be specified using a relative path, just like the
|
||||||
|
@ -24,4 +24,4 @@ all: .PHONY
|
||||||
@${MAKE} -r -f dep-duplicate.main
|
@${MAKE} -r -f dep-duplicate.main
|
||||||
|
|
||||||
@rm -f dep-duplicate.main
|
@rm -f dep-duplicate.main
|
||||||
@rm -f dep-duplicate.inc
|
@rm -f dep-duplicate.tmp
|
||||||
|
|
|
@ -16,9 +16,9 @@ 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
|
||||||
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
|
||||||
Global: .ALLTARGETS = all ${DEF2} a-${DEF2}-b ${UNDEF3} 1-${INDIRECT_1}-1 $$) undef1 def2 a-def2-b
|
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)
|
Var_Parse: $INDIRECT_2-2-1 $): (parse)
|
||||||
Global: .ALLTARGETS = all ${DEF2} a-${DEF2}-b ${UNDEF3} 1-${INDIRECT_1}-1 $$) undef1 def2 a-def2-b 1-2-$INDIRECT_2-2-1
|
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)
|
Var_Parse: $): (parse)
|
||||||
Global: .ALLTARGETS = all ${DEF2} a-${DEF2}-b ${UNDEF3} 1-${INDIRECT_1}-1 $$) undef1 def2 a-def2-b 1-2-$INDIRECT_2-2-1 $)
|
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
|
||||||
Global: .MAKEFLAGS = -r -k -d v -d 0
|
Global: .MAKEFLAGS = -r -k -d v -d 0
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
# $NetBSD: dep-var.mk,v 1.11 2023/12/19 19:33:40 rillig Exp $
|
# $NetBSD: dep-var.mk,v 1.12 2024/06/02 15:31:26 rillig Exp $
|
||||||
#
|
#
|
||||||
# Tests for variable references in dependency declarations.
|
# Tests for variable references in dependency declarations.
|
||||||
#
|
#
|
||||||
|
@ -84,8 +84,8 @@ all: $$$$)
|
||||||
# in normal mode since ParseDependency does not handle any errors after
|
# in normal mode since ParseDependency does not handle any errors after
|
||||||
# calling Var_Parse.
|
# calling Var_Parse.
|
||||||
# expect: Var_Parse: ${:U\$)}: (eval-defined)
|
# expect: Var_Parse: ${:U\$)}: (eval-defined)
|
||||||
# expect: Var_Parse: $INDIRECT_2-2-1 $): (parse-only)
|
# expect: Var_Parse: $INDIRECT_2-2-1 $): (parse)
|
||||||
# expect: Var_Parse: $): (parse-only)
|
# expect: Var_Parse: $): (parse)
|
||||||
undef1 def2 a-def2-b 1-2-$$INDIRECT_2-2-1 ${:U\$)}:
|
undef1 def2 a-def2-b 1-2-$$INDIRECT_2-2-1 ${:U\$)}:
|
||||||
@echo ${.TARGET:Q}
|
@echo ${.TARGET:Q}
|
||||||
|
|
||||||
|
|
|
@ -1,2 +1,5 @@
|
||||||
value with ${UNEXPANDED} expression
|
value with ${UNEXPANDED} expression
|
||||||
|
value literal
|
||||||
|
value indirect
|
||||||
|
value ${indirect:L}
|
||||||
exit status 0
|
exit status 0
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
# $NetBSD: directive-export-literal.mk,v 1.7 2020/12/13 01:07:54 rillig Exp $
|
# $NetBSD: directive-export-literal.mk,v 1.8 2024/06/01 18:44:05 rillig Exp $
|
||||||
#
|
#
|
||||||
# Tests for the .export-literal directive, which exports a variable value
|
# Tests for the .export-literal directive, which exports a variable value
|
||||||
# without expanding it.
|
# without expanding it.
|
||||||
|
@ -9,5 +9,28 @@ UT_VAR= value with ${UNEXPANDED} expression
|
||||||
|
|
||||||
.export-literal # oops: missing argument
|
.export-literal # oops: missing argument
|
||||||
|
|
||||||
|
# After a variable whose value does not contain a '$' is exported, a following
|
||||||
|
# .export-literal can be skipped, to avoid a setenv call, which may leak
|
||||||
|
# memory on some platforms.
|
||||||
|
UT_TWICE_LITERAL= value literal
|
||||||
|
.export UT_TWICE_LITERAL
|
||||||
|
.export-literal UT_TWICE_LITERAL
|
||||||
|
|
||||||
|
# XXX: After an .export, an .export-literal has no effect, even when the
|
||||||
|
# variable value contains a '$'.
|
||||||
|
UT_TWICE_EXPR= value ${indirect:L}
|
||||||
|
.export UT_TWICE_EXPR
|
||||||
|
.export-literal UT_TWICE_EXPR
|
||||||
|
|
||||||
|
# After an .export, an .unexport resets the variable's exported state,
|
||||||
|
# re-enabling a later .export-literal.
|
||||||
|
UT_TWICE_EXPR_UNEXPORT= value ${indirect:L}
|
||||||
|
.export UT_TWICE_EXPR_UNEXPORT
|
||||||
|
.unexport UT_TWICE_EXPR_UNEXPORT
|
||||||
|
.export-literal UT_TWICE_EXPR_UNEXPORT
|
||||||
|
|
||||||
all:
|
all:
|
||||||
@echo "$$UT_VAR"
|
@echo "$$UT_VAR"
|
||||||
|
@echo "$$UT_TWICE_LITERAL"
|
||||||
|
@echo "$$UT_TWICE_EXPR"
|
||||||
|
@echo "$$UT_TWICE_EXPR_UNEXPORT"
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
make: "directive-export.mk" line 56: 00:00:00
|
make: "directive-export.mk" line 36: warning: .export requires an argument.
|
||||||
make: "directive-export.mk" line 61: 00:00:00
|
make: "directive-export.mk" line 60: 00:00:00
|
||||||
make: "directive-export.mk" line 64: 16:00:00
|
make: "directive-export.mk" line 65: 00:00:00
|
||||||
|
make: "directive-export.mk" line 68: 16:00:00
|
||||||
exit status 0
|
exit status 0
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
# $NetBSD: directive-export.mk,v 1.10 2023/11/19 09:45:19 rillig Exp $
|
# $NetBSD: directive-export.mk,v 1.12 2024/06/01 10:06:23 rillig Exp $
|
||||||
#
|
#
|
||||||
# Tests for the .export directive.
|
# Tests for the .export directive.
|
||||||
#
|
#
|
||||||
|
@ -28,7 +28,11 @@ VAR= value $$ ${INDIRECT}
|
||||||
. error
|
. error
|
||||||
.endif
|
.endif
|
||||||
|
|
||||||
# No syntactical argument means to export all variables.
|
# Before var.c 1.1117 from 2024-06-01, a plain ".export" without a syntactical
|
||||||
|
# argument exported all global variables. This case could be triggered
|
||||||
|
# unintentionally by writing a line of the form ".export ${VARNAMES}" to a
|
||||||
|
# makefile, when VARNAMES was an empty list.
|
||||||
|
# expect+1: warning: .export requires an argument.
|
||||||
.export
|
.export
|
||||||
|
|
||||||
# An empty argument means no additional variables to export.
|
# An empty argument means no additional variables to export.
|
||||||
|
|
|
@ -1,7 +1,4 @@
|
||||||
make: "directive-for-empty.mk" line 22: 2
|
make: "directive-for-empty.mk" line 22: 2
|
||||||
make: "directive-for-empty.mk" line 38: Missing argument for ".error"
|
|
||||||
make: "directive-for-empty.mk" line 38: Missing argument for ".error"
|
|
||||||
make: "directive-for-empty.mk" line 38: Missing argument for ".error"
|
|
||||||
For: end for 1
|
For: end for 1
|
||||||
For: loop body with i = value:
|
For: loop body with i = value:
|
||||||
# The identifier 'empty' can only be used in conditions such as .if, .ifdef or
|
# The identifier 'empty' can only be used in conditions such as .if, .ifdef or
|
||||||
|
@ -22,6 +19,4 @@ CPPFLAGS+= -Dmessage="empty(i)"
|
||||||
# condition directives, they can also occur in the modifier ':?', see
|
# condition directives, they can also occur in the modifier ':?', see
|
||||||
# varmod-ifelse.mk.
|
# varmod-ifelse.mk.
|
||||||
CPPFLAGS+= -Dmacro="${empty(i):?empty:not-empty}"
|
CPPFLAGS+= -Dmacro="${empty(i):?empty:not-empty}"
|
||||||
make: Fatal errors encountered -- cannot continue
|
exit status 0
|
||||||
make: stopped in unit-tests
|
|
||||||
exit status 1
|
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
# $NetBSD: directive-for-empty.mk,v 1.3 2023/11/19 21:47:52 rillig Exp $
|
# $NetBSD: directive-for-empty.mk,v 1.4 2024/05/31 07:13:12 rillig Exp $
|
||||||
#
|
#
|
||||||
# Tests for .for loops containing conditions of the form 'empty(var:...)'.
|
# Tests for .for loops containing conditions of the form 'empty(var:...)'.
|
||||||
#
|
#
|
||||||
|
@ -26,23 +26,23 @@
|
||||||
|
|
||||||
# In conditions, the function call to 'empty' does not look like an
|
# In conditions, the function call to 'empty' does not look like an
|
||||||
# expression, therefore it is not replaced. Since there is no global variable
|
# expression, therefore it is not replaced. Since there is no global variable
|
||||||
# named 'i', this expression makes for a leaky abstraction. If the .for
|
# named 'i', this condition makes for a leaky abstraction. If the .for
|
||||||
# variables were real variables, calling 'empty' would work on them as well.
|
# variables were real variables, calling 'empty' would work on them as well.
|
||||||
.for i in 11 12 13
|
.for i in 11 12 13
|
||||||
# Asking for an empty iteration variable does not make sense as the .for loop
|
# Asking for an empty iteration variable does not make sense as the .for loop
|
||||||
# splits the iteration items into words, and such a word cannot be empty.
|
# splits the iteration items into words, and such a word cannot be empty.
|
||||||
. if empty(i)
|
. if !empty(i)
|
||||||
# expect+3: Missing argument for ".error"
|
. error # not reached, due to the leaky abstraction
|
||||||
# expect+2: Missing argument for ".error"
|
|
||||||
# expect+1: Missing argument for ".error"
|
|
||||||
. error # due to the leaky abstraction
|
|
||||||
. endif
|
. endif
|
||||||
# The typical way of using 'empty' with variables from .for loops is pattern
|
# The typical way of mistakenly using 'empty' with variables from .for loops
|
||||||
# matching using the modifiers ':M' or ':N'.
|
# is pattern matching using the modifiers ':M' or ':N'.
|
||||||
. if !empty(i:M*2*)
|
. if !empty(i:M*2*)
|
||||||
. if ${i} != "12"
|
|
||||||
. error
|
. error
|
||||||
. endif
|
. endif
|
||||||
|
# Instead of the 'empty' function, the variables from .for loops can be
|
||||||
|
# queried using conditions of the form '${var:...} != ""'.
|
||||||
|
. if $i == "12" && ${i:M*2*} != "12"
|
||||||
|
. error
|
||||||
. endif
|
. endif
|
||||||
.endfor
|
.endfor
|
||||||
|
|
||||||
|
@ -122,3 +122,5 @@ CPPFLAGS+= -Dmacro="${empty(i):?empty:not-empty}"
|
||||||
|
|
||||||
# TODO: Add code that demonstrates the current interaction between variables
|
# TODO: Add code that demonstrates the current interaction between variables
|
||||||
# from .for loops and the modifiers mentioned above.
|
# from .for loops and the modifiers mentioned above.
|
||||||
|
|
||||||
|
all:
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
# $NetBSD: directive-for-errors.mk,v 1.10 2024/04/20 10:18:55 rillig Exp $
|
# $NetBSD: directive-for-errors.mk,v 1.11 2024/06/01 11:24:11 rillig Exp $
|
||||||
#
|
#
|
||||||
# Tests for error handling in .for loops.
|
# Tests for error handling in .for loops.
|
||||||
|
|
||||||
|
@ -41,7 +41,7 @@
|
||||||
${:U\$}= dollar # see whether the "variable" '$' is local
|
${:U\$}= dollar # see whether the "variable" '$' is local
|
||||||
${:U\\}= backslash # see whether the "variable" '\' is local
|
${:U\\}= backslash # see whether the "variable" '\' is local
|
||||||
# expect+1: invalid character '$' in .for loop variable name
|
# expect+1: invalid character '$' in .for loop variable name
|
||||||
.for $ \ in 1 2 3 4
|
.for a b $ \ in 1 2 3 4
|
||||||
. info Dollar $$ ${$} $($) and backslash $\ ${\} $(\).
|
. info Dollar $$ ${$} $($) and backslash $\ ${\} $(\).
|
||||||
.endfor
|
.endfor
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
# $NetBSD: export-all.mk,v 1.5 2020/10/24 08:50:17 rillig Exp $
|
# $NetBSD: export-all.mk,v 1.6 2024/06/01 06:26:36 sjg Exp $
|
||||||
|
|
||||||
UT_OK= good
|
UT_OK= good
|
||||||
UT_F= fine
|
UT_F= fine
|
||||||
|
@ -15,7 +15,7 @@ UT_BADDIR= ${${here}/../${here:T}:L:${M_tAbad}:T}
|
||||||
# this will be ok
|
# this will be ok
|
||||||
UT_OKDIR= ${${here}/../${here:T}:L:${M_tA}:T}
|
UT_OKDIR= ${${here}/../${here:T}:L:${M_tA}:T}
|
||||||
|
|
||||||
.export
|
.export-all
|
||||||
|
|
||||||
FILTER_CMD= grep ^UT_
|
FILTER_CMD= grep ^UT_
|
||||||
.include "export.mk"
|
.include "export.mk"
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
make: "opt-debug-hash.mk" line 12: Missing argument for ".error"
|
make: "opt-debug-hash.mk" line 13: Missing argument for ".error"
|
||||||
make: Fatal errors encountered -- cannot continue
|
make: Fatal errors encountered -- cannot continue
|
||||||
HashTable targets: size=16 numEntries=0 maxchain=0
|
HashTable targets: size=16 numEntries=0 maxchain=0
|
||||||
HashTable Global variables: size=16 numEntries=<entries> maxchain=3
|
HashTable Global variables: size=16 numEntries=<entries> maxchain=3
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
# $NetBSD: opt-debug-hash.mk,v 1.4 2023/06/01 20:56:35 rillig Exp $
|
# $NetBSD: opt-debug-hash.mk,v 1.5 2024/05/31 07:13:12 rillig Exp $
|
||||||
#
|
#
|
||||||
# Tests for the -dh command line option, which adds debug logging for
|
# Tests for the -dh command line option, which adds debug logging for
|
||||||
# hash tables. Even more detailed logging is available by compiling
|
# hash tables. Even more detailed logging is available by compiling
|
||||||
|
@ -6,7 +6,8 @@
|
||||||
|
|
||||||
.MAKEFLAGS: -dh
|
.MAKEFLAGS: -dh
|
||||||
|
|
||||||
# Force a parse error, to demonstrate the newline character in the diagnostic
|
# Force a parse error, to demonstrate the newline character in the "cannot
|
||||||
# that had been missing before parse.c 1.655 from 2022-01-22.
|
# continue" diagnostic that had been missing before parse.c 1.655 from
|
||||||
|
# 2022-01-22.
|
||||||
# expect+1: Missing argument for ".error"
|
# expect+1: Missing argument for ".error"
|
||||||
.error
|
.error
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
# $NetBSD: parse-var.mk,v 1.9 2023/11/19 21:47:52 rillig Exp $
|
# $NetBSD: parse-var.mk,v 1.10 2024/06/02 15:31:26 rillig Exp $
|
||||||
#
|
#
|
||||||
# Tests for parsing expressions.
|
# Tests for parsing expressions.
|
||||||
#
|
#
|
||||||
|
@ -20,11 +20,11 @@
|
||||||
#
|
#
|
||||||
# VarEvalMode:
|
# VarEvalMode:
|
||||||
# parse
|
# parse
|
||||||
|
# parse-balanced
|
||||||
# eval
|
# eval
|
||||||
# eval-undeferr
|
# eval-defined
|
||||||
# eval-keep-dollar
|
# eval-keep-undefined
|
||||||
# eval-keep-undef
|
# eval-keep-dollar-and-undefined
|
||||||
# eval-keep-dollar-undef
|
|
||||||
#
|
#
|
||||||
# Global mode:
|
# Global mode:
|
||||||
# without -dL
|
# without -dL
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
# $NetBSD: recursive.mk,v 1.7 2023/10/19 18:24:33 rillig Exp $
|
# $NetBSD: recursive.mk,v 1.8 2024/06/02 15:31:26 rillig Exp $
|
||||||
#
|
#
|
||||||
# In -dL mode, a variable may get expanded before it makes sense.
|
# In -dL mode, a variable may get expanded before it makes sense.
|
||||||
# This would stop make from doing anything since the "recursive" error
|
# This would stop make from doing anything since the "recursive" error
|
||||||
|
@ -6,7 +6,7 @@
|
||||||
#
|
#
|
||||||
# The purpose of evaluating that variable early was just to detect
|
# The purpose of evaluating that variable early was just to detect
|
||||||
# whether there are unclosed variables. The variable value is therefore
|
# whether there are unclosed variables. The variable value is therefore
|
||||||
# parsed with VARE_PARSE_ONLY for that purpose.
|
# parsed with VARE_PARSE for that purpose.
|
||||||
#
|
#
|
||||||
|
|
||||||
.MAKEFLAGS: -dL
|
.MAKEFLAGS: -dL
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
# $NetBSD: shell-csh.mk,v 1.8 2021/04/04 09:58:51 rillig Exp $
|
# $NetBSD: shell-csh.mk,v 1.9 2024/05/25 15:37:17 rillig Exp $
|
||||||
#
|
#
|
||||||
# Tests for using a C shell for running the commands.
|
# Tests for using a C shell for running the commands.
|
||||||
|
|
||||||
|
@ -6,7 +6,7 @@ CSH!= which csh 2> /dev/null || true
|
||||||
|
|
||||||
# The shell path must be an absolute path.
|
# The shell path must be an absolute path.
|
||||||
# This is only obvious in parallel mode since in compat mode,
|
# This is only obvious in parallel mode since in compat mode,
|
||||||
# simple commands are executed via execve directly.
|
# simple commands are executed via execvp directly.
|
||||||
.if ${CSH} != ""
|
.if ${CSH} != ""
|
||||||
.SHELL: name="csh" path="${CSH}"
|
.SHELL: name="csh" path="${CSH}"
|
||||||
.endif
|
.endif
|
||||||
|
|
|
@ -17,7 +17,7 @@ ParseDependency(.a.c: ${.PREFIX}.dependency)
|
||||||
defining transformation from `.a' to `.c'
|
defining transformation from `.a' to `.c'
|
||||||
inserting ".a" (1) at end of list
|
inserting ".a" (1) at end of list
|
||||||
inserting ".c" (3) at end of list
|
inserting ".c" (3) at end of list
|
||||||
# LinkSource: added child .a.c - ${.PREFIX}.dependency
|
Target ".a.c" depends on "${.PREFIX}.dependency"
|
||||||
# .a.c, unmade, type OP_DEPENDS|OP_TRANSFORM, flags none
|
# .a.c, unmade, type OP_DEPENDS|OP_TRANSFORM, flags none
|
||||||
# ${.PREFIX}.dependency, unmade, type none, flags none
|
# ${.PREFIX}.dependency, unmade, type none, flags none
|
||||||
Parsing line 23: .DEFAULT:
|
Parsing line 23: .DEFAULT:
|
||||||
|
|
|
@ -58,7 +58,7 @@ ParseDependency(suff-main-several.1:)
|
||||||
Parsing line 39: : Making ${.TARGET} out of nothing.
|
Parsing line 39: : Making ${.TARGET} out of nothing.
|
||||||
Parsing line 40: next-main: suff-main-several.{2,3,4}
|
Parsing line 40: next-main: suff-main-several.{2,3,4}
|
||||||
ParseDependency(next-main: suff-main-several.{2,3,4})
|
ParseDependency(next-main: suff-main-several.{2,3,4})
|
||||||
# LinkSource: added child next-main - suff-main-several.{2,3,4}
|
Target "next-main" depends on "suff-main-several.{2,3,4}"
|
||||||
# next-main, unmade, type OP_DEPENDS|OP_HAS_COMMANDS, flags none
|
# next-main, unmade, type OP_DEPENDS|OP_HAS_COMMANDS, flags none
|
||||||
# suff-main-several.{2,3,4}, unmade, type none, flags none
|
# suff-main-several.{2,3,4}, unmade, type none, flags none
|
||||||
Parsing line 42: .MAKEFLAGS: -d0 -dg1
|
Parsing line 42: .MAKEFLAGS: -d0 -dg1
|
||||||
|
|
|
@ -2,26 +2,26 @@ make: "var-eval-short.mk" line 46: while evaluating "${:Uword:@${FAIL}@expr@}":
|
||||||
make: "var-eval-short.mk" line 46: Malformed conditional (0 && ${:Uword:@${FAIL}@expr@})
|
make: "var-eval-short.mk" line 46: Malformed conditional (0 && ${:Uword:@${FAIL}@expr@})
|
||||||
Parsing line 159: .if 0 && ${0:?${FAIL}then:${FAIL}else}
|
Parsing line 159: .if 0 && ${0:?${FAIL}then:${FAIL}else}
|
||||||
CondParser_Eval: 0 && ${0:?${FAIL}then:${FAIL}else}
|
CondParser_Eval: 0 && ${0:?${FAIL}then:${FAIL}else}
|
||||||
Var_Parse: ${0:?${FAIL}then:${FAIL}else} (parse-only)
|
Var_Parse: ${0:?${FAIL}then:${FAIL}else} (parse)
|
||||||
Parsing modifier ${0:?...}
|
Parsing modifier ${0:?...}
|
||||||
Var_Parse: ${FAIL}then:${FAIL}else} (parse-only)
|
Var_Parse: ${FAIL}then:${FAIL}else} (parse)
|
||||||
Modifier part: "${FAIL}then"
|
Modifier part: "${FAIL}then"
|
||||||
Var_Parse: ${FAIL}else} (parse-only)
|
Var_Parse: ${FAIL}else} (parse)
|
||||||
Modifier part: "${FAIL}else"
|
Modifier part: "${FAIL}else"
|
||||||
Result of ${0:?${FAIL}then:${FAIL}else} is "" (parse-only, defined)
|
Result of ${0:?${FAIL}then:${FAIL}else} is "" (parse, defined)
|
||||||
Parsing line 167: DEFINED= defined
|
Parsing line 167: DEFINED= defined
|
||||||
Global: DEFINED = defined
|
Global: DEFINED = defined
|
||||||
Parsing line 168: .if 0 && ${DEFINED:L:?${FAIL}then:${FAIL}else}
|
Parsing line 168: .if 0 && ${DEFINED:L:?${FAIL}then:${FAIL}else}
|
||||||
CondParser_Eval: 0 && ${DEFINED:L:?${FAIL}then:${FAIL}else}
|
CondParser_Eval: 0 && ${DEFINED:L:?${FAIL}then:${FAIL}else}
|
||||||
Var_Parse: ${DEFINED:L:?${FAIL}then:${FAIL}else} (parse-only)
|
Var_Parse: ${DEFINED:L:?${FAIL}then:${FAIL}else} (parse)
|
||||||
Parsing modifier ${DEFINED:L}
|
Parsing modifier ${DEFINED:L}
|
||||||
Result of ${DEFINED:L} is "defined" (parse-only, regular)
|
Result of ${DEFINED:L} is "defined" (parse, regular)
|
||||||
Parsing modifier ${DEFINED:?...}
|
Parsing modifier ${DEFINED:?...}
|
||||||
Var_Parse: ${FAIL}then:${FAIL}else} (parse-only)
|
Var_Parse: ${FAIL}then:${FAIL}else} (parse)
|
||||||
Modifier part: "${FAIL}then"
|
Modifier part: "${FAIL}then"
|
||||||
Var_Parse: ${FAIL}else} (parse-only)
|
Var_Parse: ${FAIL}else} (parse)
|
||||||
Modifier part: "${FAIL}else"
|
Modifier part: "${FAIL}else"
|
||||||
Result of ${DEFINED:?${FAIL}then:${FAIL}else} is "defined" (parse-only, regular)
|
Result of ${DEFINED:?${FAIL}then:${FAIL}else} is "defined" (parse, regular)
|
||||||
Parsing line 170: .MAKEFLAGS: -d0
|
Parsing line 170: .MAKEFLAGS: -d0
|
||||||
ParseDependency(.MAKEFLAGS: -d0)
|
ParseDependency(.MAKEFLAGS: -d0)
|
||||||
Global: .MAKEFLAGS = -r -k -d cpv -d
|
Global: .MAKEFLAGS = -r -k -d cpv -d
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
# $NetBSD: varmod-head.mk,v 1.5 2022/07/10 21:11:49 rillig Exp $
|
# $NetBSD: varmod-head.mk,v 1.6 2024/06/01 18:44:05 rillig Exp $
|
||||||
#
|
#
|
||||||
# Tests for the :H variable modifier, which returns the dirname of
|
# Tests for the :H variable modifier, which returns the dirname of
|
||||||
# each of the words in the variable value.
|
# each of the words in the variable value.
|
||||||
|
@ -61,4 +61,10 @@ _!= echo "The modifier ':H' generates an empty word." 1>&2; echo
|
||||||
. error
|
. error
|
||||||
.endif
|
.endif
|
||||||
|
|
||||||
|
# If the ':H' is not directly followed by a delimiting ':' or '}', the
|
||||||
|
# ':from=to' modifier is tried as a fallback.
|
||||||
|
.if ${:U Head :Head=replaced} != "replaced"
|
||||||
|
. error
|
||||||
|
.endif
|
||||||
|
|
||||||
all: .PHONY
|
all: .PHONY
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
# $NetBSD: varmod-ifelse.mk,v 1.28 2024/04/23 22:51:28 rillig Exp $
|
# $NetBSD: varmod-ifelse.mk,v 1.29 2024/06/02 15:31:26 rillig Exp $
|
||||||
#
|
#
|
||||||
# Tests for the ${cond:?then:else} variable modifier, which evaluates either
|
# Tests for the ${cond:?then:else} variable modifier, which evaluates either
|
||||||
# the then-expression or the else-expression, depending on the condition.
|
# the then-expression or the else-expression, depending on the condition.
|
||||||
|
@ -77,7 +77,7 @@ COND:= ${${UNDEF} == "":?bad-assign:bad-assign}
|
||||||
# conditional expression".
|
# conditional expression".
|
||||||
#
|
#
|
||||||
# XXX: The left-hand side is enclosed in quotes. This results in Var_Parse
|
# XXX: The left-hand side is enclosed in quotes. This results in Var_Parse
|
||||||
# being called without VARE_UNDEFERR. When ApplyModifier_IfElse
|
# being called without VARE_EVAL_DEFINED. When ApplyModifier_IfElse
|
||||||
# returns AMR_CLEANUP as result, Var_Parse returns varUndefined since the
|
# returns AMR_CLEANUP as result, Var_Parse returns varUndefined since the
|
||||||
# value of the expression is still undefined. CondParser_String is
|
# value of the expression is still undefined. CondParser_String is
|
||||||
# then supposed to do proper error handling, but since varUndefined is local
|
# then supposed to do proper error handling, but since varUndefined is local
|
||||||
|
|
|
@ -1,12 +1,12 @@
|
||||||
Parsing line 91: USE_8_DOLLARS= ${:U1:@var@${8_DOLLARS}@} ${8_DOLLARS} $$$$$$$$
|
Parsing line 89: USE_8_DOLLARS= ${:U1:@var@${8_DOLLARS}@} ${8_DOLLARS} $$$$$$$$
|
||||||
Parsing line 92: .if ${USE_8_DOLLARS} != "\$\$\$\$ \$\$\$\$ \$\$\$\$"
|
Parsing line 90: .if ${USE_8_DOLLARS} != "\$\$\$\$ \$\$\$\$ \$\$\$\$"
|
||||||
CondParser_Eval: ${USE_8_DOLLARS} != "\$\$\$\$ \$\$\$\$ \$\$\$\$"
|
CondParser_Eval: ${USE_8_DOLLARS} != "\$\$\$\$ \$\$\$\$ \$\$\$\$"
|
||||||
Comparing "$$$$ $$$$ $$$$" != "$$$$ $$$$ $$$$"
|
Comparing "$$$$ $$$$ $$$$" != "$$$$ $$$$ $$$$"
|
||||||
Parsing line 96: SUBST_CONTAINING_LOOP:= ${USE_8_DOLLARS}
|
Parsing line 94: SUBST_CONTAINING_LOOP:= ${USE_8_DOLLARS}
|
||||||
Parsing line 118: .if ${SUBST_CONTAINING_LOOP} != "\$\$ \$\$\$\$ \$\$\$\$"
|
Parsing line 116: .if ${SUBST_CONTAINING_LOOP} != "\$\$ \$\$\$\$ \$\$\$\$"
|
||||||
CondParser_Eval: ${SUBST_CONTAINING_LOOP} != "\$\$ \$\$\$\$ \$\$\$\$"
|
CondParser_Eval: ${SUBST_CONTAINING_LOOP} != "\$\$ \$\$\$\$ \$\$\$\$"
|
||||||
Comparing "$$ $$$$ $$$$" != "$$ $$$$ $$$$"
|
Comparing "$$ $$$$ $$$$" != "$$ $$$$ $$$$"
|
||||||
Parsing line 121: .MAKEFLAGS: -d0
|
Parsing line 119: .MAKEFLAGS: -d0
|
||||||
ParseDependency(.MAKEFLAGS: -d0)
|
ParseDependency(.MAKEFLAGS: -d0)
|
||||||
:varname-overwriting-target: :x1y x2y x3y: ::
|
:varname-overwriting-target: :x1y x2y x3y: ::
|
||||||
mod-loop-dollar:1:
|
mod-loop-dollar:1:
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
# $NetBSD: varmod-loop.mk,v 1.24 2023/11/19 21:47:52 rillig Exp $
|
# $NetBSD: varmod-loop.mk,v 1.26 2024/06/02 15:31:26 rillig Exp $
|
||||||
#
|
#
|
||||||
# Tests for the expression modifier ':@var@body@', which replaces each word of
|
# Tests for the expression modifier ':@var@body@', which replaces each word of
|
||||||
# the expression with the expanded body, which may contain references to the
|
# the expression with the expanded body, which may contain references to the
|
||||||
|
@ -82,10 +82,8 @@ mod-loop-dollar:
|
||||||
8_DOLLARS= $$$$$$$$
|
8_DOLLARS= $$$$$$$$
|
||||||
# This string literal is written with 8 dollars, and this is saved as the
|
# This string literal is written with 8 dollars, and this is saved as the
|
||||||
# variable value. But as soon as this value is evaluated, it goes through
|
# variable value. But as soon as this value is evaluated, it goes through
|
||||||
# Var_Subst, which replaces each '$$' with a single '$'. This could be
|
# Var_Subst, which replaces each '$$' with a single '$'.
|
||||||
# prevented by VARE_EVAL_KEEP_DOLLAR, but that flag is usually removed
|
# See ApplyModifier_Loop and ParseModifierPart for examples.
|
||||||
# before expanding subexpressions. See ApplyModifier_Loop and
|
|
||||||
# ParseModifierPart for examples.
|
|
||||||
#
|
#
|
||||||
.MAKEFLAGS: -dcp
|
.MAKEFLAGS: -dcp
|
||||||
USE_8_DOLLARS= ${:U1:@var@${8_DOLLARS}@} ${8_DOLLARS} $$$$$$$$
|
USE_8_DOLLARS= ${:U1:@var@${8_DOLLARS}@} ${8_DOLLARS} $$$$$$$$
|
||||||
|
@ -95,11 +93,11 @@ USE_8_DOLLARS= ${:U1:@var@${8_DOLLARS}@} ${8_DOLLARS} $$$$$$$$
|
||||||
#
|
#
|
||||||
SUBST_CONTAINING_LOOP:= ${USE_8_DOLLARS}
|
SUBST_CONTAINING_LOOP:= ${USE_8_DOLLARS}
|
||||||
# The ':=' assignment operator evaluates the variable value using the mode
|
# The ':=' assignment operator evaluates the variable value using the mode
|
||||||
# VARE_KEEP_DOLLAR_UNDEF, which means that some dollar signs are preserved,
|
# VARE_EVAL_KEEP_DOLLAR_AND_UNDEFINED, which means that some dollar signs are
|
||||||
# but not all. The dollar signs in the top-level expression and in the
|
# preserved, but not all. The dollar signs in the top-level expression and in
|
||||||
# indirect ${8_DOLLARS} are preserved.
|
# the indirect ${8_DOLLARS} are preserved.
|
||||||
#
|
#
|
||||||
# The variable modifier :@var@ does not preserve the dollar signs though, no
|
# The modifier :@var@ does not preserve the dollar signs though, no
|
||||||
# matter in which context it is evaluated. What happens in detail is:
|
# matter in which context it is evaluated. What happens in detail is:
|
||||||
# First, the modifier part "${8_DOLLARS}" is parsed without expanding it.
|
# First, the modifier part "${8_DOLLARS}" is parsed without expanding it.
|
||||||
# Next, each word of the value is expanded on its own, and at this moment
|
# Next, each word of the value is expanded on its own, and at this moment
|
||||||
|
|
|
@ -34,8 +34,8 @@ make: "varmod-match-escape.mk" line 43: warning: XXX: Oops
|
||||||
Global: .MAKEFLAGS = -r -k -d cv -d
|
Global: .MAKEFLAGS = -r -k -d cv -d
|
||||||
Global: .MAKEFLAGS = -r -k -d cv -d 0
|
Global: .MAKEFLAGS = -r -k -d cv -d 0
|
||||||
make: "varmod-match-escape.mk" line 69: while evaluating "${:U\$:M\$} != """: Dollar followed by nothing
|
make: "varmod-match-escape.mk" line 69: while evaluating "${:U\$:M\$} != """: Dollar followed by nothing
|
||||||
make: "varmod-match-escape.mk" line 110: while evaluating variable "WORDS": warning: Unfinished character list in pattern '[A-]' of modifier ':M'
|
make: "varmod-match-escape.mk" line 110: warning: while evaluating variable "WORDS": Unfinished character list in pattern '[A-]' of modifier ':M'
|
||||||
make: "varmod-match-escape.mk" line 110: while evaluating variable "WORDS": warning: Unfinished character list in pattern '[^A-]' of modifier ':M'
|
make: "varmod-match-escape.mk" line 110: warning: while evaluating variable "WORDS": Unfinished character list in pattern '[^A-]' of modifier ':M'
|
||||||
make: Fatal errors encountered -- cannot continue
|
make: Fatal errors encountered -- cannot continue
|
||||||
make: stopped in unit-tests
|
make: stopped in unit-tests
|
||||||
exit status 1
|
exit status 1
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
# $NetBSD: varmod-match-escape.mk,v 1.13 2024/04/20 10:18:55 rillig Exp $
|
# $NetBSD: varmod-match-escape.mk,v 1.14 2024/06/15 19:43:56 rillig Exp $
|
||||||
#
|
#
|
||||||
# As of 2020-08-01, the :M and :N modifiers interpret backslashes differently,
|
# As of 2020-08-01, the :M and :N modifiers interpret backslashes differently,
|
||||||
# depending on whether there was an expression somewhere before the
|
# depending on whether there was an expression somewhere before the
|
||||||
|
@ -105,8 +105,8 @@ EXP.[^A-]]= a
|
||||||
EXP.[^A-]]]= a]
|
EXP.[^A-]]]= a]
|
||||||
|
|
||||||
.for pattern in [A-] [A-]] [A-]]] [^A-] [^A-]] [^A-]]]
|
.for pattern in [A-] [A-]] [A-]]] [^A-] [^A-]] [^A-]]]
|
||||||
# expect+2: while evaluating variable "WORDS": warning: Unfinished character list in pattern '[A-]' of modifier ':M'
|
# expect+2: warning: while evaluating variable "WORDS": Unfinished character list in pattern '[A-]' of modifier ':M'
|
||||||
# expect+1: while evaluating variable "WORDS": warning: Unfinished character list in pattern '[^A-]' of modifier ':M'
|
# expect+1: warning: while evaluating variable "WORDS": Unfinished character list in pattern '[^A-]' of modifier ':M'
|
||||||
. if ${WORDS:M${pattern}} != ${EXP.${pattern}}
|
. if ${WORDS:M${pattern}} != ${EXP.${pattern}}
|
||||||
. warning ${pattern}: ${WORDS:M${pattern}} != ${EXP.${pattern}}
|
. warning ${pattern}: ${WORDS:M${pattern}} != ${EXP.${pattern}}
|
||||||
. endif
|
. endif
|
||||||
|
|
|
@ -1,14 +1,14 @@
|
||||||
make: "varmod-match.mk" line 290: while evaluating variable "WORDS": warning: Unfinished character list in pattern 'a[' of modifier ':M'
|
make: "varmod-match.mk" line 289: warning: while evaluating variable "WORDS": Unfinished character list in pattern 'a[' of modifier ':M'
|
||||||
make: "varmod-match.mk" line 298: while evaluating variable "WORDS": warning: Unfinished character list in pattern 'a[^' of modifier ':M'
|
make: "varmod-match.mk" line 297: warning: while evaluating variable "WORDS": Unfinished character list in pattern 'a[^' of modifier ':M'
|
||||||
make: "varmod-match.mk" line 306: while evaluating variable "WORDS": warning: Unfinished character list in pattern '[-x1-3' of modifier ':M'
|
make: "varmod-match.mk" line 305: warning: while evaluating variable "WORDS": Unfinished character list in pattern '[-x1-3' of modifier ':M'
|
||||||
make: "varmod-match.mk" line 314: while evaluating variable "WORDS": warning: Unfinished character list in pattern '*[-x1-3' of modifier ':M'
|
make: "varmod-match.mk" line 313: warning: while evaluating variable "WORDS": Unfinished character list in pattern '*[-x1-3' of modifier ':M'
|
||||||
make: "varmod-match.mk" line 323: while evaluating variable "WORDS": warning: Unfinished character list in pattern '[^-x1-3' of modifier ':M'
|
make: "varmod-match.mk" line 322: warning: while evaluating variable "WORDS": Unfinished character list in pattern '[^-x1-3' of modifier ':M'
|
||||||
make: "varmod-match.mk" line 337: while evaluating variable "WORDS": warning: Unfinished character list in pattern '?[\' of modifier ':M'
|
make: "varmod-match.mk" line 336: warning: while evaluating variable "WORDS": Unfinished character list in pattern '?[\' of modifier ':M'
|
||||||
make: "varmod-match.mk" line 345: while evaluating variable "WORDS": warning: Unfinished character range in pattern '[x-' of modifier ':M'
|
make: "varmod-match.mk" line 344: warning: while evaluating variable "WORDS": Unfinished character range in pattern '[x-' of modifier ':M'
|
||||||
make: "varmod-match.mk" line 357: while evaluating variable "WORDS": warning: Unfinished character range in pattern '[^x-' of modifier ':M'
|
make: "varmod-match.mk" line 356: warning: while evaluating variable "WORDS": Unfinished character range in pattern '[^x-' of modifier ':M'
|
||||||
make: "varmod-match.mk" line 365: while evaluating variable " : :: ": warning: Unfinished character list in pattern '[' of modifier ':M'
|
make: "varmod-match.mk" line 364: warning: while evaluating variable " : :: ": Unfinished character list in pattern '[' of modifier ':M'
|
||||||
make: "varmod-match.mk" line 365: while evaluating variable " : :: ": Unknown modifier "]"
|
make: "varmod-match.mk" line 364: while evaluating variable " : :: ": Unknown modifier "]"
|
||||||
make: "varmod-match.mk" line 365: Malformed conditional (${ ${:U\:} ${:U\:\:} :L:M[:]} != ":")
|
make: "varmod-match.mk" line 364: Malformed conditional (${ ${:U\:} ${:U\:\:} :L:M[:]} != ":")
|
||||||
make: Fatal errors encountered -- cannot continue
|
make: Fatal errors encountered -- cannot continue
|
||||||
make: stopped in unit-tests
|
make: stopped in unit-tests
|
||||||
exit status 1
|
exit status 1
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
# $NetBSD: varmod-match.mk,v 1.22 2024/04/23 22:51:28 rillig Exp $
|
# $NetBSD: varmod-match.mk,v 1.24 2024/06/15 19:43:56 rillig Exp $
|
||||||
#
|
#
|
||||||
# Tests for the ':M' modifier, which keeps only those words that match the
|
# Tests for the ':M' modifier, which keeps only those words that match the
|
||||||
# given pattern.
|
# given pattern.
|
||||||
|
@ -42,13 +42,12 @@
|
||||||
. error
|
. error
|
||||||
.endif
|
.endif
|
||||||
|
|
||||||
# A pattern that ends with '*' is anchored at the
|
# A pattern that does not start with '*' is anchored at the beginning.
|
||||||
# beginning.
|
|
||||||
.if ${a aa aaa b ba baa bab:L:Ma*} != "a aa aaa"
|
.if ${a aa aaa b ba baa bab:L:Ma*} != "a aa aaa"
|
||||||
. error
|
. error
|
||||||
.endif
|
.endif
|
||||||
|
|
||||||
# A pattern that starts with '*' is anchored at the end.
|
# A pattern that does not end with '*' is anchored at the end.
|
||||||
.if ${a aa aaa b ba baa bab:L:M*a} != "a aa aaa ba baa"
|
.if ${a aa aaa b ba baa bab:L:M*a} != "a aa aaa ba baa"
|
||||||
. error
|
. error
|
||||||
.endif
|
.endif
|
||||||
|
@ -286,7 +285,7 @@ ${:U*}= asterisk
|
||||||
|
|
||||||
# [ Incomplete empty character list, never matches.
|
# [ Incomplete empty character list, never matches.
|
||||||
WORDS= a a[
|
WORDS= a a[
|
||||||
# expect+1: while evaluating variable "WORDS": warning: Unfinished character list in pattern 'a[' of modifier ':M'
|
# expect+1: warning: while evaluating variable "WORDS": Unfinished character list in pattern 'a[' of modifier ':M'
|
||||||
.if ${WORDS:Ma[} != ""
|
.if ${WORDS:Ma[} != ""
|
||||||
. error
|
. error
|
||||||
.endif
|
.endif
|
||||||
|
@ -294,7 +293,7 @@ WORDS= a a[
|
||||||
# [^ Incomplete negated empty character list, matches any single
|
# [^ Incomplete negated empty character list, matches any single
|
||||||
# character.
|
# character.
|
||||||
WORDS= a a[ aX
|
WORDS= a a[ aX
|
||||||
# expect+1: while evaluating variable "WORDS": warning: Unfinished character list in pattern 'a[^' of modifier ':M'
|
# expect+1: warning: while evaluating variable "WORDS": Unfinished character list in pattern 'a[^' of modifier ':M'
|
||||||
.if ${WORDS:Ma[^} != "a[ aX"
|
.if ${WORDS:Ma[^} != "a[ aX"
|
||||||
. error
|
. error
|
||||||
.endif
|
.endif
|
||||||
|
@ -302,7 +301,7 @@ WORDS= a a[ aX
|
||||||
# [-x1-3 Incomplete character list, matches those elements that can be
|
# [-x1-3 Incomplete character list, matches those elements that can be
|
||||||
# parsed without lookahead.
|
# parsed without lookahead.
|
||||||
WORDS= - + x xx 0 1 2 3 4 [x1-3
|
WORDS= - + x xx 0 1 2 3 4 [x1-3
|
||||||
# expect+1: while evaluating variable "WORDS": warning: Unfinished character list in pattern '[-x1-3' of modifier ':M'
|
# expect+1: warning: while evaluating variable "WORDS": Unfinished character list in pattern '[-x1-3' of modifier ':M'
|
||||||
.if ${WORDS:M[-x1-3} != "- x 1 2 3"
|
.if ${WORDS:M[-x1-3} != "- x 1 2 3"
|
||||||
. error
|
. error
|
||||||
.endif
|
.endif
|
||||||
|
@ -310,7 +309,7 @@ WORDS= - + x xx 0 1 2 3 4 [x1-3
|
||||||
# *[-x1-3 Incomplete character list after a wildcard, matches those
|
# *[-x1-3 Incomplete character list after a wildcard, matches those
|
||||||
# words that end with one of the characters from the list.
|
# words that end with one of the characters from the list.
|
||||||
WORDS= - + x xx 0 1 2 3 4 00 01 10 11 000 001 010 011 100 101 110 111 [x1-3
|
WORDS= - + x xx 0 1 2 3 4 00 01 10 11 000 001 010 011 100 101 110 111 [x1-3
|
||||||
# expect+1: while evaluating variable "WORDS": warning: Unfinished character list in pattern '*[-x1-3' of modifier ':M'
|
# expect+1: warning: while evaluating variable "WORDS": Unfinished character list in pattern '*[-x1-3' of modifier ':M'
|
||||||
.if ${WORDS:M*[-x1-3} != "- x xx 1 2 3 01 11 001 011 101 111 [x1-3"
|
.if ${WORDS:M*[-x1-3} != "- x xx 1 2 3 01 11 001 011 101 111 [x1-3"
|
||||||
. warning ${WORDS:M*[-x1-3}
|
. warning ${WORDS:M*[-x1-3}
|
||||||
.endif
|
.endif
|
||||||
|
@ -319,7 +318,7 @@ WORDS= - + x xx 0 1 2 3 4 00 01 10 11 000 001 010 011 100 101 110 111 [x1-3
|
||||||
# Incomplete negated character list, matches any character
|
# Incomplete negated character list, matches any character
|
||||||
# except those elements that can be parsed without lookahead.
|
# except those elements that can be parsed without lookahead.
|
||||||
WORDS= - + x xx 0 1 2 3 4 [x1-3
|
WORDS= - + x xx 0 1 2 3 4 [x1-3
|
||||||
# expect+1: while evaluating variable "WORDS": warning: Unfinished character list in pattern '[^-x1-3' of modifier ':M'
|
# expect+1: warning: while evaluating variable "WORDS": Unfinished character list in pattern '[^-x1-3' of modifier ':M'
|
||||||
.if ${WORDS:M[^-x1-3} != "+ 0 4"
|
.if ${WORDS:M[^-x1-3} != "+ 0 4"
|
||||||
. error
|
. error
|
||||||
.endif
|
.endif
|
||||||
|
@ -333,7 +332,7 @@ WORDS= - + x xx 0 1 2 3 4 [x1-3
|
||||||
# '\', as there is no following space that could be escaped.
|
# '\', as there is no following space that could be escaped.
|
||||||
WORDS= \\ \a ${:Ux\\}
|
WORDS= \\ \a ${:Ux\\}
|
||||||
PATTERN= ${:U?[\\}
|
PATTERN= ${:U?[\\}
|
||||||
# expect+1: while evaluating variable "WORDS": warning: Unfinished character list in pattern '?[\' of modifier ':M'
|
# expect+1: warning: while evaluating variable "WORDS": Unfinished character list in pattern '?[\' of modifier ':M'
|
||||||
.if ${WORDS:M${PATTERN}} != "\\\\ x\\"
|
.if ${WORDS:M${PATTERN}} != "\\\\ x\\"
|
||||||
. error
|
. error
|
||||||
.endif
|
.endif
|
||||||
|
@ -341,7 +340,7 @@ PATTERN= ${:U?[\\}
|
||||||
# [x- Incomplete character list containing an incomplete character
|
# [x- Incomplete character list containing an incomplete character
|
||||||
# range, matches only the 'x'.
|
# range, matches only the 'x'.
|
||||||
WORDS= [x- x x- y
|
WORDS= [x- x x- y
|
||||||
# expect+1: while evaluating variable "WORDS": warning: Unfinished character range in pattern '[x-' of modifier ':M'
|
# expect+1: warning: while evaluating variable "WORDS": Unfinished character range in pattern '[x-' of modifier ':M'
|
||||||
.if ${WORDS:M[x-} != "x"
|
.if ${WORDS:M[x-} != "x"
|
||||||
. error
|
. error
|
||||||
.endif
|
.endif
|
||||||
|
@ -353,13 +352,13 @@ WORDS= [x- x x- y
|
||||||
# XXX: Even matches strings that are longer than a single
|
# XXX: Even matches strings that are longer than a single
|
||||||
# character.
|
# character.
|
||||||
WORDS= [x- x x- y yyyyy
|
WORDS= [x- x x- y yyyyy
|
||||||
# expect+1: while evaluating variable "WORDS": warning: Unfinished character range in pattern '[^x-' of modifier ':M'
|
# expect+1: warning: while evaluating variable "WORDS": Unfinished character range in pattern '[^x-' of modifier ':M'
|
||||||
.if ${WORDS:M[^x-} != "[x- y yyyyy"
|
.if ${WORDS:M[^x-} != "[x- y yyyyy"
|
||||||
. error
|
. error
|
||||||
.endif
|
.endif
|
||||||
|
|
||||||
# [:] matches never since the ':' starts the next modifier
|
# [:] matches never since the ':' starts the next modifier
|
||||||
# expect+3: while evaluating variable " : :: ": warning: Unfinished character list in pattern '[' of modifier ':M'
|
# expect+3: warning: while evaluating variable " : :: ": Unfinished character list in pattern '[' of modifier ':M'
|
||||||
# expect+2: while evaluating variable " : :: ": Unknown modifier "]"
|
# expect+2: while evaluating variable " : :: ": Unknown modifier "]"
|
||||||
# expect+1: Malformed conditional (${ ${:U\:} ${:U\:\:} :L:M[:]} != ":")
|
# expect+1: Malformed conditional (${ ${:U\:} ${:U\:\:} :L:M[:]} != ":")
|
||||||
.if ${ ${:U\:} ${:U\:\:} :L:M[:]} != ":"
|
.if ${ ${:U\:} ${:U\:\:} :L:M[:]} != ":"
|
||||||
|
@ -375,7 +374,7 @@ WORDS= [x- x x- y yyyyy
|
||||||
# out-of-bounds read beyond the indirect ':M' modifiers.
|
# out-of-bounds read beyond the indirect ':M' modifiers.
|
||||||
#
|
#
|
||||||
# The argument to the inner ':U' is unescaped to 'M\'.
|
# The argument to the inner ':U' is unescaped to 'M\'.
|
||||||
# This 'M\' becomes an # indirect modifier ':M' with the pattern '\'.
|
# This 'M\' becomes an indirect modifier ':M' with the pattern '\'.
|
||||||
# The pattern '\' never matches.
|
# The pattern '\' never matches.
|
||||||
.if ${:U:${:UM\\}}
|
.if ${:U:${:UM\\}}
|
||||||
. error
|
. error
|
||||||
|
|
|
@ -145,6 +145,8 @@ pre-middle-suffix pre%ffix=NPre% "NPre-middle-su"
|
||||||
suffix pre%ffix=NPre%NS "suffix"
|
suffix pre%ffix=NPre%NS "suffix"
|
||||||
prefix pre%ffix=NPre%NS "prefix"
|
prefix pre%ffix=NPre%NS "prefix"
|
||||||
pre-middle-suffix pre%ffix=NPre%NS "NPre-middle-suNS"
|
pre-middle-suffix pre%ffix=NPre%NS "NPre-middle-suNS"
|
||||||
|
make: Unfinished modifier for "error" ('}' missing)
|
||||||
|
make: "varmod-sysv.mk" line 259: Malformed conditional (${error:L:from=$(}))
|
||||||
make: Fatal errors encountered -- cannot continue
|
make: Fatal errors encountered -- cannot continue
|
||||||
make: stopped in unit-tests
|
make: stopped in unit-tests
|
||||||
exit status 1
|
exit status 1
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
# $NetBSD: varmod-sysv.mk,v 1.16 2023/11/19 21:47:52 rillig Exp $
|
# $NetBSD: varmod-sysv.mk,v 1.17 2024/06/01 18:44:05 rillig Exp $
|
||||||
#
|
#
|
||||||
# Tests for the variable modifier ':from=to', which replaces the suffix
|
# Tests for the variable modifier ':from=to', which replaces the suffix
|
||||||
# "from" with "to". It can also use '%' as a wildcard.
|
# "from" with "to". It can also use '%' as a wildcard.
|
||||||
|
@ -252,4 +252,12 @@ INDIRECT= 1:${VALUE} 2:$${VALUE} 4:$$$${VALUE}
|
||||||
. endfor
|
. endfor
|
||||||
.endfor
|
.endfor
|
||||||
|
|
||||||
|
|
||||||
|
# The error case of an unfinished ':from=to' modifier after the '=' requires
|
||||||
|
# an expression that is missing the closing '}'.
|
||||||
|
# expect+1: Malformed conditional (${error:L:from=$(}))
|
||||||
|
.if ${error:L:from=$(})
|
||||||
|
.endif
|
||||||
|
|
||||||
|
|
||||||
all:
|
all:
|
||||||
|
|
|
@ -1,8 +1,16 @@
|
||||||
# $NetBSD: varmod-tail.mk,v 1.4 2020/12/20 22:57:40 rillig Exp $
|
# $NetBSD: varmod-tail.mk,v 1.5 2024/06/01 18:44:05 rillig Exp $
|
||||||
#
|
#
|
||||||
# Tests for the :T variable modifier, which returns the basename of each of
|
# Tests for the :T variable modifier, which returns the basename of each of
|
||||||
# the words in the variable value.
|
# the words in the variable value.
|
||||||
|
|
||||||
|
|
||||||
|
# If the ':T' is not directly followed by a delimiting ':' or '}', the
|
||||||
|
# ':from=to' modifier is tried as a fallback.
|
||||||
|
.if ${:U Tail :Tail=replaced} != "replaced"
|
||||||
|
. error
|
||||||
|
.endif
|
||||||
|
|
||||||
|
|
||||||
all:
|
all:
|
||||||
.for path in a/b/c def a.b.c a.b/c a a.a .gitignore a a.a trailing/
|
.for path in a/b/c def a.b.c a.b/c a a.a .gitignore a a.a trailing/
|
||||||
@echo "tail (basename) of '"${path:Q}"' is '"${path:T:Q}"'"
|
@echo "tail (basename) of '"${path:Q}"' is '"${path:T:Q}"'"
|
||||||
|
|
|
@ -2,24 +2,28 @@ make: "varmod-to-separator.mk" line 155: while evaluating variable "WORDS": Inva
|
||||||
make: "varmod-to-separator.mk" line 155: Malformed conditional (${WORDS:[1..3]:ts\400:tu})
|
make: "varmod-to-separator.mk" line 155: Malformed conditional (${WORDS:[1..3]:ts\400:tu})
|
||||||
make: "varmod-to-separator.mk" line 171: while evaluating variable "WORDS": Invalid character number at "100:tu}"
|
make: "varmod-to-separator.mk" line 171: while evaluating variable "WORDS": Invalid character number at "100:tu}"
|
||||||
make: "varmod-to-separator.mk" line 171: Malformed conditional (${WORDS:[1..3]:ts\x100:tu})
|
make: "varmod-to-separator.mk" line 171: Malformed conditional (${WORDS:[1..3]:ts\x100:tu})
|
||||||
|
make: "varmod-to-separator.mk" line 180: while evaluating variable "word": Invalid character number at ",}"
|
||||||
|
make: "varmod-to-separator.mk" line 180: Malformed conditional (${word:L:ts\x,})
|
||||||
|
make: "varmod-to-separator.mk" line 187: while evaluating variable "word": Invalid character number at "112233445566778899}"
|
||||||
|
make: "varmod-to-separator.mk" line 187: Malformed conditional (${word:L:ts\x112233445566778899})
|
||||||
make: Bad modifier ":ts\-300" for variable "WORDS"
|
make: Bad modifier ":ts\-300" for variable "WORDS"
|
||||||
make: "varmod-to-separator.mk" line 179: Malformed conditional (${WORDS:[1..3]:ts\-300:tu})
|
make: "varmod-to-separator.mk" line 192: Malformed conditional (${WORDS:[1..3]:ts\-300:tu})
|
||||||
make: Bad modifier ":ts\8" for variable "1 2 3"
|
make: Bad modifier ":ts\8" for variable "1 2 3"
|
||||||
make: "varmod-to-separator.mk" line 188: Malformed conditional (${1 2 3:L:ts\8:tu})
|
make: "varmod-to-separator.mk" line 201: Malformed conditional (${1 2 3:L:ts\8:tu})
|
||||||
make: Bad modifier ":ts\100L" for variable "1 2 3"
|
make: Bad modifier ":ts\100L" for variable "1 2 3"
|
||||||
make: "varmod-to-separator.mk" line 196: Malformed conditional (${1 2 3:L:ts\100L})
|
make: "varmod-to-separator.mk" line 209: Malformed conditional (${1 2 3:L:ts\100L})
|
||||||
make: Bad modifier ":ts\x40g" for variable "1 2 3"
|
make: Bad modifier ":ts\x40g" for variable "1 2 3"
|
||||||
make: "varmod-to-separator.mk" line 204: Malformed conditional (${1 2 3:L:ts\x40g})
|
make: "varmod-to-separator.mk" line 217: Malformed conditional (${1 2 3:L:ts\x40g})
|
||||||
make: Bad modifier ":tx" for variable "WORDS"
|
make: Bad modifier ":tx" for variable "WORDS"
|
||||||
make: "varmod-to-separator.mk" line 214: Malformed conditional (${WORDS:tx})
|
make: "varmod-to-separator.mk" line 227: Malformed conditional (${WORDS:tx})
|
||||||
make: Bad modifier ":ts\X" for variable "WORDS"
|
make: Bad modifier ":ts\X" for variable "WORDS"
|
||||||
make: "varmod-to-separator.mk" line 223: Malformed conditional (${WORDS:ts\X})
|
make: "varmod-to-separator.mk" line 236: Malformed conditional (${WORDS:ts\X})
|
||||||
make: Bad modifier ":t\X" for variable "WORDS"
|
make: Bad modifier ":t\X" for variable "WORDS"
|
||||||
make: "varmod-to-separator.mk" line 232: Malformed conditional (${WORDS:t\X} != "anything")
|
make: "varmod-to-separator.mk" line 245: Malformed conditional (${WORDS:t\X} != "anything")
|
||||||
make: Bad modifier ":ts\69" for variable ""
|
make: Bad modifier ":ts\69" for variable ""
|
||||||
make: "varmod-to-separator.mk" line 249: Malformed conditional (${:Ua b:ts\69})
|
make: "varmod-to-separator.mk" line 262: Malformed conditional (${:Ua b:ts\69})
|
||||||
make: "varmod-to-separator.mk" line 258: while evaluating "${:Ua b:ts\x1F60E}": Invalid character number at "1F60E}"
|
make: "varmod-to-separator.mk" line 271: while evaluating "${:Ua b:ts\x1F60E}": Invalid character number at "1F60E}"
|
||||||
make: "varmod-to-separator.mk" line 258: Malformed conditional (${:Ua b:ts\x1F60E})
|
make: "varmod-to-separator.mk" line 271: Malformed conditional (${:Ua b:ts\x1F60E})
|
||||||
make: Fatal errors encountered -- cannot continue
|
make: Fatal errors encountered -- cannot continue
|
||||||
make: stopped in unit-tests
|
make: stopped in unit-tests
|
||||||
exit status 1
|
exit status 1
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
# $NetBSD: varmod-to-separator.mk,v 1.14 2024/04/20 10:18:55 rillig Exp $
|
# $NetBSD: varmod-to-separator.mk,v 1.15 2024/06/01 18:44:05 rillig Exp $
|
||||||
#
|
#
|
||||||
# Tests for the :ts variable modifier, which joins the words of the variable
|
# Tests for the :ts variable modifier, which joins the words of the variable
|
||||||
# using an arbitrary character as word separator.
|
# using an arbitrary character as word separator.
|
||||||
|
@ -174,6 +174,19 @@ WORDS= one two three four five six
|
||||||
. warning The separator \x100 is accepted even though it is out of bounds.
|
. warning The separator \x100 is accepted even though it is out of bounds.
|
||||||
.endif
|
.endif
|
||||||
|
|
||||||
|
# The number after ':ts\x' must be hexadecimal.
|
||||||
|
# expect+2: while evaluating variable "word": Invalid character number at ",}"
|
||||||
|
# expect+1: Malformed conditional (${word:L:ts\x,})
|
||||||
|
.if ${word:L:ts\x,}
|
||||||
|
.endif
|
||||||
|
|
||||||
|
# The hexadecimal number must be in the range of 'unsigned long' on all
|
||||||
|
# supported platforms.
|
||||||
|
# expect+2: while evaluating variable "word": Invalid character number at "112233445566778899}"
|
||||||
|
# expect+1: Malformed conditional (${word:L:ts\x112233445566778899})
|
||||||
|
.if ${word:L:ts\x112233445566778899}
|
||||||
|
.endif
|
||||||
|
|
||||||
# Negative numbers are not allowed for the separator character.
|
# Negative numbers are not allowed for the separator character.
|
||||||
# expect+1: Malformed conditional (${WORDS:[1..3]:ts\-300:tu})
|
# expect+1: Malformed conditional (${WORDS:[1..3]:ts\-300:tu})
|
||||||
.if ${WORDS:[1..3]:ts\-300:tu}
|
.if ${WORDS:[1..3]:ts\-300:tu}
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
# $NetBSD: varmod-undefined.mk,v 1.9 2023/11/19 21:47:52 rillig Exp $
|
# $NetBSD: varmod-undefined.mk,v 1.11 2024/06/03 02:46:29 sjg Exp $
|
||||||
#
|
#
|
||||||
# Tests for the :U variable modifier, which returns the given string
|
# Tests for the :U variable modifier, which returns the given string
|
||||||
# if the variable is undefined.
|
# if the variable is undefined.
|
||||||
|
@ -7,6 +7,9 @@
|
||||||
# directive-for.mk
|
# directive-for.mk
|
||||||
# varmod-defined.mk
|
# varmod-defined.mk
|
||||||
|
|
||||||
|
# this test depends on
|
||||||
|
.MAKE.SAVE_DOLLARS= yes
|
||||||
|
|
||||||
# The pattern ${:Uword} is heavily used when expanding .for loops.
|
# The pattern ${:Uword} is heavily used when expanding .for loops.
|
||||||
#
|
#
|
||||||
# This is how an expanded .for loop looks like.
|
# This is how an expanded .for loop looks like.
|
||||||
|
@ -53,6 +56,10 @@
|
||||||
.if ${:U \: \} \$ \\ \a \b \n } != " : } \$ \\ \\a \\b \\n "
|
.if ${:U \: \} \$ \\ \a \b \n } != " : } \$ \\ \\a \\b \\n "
|
||||||
. error
|
. error
|
||||||
.endif
|
.endif
|
||||||
|
# An expression enclosed in quotes may be based on an undefined variable.
|
||||||
|
.if "${:U \: \} \$ \\ \a \b \n }" != " : } \$ \\ \\a \\b \\n "
|
||||||
|
. error
|
||||||
|
.endif
|
||||||
|
|
||||||
# Even after the :U modifier has been applied, the expression still remembers
|
# Even after the :U modifier has been applied, the expression still remembers
|
||||||
# that it originated from an undefined variable, and the :U modifier can
|
# that it originated from an undefined variable, and the :U modifier can
|
||||||
|
@ -64,5 +71,43 @@
|
||||||
. error
|
. error
|
||||||
.endif
|
.endif
|
||||||
|
|
||||||
all:
|
|
||||||
@:;
|
# VARE_PARSE
|
||||||
|
.if 0 && ${:U . \: \} \$ \\ ${EXPR}}
|
||||||
|
. error
|
||||||
|
.endif
|
||||||
|
|
||||||
|
# VARE_EVAL_KEEP_DOLLAR_AND_UNDEFINED
|
||||||
|
SUBST:= ${:U . \: \} \$ \\ ${EXPR}}
|
||||||
|
${:U }= <space>
|
||||||
|
EXPR= <expr>
|
||||||
|
.if ${SUBST} != " . : } <space>\\ "
|
||||||
|
. error
|
||||||
|
.endif
|
||||||
|
|
||||||
|
8_DOLLAR= $$$$$$$$
|
||||||
|
.if ${8_DOLLAR} != "\$\$\$\$"
|
||||||
|
. error
|
||||||
|
.endif
|
||||||
|
.if ${:U${8_DOLLAR}} != "\$\$\$\$"
|
||||||
|
. error
|
||||||
|
.endif
|
||||||
|
.if ${x:L:@_@${8_DOLLAR}@} != "\$\$\$\$"
|
||||||
|
. error
|
||||||
|
.endif
|
||||||
|
EXPR:= ${8_DOLLAR}
|
||||||
|
.if ${EXPR} != "\$\$\$\$"
|
||||||
|
. error
|
||||||
|
.endif
|
||||||
|
EXPR:= ${:U${8_DOLLAR}}
|
||||||
|
.if ${EXPR} != "\$\$\$\$"
|
||||||
|
. error
|
||||||
|
.endif
|
||||||
|
# VARE_EVAL_KEEP_UNDEFINED
|
||||||
|
EXPR:= ${x:L:@_@${8_DOLLAR}@}
|
||||||
|
.if ${EXPR} != "\$\$"
|
||||||
|
. error
|
||||||
|
.endif
|
||||||
|
|
||||||
|
|
||||||
|
all: .PHONY
|
||||||
|
|
|
@ -3,6 +3,31 @@ make: "varmod.mk" line 101: Invalid variable name ':', at "$:L} != """
|
||||||
make: "varmod.mk" line 107: while evaluating "${:Uword:@word@${word}$@} != "word"": Dollar followed by nothing
|
make: "varmod.mk" line 107: while evaluating "${:Uword:@word@${word}$@} != "word"": Dollar followed by nothing
|
||||||
make: "varmod.mk" line 117: while evaluating variable "VAR": Missing delimiter ':' after modifier "P"
|
make: "varmod.mk" line 117: while evaluating variable "VAR": Missing delimiter ':' after modifier "P"
|
||||||
make: "varmod.mk" line 119: Missing argument for ".error"
|
make: "varmod.mk" line 119: Missing argument for ".error"
|
||||||
|
make: Bad modifier ":[99333000222000111000]" for variable "word"
|
||||||
|
make: "varmod.mk" line 125: Malformed conditional (${word:L:[99333000222000111000]})
|
||||||
|
make: Bad modifier ":[2147483648]" for variable "word"
|
||||||
|
make: "varmod.mk" line 128: Malformed conditional (${word:L:[2147483648]})
|
||||||
|
make: "varmod.mk" line 135: while evaluating variable "word": Invalid number "99333000222000111000}" for ':range' modifier
|
||||||
|
make: "varmod.mk" line 135: Malformed conditional (${word:L:range=99333000222000111000})
|
||||||
|
make: "varmod.mk" line 143: while evaluating "${:${:Ugmtime=\\}}": Invalid time value "\"
|
||||||
|
make: "varmod.mk" line 143: Malformed conditional (${:${:Ugmtime=\\}})
|
||||||
|
make: "varmod.mk" line 158: while evaluating variable "VAR": Dollar followed by nothing
|
||||||
|
make: "varmod.mk" line 164: while evaluating variable "VAR": Dollar followed by nothing
|
||||||
|
make: "varmod.mk" line 164: while evaluating variable "VAR": Dollar followed by nothing
|
||||||
|
make: "varmod.mk" line 174: while evaluating variable "word": Dollar followed by nothing
|
||||||
|
make: Bad modifier ":[$]" for variable "word"
|
||||||
|
make: "varmod.mk" line 179: Malformed conditional (${word:[$]})
|
||||||
|
make: "varmod.mk" line 196: while evaluating variable "VAR": Dollar followed by nothing
|
||||||
|
make: "varmod.mk" line 196: while evaluating variable "VAR": Invalid variable name '}', at "$} != "set""
|
||||||
|
make: "varmod.mk" line 200: while evaluating "${:Ufallback$} != "fallback"": Invalid variable name '}', at "$} != "fallback""
|
||||||
|
make: "varmod.mk" line 205: while evaluating variable "%y": Invalid time value "1000$"
|
||||||
|
make: "varmod.mk" line 205: Malformed conditional (${%y:L:gmtime=1000$})
|
||||||
|
make: "varmod.mk" line 212: while evaluating variable "%y": Invalid time value "1000$"
|
||||||
|
make: "varmod.mk" line 212: Malformed conditional (${%y:L:localtime=1000$})
|
||||||
|
make: "varmod.mk" line 218: while evaluating variable "word": Dollar followed by nothing
|
||||||
|
make: "varmod.mk" line 222: while evaluating variable "word": Dollar followed by nothing
|
||||||
|
make: "varmod.mk" line 227: while evaluating variable ".": Invalid argument 'fallback$' for modifier ':mtime'
|
||||||
|
make: "varmod.mk" line 227: Malformed conditional (${.:L:mtime=fallback$})
|
||||||
make: Fatal errors encountered -- cannot continue
|
make: Fatal errors encountered -- cannot continue
|
||||||
make: stopped in unit-tests
|
make: stopped in unit-tests
|
||||||
exit status 1
|
exit status 1
|
||||||
|
|
|
@ -1,11 +1,11 @@
|
||||||
# $NetBSD: varmod.mk,v 1.11 2024/04/20 10:18:56 rillig Exp $
|
# $NetBSD: varmod.mk,v 1.15 2024/06/06 20:41:50 rillig Exp $
|
||||||
#
|
#
|
||||||
# Tests for variable modifiers, such as :Q, :S,from,to or :Ufallback.
|
# Tests for variable modifiers, such as :Q, :S,from,to or :Ufallback.
|
||||||
#
|
#
|
||||||
# See also:
|
# See also:
|
||||||
# varparse-errors.mk
|
# varparse-errors.mk
|
||||||
|
|
||||||
# As of 2022-08-06, the possible behaviors during parsing are:
|
# As of 2024-06-05, the possible behaviors during parsing are:
|
||||||
#
|
#
|
||||||
# * `strict`: the parsing style used by most modifiers:
|
# * `strict`: the parsing style used by most modifiers:
|
||||||
# * either uses `ParseModifierPart` or parses the modifier literal
|
# * either uses `ParseModifierPart` or parses the modifier literal
|
||||||
|
@ -46,9 +46,9 @@
|
||||||
# | `U` | individual | custom parser | N/A |
|
# | `U` | individual | custom parser | N/A |
|
||||||
# | `[` | strict | | no |
|
# | `[` | strict | | no |
|
||||||
# | `_` | individual | strcspn | yes |
|
# | `_` | individual | strcspn | yes |
|
||||||
# | `gmtime` | strict | only literal value | yes |
|
# | `gmtime` | strict | | yes |
|
||||||
# | `hash` | strict | | N/A |
|
# | `hash` | strict | | N/A |
|
||||||
# | `localtime` | strict | only literal value | yes |
|
# | `localtime` | strict | | yes |
|
||||||
# | `q` | strict | | yes |
|
# | `q` | strict | | yes |
|
||||||
# | `range` | strict | | N/A |
|
# | `range` | strict | | N/A |
|
||||||
# | `sh` | strict | | N/A |
|
# | `sh` | strict | | N/A |
|
||||||
|
@ -119,4 +119,119 @@ VAR= STOP
|
||||||
. error
|
. error
|
||||||
.endif
|
.endif
|
||||||
|
|
||||||
all: # nothing
|
# Test the word selection modifier ':[n]' with a very large number that is
|
||||||
|
# larger than ULONG_MAX for any supported platform.
|
||||||
|
# expect+1: Malformed conditional (${word:L:[99333000222000111000]})
|
||||||
|
.if ${word:L:[99333000222000111000]}
|
||||||
|
.endif
|
||||||
|
# expect+1: Malformed conditional (${word:L:[2147483648]})
|
||||||
|
.if ${word:L:[2147483648]}
|
||||||
|
.endif
|
||||||
|
|
||||||
|
# Test the range generation modifier ':range=n' with a very large number that
|
||||||
|
# is larger than SIZE_MAX for any supported platform.
|
||||||
|
# expect+2: Malformed conditional (${word:L:range=99333000222000111000})
|
||||||
|
# expect+1: while evaluating variable "word": Invalid number "99333000222000111000}" for ':range' modifier
|
||||||
|
.if ${word:L:range=99333000222000111000}
|
||||||
|
.endif
|
||||||
|
|
||||||
|
# In an indirect modifier, the delimiter is '\0', which at the same time marks
|
||||||
|
# the end of the string. The sequence '\\' '\0' is not an escaped delimiter,
|
||||||
|
# as it would be wrong to skip past the end of the string.
|
||||||
|
# expect+2: while evaluating "${:${:Ugmtime=\\}}": Invalid time value "\"
|
||||||
|
# expect+1: Malformed conditional (${:${:Ugmtime=\\}})
|
||||||
|
.if ${:${:Ugmtime=\\}}
|
||||||
|
. error
|
||||||
|
.endif
|
||||||
|
|
||||||
|
# Test a '$' at the end of a modifier part, for all modifiers in the order
|
||||||
|
# listed in ApplyModifier.
|
||||||
|
#
|
||||||
|
# The only modifier parts where an unescaped '$' makes sense at the end are
|
||||||
|
# the 'from' parts of the ':S' and ':C' modifiers. In all other modifier
|
||||||
|
# parts, an unescaped '$' is an undocumented and discouraged edge case, as it
|
||||||
|
# means the same as an escaped '$'.
|
||||||
|
.if ${:U:!printf '%s\n' $!} != "\$"
|
||||||
|
. error
|
||||||
|
.endif
|
||||||
|
# expect+1: while evaluating variable "VAR": Dollar followed by nothing
|
||||||
|
.if ${VAR::=value$} != "" || ${VAR} != "value"
|
||||||
|
. error
|
||||||
|
.endif
|
||||||
|
${:U }= <space>
|
||||||
|
# expect+2: while evaluating variable "VAR": Dollar followed by nothing
|
||||||
|
# expect+1: while evaluating variable "VAR": Dollar followed by nothing
|
||||||
|
.if ${VAR::+=appended$} != "" || ${VAR} != "value<space>appended"
|
||||||
|
. error
|
||||||
|
.endif
|
||||||
|
.if ${1:?then$:else$} != "then\$"
|
||||||
|
. error
|
||||||
|
.endif
|
||||||
|
.if ${0:?then$:else$} != "else\$"
|
||||||
|
. error
|
||||||
|
.endif
|
||||||
|
# expect+1: while evaluating variable "word": Dollar followed by nothing
|
||||||
|
.if ${word:L:@w@$w$@} != "word"
|
||||||
|
. error
|
||||||
|
.endif
|
||||||
|
# expect: make: Bad modifier ":[$]" for variable "word"
|
||||||
|
# expect+1: Malformed conditional (${word:[$]})
|
||||||
|
.if ${word:[$]}
|
||||||
|
. error
|
||||||
|
.else
|
||||||
|
. error
|
||||||
|
.endif
|
||||||
|
VAR_DOLLAR= VAR$$
|
||||||
|
.if ${word:L:_=VAR$} != "word" || ${${VAR_DOLLAR}} != "word"
|
||||||
|
. error
|
||||||
|
.endif
|
||||||
|
.if ${word:L:C,d$,m,} != "worm"
|
||||||
|
. error
|
||||||
|
.endif
|
||||||
|
.if ${word:L:C,d,$,} != "wor\$"
|
||||||
|
. error
|
||||||
|
.endif
|
||||||
|
# expect+2: while evaluating variable "VAR": Invalid variable name '}', at "$} != "set""
|
||||||
|
# expect+1: while evaluating variable "VAR": Dollar followed by nothing
|
||||||
|
.if ${VAR:Dset$} != "set"
|
||||||
|
. error
|
||||||
|
.endif
|
||||||
|
# expect+1: while evaluating "${:Ufallback$} != "fallback"": Invalid variable name '}', at "$} != "fallback""
|
||||||
|
.if ${:Ufallback$} != "fallback"
|
||||||
|
. error
|
||||||
|
.endif
|
||||||
|
# expect+2: Malformed conditional (${%y:L:gmtime=1000$})
|
||||||
|
# expect+1: while evaluating variable "%y": Invalid time value "1000$"
|
||||||
|
.if ${%y:L:gmtime=1000$}
|
||||||
|
. error
|
||||||
|
.else
|
||||||
|
. error
|
||||||
|
.endif
|
||||||
|
# expect+2: Malformed conditional (${%y:L:localtime=1000$})
|
||||||
|
# expect+1: while evaluating variable "%y": Invalid time value "1000$"
|
||||||
|
.if ${%y:L:localtime=1000$}
|
||||||
|
. error
|
||||||
|
.else
|
||||||
|
. error
|
||||||
|
.endif
|
||||||
|
# expect+1: while evaluating variable "word": Dollar followed by nothing
|
||||||
|
.if ${word:L:Mw*$} != "word"
|
||||||
|
. error
|
||||||
|
.endif
|
||||||
|
# expect+1: while evaluating variable "word": Dollar followed by nothing
|
||||||
|
.if ${word:L:NX*$} != "word"
|
||||||
|
. error
|
||||||
|
.endif
|
||||||
|
# expect+2: while evaluating variable ".": Invalid argument 'fallback$' for modifier ':mtime'
|
||||||
|
# expect+1: Malformed conditional (${.:L:mtime=fallback$})
|
||||||
|
.if ${.:L:mtime=fallback$}
|
||||||
|
. error
|
||||||
|
.else
|
||||||
|
. error
|
||||||
|
.endif
|
||||||
|
.if ${word:L:S,d$,m,} != "worm"
|
||||||
|
. error
|
||||||
|
.endif
|
||||||
|
.if ${word:L:S,d,m$,} != "worm\$"
|
||||||
|
. error
|
||||||
|
.endif
|
||||||
|
|
|
@ -1 +1,4 @@
|
||||||
|
level 1: variable 0, env 1
|
||||||
|
level 2: variable 1, env 2
|
||||||
|
level 3: variable 2, env 3
|
||||||
exit status 0
|
exit status 0
|
||||||
|
|
|
@ -1,8 +1,22 @@
|
||||||
# $NetBSD: varname-dot-make-level.mk,v 1.2 2020/08/16 14:25:16 rillig Exp $
|
# $NetBSD: varname-dot-make-level.mk,v 1.3 2024/06/01 18:44:05 rillig Exp $
|
||||||
#
|
#
|
||||||
# Tests for the special .MAKE.LEVEL variable.
|
# Tests for the special .MAKE.LEVEL variable, which informs about the
|
||||||
|
# recursion level. It is related to the environment variable MAKELEVEL,
|
||||||
|
# even though they don't have the same value.
|
||||||
|
|
||||||
# TODO: Implementation
|
level_1: .PHONY
|
||||||
|
@printf 'level 1: variable %s, env %s\n' ${.MAKE.LEVEL} "$$${.MAKE.LEVEL.ENV}"
|
||||||
|
@${MAKE} -f ${MAKEFILE} level_2
|
||||||
|
|
||||||
all:
|
level_2: .PHONY
|
||||||
@:;
|
@printf 'level 2: variable %s, env %s\n' ${.MAKE.LEVEL} "$$${.MAKE.LEVEL.ENV}"
|
||||||
|
@${MAKE} -f ${MAKEFILE} level_3
|
||||||
|
|
||||||
|
level_3: .PHONY
|
||||||
|
@printf 'level 3: variable %s, env %s\n' ${.MAKE.LEVEL} "$$${.MAKE.LEVEL.ENV}"
|
||||||
|
|
||||||
|
# The .unexport-env directive clears the environment, except for the
|
||||||
|
# MAKE_LEVEL variable.
|
||||||
|
.if make(level_2)
|
||||||
|
.unexport-env
|
||||||
|
.endif
|
||||||
|
|
|
@ -1,3 +1,8 @@
|
||||||
|
make: "varname-dot-newline.mk" line 28: Cannot overwrite ".newline" as it is read-only
|
||||||
|
make: "varname-dot-newline.mk" line 30: Cannot append to ".newline" as it is read-only
|
||||||
|
make: "varname-dot-newline.mk" line 32: Cannot delete ".newline" as it is read-only
|
||||||
|
make: Fatal errors encountered -- cannot continue
|
||||||
|
make: stopped in unit-tests
|
||||||
first
|
first
|
||||||
second
|
second
|
||||||
backslash newline: <\
|
backslash newline: <\
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
# $NetBSD: varname-dot-newline.mk,v 1.6 2023/01/26 20:48:18 sjg Exp $
|
# $NetBSD: varname-dot-newline.mk,v 1.7 2024/06/15 22:06:31 rillig Exp $
|
||||||
#
|
#
|
||||||
# Tests for the special .newline variable, which contains a single newline
|
# Tests for the special .newline variable, which contains a single newline
|
||||||
# character (U+000A).
|
# character (U+000A).
|
||||||
|
@ -20,12 +20,23 @@ BACKSLASH_NEWLINE:= \${.newline}
|
||||||
|
|
||||||
NEWLINE:= ${.newline}
|
NEWLINE:= ${.newline}
|
||||||
|
|
||||||
|
.if make(try-to-modify)
|
||||||
|
# A '?=' assignment is fine. This pattern can be used to provide the variable
|
||||||
|
# to older or other variants of make that don't know that variable.
|
||||||
|
.newline?= fallback
|
||||||
|
# expect+1: Cannot overwrite ".newline" as it is read-only
|
||||||
.newline= overwritten
|
.newline= overwritten
|
||||||
|
# expect+1: Cannot append to ".newline" as it is read-only
|
||||||
|
.newline+= appended
|
||||||
|
# expect+1: Cannot delete ".newline" as it is read-only
|
||||||
|
.undef .newline
|
||||||
|
.endif
|
||||||
|
|
||||||
.if ${.newline} != ${NEWLINE}
|
.if ${.newline} != ${NEWLINE}
|
||||||
. error The .newline variable can be overwritten. It should be read-only.
|
. error The .newline variable can be overwritten. It should be read-only.
|
||||||
.endif
|
.endif
|
||||||
|
|
||||||
all:
|
all:
|
||||||
|
@${MAKE} -f ${MAKEFILE} try-to-modify || true
|
||||||
@echo 'first${.newline}second'
|
@echo 'first${.newline}second'
|
||||||
@echo 'backslash newline: <${BACKSLASH_NEWLINE}>'
|
@echo 'backslash newline: <${BACKSLASH_NEWLINE}>'
|
||||||
|
|
|
@ -1 +1,2 @@
|
||||||
|
: purge-cache was reached.
|
||||||
exit status 0
|
exit status 0
|
||||||
|
|
|
@ -1,8 +1,15 @@
|
||||||
# $NetBSD: varname-dot-objdir.mk,v 1.2 2020/08/16 14:25:16 rillig Exp $
|
# $NetBSD: varname-dot-objdir.mk,v 1.3 2024/06/01 11:06:17 rillig Exp $
|
||||||
#
|
#
|
||||||
# Tests for the special .OBJDIR variable.
|
# Tests for the special .OBJDIR variable.
|
||||||
|
|
||||||
# TODO: Implementation
|
# TODO: Implementation
|
||||||
|
|
||||||
all:
|
all:
|
||||||
@:;
|
# Add an entry to the cached_realpath table, to test cleaning up
|
||||||
|
# that table in purge_relative_cached_realpaths.
|
||||||
|
# Having a ':=' assignment in the command line is construed but works
|
||||||
|
# well enough to reach the code.
|
||||||
|
@${MAKE} -f ${MAKEFILE} 'VAR:=$${:U.:tA}' purge-cache
|
||||||
|
|
||||||
|
purge-cache:
|
||||||
|
: ${.TARGET} was reached.
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
# $NetBSD: varparse-errors.mk,v 1.12 2024/04/20 10:18:56 rillig Exp $
|
# $NetBSD: varparse-errors.mk,v 1.13 2024/06/02 15:31:26 rillig Exp $
|
||||||
|
|
||||||
# Tests for parsing and evaluating all kinds of expressions.
|
# Tests for parsing and evaluating all kinds of expressions.
|
||||||
#
|
#
|
||||||
|
@ -24,7 +24,7 @@ ERR_BAD_MOD= An ${:Uindirect:Z} expression with an unknown modifier.
|
||||||
ERR_EVAL= An evaluation error ${:Uvalue:C,.,\3,}.
|
ERR_EVAL= An evaluation error ${:Uvalue:C,.,\3,}.
|
||||||
|
|
||||||
# In a conditional, an expression that is not enclosed in quotes is
|
# In a conditional, an expression that is not enclosed in quotes is
|
||||||
# expanded using the mode VARE_UNDEFERR.
|
# expanded using the mode VARE_EVAL_DEFINED.
|
||||||
# The variable itself must be defined.
|
# The variable itself must be defined.
|
||||||
# It may refer to undefined variables though.
|
# It may refer to undefined variables though.
|
||||||
.if ${REF_UNDEF} != "A reference to an undefined variable."
|
.if ${REF_UNDEF} != "A reference to an undefined variable."
|
||||||
|
|
296
var.c
296
var.c
|
@ -1,4 +1,4 @@
|
||||||
/* $NetBSD: var.c,v 1.1109 2024/05/07 18:26:22 sjg Exp $ */
|
/* $NetBSD: var.c,v 1.1121 2024/06/15 22:06:30 rillig Exp $ */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 1988, 1989, 1990, 1993
|
* Copyright (c) 1988, 1989, 1990, 1993
|
||||||
|
@ -143,7 +143,7 @@
|
||||||
#include "metachar.h"
|
#include "metachar.h"
|
||||||
|
|
||||||
/* "@(#)var.c 8.3 (Berkeley) 3/19/94" */
|
/* "@(#)var.c 8.3 (Berkeley) 3/19/94" */
|
||||||
MAKE_RCSID("$NetBSD: var.c,v 1.1109 2024/05/07 18:26:22 sjg Exp $");
|
MAKE_RCSID("$NetBSD: var.c,v 1.1121 2024/06/15 22:06:30 rillig Exp $");
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Variables are defined using one of the VAR=value assignments. Their
|
* Variables are defined using one of the VAR=value assignments. Their
|
||||||
|
@ -202,6 +202,12 @@ typedef struct Var {
|
||||||
*/
|
*/
|
||||||
bool readOnly:1;
|
bool readOnly:1;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The variable is read-only and immune to the .NOREADONLY special
|
||||||
|
* target. Any attempt to modify it results in an error.
|
||||||
|
*/
|
||||||
|
bool readOnlyLoud:1;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The variable is currently being accessed by Var_Parse or Var_Subst.
|
* The variable is currently being accessed by Var_Parse or Var_Subst.
|
||||||
* This temporary marker is used to avoid endless recursion.
|
* This temporary marker is used to avoid endless recursion.
|
||||||
|
@ -264,10 +270,15 @@ typedef struct SepBuf {
|
||||||
char sep;
|
char sep;
|
||||||
} SepBuf;
|
} SepBuf;
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
VSK_TARGET,
|
||||||
|
VSK_VARNAME,
|
||||||
|
VSK_EXPR
|
||||||
|
} EvalStackElementKind;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
const char *target;
|
EvalStackElementKind kind;
|
||||||
const char *varname;
|
const char *str;
|
||||||
const char *expr;
|
|
||||||
} EvalStackElement;
|
} EvalStackElement;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
|
@ -289,11 +300,11 @@ char var_Error[] = "";
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Special return value for Var_Parse, indicating an undefined variable in
|
* Special return value for Var_Parse, indicating an undefined variable in
|
||||||
* a case where VARE_UNDEFERR is not set. This undefined variable is
|
* a case where VARE_EVAL_DEFINED is not set. This undefined variable is
|
||||||
* typically a dynamic variable such as ${.TARGET}, whose expansion needs to
|
* typically a dynamic variable such as ${.TARGET}, whose expansion needs to
|
||||||
* be deferred until it is defined in an actual target.
|
* be deferred until it is defined in an actual target.
|
||||||
*
|
*
|
||||||
* See VARE_EVAL_KEEP_UNDEF.
|
* See VARE_EVAL_KEEP_UNDEFINED.
|
||||||
*/
|
*/
|
||||||
static char varUndefined[] = "";
|
static char varUndefined[] = "";
|
||||||
|
|
||||||
|
@ -335,11 +346,10 @@ GNode *SCOPE_INTERNAL;
|
||||||
static VarExportedMode var_exportedVars = VAR_EXPORTED_NONE;
|
static VarExportedMode var_exportedVars = VAR_EXPORTED_NONE;
|
||||||
|
|
||||||
static const char VarEvalMode_Name[][32] = {
|
static const char VarEvalMode_Name[][32] = {
|
||||||
"parse-only",
|
"parse",
|
||||||
"parse-balanced",
|
"parse-balanced",
|
||||||
"eval",
|
"eval",
|
||||||
"eval-defined",
|
"eval-defined",
|
||||||
"eval-keep-dollar",
|
|
||||||
"eval-keep-undefined",
|
"eval-keep-undefined",
|
||||||
"eval-keep-dollar-and-undefined",
|
"eval-keep-dollar-and-undefined",
|
||||||
};
|
};
|
||||||
|
@ -347,21 +357,20 @@ static const char VarEvalMode_Name[][32] = {
|
||||||
static EvalStack evalStack;
|
static EvalStack evalStack;
|
||||||
|
|
||||||
|
|
||||||
void
|
static void
|
||||||
EvalStack_Push(const char *target, const char *expr, const char *varname)
|
EvalStack_Push(EvalStackElementKind kind, const char *str)
|
||||||
{
|
{
|
||||||
if (evalStack.len >= evalStack.cap) {
|
if (evalStack.len >= evalStack.cap) {
|
||||||
evalStack.cap = 16 + 2 * evalStack.cap;
|
evalStack.cap = 16 + 2 * evalStack.cap;
|
||||||
evalStack.elems = bmake_realloc(evalStack.elems,
|
evalStack.elems = bmake_realloc(evalStack.elems,
|
||||||
evalStack.cap * sizeof(*evalStack.elems));
|
evalStack.cap * sizeof(*evalStack.elems));
|
||||||
}
|
}
|
||||||
evalStack.elems[evalStack.len].target = target;
|
evalStack.elems[evalStack.len].kind = kind;
|
||||||
evalStack.elems[evalStack.len].expr = expr;
|
evalStack.elems[evalStack.len].str = str;
|
||||||
evalStack.elems[evalStack.len].varname = varname;
|
|
||||||
evalStack.len++;
|
evalStack.len++;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
static void
|
||||||
EvalStack_Pop(void)
|
EvalStack_Pop(void)
|
||||||
{
|
{
|
||||||
assert(evalStack.len > 0);
|
assert(evalStack.len > 0);
|
||||||
|
@ -378,22 +387,13 @@ EvalStack_Details(void)
|
||||||
buf->len = 0;
|
buf->len = 0;
|
||||||
for (i = 0; i < evalStack.len; i++) {
|
for (i = 0; i < evalStack.len; i++) {
|
||||||
EvalStackElement *elem = evalStack.elems + i;
|
EvalStackElement *elem = evalStack.elems + i;
|
||||||
if (elem->target != NULL) {
|
Buf_AddStr(buf,
|
||||||
Buf_AddStr(buf, "in target \"");
|
elem->kind == VSK_TARGET ? "in target \"" :
|
||||||
Buf_AddStr(buf, elem->target);
|
elem->kind == VSK_EXPR ? "while evaluating \"" :
|
||||||
|
"while evaluating variable \"");
|
||||||
|
Buf_AddStr(buf, elem->str);
|
||||||
Buf_AddStr(buf, "\": ");
|
Buf_AddStr(buf, "\": ");
|
||||||
}
|
}
|
||||||
if (elem->expr != NULL) {
|
|
||||||
Buf_AddStr(buf, "while evaluating \"");
|
|
||||||
Buf_AddStr(buf, elem->expr);
|
|
||||||
Buf_AddStr(buf, "\": ");
|
|
||||||
}
|
|
||||||
if (elem->varname != NULL) {
|
|
||||||
Buf_AddStr(buf, "while evaluating variable \"");
|
|
||||||
Buf_AddStr(buf, elem->varname);
|
|
||||||
Buf_AddStr(buf, "\": ");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return buf->len > 0 ? buf->data : "";
|
return buf->len > 0 ? buf->data : "";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -410,6 +410,7 @@ VarNew(FStr name, const char *value,
|
||||||
var->shortLived = shortLived;
|
var->shortLived = shortLived;
|
||||||
var->fromEnvironment = fromEnvironment;
|
var->fromEnvironment = fromEnvironment;
|
||||||
var->readOnly = readOnly;
|
var->readOnly = readOnly;
|
||||||
|
var->readOnlyLoud = false;
|
||||||
var->inUse = false;
|
var->inUse = false;
|
||||||
var->exported = false;
|
var->exported = false;
|
||||||
var->reexport = false;
|
var->reexport = false;
|
||||||
|
@ -569,6 +570,12 @@ Var_Delete(GNode *scope, const char *varname)
|
||||||
}
|
}
|
||||||
|
|
||||||
v = he->value;
|
v = he->value;
|
||||||
|
if (v->readOnlyLoud) {
|
||||||
|
Parse_Error(PARSE_FATAL,
|
||||||
|
"Cannot delete \"%s\" as it is read-only",
|
||||||
|
v->name.str);
|
||||||
|
return;
|
||||||
|
}
|
||||||
if (v->readOnly) {
|
if (v->readOnly) {
|
||||||
DEBUG2(VAR, "%s: ignoring delete '%s' as it is read-only\n",
|
DEBUG2(VAR, "%s: ignoring delete '%s' as it is read-only\n",
|
||||||
scope->name, varname);
|
scope->name, varname);
|
||||||
|
@ -593,6 +600,20 @@ Var_Delete(GNode *scope, const char *varname)
|
||||||
free(v);
|
free(v);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef CLEANUP
|
||||||
|
void
|
||||||
|
Var_DeleteAll(GNode *scope)
|
||||||
|
{
|
||||||
|
HashIter hi;
|
||||||
|
HashIter_Init(&hi, &scope->vars);
|
||||||
|
while (HashIter_Next(&hi)) {
|
||||||
|
Var *v = hi.entry->value;
|
||||||
|
Buf_Done(&v->val);
|
||||||
|
free(v);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Undefine one or more variables from the global scope.
|
* Undefine one or more variables from the global scope.
|
||||||
* The argument is expanded exactly once and then split into words.
|
* The argument is expanded exactly once and then split into words.
|
||||||
|
@ -610,7 +631,7 @@ Var_Undef(const char *arg)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
expanded = Var_Subst(arg, SCOPE_GLOBAL, VARE_WANTRES);
|
expanded = Var_Subst(arg, SCOPE_GLOBAL, VARE_EVAL);
|
||||||
if (expanded == var_Error) {
|
if (expanded == var_Error) {
|
||||||
/* TODO: Make this part of the code reachable. */
|
/* TODO: Make this part of the code reachable. */
|
||||||
Parse_Error(PARSE_FATAL,
|
Parse_Error(PARSE_FATAL,
|
||||||
|
@ -677,7 +698,7 @@ ExportVarEnv(Var *v, GNode *scope)
|
||||||
|
|
||||||
/* XXX: name is injected without escaping it */
|
/* XXX: name is injected without escaping it */
|
||||||
expr = str_concat3("${", name, "}");
|
expr = str_concat3("${", name, "}");
|
||||||
val = Var_Subst(expr, scope, VARE_WANTRES);
|
val = Var_Subst(expr, scope, VARE_EVAL);
|
||||||
if (scope != SCOPE_GLOBAL) {
|
if (scope != SCOPE_GLOBAL) {
|
||||||
/* we will need to re-export the global version */
|
/* we will need to re-export the global version */
|
||||||
v = VarFind(name, SCOPE_GLOBAL, false);
|
v = VarFind(name, SCOPE_GLOBAL, false);
|
||||||
|
@ -778,7 +799,7 @@ Var_ReexportVars(GNode *scope)
|
||||||
|
|
||||||
/* Ouch! Exporting all variables at once is crazy. */
|
/* Ouch! Exporting all variables at once is crazy. */
|
||||||
HashIter_Init(&hi, &SCOPE_GLOBAL->vars);
|
HashIter_Init(&hi, &SCOPE_GLOBAL->vars);
|
||||||
while (HashIter_Next(&hi) != NULL) {
|
while (HashIter_Next(&hi)) {
|
||||||
Var *var = hi.entry->value;
|
Var *var = hi.entry->value;
|
||||||
ExportVar(var->name.str, scope, VEM_ENV);
|
ExportVar(var->name.str, scope, VEM_ENV);
|
||||||
}
|
}
|
||||||
|
@ -786,7 +807,7 @@ Var_ReexportVars(GNode *scope)
|
||||||
}
|
}
|
||||||
|
|
||||||
xvarnames = Var_Subst("${.MAKE.EXPORTED:O:u}", SCOPE_GLOBAL,
|
xvarnames = Var_Subst("${.MAKE.EXPORTED:O:u}", SCOPE_GLOBAL,
|
||||||
VARE_WANTRES);
|
VARE_EVAL);
|
||||||
/* TODO: handle errors */
|
/* TODO: handle errors */
|
||||||
if (xvarnames[0] != '\0') {
|
if (xvarnames[0] != '\0') {
|
||||||
Words varnames = Str_Words(xvarnames, false);
|
Words varnames = Str_Words(xvarnames, false);
|
||||||
|
@ -826,7 +847,7 @@ ExportVars(const char *varnames, bool isExport, VarExportMode mode)
|
||||||
static void
|
static void
|
||||||
ExportVarsExpand(const char *uvarnames, bool isExport, VarExportMode mode)
|
ExportVarsExpand(const char *uvarnames, bool isExport, VarExportMode mode)
|
||||||
{
|
{
|
||||||
char *xvarnames = Var_Subst(uvarnames, SCOPE_GLOBAL, VARE_WANTRES);
|
char *xvarnames = Var_Subst(uvarnames, SCOPE_GLOBAL, VARE_EVAL);
|
||||||
/* TODO: handle errors */
|
/* TODO: handle errors */
|
||||||
ExportVars(xvarnames, isExport, mode);
|
ExportVars(xvarnames, isExport, mode);
|
||||||
free(xvarnames);
|
free(xvarnames);
|
||||||
|
@ -836,9 +857,12 @@ ExportVarsExpand(const char *uvarnames, bool isExport, VarExportMode mode)
|
||||||
void
|
void
|
||||||
Var_Export(VarExportMode mode, const char *varnames)
|
Var_Export(VarExportMode mode, const char *varnames)
|
||||||
{
|
{
|
||||||
if (mode == VEM_PLAIN && varnames[0] == '\0') {
|
if (mode == VEM_ALL) {
|
||||||
var_exportedVars = VAR_EXPORTED_ALL; /* use with caution! */
|
var_exportedVars = VAR_EXPORTED_ALL; /* use with caution! */
|
||||||
return;
|
return;
|
||||||
|
} else if (mode == VEM_PLAIN && varnames[0] == '\0') {
|
||||||
|
Parse_Error(PARSE_WARNING, ".export requires an argument.");
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
ExportVarsExpand(varnames, true, mode);
|
ExportVarsExpand(varnames, true, mode);
|
||||||
|
@ -901,7 +925,7 @@ GetVarnamesToUnexport(bool isEnv, const char *arg,
|
||||||
|
|
||||||
if (what != UNEXPORT_NAMED) {
|
if (what != UNEXPORT_NAMED) {
|
||||||
char *expanded = Var_Subst("${.MAKE.EXPORTED:O:u}",
|
char *expanded = Var_Subst("${.MAKE.EXPORTED:O:u}",
|
||||||
SCOPE_GLOBAL, VARE_WANTRES);
|
SCOPE_GLOBAL, VARE_EVAL);
|
||||||
/* TODO: handle errors */
|
/* TODO: handle errors */
|
||||||
varnames = FStr_InitOwn(expanded);
|
varnames = FStr_InitOwn(expanded);
|
||||||
}
|
}
|
||||||
|
@ -932,7 +956,7 @@ UnexportVar(Substring varname, UnexportWhat what)
|
||||||
/* XXX: v->name is injected without escaping it */
|
/* XXX: v->name is injected without escaping it */
|
||||||
char *expr = str_concat3(
|
char *expr = str_concat3(
|
||||||
"${.MAKE.EXPORTED:N", v->name.str, "}");
|
"${.MAKE.EXPORTED:N", v->name.str, "}");
|
||||||
char *filtered = Var_Subst(expr, SCOPE_GLOBAL, VARE_WANTRES);
|
char *filtered = Var_Subst(expr, SCOPE_GLOBAL, VARE_EVAL);
|
||||||
/* TODO: handle errors */
|
/* TODO: handle errors */
|
||||||
Global_Set(".MAKE.EXPORTED", filtered);
|
Global_Set(".MAKE.EXPORTED", filtered);
|
||||||
free(filtered);
|
free(filtered);
|
||||||
|
@ -1025,6 +1049,12 @@ Var_SetWithFlags(GNode *scope, const char *name, const char *val,
|
||||||
}
|
}
|
||||||
v = VarAdd(name, val, scope, flags);
|
v = VarAdd(name, val, scope, flags);
|
||||||
} else {
|
} else {
|
||||||
|
if (v->readOnlyLoud) {
|
||||||
|
Parse_Error(PARSE_FATAL,
|
||||||
|
"Cannot overwrite \"%s\" as it is read-only",
|
||||||
|
name);
|
||||||
|
return;
|
||||||
|
}
|
||||||
if (v->readOnly && !(flags & VAR_SET_READONLY)) {
|
if (v->readOnly && !(flags & VAR_SET_READONLY)) {
|
||||||
DEBUG3(VAR,
|
DEBUG3(VAR,
|
||||||
"%s: ignoring '%s = %s' as it is read-only\n",
|
"%s: ignoring '%s = %s' as it is read-only\n",
|
||||||
|
@ -1089,7 +1119,7 @@ Var_SetExpand(GNode *scope, const char *name, const char *val)
|
||||||
|
|
||||||
assert(val != NULL);
|
assert(val != NULL);
|
||||||
|
|
||||||
Var_Expand(&varname, scope, VARE_WANTRES);
|
Var_Expand(&varname, scope, VARE_EVAL);
|
||||||
|
|
||||||
if (varname.str[0] == '\0') {
|
if (varname.str[0] == '\0') {
|
||||||
DEBUG4(VAR,
|
DEBUG4(VAR,
|
||||||
|
@ -1117,7 +1147,8 @@ Global_Delete(const char *name)
|
||||||
void
|
void
|
||||||
Global_Set_ReadOnly(const char *name, const char *value)
|
Global_Set_ReadOnly(const char *name, const char *value)
|
||||||
{
|
{
|
||||||
Var_SetWithFlags(SCOPE_GLOBAL, name, value, VAR_SET_READONLY);
|
Var_SetWithFlags(SCOPE_GLOBAL, name, value, VAR_SET_NONE);
|
||||||
|
VarFind(name, SCOPE_GLOBAL, false)->readOnlyLoud = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -1135,6 +1166,10 @@ Var_Append(GNode *scope, const char *name, const char *val)
|
||||||
|
|
||||||
if (v == NULL) {
|
if (v == NULL) {
|
||||||
Var_SetWithFlags(scope, name, val, VAR_SET_NONE);
|
Var_SetWithFlags(scope, name, val, VAR_SET_NONE);
|
||||||
|
} else if (v->readOnlyLoud) {
|
||||||
|
Parse_Error(PARSE_FATAL,
|
||||||
|
"Cannot append to \"%s\" as it is read-only", name);
|
||||||
|
return;
|
||||||
} else if (v->readOnly) {
|
} else if (v->readOnly) {
|
||||||
DEBUG3(VAR, "%s: ignoring '%s += %s' as it is read-only\n",
|
DEBUG3(VAR, "%s: ignoring '%s += %s' as it is read-only\n",
|
||||||
scope->name, name, val);
|
scope->name, name, val);
|
||||||
|
@ -1172,7 +1207,7 @@ Var_AppendExpand(GNode *scope, const char *name, const char *val)
|
||||||
|
|
||||||
assert(val != NULL);
|
assert(val != NULL);
|
||||||
|
|
||||||
Var_Expand(&xname, scope, VARE_WANTRES);
|
Var_Expand(&xname, scope, VARE_EVAL);
|
||||||
if (xname.str != name && xname.str[0] == '\0')
|
if (xname.str != name && xname.str[0] == '\0')
|
||||||
DEBUG4(VAR,
|
DEBUG4(VAR,
|
||||||
"%s: ignoring '%s += %s' "
|
"%s: ignoring '%s += %s' "
|
||||||
|
@ -1215,7 +1250,7 @@ Var_ExistsExpand(GNode *scope, const char *name)
|
||||||
FStr varname = FStr_InitRefer(name);
|
FStr varname = FStr_InitRefer(name);
|
||||||
bool exists;
|
bool exists;
|
||||||
|
|
||||||
Var_Expand(&varname, scope, VARE_WANTRES);
|
Var_Expand(&varname, scope, VARE_EVAL);
|
||||||
exists = Var_Exists(scope, varname.str);
|
exists = Var_Exists(scope, varname.str);
|
||||||
FStr_Done(&varname);
|
FStr_Done(&varname);
|
||||||
return exists;
|
return exists;
|
||||||
|
@ -1281,37 +1316,33 @@ GNode_ValueDirect(GNode *gn, const char *name)
|
||||||
static VarEvalMode
|
static VarEvalMode
|
||||||
VarEvalMode_WithoutKeepDollar(VarEvalMode emode)
|
VarEvalMode_WithoutKeepDollar(VarEvalMode emode)
|
||||||
{
|
{
|
||||||
if (emode == VARE_KEEP_DOLLAR_UNDEF)
|
return emode == VARE_EVAL_KEEP_DOLLAR_AND_UNDEFINED
|
||||||
return VARE_EVAL_KEEP_UNDEF;
|
? VARE_EVAL_KEEP_UNDEFINED : emode;
|
||||||
if (emode == VARE_EVAL_KEEP_DOLLAR)
|
|
||||||
return VARE_WANTRES;
|
|
||||||
return emode;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static VarEvalMode
|
static VarEvalMode
|
||||||
VarEvalMode_UndefOk(VarEvalMode emode)
|
VarEvalMode_UndefOk(VarEvalMode emode)
|
||||||
{
|
{
|
||||||
return emode == VARE_UNDEFERR ? VARE_WANTRES : emode;
|
return emode == VARE_EVAL_DEFINED ? VARE_EVAL : emode;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool
|
static bool
|
||||||
VarEvalMode_ShouldEval(VarEvalMode emode)
|
VarEvalMode_ShouldEval(VarEvalMode emode)
|
||||||
{
|
{
|
||||||
return emode != VARE_PARSE_ONLY;
|
return emode != VARE_PARSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool
|
static bool
|
||||||
VarEvalMode_ShouldKeepUndef(VarEvalMode emode)
|
VarEvalMode_ShouldKeepUndef(VarEvalMode emode)
|
||||||
{
|
{
|
||||||
return emode == VARE_EVAL_KEEP_UNDEF ||
|
return emode == VARE_EVAL_KEEP_UNDEFINED ||
|
||||||
emode == VARE_KEEP_DOLLAR_UNDEF;
|
emode == VARE_EVAL_KEEP_DOLLAR_AND_UNDEFINED;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool
|
static bool
|
||||||
VarEvalMode_ShouldKeepDollar(VarEvalMode emode)
|
VarEvalMode_ShouldKeepDollar(VarEvalMode emode)
|
||||||
{
|
{
|
||||||
return emode == VARE_EVAL_KEEP_DOLLAR ||
|
return emode == VARE_EVAL_KEEP_DOLLAR_AND_UNDEFINED;
|
||||||
emode == VARE_KEEP_DOLLAR_UNDEF;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -1440,7 +1471,7 @@ ModifyWord_SysVSubst(Substring word, SepBuf *buf, void *data)
|
||||||
}
|
}
|
||||||
|
|
||||||
rhs = FStr_InitRefer(args->rhs);
|
rhs = FStr_InitRefer(args->rhs);
|
||||||
Var_Expand(&rhs, args->scope, VARE_WANTRES);
|
Var_Expand(&rhs, args->scope, VARE_EVAL);
|
||||||
|
|
||||||
percent = args->lhsPercent ? strchr(rhs.str, '%') : NULL;
|
percent = args->lhsPercent ? strchr(rhs.str, '%') : NULL;
|
||||||
|
|
||||||
|
@ -2084,7 +2115,7 @@ static bool
|
||||||
IsEscapedModifierPart(const char *p, char delim,
|
IsEscapedModifierPart(const char *p, char delim,
|
||||||
struct ModifyWord_SubstArgs *subst)
|
struct ModifyWord_SubstArgs *subst)
|
||||||
{
|
{
|
||||||
if (p[0] != '\\')
|
if (p[0] != '\\' || p[1] == '\0')
|
||||||
return false;
|
return false;
|
||||||
if (p[1] == delim || p[1] == '\\' || p[1] == '$')
|
if (p[1] == delim || p[1] == '\\' || p[1] == '$')
|
||||||
return true;
|
return true;
|
||||||
|
@ -2143,13 +2174,23 @@ ParseModifierPartBalanced(const char **pp, LazyBuf *part)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* See ParseModifierPart for the documentation. */
|
/*
|
||||||
|
* Parse a part of a modifier such as the "from" and "to" in :S/from/to/ or
|
||||||
|
* the "var" or "replacement ${var}" in :@var@replacement ${var}@, up to and
|
||||||
|
* including the next unescaped delimiter. The delimiter, as well as the
|
||||||
|
* backslash or the dollar, can be escaped with a backslash.
|
||||||
|
*
|
||||||
|
* 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 bool
|
static bool
|
||||||
ParseModifierPartSubst(
|
ParseModifierPart(
|
||||||
|
/* The parsing position, updated upon return */
|
||||||
const char **pp,
|
const char **pp,
|
||||||
/* If true, parse up to but excluding the next ':' or ch->endc. */
|
char end1,
|
||||||
bool whole,
|
char end2,
|
||||||
char delim,
|
/* Mode for evaluating nested expressions. */
|
||||||
VarEvalMode emode,
|
VarEvalMode emode,
|
||||||
ModChain *ch,
|
ModChain *ch,
|
||||||
LazyBuf *part,
|
LazyBuf *part,
|
||||||
|
@ -2165,16 +2206,11 @@ ParseModifierPartSubst(
|
||||||
struct ModifyWord_SubstArgs *subst
|
struct ModifyWord_SubstArgs *subst
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
const char *p;
|
const char *p = *pp;
|
||||||
char end1, end2;
|
|
||||||
|
|
||||||
p = *pp;
|
|
||||||
LazyBuf_Init(part, p);
|
LazyBuf_Init(part, p);
|
||||||
|
|
||||||
end1 = whole ? ':' : delim;
|
|
||||||
end2 = whole ? ch->endc : delim;
|
|
||||||
while (*p != '\0' && *p != end1 && *p != end2) {
|
while (*p != '\0' && *p != end1 && *p != end2) {
|
||||||
if (IsEscapedModifierPart(p, delim, subst)) {
|
if (IsEscapedModifierPart(p, end2, subst)) {
|
||||||
LazyBuf_Add(part, p[1]);
|
LazyBuf_Add(part, p[1]);
|
||||||
p += 2;
|
p += 2;
|
||||||
} else if (*p != '$') { /* Unescaped, simple text */
|
} else if (*p != '$') { /* Unescaped, simple text */
|
||||||
|
@ -2183,7 +2219,7 @@ ParseModifierPartSubst(
|
||||||
else
|
else
|
||||||
LazyBuf_Add(part, *p);
|
LazyBuf_Add(part, *p);
|
||||||
p++;
|
p++;
|
||||||
} else if (p[1] == delim) { /* Unescaped '$' at end */
|
} else if (p[1] == end2) { /* Unescaped '$' at end */
|
||||||
if (out_pflags != NULL)
|
if (out_pflags != NULL)
|
||||||
out_pflags->anchorEnd = true;
|
out_pflags->anchorEnd = true;
|
||||||
else
|
else
|
||||||
|
@ -2202,7 +2238,7 @@ ParseModifierPartSubst(
|
||||||
LazyBuf_Done(part);
|
LazyBuf_Done(part);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (!whole)
|
if (end1 == end2)
|
||||||
(*pp)++;
|
(*pp)++;
|
||||||
|
|
||||||
{
|
{
|
||||||
|
@ -2214,32 +2250,6 @@ ParseModifierPartSubst(
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* Parse a part of a modifier such as the "from" and "to" in :S/from/to/ or
|
|
||||||
* the "var" or "replacement ${var}" in :@var@replacement ${var}@, up to and
|
|
||||||
* including the next unescaped delimiter. The delimiter, as well as the
|
|
||||||
* backslash or the dollar, can be escaped with a backslash.
|
|
||||||
*
|
|
||||||
* 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 bool
|
|
||||||
ParseModifierPart(
|
|
||||||
/* The parsing position, updated upon return */
|
|
||||||
const char **pp,
|
|
||||||
/* Parsing stops at this delimiter */
|
|
||||||
char delim,
|
|
||||||
/* Mode for evaluating nested expressions. */
|
|
||||||
VarEvalMode emode,
|
|
||||||
ModChain *ch,
|
|
||||||
LazyBuf *part
|
|
||||||
)
|
|
||||||
{
|
|
||||||
return ParseModifierPartSubst(pp, false, delim, emode, ch, part,
|
|
||||||
NULL, NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
MAKE_INLINE bool
|
MAKE_INLINE bool
|
||||||
IsDelimiter(char c, const ModChain *ch)
|
IsDelimiter(char c, const ModChain *ch)
|
||||||
{
|
{
|
||||||
|
@ -2384,7 +2394,8 @@ ApplyModifier_Loop(const char **pp, ModChain *ch)
|
||||||
args.scope = expr->scope;
|
args.scope = expr->scope;
|
||||||
|
|
||||||
(*pp)++; /* Skip the first '@' */
|
(*pp)++; /* Skip the first '@' */
|
||||||
if (!ParseModifierPart(pp, '@', VARE_PARSE_ONLY, ch, &tvarBuf))
|
if (!ParseModifierPart(pp, '@', '@', VARE_PARSE,
|
||||||
|
ch, &tvarBuf, NULL, NULL))
|
||||||
return AMR_CLEANUP;
|
return AMR_CLEANUP;
|
||||||
tvar = LazyBuf_DoneGet(&tvarBuf);
|
tvar = LazyBuf_DoneGet(&tvarBuf);
|
||||||
args.var = tvar.str;
|
args.var = tvar.str;
|
||||||
|
@ -2393,11 +2404,12 @@ ApplyModifier_Loop(const char **pp, ModChain *ch)
|
||||||
"In the :@ modifier, the variable name \"%s\" "
|
"In the :@ modifier, the variable name \"%s\" "
|
||||||
"must not contain a dollar",
|
"must not contain a dollar",
|
||||||
args.var);
|
args.var);
|
||||||
return AMR_CLEANUP;
|
goto cleanup_tvar;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!ParseModifierPart(pp, '@', VARE_PARSE_BALANCED, ch, &strBuf))
|
if (!ParseModifierPart(pp, '@', '@', VARE_PARSE_BALANCED,
|
||||||
return AMR_CLEANUP;
|
ch, &strBuf, NULL, NULL))
|
||||||
|
goto cleanup_tvar;
|
||||||
str = LazyBuf_DoneGet(&strBuf);
|
str = LazyBuf_DoneGet(&strBuf);
|
||||||
args.body = str.str;
|
args.body = str.str;
|
||||||
|
|
||||||
|
@ -2416,6 +2428,10 @@ ApplyModifier_Loop(const char **pp, ModChain *ch)
|
||||||
FStr_Done(&tvar);
|
FStr_Done(&tvar);
|
||||||
FStr_Done(&str);
|
FStr_Done(&str);
|
||||||
return AMR_OK;
|
return AMR_OK;
|
||||||
|
|
||||||
|
cleanup_tvar:
|
||||||
|
FStr_Done(&tvar);
|
||||||
|
return AMR_CLEANUP;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
@ -2448,7 +2464,7 @@ ParseModifier_Defined(const char **pp, ModChain *ch, bool shouldEval,
|
||||||
|
|
||||||
if (*p == '$') {
|
if (*p == '$') {
|
||||||
FStr val = Var_Parse(&p, ch->expr->scope,
|
FStr val = Var_Parse(&p, ch->expr->scope,
|
||||||
shouldEval ? ch->expr->emode : VARE_PARSE_ONLY);
|
shouldEval ? ch->expr->emode : VARE_PARSE);
|
||||||
/* TODO: handle errors */
|
/* TODO: handle errors */
|
||||||
if (shouldEval)
|
if (shouldEval)
|
||||||
LazyBuf_AddStr(buf, val.str);
|
LazyBuf_AddStr(buf, val.str);
|
||||||
|
@ -2478,6 +2494,7 @@ ApplyModifier_Defined(const char **pp, ModChain *ch)
|
||||||
Expr_Define(expr);
|
Expr_Define(expr);
|
||||||
if (shouldEval)
|
if (shouldEval)
|
||||||
Expr_SetValue(expr, Substring_Str(LazyBuf_Get(&buf)));
|
Expr_SetValue(expr, Substring_Str(LazyBuf_Get(&buf)));
|
||||||
|
LazyBuf_Done(&buf);
|
||||||
|
|
||||||
return AMR_OK;
|
return AMR_OK;
|
||||||
}
|
}
|
||||||
|
@ -2535,7 +2552,7 @@ ApplyModifier_Time(const char **pp, ModChain *ch)
|
||||||
const char *p = args + 1;
|
const char *p = args + 1;
|
||||||
LazyBuf buf;
|
LazyBuf buf;
|
||||||
FStr arg;
|
FStr arg;
|
||||||
if (!ParseModifierPartSubst(&p, true, '\0', ch->expr->emode,
|
if (!ParseModifierPart(&p, ':', ch->endc, ch->expr->emode,
|
||||||
ch, &buf, NULL, NULL))
|
ch, &buf, NULL, NULL))
|
||||||
return AMR_CLEANUP;
|
return AMR_CLEANUP;
|
||||||
arg = LazyBuf_DoneGet(&buf);
|
arg = LazyBuf_DoneGet(&buf);
|
||||||
|
@ -2617,7 +2634,8 @@ ApplyModifier_ShellCommand(const char **pp, ModChain *ch)
|
||||||
FStr cmd;
|
FStr cmd;
|
||||||
|
|
||||||
(*pp)++;
|
(*pp)++;
|
||||||
if (!ParseModifierPart(pp, '!', expr->emode, ch, &cmdBuf))
|
if (!ParseModifierPart(pp, '!', '!', expr->emode,
|
||||||
|
ch, &cmdBuf, NULL, NULL))
|
||||||
return AMR_CLEANUP;
|
return AMR_CLEANUP;
|
||||||
cmd = LazyBuf_DoneGet(&cmdBuf);
|
cmd = LazyBuf_DoneGet(&cmdBuf);
|
||||||
|
|
||||||
|
@ -2934,13 +2952,13 @@ ApplyModifier_Subst(const char **pp, ModChain *ch)
|
||||||
(*pp)++;
|
(*pp)++;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!ParseModifierPartSubst(pp,
|
if (!ParseModifierPart(pp, delim, delim, ch->expr->emode,
|
||||||
false, delim, ch->expr->emode, ch, &lhsBuf, &args.pflags, NULL))
|
ch, &lhsBuf, &args.pflags, NULL))
|
||||||
return AMR_CLEANUP;
|
return AMR_CLEANUP;
|
||||||
args.lhs = LazyBuf_Get(&lhsBuf);
|
args.lhs = LazyBuf_Get(&lhsBuf);
|
||||||
|
|
||||||
if (!ParseModifierPartSubst(pp,
|
if (!ParseModifierPart(pp, delim, delim, ch->expr->emode,
|
||||||
false, delim, ch->expr->emode, ch, &rhsBuf, NULL, &args)) {
|
ch, &rhsBuf, NULL, &args)) {
|
||||||
LazyBuf_Done(&lhsBuf);
|
LazyBuf_Done(&lhsBuf);
|
||||||
return AMR_CLEANUP;
|
return AMR_CLEANUP;
|
||||||
}
|
}
|
||||||
|
@ -2977,11 +2995,13 @@ ApplyModifier_Regex(const char **pp, ModChain *ch)
|
||||||
|
|
||||||
*pp += 2;
|
*pp += 2;
|
||||||
|
|
||||||
if (!ParseModifierPart(pp, delim, ch->expr->emode, ch, &reBuf))
|
if (!ParseModifierPart(pp, delim, delim, ch->expr->emode,
|
||||||
|
ch, &reBuf, NULL, NULL))
|
||||||
return AMR_CLEANUP;
|
return AMR_CLEANUP;
|
||||||
re = LazyBuf_DoneGet(&reBuf);
|
re = LazyBuf_DoneGet(&reBuf);
|
||||||
|
|
||||||
if (!ParseModifierPart(pp, delim, ch->expr->emode, ch, &replaceBuf)) {
|
if (!ParseModifierPart(pp, delim, delim, ch->expr->emode,
|
||||||
|
ch, &replaceBuf, NULL, NULL)) {
|
||||||
FStr_Done(&re);
|
FStr_Done(&re);
|
||||||
return AMR_CLEANUP;
|
return AMR_CLEANUP;
|
||||||
}
|
}
|
||||||
|
@ -3058,7 +3078,7 @@ ApplyModifier_ToSep(const char **pp, ModChain *ch)
|
||||||
/*
|
/*
|
||||||
* Even in parse-only mode, apply the side effects, since the side
|
* Even in parse-only mode, apply the side effects, since the side
|
||||||
* effects are neither observable nor is there a performance penalty.
|
* effects are neither observable nor is there a performance penalty.
|
||||||
* Checking for wantRes for every single piece of code in here
|
* Checking for VARE_EVAL for every single piece of code in here
|
||||||
* would make the code in this function too hard to read.
|
* would make the code in this function too hard to read.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
@ -3210,7 +3230,8 @@ ApplyModifier_Words(const char **pp, ModChain *ch)
|
||||||
FStr arg;
|
FStr arg;
|
||||||
|
|
||||||
(*pp)++; /* skip the '[' */
|
(*pp)++; /* skip the '[' */
|
||||||
if (!ParseModifierPart(pp, ']', expr->emode, ch, &argBuf))
|
if (!ParseModifierPart(pp, ']', ']', expr->emode,
|
||||||
|
ch, &argBuf, NULL, NULL))
|
||||||
return AMR_CLEANUP;
|
return AMR_CLEANUP;
|
||||||
arg = LazyBuf_DoneGet(&argBuf);
|
arg = LazyBuf_DoneGet(&argBuf);
|
||||||
p = arg.str;
|
p = arg.str;
|
||||||
|
@ -3434,8 +3455,8 @@ ApplyModifier_IfElse(const char **pp, ModChain *ch)
|
||||||
LazyBuf thenBuf;
|
LazyBuf thenBuf;
|
||||||
LazyBuf elseBuf;
|
LazyBuf elseBuf;
|
||||||
|
|
||||||
VarEvalMode then_emode = VARE_PARSE_ONLY;
|
VarEvalMode then_emode = VARE_PARSE;
|
||||||
VarEvalMode else_emode = VARE_PARSE_ONLY;
|
VarEvalMode else_emode = VARE_PARSE;
|
||||||
|
|
||||||
CondResult cond_rc = CR_TRUE; /* just not CR_ERROR */
|
CondResult cond_rc = CR_TRUE; /* just not CR_ERROR */
|
||||||
if (Expr_ShouldEval(expr)) {
|
if (Expr_ShouldEval(expr)) {
|
||||||
|
@ -3447,10 +3468,12 @@ ApplyModifier_IfElse(const char **pp, ModChain *ch)
|
||||||
}
|
}
|
||||||
|
|
||||||
(*pp)++; /* skip past the '?' */
|
(*pp)++; /* skip past the '?' */
|
||||||
if (!ParseModifierPart(pp, ':', then_emode, ch, &thenBuf))
|
if (!ParseModifierPart(pp, ':', ':', then_emode,
|
||||||
|
ch, &thenBuf, NULL, NULL))
|
||||||
return AMR_CLEANUP;
|
return AMR_CLEANUP;
|
||||||
|
|
||||||
if (!ParseModifierPart(pp, ch->endc, else_emode, ch, &elseBuf)) {
|
if (!ParseModifierPart(pp, ch->endc, ch->endc, else_emode,
|
||||||
|
ch, &elseBuf, NULL, NULL)) {
|
||||||
LazyBuf_Done(&thenBuf);
|
LazyBuf_Done(&thenBuf);
|
||||||
return AMR_CLEANUP;
|
return AMR_CLEANUP;
|
||||||
}
|
}
|
||||||
|
@ -3530,7 +3553,8 @@ ApplyModifier_Assign(const char **pp, ModChain *ch)
|
||||||
|
|
||||||
*pp = mod + (op[0] != '=' ? 3 : 2);
|
*pp = mod + (op[0] != '=' ? 3 : 2);
|
||||||
|
|
||||||
if (!ParseModifierPart(pp, ch->endc, expr->emode, ch, &buf))
|
if (!ParseModifierPart(pp, ch->endc, ch->endc, expr->emode,
|
||||||
|
ch, &buf, NULL, NULL))
|
||||||
return AMR_CLEANUP;
|
return AMR_CLEANUP;
|
||||||
val = LazyBuf_DoneGet(&buf);
|
val = LazyBuf_DoneGet(&buf);
|
||||||
|
|
||||||
|
@ -3689,13 +3713,12 @@ ApplyModifier_SysV(const char **pp, ModChain *ch)
|
||||||
if (!IsSysVModifier(mod, ch->startc, ch->endc))
|
if (!IsSysVModifier(mod, ch->startc, ch->endc))
|
||||||
return AMR_UNKNOWN;
|
return AMR_UNKNOWN;
|
||||||
|
|
||||||
if (!ParseModifierPart(pp, '=', expr->emode, ch, &lhsBuf))
|
if (!ParseModifierPart(pp, '=', '=', expr->emode,
|
||||||
|
ch, &lhsBuf, NULL, NULL))
|
||||||
return AMR_CLEANUP;
|
return AMR_CLEANUP;
|
||||||
|
|
||||||
/*
|
if (!ParseModifierPart(pp, ch->endc, ch->endc, expr->emode,
|
||||||
* The SysV modifier lasts until the end of the expression.
|
ch, &rhsBuf, NULL, NULL)) {
|
||||||
*/
|
|
||||||
if (!ParseModifierPart(pp, ch->endc, expr->emode, ch, &rhsBuf)) {
|
|
||||||
LazyBuf_Done(&lhsBuf);
|
LazyBuf_Done(&lhsBuf);
|
||||||
return AMR_CLEANUP;
|
return AMR_CLEANUP;
|
||||||
}
|
}
|
||||||
|
@ -3755,9 +3778,8 @@ ApplyModifier_SunShell(const char **pp, ModChain *ch)
|
||||||
static bool
|
static bool
|
||||||
ShouldLogInSimpleFormat(const Expr *expr)
|
ShouldLogInSimpleFormat(const Expr *expr)
|
||||||
{
|
{
|
||||||
return (expr->emode == VARE_WANTRES ||
|
return (expr->emode == VARE_EVAL || expr->emode == VARE_EVAL_DEFINED)
|
||||||
expr->emode == VARE_UNDEFERR) &&
|
&& expr->defined == DEF_REGULAR;
|
||||||
expr->defined == DEF_REGULAR;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
@ -4245,7 +4267,7 @@ ParseVarnameShort(char varname, const char **pp, GNode *scope,
|
||||||
|
|
||||||
val = UndefinedShortVarValue(varname, scope);
|
val = UndefinedShortVarValue(varname, scope);
|
||||||
if (val == NULL)
|
if (val == NULL)
|
||||||
val = emode == VARE_UNDEFERR ? var_Error : varUndefined;
|
val = emode == VARE_EVAL_DEFINED ? var_Error : varUndefined;
|
||||||
|
|
||||||
if (opts.strict && val == var_Error) {
|
if (opts.strict && val == var_Error) {
|
||||||
Parse_Error(PARSE_FATAL,
|
Parse_Error(PARSE_FATAL,
|
||||||
|
@ -4290,7 +4312,7 @@ EvalUndefined(bool dynamic, const char *start, const char *p,
|
||||||
if (dynamic)
|
if (dynamic)
|
||||||
return FStr_InitOwn(bmake_strsedup(start, p));
|
return FStr_InitOwn(bmake_strsedup(start, p));
|
||||||
|
|
||||||
if (emode == VARE_UNDEFERR && opts.strict) {
|
if (emode == VARE_EVAL_DEFINED && opts.strict) {
|
||||||
Parse_Error(PARSE_FATAL,
|
Parse_Error(PARSE_FATAL,
|
||||||
"Variable \"%.*s\" is undefined",
|
"Variable \"%.*s\" is undefined",
|
||||||
(int)Substring_Length(varname), varname.start);
|
(int)Substring_Length(varname), varname.start);
|
||||||
|
@ -4298,7 +4320,7 @@ EvalUndefined(bool dynamic, const char *start, const char *p,
|
||||||
}
|
}
|
||||||
|
|
||||||
return FStr_InitRefer(
|
return FStr_InitRefer(
|
||||||
emode == VARE_UNDEFERR ? var_Error : varUndefined);
|
emode == VARE_EVAL_DEFINED ? var_Error : varUndefined);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -4451,7 +4473,7 @@ Var_Parse_U(const char **pp, VarEvalMode emode, FStr *out_value)
|
||||||
if (*p != '}')
|
if (*p != '}')
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
*out_value = emode == VARE_PARSE_ONLY
|
*out_value = emode == VARE_PARSE
|
||||||
? FStr_InitRefer("")
|
? FStr_InitRefer("")
|
||||||
: FStr_InitOwn(bmake_strsedup(*pp + 4, p));
|
: FStr_InitOwn(bmake_strsedup(*pp + 4, p));
|
||||||
*pp = p + 1;
|
*pp = p + 1;
|
||||||
|
@ -4480,13 +4502,13 @@ Var_Parse_U(const char **pp, VarEvalMode emode, FStr *out_value)
|
||||||
* return The value of the expression, never NULL.
|
* return The value of the expression, never NULL.
|
||||||
* return var_Error if there was a parse error.
|
* return var_Error if there was a parse error.
|
||||||
* return var_Error if the base variable of the expression was
|
* return var_Error if the base variable of the expression was
|
||||||
* undefined, emode is VARE_UNDEFERR, and none of
|
* undefined, emode is VARE_EVAL_DEFINED, and none of
|
||||||
* the modifiers turned the undefined expression into a
|
* the modifiers turned the undefined expression into a
|
||||||
* defined expression.
|
* defined expression.
|
||||||
* XXX: It is not guaranteed that an error message has
|
* XXX: It is not guaranteed that an error message has
|
||||||
* been printed.
|
* been printed.
|
||||||
* return varUndefined if the base variable of the expression
|
* return varUndefined if the base variable of the expression
|
||||||
* was undefined, emode was not VARE_UNDEFERR,
|
* was undefined, emode was not VARE_EVAL_DEFINED,
|
||||||
* and none of the modifiers turned the undefined
|
* and none of the modifiers turned the undefined
|
||||||
* expression into a defined expression.
|
* expression into a defined expression.
|
||||||
* XXX: It is not guaranteed that an error message has
|
* XXX: It is not guaranteed that an error message has
|
||||||
|
@ -4569,9 +4591,9 @@ Var_Parse(const char **pp, GNode *scope, VarEvalMode emode)
|
||||||
expr.value = FStr_InitRefer(v->val.data);
|
expr.value = FStr_InitRefer(v->val.data);
|
||||||
|
|
||||||
if (expr.name[0] != '\0')
|
if (expr.name[0] != '\0')
|
||||||
EvalStack_Push(NULL, NULL, expr.name);
|
EvalStack_Push(VSK_VARNAME, expr.name);
|
||||||
else
|
else
|
||||||
EvalStack_Push(NULL, start, NULL);
|
EvalStack_Push(VSK_EXPR, start);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Before applying any modifiers, expand any nested expressions from
|
* Before applying any modifiers, expand any nested expressions from
|
||||||
|
@ -4615,7 +4637,7 @@ Var_Parse(const char **pp, GNode *scope, VarEvalMode emode)
|
||||||
* instead.
|
* instead.
|
||||||
*/
|
*/
|
||||||
Expr_SetValueRefer(&expr,
|
Expr_SetValueRefer(&expr,
|
||||||
emode == VARE_UNDEFERR
|
emode == VARE_EVAL_DEFINED
|
||||||
? var_Error : varUndefined);
|
? var_Error : varUndefined);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -4749,6 +4771,16 @@ Var_Subst(const char *str, GNode *scope, VarEvalMode emode)
|
||||||
return Buf_DoneData(&res);
|
return Buf_DoneData(&res);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
char *
|
||||||
|
Var_SubstInTarget(const char *str, GNode *scope)
|
||||||
|
{
|
||||||
|
char *res;
|
||||||
|
EvalStack_Push(VSK_TARGET, scope->name);
|
||||||
|
res = Var_Subst(str, scope, VARE_EVAL);
|
||||||
|
EvalStack_Pop();
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
Var_Expand(FStr *str, GNode *scope, VarEvalMode emode)
|
Var_Expand(FStr *str, GNode *scope, VarEvalMode emode)
|
||||||
{
|
{
|
||||||
|
@ -4804,7 +4836,7 @@ Var_Dump(GNode *scope)
|
||||||
Vector_Init(&vec, sizeof(const char *));
|
Vector_Init(&vec, sizeof(const char *));
|
||||||
|
|
||||||
HashIter_Init(&hi, &scope->vars);
|
HashIter_Init(&hi, &scope->vars);
|
||||||
while (HashIter_Next(&hi) != NULL)
|
while (HashIter_Next(&hi))
|
||||||
*(const char **)Vector_Push(&vec) = hi.entry->key;
|
*(const char **)Vector_Push(&vec) = hi.entry->key;
|
||||||
varnames = vec.items;
|
varnames = vec.items;
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue