diff options
74 files changed, 958 insertions, 603 deletions
diff --git a/ChangeLog b/ChangeLog index 11b1684bf7d5..2145b25f809f 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,85 @@ +2026-03-12 Simon J Gerraty <sjg@beast.crufty.net> + + * VERSION (_MAKE_VERSION): 20260313 + Merge with NetBSD make, pick up + o make: ensure .MAKE.SAVE_DOLLARS is initialized so makefiles like + sys.vars.mk can test its value to know how to deal with macros + that need to save '$' during ':='. + + * Makefile: default MAKE_SAVE_DOLLARS_DEFAULT to "no" + for traditional behavior. + +2026-03-10 Simon J Gerraty <sjg@beast.crufty.net> + + * VERSION (_MAKE_VERSION): 20260310 + Merge with NetBSD make, pick up + o unit-tests ensure TEST_MAKE is absolute path + and tests that make symlink for ${MAKE} can run in parallel. + +2026-03-03 Simon J Gerraty <sjg@beast.crufty.net> + + * VERSION (_MAKE_VERSION): 20260303 + Merge with NetBSD make, pick up + o job.c: MaybeSubMake: Look for expansion of ${.MAKE} + and if necessary its basename, and only match if at start of line + or preceded by space. + +2026-02-28 Simon J Gerraty <sjg@beast.crufty.net> + + * Makefile: mark ${PROG} and ${OBJS} as .META + MaybeSubMake will otherwise mistake them for sub-makes + + * VERSION (_MAKE_VERSION): 20260301 + Merge with NetBSD make, pick up + o job.c: MaybeSubMake: skip control chars [@+-] at start of line + when checking for ${MAKE} + +2026-02-22 Simon J Gerraty <sjg@beast.crufty.net> + + * VERSION (_MAKE_VERSION): 20260222 + o mk file update + +2026-02-16 Simon J Gerraty <sjg@beast.crufty.net> + + * VERSION (_MAKE_VERSION): 20260216 + Merge with NetBSD make, pick up + o minor cleanups + +2026-02-10 Simon J Gerraty <sjg@beast.crufty.net> + + * VERSION (_MAKE_VERSION): 20260210 + Merge with NetBSD make, pick up + o document that multiple variables can be set on command line. + o move MaybeSubMake to job.c so it can be called on expanded + commands for more accuracy and less overhead. + o main.c: set .MAKE.VERSION as read-only. + + * unit-tests/opt-{chdir,where-am-i}.mk: use MAKEOBJDIRPREFIX=/ + to avoid tripping over an unreadable /usr/obj + +2026-02-04 Simon J Gerraty <sjg@beast.crufty.net> + + * unit-tests/varname-make_stack_trace.mk: for + FreeBSD and similar set .MAKE.ALWAYS_PASS_JOB_QUEUE=no + to ensure we get the expected errors. + + * VERSION (_MAKE_VERSION): 20260202 + Merge with NetBSD make, pick up + o on error avoid duplicate stack trace to stderr + +2026-01-11 Simon J Gerraty <sjg@beast.crufty.net> + + * VERSION (_MAKE_VERSION): 20260111 + Merge with NetBSD make, pick up + o var.c: add explicit check for empty re as not all + regex libs throw an error as expected, in this case. + +2026-01-10 Simon J Gerraty <sjg@beast.crufty.net> + + * VERSION (_MAKE_VERSION): 20260110 + Merge with NetBSD make, pick up + o minor cleanups + 2025-11-15 Simon J Gerraty <sjg@beast.crufty.net> * boot-strap: unset more things from env and save a copy @@ -2,11 +2,11 @@ The individual files in this distribution are copyright their original contributors or assignees. Including: - Copyright (c) 1993-2025, Simon J Gerraty + Copyright (c) 1993-2026, Simon J Gerraty Copyright (c) 2020-2021, Roland Illig <rillig@NetBSD.org> Copyright (c) 2009-2016, Juniper Networks, Inc. Copyright (c) 2009, John Birrell. - Copyright (c) 1997-2025 The NetBSD Foundation, Inc. + Copyright (c) 1997-2026 The NetBSD Foundation, Inc. Copyright (c) 1998 Todd C. Miller <Todd.Miller@courtesan.com> Copyright (c) 1989 by Berkeley Softworks Copyright (c) 1988, 1989, 1990, 1992, 1993 @@ -1,4 +1,4 @@ -# $Id: Makefile,v 1.133 2025/03/08 20:12:56 sjg Exp $ +# $Id: Makefile,v 1.137 2026/03/13 15:37:22 sjg Exp $ PROG = bmake @@ -27,9 +27,6 @@ SRCS = \ .MAIN: all -MAN = ${PROG}.1 -SRCS.${MAN} = ${srcdir}/make.1 - .-include "VERSION" .-include "Makefile.inc" @@ -45,6 +42,9 @@ prefix ?= /usr srcdir ?= ${.PARSEDIR} srcdir := ${srcdir} +MAN ?= ${PROG}.1 +SRCS.${MAN} ?= ${srcdir}/make.1 + DEFAULT_SYS_PATH ?= ${prefix}/share/mk CPPFLAGS += -DUSE_META @@ -54,7 +54,13 @@ CFLAGS += -I. -I${srcdir} ${XDEFS} -DMAKE_NATIVE CFLAGS += ${COPTS.${.ALLSRC:M*.c:T:u}} COPTS.main.c += "-DMAKE_VERSION=\"${_MAKE_VERSION}\"" -.for x in FORCE_MAKE_OS FORCE_MACHINE FORCE_MACHINE_ARCH +# bmake defaults to the traditional behavior +MAKE_SAVE_DOLLARS_DEFAULT ?= no + +VARS.main += FORCE_MAKE_OS FORCE_MACHINE FORCE_MACHINE_ARCH \ + MAKE_SAVE_DOLLARS_DEFAULT \ + +.for x in ${VARS.main} .ifdef $x COPTS.main.c += "-D$x=\"${$x}\"" .endif @@ -206,7 +212,8 @@ SHAREDIR = ${SHAREDIR.bmake:U${prefix}/share} BINDIR = ${BINDIR.bmake:U${prefix}/bin} MANDIR = ${MANDIR.bmake:U${SHAREDIR}/man} -${OBJS}: config.h +${OBJS}: .META config.h +${PROG}: .META # start-delete2 for bsd.after-import.mk @@ -1,2 +1,2 @@ # keep this compatible with sh and make -_MAKE_VERSION=20251111 +_MAKE_VERSION=20260313 @@ -1,4 +1,4 @@ -.\" $NetBSD: make.1,v 1.388 2025/11/12 22:14:07 sjg Exp $ +.\" $NetBSD: make.1,v 1.390 2026/02/08 11:02:03 rillig Exp $ .\" .\" Copyright (c) 1990, 1993 .\" The Regents of the University of California. All rights reserved. @@ -29,7 +29,7 @@ .\" .\" from: @(#)make.1 8.4 (Berkeley) 3/19/94 .\" -.Dd November 11, 2025 +.Dd February 8, 2026 .Dt BMAKE 1 .Os .Sh NAME @@ -49,7 +49,7 @@ .Op Fl T Ar file .Op Fl V Ar variable .Op Fl v Ar variable -.Op Ar variable\| Ns Cm \&= Ns Ar value +.Op Ar variable\| Ns Cm \&= Ns Ar value No ... .Op Ar target No ... .Sh DESCRIPTION .Nm @@ -1655,33 +1655,22 @@ Causes the value to be treated as a list of words. See also .Sq Cm \&:[@] . .Sm off -.It Cm \&:S\| No \&/ Ar old_string\| No \&/ Ar new_string\| No \&/ Op Cm 1gW +.It Cm \&:S\| No \&/ Oo Cm \&^ Oc Ar old_string\| No Oo Cm \&$ Oc \&/ Ar new_string\| No \&/ Op Cm 1gW .Sm on Modifies the first occurrence of .Ar old_string in each word of the value, replacing it with .Ar new_string . -If a -.Ql g -is appended to the last delimiter of the pattern, -all occurrences in each word are replaced. -If a -.Ql 1 -is appended to the last delimiter of the pattern, -only the first occurrence is affected. -If a -.Ql W -is appended to the last delimiter of the pattern, -the value is treated as a single word. +.Pp If .Ar old_string -begins with a caret +is preceded by a caret .Pq Ql ^ , .Ar old_string is anchored at the beginning of each word. If .Ar old_string -ends with a dollar sign +is followed by a dollar sign .Pq Ql \&$ , it is anchored at the end of each word. Inside @@ -1689,63 +1678,61 @@ Inside an ampersand .Pq Ql & is replaced by -.Ar old_string -(without the anchoring -.Ql ^ -or -.Ql \&$ ) . -Any character may be used as the delimiter for the parts of the modifier -string. -The anchoring, ampersand and delimiter characters can be escaped with a -backslash -.Pq Ql \e . -.Pp +.Ar old_string . Both .Ar old_string and .Ar new_string may contain nested expressions. -To prevent a dollar sign from starting a nested expression, -escape it with a backslash. +.Pp +Further options: +.Bl -tag +.It Cm 1 +Only the word of the first occurrence is affected. +.It Cm g +All occurrences in each affected word are replaced. +.It Cm W +The expression value is treated as a single word. +.El +.Pp +Any character may be used as the delimiter for the parts of the modifier +string. +The anchoring, ampersand, dollar and delimiter characters +can be escaped with a backslash +.Pq Ql \e . .Sm off .It Cm \&:C\| No \&/ Ar pattern\| No \&/ Ar replacement\| No \&/ Op Cm 1gW .Sm on -The -.Cm \&:C -modifier works like the -.Cm \&:S -modifier except that the old and new strings, instead of being -simple strings, are an extended regular expression +Modifies the first occurrence of the extended regular expression .Ar pattern (see .Xr regex 3 ) -and an +in each word of the value, replacing it with +an .Xr ed 1 Ns \-style .Ar replacement . -Normally, the first occurrence of the pattern -.Ar pattern -in each word of the value is substituted with -.Ar replacement . -The -.Ql 1 -modifier causes the substitution to apply to at most one word; the -.Ql g -modifier causes the substitution to apply to as many instances of the -search pattern -.Ar pattern -as occur in the word or words it is found in; the -.Ql W -modifier causes the value to be treated as a single word -(possibly containing embedded whitespace). .Pp -As for the -.Cm \&:S -modifier, the +Both .Ar pattern and .Ar replacement -are subjected to variable expansion before being parsed as -regular expressions. +may contain nested expressions. +.Pp +Further options: +.Bl -tag +.It Cm 1 +Only the word of the first occurrence is affected. +.It Cm g +All occurrences in each affected word are replaced. +.It Cm W +The expression value is treated as a single word. +.El +.Pp +Any character may be used as the delimiter for the parts of the modifier +string. +The anchoring, ampersand, dollar and delimiter characters +can be escaped with a backslash +.Pq Ql \e . .It Cm \&:T Replaces each word with its last path component (basename). .It Cm \&:u @@ -2494,7 +2481,7 @@ Any command lines attached to this target are executed after everything else is done successfully. .It Ic .ERROR Any command lines attached to this target are executed when another target fails. -See +See .Va MAKE_PRINT_VAR_ON_ERROR for the variables that will be set. .It Ic .IGNORE diff --git a/bmake.cat1 b/bmake.cat1 index baaad7b4ed70..ecfa7cbadf9a 100644 --- a/bmake.cat1 +++ b/bmake.cat1 @@ -7,7 +7,7 @@ SSYYNNOOPPSSIISS bbmmaakkee [--BBeeiikkNNnnqqrrSSssttWWwwXX] [--CC _d_i_r_e_c_t_o_r_y] [--DD _v_a_r_i_a_b_l_e] [--dd _f_l_a_g_s] [--ff _m_a_k_e_f_i_l_e] [--II _d_i_r_e_c_t_o_r_y] [--JJ _p_r_i_v_a_t_e] [--jj _m_a_x___j_o_b_s] [--mm _d_i_r_e_c_t_o_r_y] [--TT _f_i_l_e] [--VV _v_a_r_i_a_b_l_e] [--vv _v_a_r_i_a_b_l_e] - [_v_a_r_i_a_b_l_e==_v_a_l_u_e] [_t_a_r_g_e_t ...] + [_v_a_r_i_a_b_l_e==_v_a_l_u_e ...] [_t_a_r_g_e_t ...] DDEESSCCRRIIPPTTIIOONN bbmmaakkee is a program designed to simplify the maintenance of other @@ -1073,40 +1073,46 @@ VVAARRIIAABBLLEE AASSSSIIGGNNMMEENNTTSS ::ttww Causes the value to be treated as a list of words. See also `::[[@@]]'. - ::SS/_o_l_d___s_t_r_i_n_g/_n_e_w___s_t_r_i_n_g/[11ggWW] + ::SS/[^^]_o_l_d___s_t_r_i_n_g[$$]/_n_e_w___s_t_r_i_n_g/[11ggWW] Modifies the first occurrence of _o_l_d___s_t_r_i_n_g in each word of the - value, replacing it with _n_e_w___s_t_r_i_n_g. If a `g' is appended to the - last delimiter of the pattern, all occurrences in each word are - replaced. If a `1' is appended to the last delimiter of the - pattern, only the first occurrence is affected. If a `W' is - appended to the last delimiter of the pattern, the value is treated - as a single word. If _o_l_d___s_t_r_i_n_g begins with a caret (`^'), - _o_l_d___s_t_r_i_n_g is anchored at the beginning of each word. If _o_l_d___s_t_r_i_n_g - ends with a dollar sign (`$'), it is anchored at the end of each - word. Inside _n_e_w___s_t_r_i_n_g, an ampersand (`&') is replaced by - _o_l_d___s_t_r_i_n_g (without the anchoring `^' or `$'). Any character may be - used as the delimiter for the parts of the modifier string. The - anchoring, ampersand and delimiter characters can be escaped with a - backslash (`\'). + value, replacing it with _n_e_w___s_t_r_i_n_g. - Both _o_l_d___s_t_r_i_n_g and _n_e_w___s_t_r_i_n_g may contain nested expressions. To - prevent a dollar sign from starting a nested expression, escape it - with a backslash. + If _o_l_d___s_t_r_i_n_g is preceded by a caret (`^'), _o_l_d___s_t_r_i_n_g is anchored + at the beginning of each word. If _o_l_d___s_t_r_i_n_g is followed by a + dollar sign (`$'), it is anchored at the end of each word. Inside + _n_e_w___s_t_r_i_n_g, an ampersand (`&') is replaced by _o_l_d___s_t_r_i_n_g. Both + _o_l_d___s_t_r_i_n_g and _n_e_w___s_t_r_i_n_g may contain nested expressions. + + Further options: + + 11 Only the word of the first occurrence is affected. + + gg All occurrences in each affected word are replaced. + + WW The expression value is treated as a single word. + + Any character may be used as the delimiter for the parts of the + modifier string. The anchoring, ampersand, dollar and delimiter + characters can be escaped with a backslash (`\'). ::CC/_p_a_t_t_e_r_n/_r_e_p_l_a_c_e_m_e_n_t/[11ggWW] - The ::CC modifier works like the ::SS modifier except that the old and - new strings, instead of being simple strings, are an extended - regular expression _p_a_t_t_e_r_n (see regex(3)) and an ed(1)-style - _r_e_p_l_a_c_e_m_e_n_t. Normally, the first occurrence of the pattern _p_a_t_t_e_r_n - in each word of the value is substituted with _r_e_p_l_a_c_e_m_e_n_t. The `1' - modifier causes the substitution to apply to at most one word; the - `g' modifier causes the substitution to apply to as many instances - of the search pattern _p_a_t_t_e_r_n as occur in the word or words it is - found in; the `W' modifier causes the value to be treated as a - single word (possibly containing embedded whitespace). + Modifies the first occurrence of the extended regular expression + _p_a_t_t_e_r_n (see regex(3)) in each word of the value, replacing it with + an ed(1)-style _r_e_p_l_a_c_e_m_e_n_t. + + Both _p_a_t_t_e_r_n and _r_e_p_l_a_c_e_m_e_n_t may contain nested expressions. + + Further options: + + 11 Only the word of the first occurrence is affected. + + gg All occurrences in each affected word are replaced. + + WW The expression value is treated as a single word. - As for the ::SS modifier, the _p_a_t_t_e_r_n and _r_e_p_l_a_c_e_m_e_n_t are subjected to - variable expansion before being parsed as regular expressions. + Any character may be used as the delimiter for the parts of the + modifier string. The anchoring, ampersand, dollar and delimiter + characters can be escaped with a backslash (`\'). ::TT Replaces each word with its last path component (basename). @@ -1874,4 +1880,4 @@ BBUUGGSS attempt to suppress a cascade of unnecessary errors, can result in a seemingly unexplained `*** Error code 6' -FreeBSD 14.3-RELEASE-p3 November 11, 2025 FreeBSD 14.3-RELEASE-p3 +FreeBSD 14.3-RELEASE-p9 February 8, 2026 FreeBSD 14.3-RELEASE-p9 @@ -1,4 +1,4 @@ -/* $NetBSD: job.c,v 1.519 2025/08/04 15:40:39 sjg Exp $ */ +/* $NetBSD: job.c,v 1.528 2026/03/03 20:12:20 sjg Exp $ */ /* * Copyright (c) 1988, 1989, 1990 The Regents of the University of California. @@ -137,7 +137,7 @@ #include "trace.h" /* "@(#)job.c 8.2 (Berkeley) 3/19/94" */ -MAKE_RCSID("$NetBSD: job.c,v 1.519 2025/08/04 15:40:39 sjg Exp $"); +MAKE_RCSID("$NetBSD: job.c,v 1.528 2026/03/03 20:12:20 sjg Exp $"); #ifdef USE_SELECT @@ -971,6 +971,54 @@ JobWriteSpecials(Job *job, ShellWriter *wr, const char *escCmd, bool run, inout_cmdFlags->ignerr = false; } +static bool +find_make(const char *cmd, const char *make, size_t len) +{ + const char *p; + + for (p = strstr(cmd, make); p != NULL; p = strstr(&p[1], make)) { + if (p == cmd || ch_isspace(p[-1])) { + if (p[len] == '\0' || ch_isspace(p[len])) { + DEBUG4(JOB, "find_make: matched \"%.*s\" in \"%.*s...\"\n", + (int)len, p, + (int)len + 32, cmd); + + return true; + } + } + } + return false; +} + +/* + * See if the command possibly calls a sub-make by checking + * for expansion of ${.MAKE} and possibly ${.MAKE:T}. + */ +bool +MaybeSubMake(const char *cmd) +{ + static char *make, *make_name; + static size_t make_len, make_name_len; + + if (make == NULL) { + make = Var_Subst("${.MAKE}", SCOPE_GLOBAL, VARE_EVAL); + make_len = strlen(make); + make_name = strrchr(make, '/'); + if (make_name != NULL) { + make_name++; + make_name_len = strlen(make_name); + } else + make_name_len = 0; + DEBUG1(JOB, "MaybeSubMake: Looking for \"%s\"\n", make); + } + cmd += strspn(cmd, "@ \t+-"); + if (find_make(cmd, make, make_len)) + return true; + if (make_name_len > 0 && find_make(cmd, make_name, make_name_len)) + return true; + return false; +} + /* * Write a shell command to the job's commands file, to be run later. * @@ -1004,6 +1052,12 @@ JobWriteCommand(Job *job, ShellWriter *wr, StringListNode *ln, const char *ucmd) /* TODO: handle errors */ xcmdStart = xcmd; + if (job->node->flags.doneSubmake == false + && (job->node->type & (OP_MAKE | OP_SUBMAKE)) == 0) { + if (MaybeSubMake(xcmd)) + job->node->type |= OP_SUBMAKE; + } + cmdTemplate = "%s\n"; ParseCommandFlags(&xcmd, &cmdFlags); @@ -1106,6 +1160,7 @@ JobWriteCommands(Job *job) JobWriteCommand(job, &wr, ln, ln->datum); seen = true; } + job->node->flags.doneSubmake = true; return seen; } @@ -1,4 +1,4 @@ -/* $NetBSD: job.h,v 1.85 2025/07/06 07:11:31 rillig Exp $ */ +/* $NetBSD: job.h,v 1.86 2026/02/10 18:53:34 sjg Exp $ */ /* * Copyright (c) 1988, 1989, 1990 The Regents of the University of California. @@ -93,6 +93,7 @@ void TokenPool_Init(int, int, int); bool TokenPool_Take(void) MAKE_ATTR_USE; void TokenPool_Return(void); +bool MaybeSubMake(const char *); void Job_Touch(GNode *, bool); bool Job_CheckCommands(GNode *, void (*abortProc)(const char *, ...)) MAKE_ATTR_USE; @@ -1,4 +1,4 @@ -/* $NetBSD: main.c,v 1.662 2025/08/09 23:13:28 rillig Exp $ */ +/* $NetBSD: main.c,v 1.668 2026/03/13 04:22:03 sjg Exp $ */ /* * Copyright (c) 1988, 1989, 1990, 1993 @@ -111,7 +111,7 @@ #include "trace.h" /* "@(#)main.c 8.3 (Berkeley) 3/19/94" */ -MAKE_RCSID("$NetBSD: main.c,v 1.662 2025/08/09 23:13:28 rillig Exp $"); +MAKE_RCSID("$NetBSD: main.c,v 1.668 2026/03/13 04:22:03 sjg Exp $"); #if defined(MAKE_NATIVE) __COPYRIGHT("@(#) Copyright (c) 1988, 1989, 1990, 1993 " "The Regents of the University of California. " @@ -186,8 +186,9 @@ usage(void) (void)fprintf(stderr, "usage: %.*s [-BeikNnqrSstWwX]\n" " [-C directory] [-D variable] [-d flags] [-f makefile]\n" -" [-I directory] [-J private] [-j max_jobs] [-m directory] [-T file]\n" -" [-V variable] [-v variable] [variable=value] [target ...]\n", +" [-I directory] [-J private] [-j max_jobs] [-m directory]\n" +" [-T file] [-V variable] [-v variable]\n" +" [variable=value ...] [target ...]\n", (int)prognameLen, progname); exit(2); } @@ -464,8 +465,6 @@ static bool MainParseOption(char c, const char *argvalue) { switch (c) { - case '\0': - break; case 'B': opts.compatMake = true; Global_Append(MAKEFLAGS, "-B"); @@ -1224,7 +1223,6 @@ InitMaxJobs(void) "Invalid internal option \"-J\" in \"%s\"; " "see the manual page", curdir); - PrintStackTrace(true); return; } if (forceJobs || opts.compatMake || @@ -1316,6 +1314,10 @@ ReadFirstDefaultMakefile(void) free(prefs); } +#ifndef MAKE_SAVE_DOLLARS_DEFAULT +# define MAKE_SAVE_DOLLARS_DEFAULT "yes" +#endif + /* * Initialize variables such as MAKE, MACHINE, .MAKEFLAGS. * Initialize a few modules. @@ -1367,6 +1369,8 @@ main_Init(int argc, char **argv) Global_Set("MACHINE", machine); Global_Set("MACHINE_ARCH", machine_arch); #ifdef MAKE_VERSION + Global_Set_ReadOnly(".MAKE.VERSION", MAKE_VERSION); + /* for backwards compatibility */ Global_Set("MAKE_VERSION", MAKE_VERSION); #endif Global_Set_ReadOnly(".newline", "\n"); @@ -1382,6 +1386,7 @@ main_Init(int argc, char **argv) #else Global_Set_ReadOnly(".MAKE.JOBS.C", "no"); #endif + Global_Set(MAKE_SAVE_DOLLARS, MAKE_SAVE_DOLLARS_DEFAULT); CmdOpts_Init(); allPrecious = false; /* Remove targets when interrupted */ @@ -1909,7 +1914,7 @@ Fatal(const char *fmt, ...) va_end(ap); (void)fprintf(stderr, "\n"); (void)fflush(stderr); - PrintStackTrace(true); + PrintStackTrace(stderr, true); PrintOnError(NULL, "\n"); @@ -1,4 +1,4 @@ -.\" $NetBSD: make.1,v 1.388 2025/11/12 22:14:07 sjg Exp $ +.\" $NetBSD: make.1,v 1.390 2026/02/08 11:02:03 rillig Exp $ .\" .\" Copyright (c) 1990, 1993 .\" The Regents of the University of California. All rights reserved. @@ -29,7 +29,7 @@ .\" .\" from: @(#)make.1 8.4 (Berkeley) 3/19/94 .\" -.Dd November 11, 2025 +.Dd February 8, 2026 .Dt MAKE 1 .Os .Sh NAME @@ -49,7 +49,7 @@ .Op Fl T Ar file .Op Fl V Ar variable .Op Fl v Ar variable -.Op Ar variable\| Ns Cm \&= Ns Ar value +.Op Ar variable\| Ns Cm \&= Ns Ar value No ... .Op Ar target No ... .Sh DESCRIPTION .Nm @@ -1655,33 +1655,22 @@ Causes the value to be treated as a list of words. See also .Sq Cm \&:[@] . .Sm off -.It Cm \&:S\| No \&/ Ar old_string\| No \&/ Ar new_string\| No \&/ Op Cm 1gW +.It Cm \&:S\| No \&/ Oo Cm \&^ Oc Ar old_string\| No Oo Cm \&$ Oc \&/ Ar new_string\| No \&/ Op Cm 1gW .Sm on Modifies the first occurrence of .Ar old_string in each word of the value, replacing it with .Ar new_string . -If a -.Ql g -is appended to the last delimiter of the pattern, -all occurrences in each word are replaced. -If a -.Ql 1 -is appended to the last delimiter of the pattern, -only the first occurrence is affected. -If a -.Ql W -is appended to the last delimiter of the pattern, -the value is treated as a single word. +.Pp If .Ar old_string -begins with a caret +is preceded by a caret .Pq Ql ^ , .Ar old_string is anchored at the beginning of each word. If .Ar old_string -ends with a dollar sign +is followed by a dollar sign .Pq Ql \&$ , it is anchored at the end of each word. Inside @@ -1689,63 +1678,61 @@ Inside an ampersand .Pq Ql & is replaced by -.Ar old_string -(without the anchoring -.Ql ^ -or -.Ql \&$ ) . -Any character may be used as the delimiter for the parts of the modifier -string. -The anchoring, ampersand and delimiter characters can be escaped with a -backslash -.Pq Ql \e . -.Pp +.Ar old_string . Both .Ar old_string and .Ar new_string may contain nested expressions. -To prevent a dollar sign from starting a nested expression, -escape it with a backslash. +.Pp +Further options: +.Bl -tag +.It Cm 1 +Only the word of the first occurrence is affected. +.It Cm g +All occurrences in each affected word are replaced. +.It Cm W +The expression value is treated as a single word. +.El +.Pp +Any character may be used as the delimiter for the parts of the modifier +string. +The anchoring, ampersand, dollar and delimiter characters +can be escaped with a backslash +.Pq Ql \e . .Sm off .It Cm \&:C\| No \&/ Ar pattern\| No \&/ Ar replacement\| No \&/ Op Cm 1gW .Sm on -The -.Cm \&:C -modifier works like the -.Cm \&:S -modifier except that the old and new strings, instead of being -simple strings, are an extended regular expression +Modifies the first occurrence of the extended regular expression .Ar pattern (see .Xr regex 3 ) -and an +in each word of the value, replacing it with +an .Xr ed 1 Ns \-style .Ar replacement . -Normally, the first occurrence of the pattern -.Ar pattern -in each word of the value is substituted with -.Ar replacement . -The -.Ql 1 -modifier causes the substitution to apply to at most one word; the -.Ql g -modifier causes the substitution to apply to as many instances of the -search pattern -.Ar pattern -as occur in the word or words it is found in; the -.Ql W -modifier causes the value to be treated as a single word -(possibly containing embedded whitespace). .Pp -As for the -.Cm \&:S -modifier, the +Both .Ar pattern and .Ar replacement -are subjected to variable expansion before being parsed as -regular expressions. +may contain nested expressions. +.Pp +Further options: +.Bl -tag +.It Cm 1 +Only the word of the first occurrence is affected. +.It Cm g +All occurrences in each affected word are replaced. +.It Cm W +The expression value is treated as a single word. +.El +.Pp +Any character may be used as the delimiter for the parts of the modifier +string. +The anchoring, ampersand, dollar and delimiter characters +can be escaped with a backslash +.Pq Ql \e . .It Cm \&:T Replaces each word with its last path component (basename). .It Cm \&:u @@ -2494,7 +2481,7 @@ Any command lines attached to this target are executed after everything else is done successfully. .It Ic .ERROR Any command lines attached to this target are executed when another target fails. -See +See .Va MAKE_PRINT_VAR_ON_ERROR for the variables that will be set. .It Ic .IGNORE @@ -1,4 +1,4 @@ -/* $NetBSD: make.c,v 1.273 2025/07/06 07:11:31 rillig Exp $ */ +/* $NetBSD: make.c,v 1.274 2026/02/10 18:53:34 sjg Exp $ */ /* * Copyright (c) 1988, 1989, 1990, 1993 @@ -107,7 +107,7 @@ #endif /* "@(#)make.c 8.1 (Berkeley) 6/6/93" */ -MAKE_RCSID("$NetBSD: make.c,v 1.273 2025/07/06 07:11:31 rillig Exp $"); +MAKE_RCSID("$NetBSD: make.c,v 1.274 2026/02/10 18:53:34 sjg Exp $"); /* Sequence # to detect recursion. */ static unsigned checked_seqno = 1; @@ -187,6 +187,7 @@ GNodeFlags_ToString(GNodeFlags flags) Buf_AddFlag(&buf, flags.doneOrder, "DONE_ORDER"); Buf_AddFlag(&buf, flags.fromDepend, "FROM_DEPEND"); Buf_AddFlag(&buf, flags.doneAllsrc, "DONE_ALLSRC"); + Buf_AddFlag(&buf, flags.doneSubmake, "DONE_SUBMAKE"); Buf_AddFlag(&buf, flags.cycle, "CYCLE"); Buf_AddFlag(&buf, flags.doneCycle, "DONECYCLE"); if (buf.len == 0) @@ -1,4 +1,4 @@ -/* $NetBSD: make.h,v 1.361 2025/07/06 07:11:31 rillig Exp $ */ +/* $NetBSD: make.h,v 1.365 2026/03/13 04:22:03 sjg Exp $ */ /* * Copyright (c) 1988, 1989, 1990, 1993 @@ -419,6 +419,8 @@ typedef struct GNodeFlags { bool fromDepend:1; /* We do it once only */ bool doneAllsrc:1; + /* Have we checked for submake? */ + bool doneSubmake:1; /* Used by MakePrintStatus */ bool cycle:1; /* Used by MakePrintStatus */ @@ -909,7 +911,7 @@ void Parse_End(void); void PrintLocation(FILE *, bool, const GNode *); const char *GetParentStackTrace(void); char *GetStackTrace(bool); -void PrintStackTrace(bool); +void PrintStackTrace(FILE *, bool); void Parse_Error(ParseErrorLevel, const char *, ...) MAKE_ATTR_PRINTFLIKE(2, 3); bool Parse_VarAssign(const char *, bool, GNode *) MAKE_ATTR_USE; void Parse_File(const char *, int); @@ -995,14 +997,16 @@ typedef enum VarEvalMode { VARE_EVAL, /* - * Parse and evaluate the expression. It is an error if a - * subexpression evaluates to undefined. + * Only for Var_Parse, not for Var_Subst or Var_Expand: Parse and + * evaluate the expression. It is an error if the expression + * evaluates to undefined. Subexpressions or indirect expressions + * may evaluate to undefined, though. */ VARE_EVAL_DEFINED_LOUD, /* * Parse and evaluate the expression. It is a silent error if a - * subexpression evaluates to undefined. + * top-level expression evaluates to undefined. */ VARE_EVAL_DEFINED, @@ -1052,6 +1056,8 @@ typedef enum VarExportMode { VEM_LITERAL } VarExportMode; +#define MAKE_SAVE_DOLLARS ".MAKE.SAVE_DOLLARS" + void Var_Delete(GNode *, const char *); #ifdef CLEANUP void Var_DeleteAll(GNode *scope); @@ -1,4 +1,4 @@ -/* $NetBSD: meta.c,v 1.219 2025/08/04 18:57:20 rillig Exp $ */ +/* $NetBSD: meta.c,v 1.220 2026/02/10 18:53:34 sjg Exp $ */ /* * Implement 'meta' mode. @@ -312,62 +312,20 @@ meta_name(char *mname, size_t mnamelen, return mname; } -/* - * Return true if running ${.MAKE} - * Bypassed if target is flagged .MAKE - */ -static bool -is_submake(const char *cmd, GNode *gn) -{ - static const char *p_make = NULL; - static size_t p_len; - char *mp = NULL; - const char *cp2; - bool rc = false; - - if (p_make == NULL) { - p_make = Var_Value(gn, ".MAKE").str; - p_len = strlen(p_make); - } - if (strchr(cmd, '$') != NULL) { - mp = Var_Subst(cmd, gn, VARE_EVAL); - /* TODO: handle errors */ - cmd = mp; - } - cp2 = strstr(cmd, p_make); - if (cp2 != NULL) { - switch (cp2[p_len]) { - case '\0': - case ' ': - case '\t': - case '\n': - rc = true; - break; - } - if (cp2 > cmd && rc) { - switch (cp2[-1]) { - case ' ': - case '\t': - case '\n': - break; - default: - rc = false; /* no match */ - break; - } - } - } - free(mp); - return rc; -} - static bool any_is_submake(GNode *gn) { StringListNode *ln; + char *cmd; - for (ln = gn->commands.first; ln != NULL; ln = ln->next) - if (is_submake(ln->datum, gn)) + for (ln = gn->commands.first; ln != NULL; ln = ln->next) { + cmd = Var_Subst(ln->datum, gn, VARE_EVAL); + if (MaybeSubMake(cmd)) { + free(cmd); return true; + } + free(cmd); + } return false; } @@ -423,6 +381,7 @@ meta_needed(GNode *gn, const char *dname, SKIP_META_TYPE(OP_PHONY, "PHONY"); SKIP_META_TYPE(OP_SPECIAL, "SPECIAL"); SKIP_META_TYPE(OP_MAKE, "MAKE"); + SKIP_META_TYPE(OP_SUBMAKE, "SUBMAKE"); } /* Check if there are no commands to execute. */ @@ -431,11 +390,19 @@ meta_needed(GNode *gn, const char *dname, debug_printf("Skipping meta for %s: no commands\n", gn->name); return false; } - if ((gn->type & (OP_META|OP_SUBMAKE)) == OP_SUBMAKE) { - /* OP_SUBMAKE is a bit too aggressive */ + + /* + * If called from meta_oodate, gn->flags.doneSubmake will be false. + * While OP_SUBMAKE only matters in jobs mode, + * we normally skip .meta files for sub-makes, so we want to check + * even in compat mode. + */ + if (gn->flags.doneSubmake == false + && (gn->type & (OP_MAKE | OP_META)) == 0) { + gn->flags.doneSubmake = true; if (any_is_submake(gn)) { - DEBUG1(META, "Skipping meta for %s: .SUBMAKE\n", gn->name); - return false; + gn->type |= OP_SUBMAKE; + SKIP_META_TYPE(OP_SUBMAKE, "SUBMAKE"); } } diff --git a/mk/ChangeLog b/mk/ChangeLog index daacc97ec045..0322cae09232 100644 --- a/mk/ChangeLog +++ b/mk/ChangeLog @@ -1,3 +1,41 @@ +2026-03-12 Simon J Gerraty <sjg@beast.crufty.net> + + * install-mk (MK_VERSION): 20260313 + + * sys.vars.mk: use .MAKE.VERSION + M_type can simply use '$x' + +2026-02-22 Simon J Gerraty <sjg@beast.crufty.net> + + * install-mk (MK_VERSION): 20260222 + + * dirdeps.mk, sys.mk: add dependent option + UPDATE_DIRDEPS_CACHE/DIRDEPS_CACHE. + It can be useful to use -DWITHOUT_UPDATE_DIRDEPS_CACHE to + temporarily treat dynamic DIRDEPS_CACHE as static. + +2026-01-10 Simon J Gerraty <sjg@beast.crufty.net> + + * meta.autodep.mk (${_DEPENDFILE}): add .NOMETA + +2026-01-08 Simon J Gerraty <sjg@beast.crufty.net> + + * rust.mk: better accommodation for RUST_LIBS. + Set RUST_{LIBS,PROGS}_CARGO_BUILD_OUTPUT_LIST to + simplify staging. + +2025-12-08 Simon J Gerraty <sjg@beast.crufty.net> + + * install-mk (MK_VERSION): 20251207 + + * sys.vars.mk: replace MAKE_POSIX_SHELL usage with isPOSIX_SHELL + Using ${isPOSIX_SHELL:U:Nfalse} provides a boolean for make + and ${isPOSIX_SHELL:Ufalse} does the same for target scripts. + Both will be false if isPOSIX_SHELL is not set or set to false. + + This has the advantage that if only POSIX shells are expected + sys.mk (or something it includes) can simply do isPOSIX_SHELL?=: + 2025-11-18 Simon J Gerraty <sjg@beast.crufty.net> * sys.vars.mk: set MAKE_POSIX_SHELL to 1 if .SHELL is POSIX, 0 if not. diff --git a/mk/dirdeps.mk b/mk/dirdeps.mk index b281d15ec346..9f51713cc5d5 100644 --- a/mk/dirdeps.mk +++ b/mk/dirdeps.mk @@ -1,4 +1,4 @@ -# $Id: dirdeps.mk,v 1.175 2025/01/05 01:16:19 sjg Exp $ +# $Id: dirdeps.mk,v 1.176 2026/02/23 21:37:10 sjg Exp $ # SPDX-License-Identifier: BSD-2-Clause # @@ -585,6 +585,11 @@ BUILD_DIRDEPS_MAKEFILE ?= BUILD_DIRDEPS_OVERRIDES ?= BUILD_DIRDEPS_TARGETS ?= ${.TARGETS} +# sometimes we temporarily want to block updating of DIRDEPS_CACHE +.if ${MK_UPDATE_DIRDEPS_CACHE:Uyes} == "no" && exists(${DIRDEPS_CACHE}) +STATIC_DIRDEPS_CACHE ?= ${DIRDEPS_CACHE} +.endif + .if ${DIRDEPS_CACHE} != ${STATIC_DIRDEPS_CACHE:Uno} && ${DIRDEPS_CACHE:M${SRCTOP}/*} == "" # export this for dirdeps-cache-update.mk DYNAMIC_DIRDEPS_CACHE := ${DIRDEPS_CACHE} diff --git a/mk/install-mk b/mk/install-mk index f61d38947b11..20b24ca92ee0 100644 --- a/mk/install-mk +++ b/mk/install-mk @@ -59,7 +59,7 @@ # Simon J. Gerraty <sjg@crufty.net> # RCSid: -# $Id: install-mk,v 1.271 2025/11/11 18:08:02 sjg Exp $ +# $Id: install-mk,v 1.274 2026/03/13 05:13:00 sjg Exp $ # # @(#) Copyright (c) 1994-2025 Simon J. Gerraty # @@ -69,7 +69,7 @@ # sjg@crufty.net # -MK_VERSION=20251111 +MK_VERSION=20260313 OWNER= GROUP= MODE=444 diff --git a/mk/meta.autodep.mk b/mk/meta.autodep.mk index 2120c0892475..1998689306d4 100644 --- a/mk/meta.autodep.mk +++ b/mk/meta.autodep.mk @@ -1,4 +1,4 @@ -# $Id: meta.autodep.mk,v 1.71 2025/08/09 22:42:24 sjg Exp $ +# $Id: meta.autodep.mk,v 1.72 2026/01/11 05:32:29 sjg Exp $ # # @(#) Copyright (c) 2010-2025, Simon J. Gerraty # @@ -305,7 +305,7 @@ GENDIRDEPS_ENV += MAKESYSPATH=${_makesyspath} GENDIRDEPS_ENV += MAKESYSPATH=${.SYSPATH:ts:} .endif -${_DEPENDFILE}: ${_depend} ${.PARSEDIR}/gendirdeps.mk ${META2DEPS} $${.MAKE.META.CREATED} +${_DEPENDFILE}: .NOMETA ${_depend} ${.PARSEDIR}/gendirdeps.mk ${META2DEPS} $${.MAKE.META.CREATED} @echo Checking $@: ${.OODATE:T:[1..8]} @(cd . && ${GENDIRDEPS_ENV} \ SKIP_GENDIRDEPS='${SKIP_GENDIRDEPS:O:u}' \ diff --git a/mk/meta.stage.mk b/mk/meta.stage.mk index c98f0c251c67..b4d1ea4d6773 100644 --- a/mk/meta.stage.mk +++ b/mk/meta.stage.mk @@ -1,4 +1,4 @@ -# $Id: meta.stage.mk,v 1.74 2025/11/19 17:44:15 sjg Exp $ +# $Id: meta.stage.mk,v 1.75 2025/12/08 17:44:57 sjg Exp $ # # @(#) Copyright (c) 2011-2025, Simon J. Gerraty # @@ -31,12 +31,7 @@ CLEANFILES+= .dirdep @echo '${_dirdep}' > $@ .endif -.ifndef MAKE_POSIX_SHELL -MAKE_POSIX_SHELL != (echo $${PATH%:*}) > /dev/null 2>&1 && echo 1 || echo 0 -.export MAKE_POSIX_SHELL -.endif - -.if ${MAKE_POSIX_SHELL} +.if ${isPOSIX_SHELL:U:Nfalse} _stage_file_basename = $${f\#\#*/} _stage_file_dirname = $${f%/*} _stage_target_dirname = $${t%/*} diff --git a/mk/meta2deps.py b/mk/meta2deps.py index 77ed86397a0f..42085e9e7f7d 100755 --- a/mk/meta2deps.py +++ b/mk/meta2deps.py @@ -39,7 +39,7 @@ We only pay attention to a subset of the information in the SPDX-License-Identifier: BSD-2-Clause RCSid: - $Id: meta2deps.py,v 1.54 2025/07/24 16:05:48 sjg Exp $ + $Id: meta2deps.py,v 1.55 2026/01/13 04:32:45 sjg Exp $ Copyright (c) 2011-2025, Simon J. Gerraty Copyright (c) 2011-2017, Juniper Networks, Inc. @@ -446,7 +446,7 @@ class MetaFile: version = 0 # unknown if name: - self.name = name; + self.name = name if file: f = file cwd = self.last_dir = self.cwd @@ -669,7 +669,7 @@ class MetaFile: return if os.path.isdir(path): if op in 'RW': - self.last_dir = path; + self.last_dir = path if self.debug > 1: print("ldir=", self.last_dir, file=self.debug_out) return @@ -703,7 +703,7 @@ class MetaFile: self.seenit(dir) -def main(argv, klass=MetaFile, xopts='', xoptf=None): +def main(argv, klass=MetaFile, xopts='', xoptf=None, conf=None): """Simple driver for class MetaFile. Usage: @@ -743,11 +743,12 @@ def main(argv, klass=MetaFile, xopts='', xoptf=None): except: pass - conf = { - 'SRCTOPS': [], - 'OBJROOTS': [], - 'EXCLUDES': [], - } + if not conf: + conf = {} + + for k in ['EXCLUDES', 'OBJROOTS', 'SRCTOPS']: + if k not in conf: + conf[k] = [] conf['SB'] = os.getenv('SB', '') diff --git a/mk/meta2deps.sh b/mk/meta2deps.sh index 75ef1a4314eb..293ebdab6e7c 100755 --- a/mk/meta2deps.sh +++ b/mk/meta2deps.sh @@ -77,7 +77,7 @@ # RCSid: -# $Id: meta2deps.sh,v 1.25 2025/11/11 18:08:02 sjg Exp $ +# $Id: meta2deps.sh,v 1.26 2025/12/08 17:34:02 sjg Exp $ # SPDX-License-Identifier: BSD-2-Clause # @@ -263,8 +263,8 @@ meta2deps() { # first a sanity check - filemon on Linux is not very reliable # path2 should only be non-empty for op L or M # and it should not contain spaces. - # It will also be non-empty for # Meta line - # which tells us which meta_file we are processing + # It will also be non-empty for # Meta line + # which tells us which meta_file we are processing case "$op,$path2" in \#*,*.meta) # new file, reset some vars version=no epids= xpids= eof_token=no lpid= diff --git a/mk/rust.mk b/mk/rust.mk index 8a3c90116c6e..eab6d8b10181 100644 --- a/mk/rust.mk +++ b/mk/rust.mk @@ -1,6 +1,6 @@ -# $Id: rust.mk,v 1.38 2025/08/09 22:42:24 sjg Exp $ +# $Id: rust.mk,v 1.40 2026/01/08 20:34:30 sjg Exp $ # -# @(#) Copyright (c) 2024, Simon J. Gerraty +# @(#) Copyright (c) 2024-2026, Simon J. Gerraty # # SPDX-License-Identifier: BSD-2-Clause # @@ -180,15 +180,24 @@ all: cargo.clippy .if !defined(RUST_LIBS) RUST_PROGS ?= ${RUST_PROJECT_DIR:T} .endif -.if !empty(RUST_PROGS) -BINDIR ?= ${prefix}/bin +.if !empty(RUST_LIBS) || !empty(RUST_PROGS) # there could be a target triple involved RUST_CARGO_TARGET_DIR ?= ${CARGO_TARGET_DIR} RUST_CARGO_OUTPUT_DIR ?= ${RUST_CARGO_TARGET_DIR}/${RUST_CARGO_TARGET} -RUST_CARGO_BUILD_OUTPUT_LIST := ${RUST_PROGS:S,^,${RUST_CARGO_OUTPUT_DIR}/,} +.if !empty(RUST_LIBS) +LIBDIR ?= ${prefix}/lib +RUST_LIBS_CARGO_BUILD_OUTPUT_LIST := ${RUST_LIBS:S,^,${RUST_CARGO_OUTPUT_DIR}/,} + +${RUST_LIBS_CARGO_BUILD_OUTPUT_LIST}: cargo.build +.endif + +.if !empty(RUST_PROGS) +BINDIR ?= ${prefix}/bin +RUST_PROGS_CARGO_BUILD_OUTPUT_LIST := ${RUST_PROGS:S,^,${RUST_CARGO_OUTPUT_DIR}/,} -${RUST_CARGO_BUILD_OUTPUT_LIST}: cargo.build +${RUST_PROGS_CARGO_BUILD_OUTPUT_LIST}: cargo.build +.endif .endif # for late customizations diff --git a/mk/sys.dirdeps.mk b/mk/sys.dirdeps.mk index 66b7f900697c..2d68c0490d81 100644 --- a/mk/sys.dirdeps.mk +++ b/mk/sys.dirdeps.mk @@ -1,4 +1,4 @@ -# $Id: sys.dirdeps.mk,v 1.16 2025/08/09 22:42:24 sjg Exp $ +# $Id: sys.dirdeps.mk,v 1.17 2026/02/15 17:04:27 sjg Exp $ # # @(#) Copyright (c) 2012-2023, Simon J. Gerraty # @@ -96,10 +96,15 @@ TARGET_SPEC = ${TARGET_SPEC_VARS:@v@${$v:U}@:ts,} .if ${TARGET_SPEC_VARS:[#]} > 1 TARGET_SPEC_VARSr := ${TARGET_SPEC_VARS:[-1..1]} -# alternatives might be -# TARGET_OBJ_SPEC = ${TARGET_SPEC_VARSr:@v@${$v:U}@:ts/} -# TARGET_OBJ_SPEC = ${TARGET_SPEC_VARS:@v@${$v:U}@:ts/} -TARGET_OBJ_SPEC ?= ${TARGET_SPEC_VARS:@v@${$v:U}@:ts.} +# +# local.sys.*mk can control the format of TARGET_OBJ_SPEC +# by setting eg. +# TARGET_OBJ_SPEC_VARS = ${TARGET_SPEC_VARSr} +# TARGET_OBJ_SPEC_SEP = / +# +TARGET_OBJ_SPEC_VARS ?= ${TARGET_SPEC_VARS} +TARGET_OBJ_SPEC_SEP ?= . +TARGET_OBJ_SPEC = ${TARGET_OBJ_SPEC_VARS:@v@${$v:U}@:ts${TARGET_OBJ_SPEC_SEP}} .else TARGET_OBJ_SPEC ?= ${MACHINE} .endif diff --git a/mk/sys.mk b/mk/sys.mk index 4cbe976b439f..5b8d55e53604 100644 --- a/mk/sys.mk +++ b/mk/sys.mk @@ -1,4 +1,4 @@ -# $Id: sys.mk,v 1.66 2025/11/19 03:38:20 sjg Exp $ +# $Id: sys.mk,v 1.67 2026/02/23 21:37:10 sjg Exp $ # # @(#) Copyright (c) 2003-2023, Simon J. Gerraty # @@ -86,7 +86,7 @@ EGREP ?= egrep # some options we need to know early OPTIONS_DEFAULT_NO += \ DIRDEPS_BUILD \ - DIRDEPS_CACHE + DIRDEPS_CACHE \ OPTIONS_DEFAULT_DEPENDENT += \ AUTO_OBJ/DIRDEPS_BUILD \ @@ -95,6 +95,7 @@ OPTIONS_DEFAULT_DEPENDENT += \ STAGING/DIRDEPS_BUILD \ STATIC_DIRDEPS_CACHE/DIRDEPS_CACHE \ UPDATE_DEPENDFILE/DIRDEPS_BUILD \ + UPDATE_DIRDEPS_CACHE/DIRDEPS_CACHE \ .-include <options.mk> diff --git a/mk/sys.vars.mk b/mk/sys.vars.mk index f8e6dd7f2c87..7d9cd2f6641f 100644 --- a/mk/sys.vars.mk +++ b/mk/sys.vars.mk @@ -1,4 +1,4 @@ -# $Id: sys.vars.mk,v 1.24 2025/11/19 17:44:15 sjg Exp $ +# $Id: sys.vars.mk,v 1.27 2026/03/13 16:02:44 sjg Exp $ # # @(#) Copyright (c) 2003-2023, Simon J. Gerraty # @@ -24,25 +24,21 @@ MAKE_VERSION ?= 0 MAKE_VERSION := ${MAKE_VERSION:[1]:C,.*-,,} .endif -.if ${MAKE_VERSION} < 20100414 +# from (20260210) .MAKE.VERSION is read-only +.MAKE.VERSION ?= ${MAKE_VERSION} + +.if ${.MAKE.VERSION} < 20100414 _this = ${.PARSEDIR}/${.PARSEFILE} .else _this = ${.PARSEDIR:tA}/${.PARSEFILE} .endif -# This is a boolean we can use in makefiles as below -.ifndef MAKE_POSIX_SHELL -MAKE_POSIX_SHELL != (echo $${PATH%:*}) > /dev/null 2>&1 && echo 1 || echo 0 -.export MAKE_POSIX_SHELL -.endif - -# This is a boolean we can use in target scripts -.ifndef isPOSIX_SHELL -.if ${MAKE_POSIX_SHELL} -isPOSIX_SHELL = : -.else -isPOSIX_SHELL = false -.endif +# This is a boolean we can use in makefiles: +# .if ${isPOSIX_SHELL:U:Nfalse} +# as well as in target scripts: +# if ${isPOSIX_SHELL:Ufalse}; then +.if empty(isPOSIX_SHELL) +isPOSIX_SHELL != (echo $${PATH%:*}) > /dev/null 2>&1 && echo : || echo false .export isPOSIX_SHELL .endif @@ -66,14 +62,14 @@ _type_sh = which .endif # :sh1 evaluates command only once and caches the result. -.if ${MAKE_VERSION} < 20251111 +.if ${.MAKE.VERSION} < 20251111 M_sh1 = sh .else M_sh1 = sh1 .endif # AUTOCONF := ${autoconf:L:${M_whence}} -M_type = @x@(${_type_sh:Utype} $$x) 2> /dev/null; echo;@:${M_sh1:Ush}:[0]:N* found*:[@]:C,[()],,g +M_type = @x@(${_type_sh:Utype} $x) 2> /dev/null; echo;@:${M_sh1:Ush}:[0]:N* found*:[@]:C,[()],,g M_whence = ${M_type}:M/*:[1] # produce similar output to jot(1) or seq(1) @@ -98,7 +94,7 @@ M_JOT = [1]:@x@i=1;while [ $$$$i -le $$x ]; do echo $$$$i; i=$$$$((i + 1)); done .endif # ${LIST:${M_RANGE}} is 1 2 3 4 5 if LIST has 5 words -.if ${MAKE_VERSION} < 20170130 +.if ${.MAKE.VERSION} < 20170130 M_RANGE = [#]:${M_JOT} .else M_RANGE = range @@ -108,7 +104,7 @@ M_RANGE = range M_P2V = tu:C,[./-],_,g # convert path to absolute -.if ${MAKE_VERSION} < 20100414 +.if ${.MAKE.VERSION} < 20100414 M_tA = C,.*,('cd' & \&\& 'pwd') 2> /dev/null || echo &,:sh .else M_tA = tA @@ -117,7 +113,7 @@ M_tA = tA # absoulte path to what we are reading. _PARSEDIR = ${.PARSEDIR:${M_tA}} -.if ${MAKE_VERSION} >= 20170130 +.if ${.MAKE.VERSION} >= 20170130 # M_cmpv allows comparing dotted versions like 3.1.2 # ${3.1.2:L:${M_cmpv}} -> 3001002 # we use big jumps to handle 3 digits per dot: @@ -132,7 +128,7 @@ M_cmpv = S,., ,g:C,^0*([0-9]),\1,:_:range:@i@+ $${_:[-$$i]} \* $${M_cmpv.units:[ M_M.M.P_VERSION = L:@v@$${MAJOR MINOR PATCH:L:@t@$${$$v_$$t_VERSION:U0}@}@:ts. # numeric sort -.if ${MAKE_VERSION} < 20210803 +.if ${.MAKE.VERSION} < 20210803 M_On = O M_Onr = O .else @@ -17,9 +17,9 @@ # Simon J. Gerraty <sjg@crufty.net> # RCSid: -# $Id: os.sh,v 1.68 2025/08/07 21:59:54 sjg Exp $ +# $Id: os.sh,v 1.70 2026/02/25 05:44:34 sjg Exp $ # -# @(#) Copyright (c) 1994 Simon J. Gerraty +# @(#) Copyright (c) 1994-2026 Simon J. Gerraty # # SPDX-License-Identifier: BSD-2-Clause # @@ -226,6 +226,10 @@ x86*64|amd64) MACHINE32_ARCH=i386;; *) MACHINE32_ARCH=$MACHINE_ARCH;; esac HOST_ARCH32=${HOST_ARCH32:-$MACHINE32_ARCH} +MACHINE32=${HOST_ARCH32:-$MACHINE} +HOST_MACHINE=${HOST_MACHINE:-$MACHINE} +HOST_MACHINE32=${HOST_MACHINE32:-$MACHINE32} +export HOST_MACHINE HOST_MACHINE32 export HOST_ARCH HOST_ARCH32 # we mount server:/share/arch/$SHARE_ARCH as /usr/local SHARE_ARCH_DEFAULT=$OS/$OSMAJOR.X/$HOST_ARCH @@ -1,4 +1,4 @@ -/* $NetBSD: parse.c,v 1.753 2025/06/28 22:39:27 rillig Exp $ */ +/* $NetBSD: parse.c,v 1.755 2026/02/10 18:53:34 sjg Exp $ */ /* * Copyright (c) 1988, 1989, 1990, 1993 @@ -110,7 +110,7 @@ #include "pathnames.h" /* "@(#)parse.c 8.3 (Berkeley) 3/19/94" */ -MAKE_RCSID("$NetBSD: parse.c,v 1.753 2025/06/28 22:39:27 rillig Exp $"); +MAKE_RCSID("$NetBSD: parse.c,v 1.755 2026/02/10 18:53:34 sjg Exp $"); /* Detects a multiple-inclusion guard in a makefile. */ typedef enum { @@ -481,11 +481,11 @@ add_parent_stack_trace: } void -PrintStackTrace(bool includingInnermost) +PrintStackTrace(FILE *f, bool includingInnermost) { char *stackTrace = GetStackTrace(includingInnermost); - fprintf(stderr, "%s", stackTrace); - fflush(stderr); + fprintf(f, "%s", stackTrace); + fflush(f); free(stackTrace); } @@ -602,7 +602,7 @@ ParseVErrorInternal(FILE *f, bool useVars, const GNode *gn, if (level == PARSE_FATAL || DEBUG(PARSE) || (gn == NULL && includes.len == 0 /* see PrintLocation */)) - PrintStackTrace(false); + PrintStackTrace(f, false); } static void MAKE_ATTR_PRINTFLIKE(3, 4) @@ -1985,46 +1985,6 @@ Parse_Var(VarAssign *var, GNode *scope) } -/* - * See if the command possibly calls a sub-make by using the - * expressions ${.MAKE}, ${MAKE} or the plain word "make". - */ -static bool -MaybeSubMake(const char *cmd) -{ - const char *start; - - for (start = cmd; *start != '\0'; start++) { - const char *p = start; - char endc; - - /* XXX: What if progname != "make"? */ - if (strncmp(p, "make", 4) == 0) - if (start == cmd || !ch_isalnum(p[-1])) - if (!ch_isalnum(p[4])) - return true; - - if (*p != '$') - continue; - p++; - - if (*p == '{') - endc = '}'; - else if (*p == '(') - endc = ')'; - else - continue; - p++; - - if (*p == '.') /* Accept either ${.MAKE} or ${MAKE}. */ - p++; - - if (strncmp(p, "MAKE", 4) == 0 && p[4] == endc) - return true; - } - return false; -} - /* Append the command to the target node. */ static void GNode_AddCommand(GNode *gn, char *cmd) @@ -2035,8 +1995,6 @@ GNode_AddCommand(GNode *gn, char *cmd) /* if target already supplied, ignore commands */ if (!(gn->type & OP_HAS_COMMANDS)) { Lst_Append(&gn->commands, cmd); - if (MaybeSubMake(cmd)) - gn->type |= OP_SUBMAKE; RememberLocation(gn); } else { Parse_Error(PARSE_WARNING, @@ -1,37 +1,35 @@ -/* $NetBSD: str.h,v 1.20 2024/07/07 07:50:57 rillig Exp $ */ +/* $NetBSD: str.h,v 1.21 2026/01/03 19:57:38 rillig Exp $ */ /* - Copyright (c) 2021 Roland Illig <rillig@NetBSD.org> - All rights reserved. - - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions - are met: - - 1. Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - 2. Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the - documentation and/or other materials provided with the distribution. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED - TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS - BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - POSSIBILITY OF SUCH DAMAGE. - */ - - -/* - * Memory-efficient string handling. + * Copyright (c) 2021 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Roland Illig. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. */ +/* Memory-efficient string handling. */ /* A read-only string that may need to be freed after use. */ typedef struct FStr { @@ -1,4 +1,4 @@ -/* $NetBSD: suff.c,v 1.384 2025/05/18 06:24:27 rillig Exp $ */ +/* $NetBSD: suff.c,v 1.385 2026/01/03 19:57:38 rillig Exp $ */ /* * Copyright (c) 1988, 1989, 1990, 1993 @@ -115,7 +115,7 @@ #include "dir.h" /* "@(#)suff.c 8.4 (Berkeley) 3/21/94" */ -MAKE_RCSID("$NetBSD: suff.c,v 1.384 2025/05/18 06:24:27 rillig Exp $"); +MAKE_RCSID("$NetBSD: suff.c,v 1.385 2026/01/03 19:57:38 rillig Exp $"); typedef List SuffixList; typedef ListNode SuffixListNode; @@ -1431,7 +1431,7 @@ Suff_FindPath(GNode *gn) return suff->searchPath; } else { DEBUG0(SUFF, "\n"); - return &dirSearchPath; /* Use default search path */ + return &dirSearchPath; /* Use the default search path */ } } @@ -1439,8 +1439,8 @@ Suff_FindPath(GNode *gn) * Apply a transformation rule, given the source and target nodes and * suffixes. * - * The source and target are linked and the commands from the transformation - * are added to the target node's commands list. The target also inherits all + * The source and target are linked, and the commands from the transformation + * are added to the target node's commands. The target also inherits all * the sources for the transformation rule. * * Results: @@ -1470,7 +1470,7 @@ ApplyTransform(GNode *tgn, GNode *sgn, Suffix *tsuff, Suffix *ssuff) DEBUG3(SUFF, "\tapplying %s -> %s to \"%s\"\n", ssuff->name, tsuff->name, tgn->name); - /* Record last child; Make_HandleUse may add child nodes. */ + /* Record the last child; Make_HandleUse may add child nodes. */ ln = tgn->children.last; /* Apply the rule. */ diff --git a/unit-tests/Makefile b/unit-tests/Makefile index 63671a6d9b74..b12ef7decb4d 100644 --- a/unit-tests/Makefile +++ b/unit-tests/Makefile @@ -1,6 +1,6 @@ -# $Id: Makefile,v 1.251 2025/11/15 17:17:18 sjg Exp $ +# $Id: Makefile,v 1.260 2026/03/10 15:45:51 sjg Exp $ # -# $NetBSD: Makefile,v 1.373 2025/11/12 22:14:08 sjg Exp $ +# $NetBSD: Makefile,v 1.383 2026/03/10 15:38:26 sjg Exp $ # # Unit tests for make(1) # @@ -629,6 +629,9 @@ SED_CMDS.opt-chdir= -e 's,\(nonexistent\).[1-9][0-9]*,\1,' \ -e 's,no such,No such,' \ -e 's,Filename,File name,' +SED_CMDS.gnode-submake= ${STD_SED_CMDS.dj} +SED_CMDS.gnode-submake= ${STD_SED_CMDS.dg2} + # meta line numbers can vary based on filemon implementation SED_CMDS.meta-ignore= -e 's,\(\.meta:\)[1-9][0-9]*:,\1<line>:,' @@ -642,6 +645,7 @@ SED_CMDS.opt-debug-lint+= ${STD_SED_CMDS.regex} SED_CMDS.opt-jobs-no-action= ${STD_SED_CMDS.hide-from-output} SED_CMDS.opt-no-action-runflags= ${STD_SED_CMDS.hide-from-output} SED_CMDS.opt-where-am-i= -e '/usr.obj/d' +SED_CMDS.opt-where-am-i+= -e '/\/\//d' # For Compat_RunCommand, useShell == false. SED_CMDS.sh-dots= -e 's,^.*\.\.\.:.*,<not found: ...>,' # For Compat_RunCommand, useShell == true. @@ -662,6 +666,7 @@ SED_CMDS.var-op-shell+= -e '/command/s,No such.*,not found,' SED_CMDS.var-op-shell+= ${STD_SED_CMDS.white-space} SED_CMDS.vardebug+= -e 's,${.SHELL},</path/to/shell>,' SED_CMDS.varmod-mtime+= -e "s,\(mtime for .*\): .*,\1: <ENOENT>," +SED_CMDS.varmod-subst+= ${STD_SED_CMDS.regex} SED_CMDS.varmod-subst-regex+= ${STD_SED_CMDS.regex} SED_CMDS.varparse-errors+= ${STD_SED_CMDS.timestamp} SED_CMDS.varname-dot-make-meta-ignore_filter+= ${SED_CMDS.meta-ignore} @@ -677,7 +682,10 @@ SED_CMDS.varname-empty= ${.OBJDIR .PARSEDIR .PATH .SHELL .SYSPATH:L:@v@-e '/\\$ # Some tests need an additional round of postprocessing. POSTPROC.depsrc-wait= sed -e '/^---/d' -e 's,^\(: Making 3[abc]\)[123]$$,\1,' POSTPROC.deptgt-suffixes= awk '/^\#\*\*\* Suffixes/,/^never-stop/' -POSTPROC.gnode-submake= awk '/Begin input graph/, /^$$/' +POSTPROC.gnode-submake= \ + awk '/Begin input graph/, /^\# \.END/ { \ + if (/made,/) print $$0 \ + }' POSTPROC.varname-dot-make-mode= sed 's,^\(: Making [abc]\)[123]$$,\1,' # Some tests reuse other tests, which makes them unnecessarily fragile. @@ -700,6 +708,7 @@ STD_SED_CMDS.dg1= -e '/\#.* \.$$/d' STD_SED_CMDS.dg1+= -e '/\.MAKE.PATH_FILEMON/d' STD_SED_CMDS.dg1+= -e '/^\#.*\/mk/d' STD_SED_CMDS.dg1+= -e 's, ${DEFSYSPATH:U/usr/share/mk}$$, <defsyspath>,' +STD_SED_CMDS.dg1+= -e '/^\.MAKE\.PATH_FILEMON/d' STD_SED_CMDS.dg1+= -e 's,^\(\.MAKE *=\) .*,\1 <details omitted>,' STD_SED_CMDS.dg1+= -e 's,^\(\.MAKE\.[A-Z_]* *=\) .*,\1 <details omitted>,' STD_SED_CMDS.dg1+= -e 's,^\(\.MAKE\.JOBS\.C *=\) .*,\1 <details omitted>,' @@ -710,6 +719,7 @@ STD_SED_CMDS.dg1+= -e '/\.SYSPATH/d' STD_SED_CMDS.dg2= ${STD_SED_CMDS.dg1} STD_SED_CMDS.dg2+= -e 's,\(last modified\) ..:..:.. ... ..\, ....,\1 <timestamp>,' + STD_SED_CMDS.dg3= ${STD_SED_CMDS.dg2} # Omit details such as process IDs from the output of the -dj option. @@ -792,6 +802,16 @@ clean: rm -f ${CLEANFILES} TEST_MAKE?= ${.MAKE} +.if ${TEST_MAKE:M/*} == "" +# we want an absolute path for TEST_MAKE +tm!= for d in ${PATH:S,:, ,g:M/*}; do \ + test -x $$d/${TEST_MAKE} || continue; \ + echo $$d/${TEST_MAKE}; break; done +.if ${tm:M/*} +TEST_MAKE:= ${tm} +.endif +.endif + TOOL_SED?= sed TOOL_TR?= tr TOOL_DIFF?= diff @@ -831,7 +851,7 @@ LIMIT_RESOURCES?= : # each other, and because they use different environment variables and # command line options. .SUFFIXES: .mk .rawout .out -.mk.rawout: +.mk.rawout: .META @${_MKMSG_TEST:Uecho '# test '} ${.PREFIX} @set -eu; \ ${LIMIT_RESOURCES}; \ @@ -873,7 +893,8 @@ _SED_CMDS+= -e 's,^usage: ${TEST_MAKE:T:S,.,\\.,g} ,usage: make ,' _SED_CMDS+= -e 's,${TEST_MAKE:T:S,.,\\.,g}\(\[[1-9][0-9]*\][: ]\),make\1,' _SED_CMDS+= -e 's,<curdir>/,,g' _SED_CMDS+= -e 's,${UNIT_TESTS:S,.,\\.,g}/,,g' -_SED_CMDS+= -e '/MAKE_VERSION/d' +_SED_CMDS+= -e 's,\(\.make\)[1-9][0-9]*,\1,g' +_SED_CMDS+= -e '/MAKE.VERSION/d' _SED_CMDS+= -e '/EGREP=/d' # on AT&T derived systems: false exits 255 not 1 @@ -886,7 +907,7 @@ SED_CMDS.opt-debug-jobs+= -e 's,Command: ksh -v,Command: <shell>,' SED_CMDS.opt-debug-jobs+= -e 's,Command: <shell> -v,Command: <shell>,' .endif -.rawout.out: +.rawout.out: .META @${TOOL_SED} ${_SED_CMDS} ${SED_CMDS.${.PREFIX:T}} ${_SED_CMDS_LAST} \ < ${.IMPSRC} > ${.TARGET}.tmp @${POSTPROC.${.PREFIX:T}:D \ diff --git a/unit-tests/cmd-errors-jobs.exp b/unit-tests/cmd-errors-jobs.exp index 3be1bb9b0773..3846f9eef260 100644 --- a/unit-tests/cmd-errors-jobs.exp +++ b/unit-tests/cmd-errors-jobs.exp @@ -9,34 +9,34 @@ end undefined-indirect with status 0 begin parse-error-direct make: Unclosed variable "UNCLOSED" in command ": unexpected $@-${UNCLOSED" - in target "parse-error-unclosed-expression" + in target "parse-error-unclosed-expression" from cmd-errors-jobs.mk:42 in make[1] in directory "<curdir>" make: Unclosed expression, expecting "}" while evaluating variable "UNCLOSED" with value "" in command ": unexpected $@-${UNCLOSED:" - in target "parse-error-unclosed-modifier" + in target "parse-error-unclosed-modifier" from cmd-errors-jobs.mk:45 in make[1] in directory "<curdir>" make: Unknown modifier ":Z" while evaluating variable "UNKNOWN" with value "" in command ": unexpected $@-${UNKNOWN:Z}-eol" - in target "parse-error-unknown-modifier" + in target "parse-error-unknown-modifier" from cmd-errors-jobs.mk:48 in make[1] in directory "<curdir>" end parse-error-direct with status 2 begin parse-error-indirect make: Unclosed variable "UNCLOSED" in command ": unexpected $@-${UNCLOSED" - in target "parse-error-unclosed-expression" + in target "parse-error-unclosed-expression" from cmd-errors-jobs.mk:42 in make[1] in directory "<curdir>" make: Unclosed expression, expecting "}" while evaluating variable "UNCLOSED" with value "" in command ": unexpected $@-${UNCLOSED:" - in target "parse-error-unclosed-modifier" + in target "parse-error-unclosed-modifier" from cmd-errors-jobs.mk:45 in make[1] in directory "<curdir>" make: Unknown modifier ":Z" while evaluating variable "UNKNOWN" with value "" in command ": unexpected $@-${UNKNOWN:Z}-eol" - in target "parse-error-unknown-modifier" + in target "parse-error-unknown-modifier" from cmd-errors-jobs.mk:48 in make[1] in directory "<curdir>" end parse-error-indirect with status 2 diff --git a/unit-tests/cmd-errors-lint.exp b/unit-tests/cmd-errors-lint.exp index b08a65ff96dc..4b010732f8b2 100644 --- a/unit-tests/cmd-errors-lint.exp +++ b/unit-tests/cmd-errors-lint.exp @@ -1,14 +1,14 @@ : undefined make: Unclosed variable "UNCLOSED" in command ": $@ ${UNCLOSED" - in target "unclosed-expression" + in target "unclosed-expression" from cmd-errors-lint.mk:19 make: Unclosed expression, expecting "}" while evaluating variable "UNCLOSED" with value "" in command ": $@ ${UNCLOSED:" - in target "unclosed-modifier" + in target "unclosed-modifier" from cmd-errors-lint.mk:24 make: Unknown modifier ":Z" while evaluating variable "UNKNOWN" with value "" in command ": $@ ${UNKNOWN:Z}" - in target "unknown-modifier" + in target "unknown-modifier" from cmd-errors-lint.mk:29 : end exit status 2 diff --git a/unit-tests/cmd-errors.exp b/unit-tests/cmd-errors.exp index 2916d423029e..8936c0a671ae 100644 --- a/unit-tests/cmd-errors.exp +++ b/unit-tests/cmd-errors.exp @@ -1,14 +1,14 @@ : undefined--eol make: Unclosed variable "UNCLOSED" in command ": $@-${UNCLOSED" - in target "unclosed-expression" + in target "unclosed-expression" from cmd-errors.mk:17 make: Unclosed expression, expecting "}" while evaluating variable "UNCLOSED" with value "" in command ": $@-${UNCLOSED:" - in target "unclosed-modifier" + in target "unclosed-modifier" from cmd-errors.mk:22 make: Unknown modifier ":Z" while evaluating variable "UNKNOWN" with value "" in command ": $@-${UNKNOWN:Z}-eol" - in target "unknown-modifier" + in target "unknown-modifier" from cmd-errors.mk:27 : end-eol exit status 2 diff --git a/unit-tests/cond-func-exists.mk b/unit-tests/cond-func-exists.mk index c68507ca1ab9..360c4741f9c0 100644 --- a/unit-tests/cond-func-exists.mk +++ b/unit-tests/cond-func-exists.mk @@ -1,4 +1,4 @@ -# $NetBSD: cond-func-exists.mk,v 1.8 2025/01/10 23:00:38 rillig Exp $ +# $NetBSD: cond-func-exists.mk,v 1.9 2026/03/02 21:49:37 rillig Exp $ # # Tests for the exists() function in .if conditions. @@ -52,5 +52,17 @@ _!= > cond-func-exists.just-created .endif _!= rm cond-func-exists.just-created + +# The exists function aims at source and target files, but not at makefiles. +# In particular, the file is not searched in ${.PARSEDIR}. +_!= mkdir -p cond-func-exists && \ + printf '%s\n' \ + '.if exists(file.inc)' \ + '. error' \ + '.endif' \ + > cond-func-exists/file.inc +.include "cond-func-exists/file.inc" +_!= rm -f cond-func-exists/file.inc + + all: - @:; diff --git a/unit-tests/cond-undef-lint.mk b/unit-tests/cond-undef-lint.mk index 1b4d19636c41..27e42d208aa3 100755 --- a/unit-tests/cond-undef-lint.mk +++ b/unit-tests/cond-undef-lint.mk @@ -1,4 +1,4 @@ -# $NetBSD: cond-undef-lint.mk,v 1.8 2025/01/11 21:21:33 rillig Exp $ +# $NetBSD: cond-undef-lint.mk,v 1.9 2026/02/13 03:16:15 lukem Exp $ # # Tests for defined and undefined variables in .if conditions, in lint mode. # @@ -51,7 +51,7 @@ DEF= defined # Variables that are referenced indirectly may be undefined in a condition. # -# A practical example for this is CFLAGS, which consists of CWARNS, COPTS +# A practical example for this is CFLAGS, which consists of CWARNFLAGS, COPTS # and a few others. Just because these nested variables are not defined, # this does not make the condition invalid. # diff --git a/unit-tests/directive-dinclude.mk b/unit-tests/directive-dinclude.mk index c05d1a55f51b..40fcb5306bb8 100755 --- a/unit-tests/directive-dinclude.mk +++ b/unit-tests/directive-dinclude.mk @@ -1,4 +1,4 @@ -# $NetBSD: directive-dinclude.mk,v 1.5 2025/06/28 22:39:28 rillig Exp $ +# $NetBSD: directive-dinclude.mk,v 1.6 2025/11/16 16:43:56 sjg Exp $ # # Tests for the .dinclude directive, which includes another file, # silently skipping it if it cannot be opened. This is primarily used for diff --git a/unit-tests/directive-export-gmake.mk b/unit-tests/directive-export-gmake.mk index 6e1d57c6a62d..36efc96e5114 100644 --- a/unit-tests/directive-export-gmake.mk +++ b/unit-tests/directive-export-gmake.mk @@ -1,4 +1,4 @@ -# $NetBSD: directive-export-gmake.mk,v 1.10 2025/06/28 22:39:28 rillig Exp $ +# $NetBSD: directive-export-gmake.mk,v 1.11 2026/01/02 14:21:46 rillig Exp $ # # Tests for the export directive (without leading dot), as in GNU make. @@ -104,3 +104,12 @@ export ${INDIRECT_NAME}=${INDIRECT_VALUE} .if ${:!env!:MI_NAME=*} . error .endif + + +# Quotes and other special characters are preserved. +export DQUOT="dquot" +export SQUOT='squot' +export PLAIN=plain +.if ${:!echo "\$DQUOT \$SQUOT \$PLAIN"!} != "\"dquot\" 'squot' plain" +. error +.endif diff --git a/unit-tests/directive-hyphen-include.mk b/unit-tests/directive-hyphen-include.mk index e3817ef15539..e3cc48238eff 100755 --- a/unit-tests/directive-hyphen-include.mk +++ b/unit-tests/directive-hyphen-include.mk @@ -1,4 +1,4 @@ -# $NetBSD: directive-hyphen-include.mk,v 1.5 2025/06/28 22:39:28 rillig Exp $ +# $NetBSD: directive-hyphen-include.mk,v 1.6 2025/11/16 16:43:57 sjg Exp $ # # Tests for the .-include directive, which includes another file, # silently skipping it if it cannot be opened. diff --git a/unit-tests/directive-include-guard.mk b/unit-tests/directive-include-guard.mk index 5dc7f1aac178..acbe61d66d41 100644 --- a/unit-tests/directive-include-guard.mk +++ b/unit-tests/directive-include-guard.mk @@ -1,4 +1,4 @@ -# $NetBSD: directive-include-guard.mk,v 1.19 2025/04/11 17:21:31 rillig Exp $ +# $NetBSD: directive-include-guard.mk,v 1.20 2025/11/16 16:43:57 sjg Exp $ # # Tests for multiple-inclusion guards in makefiles. # diff --git a/unit-tests/directive-include.mk b/unit-tests/directive-include.mk index a694b9ca4e91..eedb9ce220e0 100755 --- a/unit-tests/directive-include.mk +++ b/unit-tests/directive-include.mk @@ -1,4 +1,4 @@ -# $NetBSD: directive-include.mk,v 1.20 2025/06/28 22:39:28 rillig Exp $ +# $NetBSD: directive-include.mk,v 1.21 2025/11/16 16:43:57 sjg Exp $ # # Tests for the .include directive, which includes another file. diff --git a/unit-tests/directive-sinclude.mk b/unit-tests/directive-sinclude.mk index 3c2ffbdc9f6c..d995d315518b 100755 --- a/unit-tests/directive-sinclude.mk +++ b/unit-tests/directive-sinclude.mk @@ -1,4 +1,4 @@ -# $NetBSD: directive-sinclude.mk,v 1.7 2025/06/28 22:39:28 rillig Exp $ +# $NetBSD: directive-sinclude.mk,v 1.8 2025/11/16 16:43:57 sjg Exp $ # # Tests for the .sinclude directive, which includes another file, # silently skipping it if it cannot be opened. diff --git a/unit-tests/gnode-submake.exp b/unit-tests/gnode-submake.exp index c9cfada91c69..7ed8335bf73d 100644 --- a/unit-tests/gnode-submake.exp +++ b/unit-tests/gnode-submake.exp @@ -1,11 +1,11 @@ -#*** Begin input graph for pass 1 in <curdir>: -# all, unmade, type OP_DEPENDS, flags none -# makeinfo, unmade, type OP_DEPENDS|OP_HAS_COMMANDS, flags none -# make-index, unmade, type OP_DEPENDS|OP_SUBMAKE|OP_HAS_COMMANDS, flags none -# braces-dot, unmade, type OP_DEPENDS|OP_SUBMAKE|OP_HAS_COMMANDS, flags none -# braces-no-dot, unmade, type OP_DEPENDS|OP_SUBMAKE|OP_HAS_COMMANDS, flags none -# braces-no-dot-modifier, unmade, type OP_DEPENDS|OP_HAS_COMMANDS, flags none -# parentheses-dot, unmade, type OP_DEPENDS|OP_SUBMAKE|OP_HAS_COMMANDS, flags none -# parentheses-no-dot, unmade, type OP_DEPENDS|OP_SUBMAKE|OP_HAS_COMMANDS, flags none - +# .MAIN, made, type OP_DEPENDS|OP_PHONY, flags REMAKE|CHILDMADE|FORCE|DONE_WAIT|DONE_ALLSRC +# all, made, type OP_DEPENDS|OP_DEPS_FOUND|OP_MARK, flags REMAKE|CHILDMADE|FORCE|DONE_WAIT|DONE_ALLSRC|DONECYCLE +# makeinfo, made, type OP_DEPENDS|OP_HAS_COMMANDS|OP_DEPS_FOUND|OP_MARK, flags REMAKE|DONE_WAIT|DONE_ALLSRC|DONE_SUBMAKE +# make-index, made, type OP_DEPENDS|OP_HAS_COMMANDS|OP_DEPS_FOUND|OP_MARK, flags REMAKE|DONE_WAIT|DONE_ALLSRC|DONE_SUBMAKE +# braces-dot, made, type OP_DEPENDS|OP_SUBMAKE|OP_HAS_COMMANDS|OP_DEPS_FOUND|OP_MARK, flags REMAKE|DONE_WAIT|DONE_ALLSRC|DONE_SUBMAKE +# braces-no-dot, made, type OP_DEPENDS|OP_SUBMAKE|OP_HAS_COMMANDS|OP_DEPS_FOUND|OP_MARK, flags REMAKE|DONE_WAIT|DONE_ALLSRC|DONE_SUBMAKE +# braces-no-dot-modifier, made, type OP_DEPENDS|OP_SUBMAKE|OP_HAS_COMMANDS|OP_DEPS_FOUND|OP_MARK, flags REMAKE|DONE_WAIT|DONE_ALLSRC|DONE_SUBMAKE +# parentheses-dot, made, type OP_DEPENDS|OP_SUBMAKE|OP_HAS_COMMANDS|OP_DEPS_FOUND|OP_MARK, flags REMAKE|DONE_WAIT|DONE_ALLSRC|DONE_SUBMAKE +# parentheses-no-dot, made, type OP_DEPENDS|OP_SUBMAKE|OP_HAS_COMMANDS|OP_DEPS_FOUND|OP_MARK, flags REMAKE|DONE_WAIT|DONE_ALLSRC|DONE_SUBMAKE +# .END, unmade, type OP_SPECIAL, flags none exit status 0 diff --git a/unit-tests/gnode-submake.mk b/unit-tests/gnode-submake.mk index 40ff20276df9..2cd7fac81f72 100644 --- a/unit-tests/gnode-submake.mk +++ b/unit-tests/gnode-submake.mk @@ -1,4 +1,4 @@ -# $NetBSD: gnode-submake.mk,v 1.1 2020/11/07 23:25:06 rillig Exp $ +# $NetBSD: gnode-submake.mk,v 1.2 2026/02/10 18:53:34 sjg Exp $ # # Test whether OP_SUBMAKE is determined correctly. If it is, this node's # shell commands are connected to the make process via pipes, to coordinate @@ -8,7 +8,7 @@ # parsed. This information is only used in parallel mode, but the result # from parsing is available in compat mode as well. -.MAKEFLAGS: -n -dg1 +.MAKEFLAGS: -dg2 -j1 all: makeinfo make-index all: braces-dot braces-no-dot diff --git a/unit-tests/lint.exp b/unit-tests/lint.exp index 61188d6d5c29..6c08bdcbe01b 100755 --- a/unit-tests/lint.exp +++ b/unit-tests/lint.exp @@ -1,5 +1,5 @@ make: In the :@ modifier, the variable name "${:Ubar:S,b,v,}" must not contain a dollar while evaluating variable "VAR" with value "value" in command "@echo ${VAR:Uvalue:@${:Ubar:S,b,v,}@x${var}y@:Q}" - in target "mod-loop-varname" + in target "mod-loop-varname" from lint.mk:22 exit status 2 diff --git a/unit-tests/moderrs.exp b/unit-tests/moderrs.exp index 4758294f0993..1fa7dd57f52a 100644 --- a/unit-tests/moderrs.exp +++ b/unit-tests/moderrs.exp @@ -1,173 +1,173 @@ make: Unknown modifier ":Z" while evaluating variable "VAR" with value "TheVariable" in command "@echo 'VAR:Z=before-${VAR:Z}-after'" - in target "mod-unknown-direct" + in target "mod-unknown-direct" from moderrs.mk:29 make: Unknown modifier ":Z" while evaluating indirect modifiers "Z" while evaluating variable "VAR" with value "TheVariable" in command "@echo 'VAR:${MOD_UNKN}=before-${VAR:${MOD_UNKN}:inner}-after'" - in target "mod-unknown-indirect" + in target "mod-unknown-indirect" from moderrs.mk:33 make: Unclosed expression, expecting "}" for modifier "S,V,v," while evaluating variable "VAR" with value "Thevariable" in command "@echo VAR:S,V,v,=${VAR:S,V,v," - in target "unclosed-direct" + in target "unclosed-direct" from moderrs.mk:37 make: Unclosed expression after indirect modifier, expecting "}" while evaluating variable "VAR" with value "Thevariable" in command "@echo VAR:${MOD_TERM},=${VAR:${MOD_S}" - in target "unclosed-indirect" + in target "unclosed-indirect" from moderrs.mk:41 make: Unfinished modifier after "v", expecting "," while evaluating indirect modifiers "S,V,v" while evaluating variable "VAR" with value "TheVariable" in command "-@echo "VAR:${MOD_TERM}=${VAR:${MOD_TERM}}"" - in target "unfinished-indirect" + in target "unfinished-indirect" from moderrs.mk:45 make: Unfinished modifier after "var}", expecting "@" while evaluating variable "UNDEF" with value "1 2 3" in command "@echo ${UNDEF:U1 2 3:@var}" - in target "unfinished-loop-1" + in target "unfinished-loop-1" from moderrs.mk:49 make: Unfinished modifier after "...}", expecting "@" while evaluating variable "UNDEF" with value "1 2 3" in command "@echo ${UNDEF:U1 2 3:@var@...}" - in target "unfinished-loop-2" + in target "unfinished-loop-2" from moderrs.mk:52 1 2 3 make: Unclosed expression, expecting "}" for modifier "@var@${var}}...@" while evaluating variable "UNDEF" with value "1}... 2}... 3}..." in command "@echo ${UNDEF:U1 2 3:@var@${var}}...@" - in target "loop-close-1" + in target "loop-close-1" from moderrs.mk:64 1}... 2}... 3}... make: Unfinished modifier after "}", expecting "]" while evaluating variable "UNDEF" with value "1 2 3" in command "@echo ${UNDEF:U1 2 3:[}" - in target "words-1" + in target "words-1" from moderrs.mk:70 make: Unfinished modifier after "#}", expecting "]" while evaluating variable "UNDEF" with value "1 2 3" in command "@echo ${UNDEF:U1 2 3:[#}" - in target "words-2" + in target "words-2" from moderrs.mk:73 13= make: Invalid modifier ":[123451234512345123451234512345]" while evaluating variable "UNDEF" with value "1 2 3" in command "@echo 12345=${UNDEF:U1 2 3:[123451234512345123451234512345]:S,^$,ok,:S,^3$,ok,}" - in target "words-3" + in target "words-3" from moderrs.mk:96 make: Unfinished modifier after "echo}", expecting "!" while evaluating variable "VARNAME" with value "" in command "@echo ${VARNAME:!echo}" - in target "exclam-1" + in target "exclam-1" from moderrs.mk:100 make: Unfinished modifier after "=exclam}", expecting "!" while evaluating variable "!" with value "!" in command "@echo ${!:L:!=exclam}" - in target "exclam-2" + in target "exclam-2" from moderrs.mk:107 make: Missing delimiter for modifier ":S" while evaluating variable "VAR" with value "TheVariable" in command "@echo 1: ${VAR:S" - in target "mod-subst-delimiter-1" + in target "mod-subst-delimiter-1" from moderrs.mk:111 make: Unfinished modifier after "", expecting "," while evaluating variable "VAR" with value "TheVariable" in command "@echo 2: ${VAR:S," - in target "mod-subst-delimiter-2" + in target "mod-subst-delimiter-2" from moderrs.mk:114 make: Unfinished modifier after "from", expecting "," while evaluating variable "VAR" with value "TheVariable" in command "@echo 3: ${VAR:S,from" - in target "mod-subst-delimiter-3" + in target "mod-subst-delimiter-3" from moderrs.mk:117 make: Unfinished modifier after "", expecting "," while evaluating variable "VAR" with value "TheVariable" in command "@echo 4: ${VAR:S,from," - in target "mod-subst-delimiter-4" + in target "mod-subst-delimiter-4" from moderrs.mk:120 make: Unfinished modifier after "to", expecting "," while evaluating variable "VAR" with value "TheVariable" in command "@echo 5: ${VAR:S,from,to" - in target "mod-subst-delimiter-5" + in target "mod-subst-delimiter-5" from moderrs.mk:123 make: Unclosed expression, expecting "}" for modifier "S,from,to," while evaluating variable "VAR" with value "TheVariable" in command "@echo 6: ${VAR:S,from,to," - in target "mod-subst-delimiter-6" + in target "mod-subst-delimiter-6" from moderrs.mk:126 7: TheVariable make: Missing delimiter for modifier ":C" while evaluating variable "VAR" with value "TheVariable" in command "@echo 1: ${VAR:C" - in target "mod-regex-delimiter-1" + in target "mod-regex-delimiter-1" from moderrs.mk:132 make: Unfinished modifier after "", expecting "," while evaluating variable "VAR" with value "TheVariable" in command "@echo 2: ${VAR:C," - in target "mod-regex-delimiter-2" + in target "mod-regex-delimiter-2" from moderrs.mk:135 make: Unfinished modifier after "from", expecting "," while evaluating variable "VAR" with value "TheVariable" in command "@echo 3: ${VAR:C,from" - in target "mod-regex-delimiter-3" + in target "mod-regex-delimiter-3" from moderrs.mk:138 make: Unfinished modifier after "", expecting "," while evaluating variable "VAR" with value "TheVariable" in command "@echo 4: ${VAR:C,from," - in target "mod-regex-delimiter-4" + in target "mod-regex-delimiter-4" from moderrs.mk:141 make: Unfinished modifier after "to", expecting "," while evaluating variable "VAR" with value "TheVariable" in command "@echo 5: ${VAR:C,from,to" - in target "mod-regex-delimiter-5" + in target "mod-regex-delimiter-5" from moderrs.mk:144 make: Unclosed expression, expecting "}" for modifier "C,from,to," while evaluating variable "VAR" with value "TheVariable" in command "@echo 6: ${VAR:C,from,to," - in target "mod-regex-delimiter-6" + in target "mod-regex-delimiter-6" from moderrs.mk:147 7: TheVariable 112358132134 15152535558513521534 make: Unknown modifier ":ts\65oct" while evaluating variable "FIB" with value "1 1 2 3 5 8 13 21 34" in command "@echo ${FIB:ts\65oct} # bad modifier" - in target "mod-ts-parse-3" + in target "mod-ts-parse-3" from moderrs.mk:157 make: Unknown modifier ":ts\65oct" while evaluating "${:U${FIB}:ts\65oct} # bad modifier, variable name is """ with value "1 1 2 3 5 8 13 21 34" in command "@echo ${:U${FIB}:ts\65oct} # bad modifier, variable name is """ - in target "mod-ts-parse-4" + in target "mod-ts-parse-4" from moderrs.mk:160 make: Unknown modifier ":tsxy" while evaluating variable "FIB" with value "1 1 2 3 5 8 13 21 34" in command "@echo ${FIB:tsxy} # modifier too long" - in target "mod-ts-parse-5" + in target "mod-ts-parse-5" from moderrs.mk:163 make: Unknown modifier ":t" while evaluating variable "FIB" with value "1 1 2 3 5 8 13 21 34" in command "@echo ${FIB:t" - in target "mod-t-parse-1" + in target "mod-t-parse-1" from moderrs.mk:167 make: Unknown modifier ":txy" while evaluating variable "FIB" with value "1 1 2 3 5 8 13 21 34" in command "@echo ${FIB:txy}" - in target "mod-t-parse-2" + in target "mod-t-parse-2" from moderrs.mk:170 make: Unknown modifier ":t" while evaluating variable "FIB" with value "1 1 2 3 5 8 13 21 34" in command "@echo ${FIB:t}" - in target "mod-t-parse-3" + in target "mod-t-parse-3" from moderrs.mk:173 make: Unknown modifier ":t" while evaluating variable "FIB" with value "1 1 2 3 5 8 13 21 34" in command "@echo ${FIB:t:M*}" - in target "mod-t-parse-4" + in target "mod-t-parse-4" from moderrs.mk:176 make: Unfinished modifier after "", expecting ":" while evaluating then-branch of condition "FIB" in command "@echo ${FIB:?" - in target "mod-ifelse-parse-1" + in target "mod-ifelse-parse-1" from moderrs.mk:180 make: Unfinished modifier after "then", expecting ":" while evaluating then-branch of condition "FIB" in command "@echo ${FIB:?then" - in target "mod-ifelse-parse-2" + in target "mod-ifelse-parse-2" from moderrs.mk:183 make: Unfinished modifier after "", expecting "}" while evaluating else-branch of condition "FIB" in command "@echo ${FIB:?then:" - in target "mod-ifelse-parse-3" + in target "mod-ifelse-parse-3" from moderrs.mk:186 make: Unfinished modifier after "else", expecting "}" while evaluating else-branch of condition "FIB" in command "@echo ${FIB:?then:else" - in target "mod-ifelse-parse-4" + in target "mod-ifelse-parse-4" from moderrs.mk:189 then 1 1 2 3 5 8 13 21 34 make: Unknown modifier ":__" while evaluating variable "FIB" with value "1 1 2 3 5 8 13 21 34" in command "@echo ${FIB:__} # modifier name too long" - in target "mod-remember-parse" + in target "mod-remember-parse" from moderrs.mk:196 make: Unknown modifier ":3" while evaluating variable "FIB" with value "1 1 2 3 5 8 13 21 34" in command "@echo ${FIB:3" - in target "mod-sysv-parse-1" + in target "mod-sysv-parse-1" from moderrs.mk:200 make: Unfinished modifier after "", expecting "}" while evaluating variable "FIB" with value "1 1 2 3 5 8 13 21 34" in command "@echo ${FIB:3=" - in target "mod-sysv-parse-2" + in target "mod-sysv-parse-2" from moderrs.mk:203 make: Unfinished modifier after "x3", expecting "}" while evaluating variable "FIB" with value "1 1 2 3 5 8 13 21 34" in command "@echo ${FIB:3=x3" - in target "mod-sysv-parse-3" + in target "mod-sysv-parse-3" from moderrs.mk:206 1 1 2 x3 5 8 1x3 21 34 exit status 2 diff --git a/unit-tests/opt-chdir.mk b/unit-tests/opt-chdir.mk index e94b8799af2e..19055aba0824 100644 --- a/unit-tests/opt-chdir.mk +++ b/unit-tests/opt-chdir.mk @@ -1,4 +1,4 @@ -# $NetBSD: opt-chdir.mk,v 1.7 2024/04/02 11:11:00 rillig Exp $ +# $NetBSD: opt-chdir.mk,v 1.8 2026/02/10 21:22:13 sjg Exp $ # # Tests for the -C command line option, which changes the directory at the # beginning. @@ -13,8 +13,10 @@ all: chdir-nonexistent # Changing to another directory is possible via the command line. # In this test, it is the root directory since almost any other directory # is not guaranteed to exist on every platform. +# Force MAKEOBJDIRPREFIX=/ to avoid looking elsewhere for .OBJDIR chdir-root: .PHONY .IGNORE - @MAKE_OBJDIR_CHECK_WRITABLE=no ${MAKE} -C / -V 'cwd: $${.CURDIR}' + @MAKE_OBJDIR_CHECK_WRITABLE=no MAKEOBJDIRPREFIX=/ \ + ${MAKE} -C / -V 'cwd: $${.CURDIR}' # Trying to change to a nonexistent directory exits immediately. # Note: just because the whole point of /nonexistent is that it should diff --git a/unit-tests/opt-debug-graph1.exp b/unit-tests/opt-debug-graph1.exp index 9dae95302318..43c49a957ebb 100644 --- a/unit-tests/opt-debug-graph1.exp +++ b/unit-tests/opt-debug-graph1.exp @@ -29,6 +29,7 @@ .MAKE.OS = <details omitted> .MAKE.PID = <details omitted> .MAKE.PPID = <details omitted> +.MAKE.SAVE_DOLLARS = <details omitted> .MAKE.UID = <details omitted> .MAKEFLAGS = -r -k -d g1 .MAKEOVERRIDES = # (empty) diff --git a/unit-tests/opt-debug-graph2.exp b/unit-tests/opt-debug-graph2.exp index e4160e413787..6fd8de68fd98 100644 --- a/unit-tests/opt-debug-graph2.exp +++ b/unit-tests/opt-debug-graph2.exp @@ -63,6 +63,7 @@ all : made-target error-target aborted-target .MAKE.OS = <details omitted> .MAKE.PID = <details omitted> .MAKE.PPID = <details omitted> +.MAKE.SAVE_DOLLARS = <details omitted> .MAKE.UID = <details omitted> .MAKEFLAGS = -r -k -d g2 .MAKEOVERRIDES = # (empty) diff --git a/unit-tests/opt-debug-graph3.exp b/unit-tests/opt-debug-graph3.exp index ccebfd7b16bc..8ce5d2e5cfa5 100644 --- a/unit-tests/opt-debug-graph3.exp +++ b/unit-tests/opt-debug-graph3.exp @@ -63,6 +63,7 @@ all : made-target error-target aborted-target .MAKE.OS = <details omitted> .MAKE.PID = <details omitted> .MAKE.PPID = <details omitted> +.MAKE.SAVE_DOLLARS = <details omitted> .MAKE.UID = <details omitted> .MAKEFLAGS = -r -k -d g3 .MAKEOVERRIDES = # (empty) diff --git a/unit-tests/opt-debug-jobs.exp b/unit-tests/opt-debug-jobs.exp index 6cda45107702..0e818245246f 100644 --- a/unit-tests/opt-debug-jobs.exp +++ b/unit-tests/opt-debug-jobs.exp @@ -1,6 +1,7 @@ job_pipe -1 -1, maxjobs 1, tokens 1, compat 0 TokenPool_Take: pid <pid>, aborting NONE, running 0 TokenPool_Take: pid <pid> took a token +MaybeSubMake: Looking for "make" echo ": expanded expression" { : expanded expression } || exit $? diff --git a/unit-tests/opt-jobs-internal.exp b/unit-tests/opt-jobs-internal.exp index 61c96256a2e4..a13d44bb38ed 100644 --- a/unit-tests/opt-jobs-internal.exp +++ b/unit-tests/opt-jobs-internal.exp @@ -3,12 +3,12 @@ make: error: invalid internal option "-J garbage" in "<curdir>" make: warning: Invalid internal option "-J" in "<curdir>"; see the manual page in make[2] in directory "<curdir>" direct-open: mode=compat -make: warning: Invalid internal option "-J" in "<curdir>"; see the manual page - in make[2] in directory "<curdir>" +.make[2]: warning: Invalid internal option "-J" in "<curdir>"; see the manual page + in .make[2] in directory "<curdir>" indirect-open: mode=compat indirect-expr: mode=parallel -make: warning: Invalid internal option "-J" in "<curdir>"; see the manual page - in make[2] in directory "<curdir>" +.make[2]: warning: Invalid internal option "-J" in "<curdir>"; see the manual page + in .make[2] in directory "<curdir>" indirect-comment: mode=compat indirect-silent-comment: mode=parallel indirect-expr-empty: mode=parallel diff --git a/unit-tests/opt-jobs-internal.mk b/unit-tests/opt-jobs-internal.mk index 13db820f86c1..4a1c39c75cd7 100644 --- a/unit-tests/opt-jobs-internal.mk +++ b/unit-tests/opt-jobs-internal.mk @@ -1,9 +1,12 @@ -# $NetBSD: opt-jobs-internal.mk,v 1.6 2025/05/23 21:05:56 rillig Exp $ +# $NetBSD: opt-jobs-internal.mk,v 1.10 2026/03/10 05:02:00 sjg Exp $ # # Tests for the (intentionally undocumented) internal -J command line option. +.if ${DEBUG_TEST:U:M${.PARSEFILE:R}} != "" +.MAKEFLAGS: -djg2 +.endif -# This test expects -.MAKE.ALWAYS_PASS_JOB_QUEUE= no +_make ?= .make${.MAKE.PID} +.export _make all: .PHONY @${MAKE} -f ${MAKEFILE} -j1 direct @@ -14,6 +17,7 @@ all: .PHONY @${MAKE} -f ${MAKEFILE} -j1 indirect-comment @${MAKE} -f ${MAKEFILE} -j1 indirect-silent-comment @${MAKE} -f ${MAKEFILE} -j1 indirect-expr-empty + @rm -f ${_make} detect-mode: .PHONY @mode=parallel @@ -33,8 +37,8 @@ direct-open: .PHONY @${MAKE} -f ${MAKEFILE} -J 31,32 detect-mode HEADING=${.TARGET} # expect: indirect-open: mode=compat -indirect-open: .PHONY - @${MAKE:U} -f ${MAKEFILE} detect-mode HEADING=${.TARGET} +indirect-open: .PHONY ${_make} + @./${_make} -f ${MAKEFILE} detect-mode HEADING=${.TARGET} # When a command in its unexpanded form contains the expression "${MAKE}" # without any modifiers, the file descriptors get passed around. @@ -45,9 +49,9 @@ indirect-expr: .PHONY # The "# make" comment starts directly after the leading tab and is thus not # considered a shell command line. No file descriptors are passed around. # expect: indirect-comment: mode=compat -indirect-comment: .PHONY +indirect-comment: .PHONY ${_make} # make - @${MAKE:U} -f ${MAKEFILE} detect-mode HEADING=${.TARGET} + @./${_make} -f ${MAKEFILE} detect-mode HEADING=${.TARGET} # When the "# make" comment is prefixed with "@", it becomes a shell command. # As that shell command contains the plain word "make", the file descriptors @@ -57,9 +61,12 @@ indirect-silent-comment: .PHONY @# make @${MAKE:U} -f ${MAKEFILE} detect-mode HEADING=${.TARGET} -# When a command in its unexpanded form contains the plain word "make", the -# file descriptors get passed around. # expect: indirect-expr-empty: mode=parallel indirect-expr-empty: .PHONY - @${:D make} @${MAKE:U} -f ${MAKEFILE} detect-mode HEADING=${.TARGET} + +${_make}: + @ln -s ${MAKE} ${.TARGET} + +# This test expects +.MAKE.ALWAYS_PASS_JOB_QUEUE= no diff --git a/unit-tests/opt-where-am-i.mk b/unit-tests/opt-where-am-i.mk index f1eeca920a32..1d849b8d8047 100644 --- a/unit-tests/opt-where-am-i.mk +++ b/unit-tests/opt-where-am-i.mk @@ -1,4 +1,4 @@ -# $NetBSD: opt-where-am-i.mk,v 1.4 2022/01/27 02:24:46 sjg Exp $ +# $NetBSD: opt-where-am-i.mk,v 1.5 2026/02/10 22:33:36 sjg Exp $ # # Tests for the -w command line option, which outputs the current directory # at the beginning and end of running make. This is useful when building @@ -6,9 +6,11 @@ # The first "Entering directory" is missing since the below .MAKEFLAGS comes # too late for it. +# We force MAKEOBJDIRPREFIX=/ to avoid looking elsewhere for .OBJDIR .MAKEFLAGS: -w all: .if ${.CURDIR} != "/" - @MAKE_OBJDIR_CHECK_WRITABLE=no ${MAKE} -r -f ${MAKEFILE:tA} -C / + @MAKE_OBJDIR_CHECK_WRITABLE=no MAKEOBJDIRPREFIX=/ \ + ${MAKE} -r -f ${MAKEFILE:tA} -C / .endif diff --git a/unit-tests/opt.exp b/unit-tests/opt.exp index daeecc8ca726..0680cbc2761f 100644 --- a/unit-tests/opt.exp +++ b/unit-tests/opt.exp @@ -1,11 +1,12 @@ -make -r -f /dev/null -V MAKEFLAGS - -r -k -d 0 +make -r -f /dev/null -V 'begin ${MAKEFLAGS} end' +begin -r -k -d 0 end make -: usage: make [-BeikNnqrSstWwX] [-C directory] [-D variable] [-d flags] [-f makefile] - [-I directory] [-J private] [-j max_jobs] [-m directory] [-T file] - [-V variable] [-v variable] [variable=value] [target ...] + [-I directory] [-J private] [-j max_jobs] [-m directory] + [-T file] [-V variable] [-v variable] + [variable=value ...] [target ...] *** Error code 2 (ignored) make -r -f /dev/null -- -VAR=value -f /dev/null @@ -19,8 +20,9 @@ make: stopped making "-f /dev/null" in unit-tests make -? usage: make [-BeikNnqrSstWwX] [-C directory] [-D variable] [-d flags] [-f makefile] - [-I directory] [-J private] [-j max_jobs] [-m directory] [-T file] - [-V variable] [-v variable] [variable=value] [target ...] + [-I directory] [-J private] [-j max_jobs] [-m directory] + [-T file] [-V variable] [-v variable] + [variable=value ...] [target ...] *** Error code 2 (ignored) exit status 0 diff --git a/unit-tests/opt.mk b/unit-tests/opt.mk index 939d5ec35aeb..e7861fffbf84 100644 --- a/unit-tests/opt.mk +++ b/unit-tests/opt.mk @@ -1,4 +1,4 @@ -# $NetBSD: opt.mk,v 1.7 2023/02/25 00:07:08 rillig Exp $ +# $NetBSD: opt.mk,v 1.8 2026/02/08 11:02:03 rillig Exp $ # # Tests for the command line options. @@ -8,7 +8,7 @@ all: .IGNORE # The options from the top-level make are passed to the sub-makes via # the environment variable MAKEFLAGS. This is where the " -r -k -d 0" # comes from. See MainParseOption. - ${MAKE} -r -f /dev/null -V MAKEFLAGS + ${MAKE} -r -f /dev/null -V 'begin $${MAKEFLAGS} end' @echo # Just to see how the custom argument parsing code reacts to a syntax diff --git a/unit-tests/sh-errctl.exp b/unit-tests/sh-errctl.exp index 8419d215fe38..6dfa3fafc85f 100644 --- a/unit-tests/sh-errctl.exp +++ b/unit-tests/sh-errctl.exp @@ -1,6 +1,7 @@ job_pipe -1 -1, maxjobs 1, tokens 1, compat 0 TokenPool_Take: pid <pid>, aborting NONE, running 0 TokenPool_Take: pid <pid> took a token +MaybeSubMake: Looking for "make" # echo off echo silent # echo on diff --git a/unit-tests/suff-main-several.exp b/unit-tests/suff-main-several.exp index bb1fc91ea21d..a7bf6eb088e9 100644 --- a/unit-tests/suff-main-several.exp +++ b/unit-tests/suff-main-several.exp @@ -94,6 +94,7 @@ ParseDependency(.MAKEFLAGS: -d0 -dg1) .MAKE.OS = <details omitted> .MAKE.PID = <details omitted> .MAKE.PPID = <details omitted> +.MAKE.SAVE_DOLLARS = <details omitted> .MAKE.UID = <details omitted> .MAKEFLAGS = -r -k -d mps -d 0 -d g1 .MAKEOVERRIDES = # (empty) diff --git a/unit-tests/suff-transform-debug.exp b/unit-tests/suff-transform-debug.exp index ad0584f204d1..14d8b9050a08 100644 --- a/unit-tests/suff-transform-debug.exp +++ b/unit-tests/suff-transform-debug.exp @@ -20,6 +20,7 @@ .MAKE.OS = <details omitted> .MAKE.PID = <details omitted> .MAKE.PPID = <details omitted> +.MAKE.SAVE_DOLLARS = <details omitted> .MAKE.UID = <details omitted> .MAKEFLAGS = -r -k -d g1 .MAKEOVERRIDES = # (empty) diff --git a/unit-tests/var-recursive.exp b/unit-tests/var-recursive.exp index 97568873bf1b..768b41c4b0ff 100644 --- a/unit-tests/var-recursive.exp +++ b/unit-tests/var-recursive.exp @@ -23,7 +23,7 @@ sub-exit status 1 make: Variable VAR is recursive. while evaluating variable "VAR" with value "${VAR}" in command ": recursive-line-before <${VAR}> recursive-line-after" - in target "runtime" + in target "runtime" from var-recursive.mk:56 in make[1] in directory "<curdir>" sub-exit status 2 exit status 0 diff --git a/unit-tests/var-scope-local.exp b/unit-tests/var-scope-local.exp index eddf5985a0ed..dbf3f474d69e 100644 --- a/unit-tests/var-scope-local.exp +++ b/unit-tests/var-scope-local.exp @@ -67,5 +67,15 @@ Making var-scope-local-default.o with make 'global' and env 'global'. Making var-scope-local-subst.o with make 'global+local' and env 'global+local'. Making var-scope-local-shell.o with make 'output' and env 'output'. Making .USE var-scope-local-use.o with make 'global' and env 'global'. +begin pr-59073 compat +$@ is pr-59073/file.o59703 +$< is pr-59073/file.c59703 +$* is pr-59073/file +end pr-59073 compat +begin pr-59073 parallel +$@ is pr-59073/file.o59703 +$< is pr-59073/file.c59703 +$* is file +end pr-59073 parallel : all overwritten exit status 0 diff --git a/unit-tests/var-scope-local.mk b/unit-tests/var-scope-local.mk index 7a031373e7da..be10c4c9f7da 100644 --- a/unit-tests/var-scope-local.mk +++ b/unit-tests/var-scope-local.mk @@ -1,4 +1,4 @@ -# $NetBSD: var-scope-local.mk,v 1.11 2024/03/05 23:07:58 rillig Exp $ +# $NetBSD: var-scope-local.mk,v 1.12 2026/01/05 22:44:14 rillig Exp $ # # Tests for target-local variables, such as ${.TARGET} or $@. These variables # are relatively short-lived as they are created just before making the @@ -138,7 +138,9 @@ dir/subdir/inference-rule-chain.ir-gen-from: .PHONY # Custom local variables # # Additional target-local variables may be defined in dependency lines. +.if !make(pr-59703-mode) .MAKEFLAGS: -dv +.endif # In the following line, the ':=' may either be interpreted as an assignment # operator or as the dependency operator ':', followed by an empty variable # name and the assignment operator '='. It is the latter since in an @@ -154,7 +156,9 @@ one two:=three # word. # expect: Global: one two = three ${:Uone two}:=three +.if !make(pr-59703-mode) .MAKEFLAGS: -d0 +.endif .SUFFIXES: .c .o @@ -268,3 +272,44 @@ a_use: .USE VAR=use all: var-scope-local-use.o var-scope-local-use.o: a_use + + +# begin https://gnats.netbsd.org/59073 +# make(1) sets $* / $(.PREFIX) wrong in -j mode + +all: pr-59073 + +# expect: begin pr-59073 compat +# expect: $@ is pr-59073/file.o59703 +# expect: $< is pr-59073/file.c59703 +# expect: $* is pr-59073/file +# expect: end pr-59073 compat +# expect: begin pr-59073 parallel +# expect: $@ is pr-59073/file.o59703 +# expect: $< is pr-59073/file.c59703 +# FIXME: The subdirectory is missing. +# expect: $* is file +# expect: end pr-59073 parallel + +pr-59073: .PHONY + # This has to be an actual file; using a memory-only target + # generates the correct value for "$*". + @mkdir -p pr-59073 && touch pr-59073/file.c59703 + @echo begin pr-59073 compat + @MAKEFLAGS= ${MAKE} -r -f ${MAKEFILE} pr-59703-mode + @echo end pr-59073 compat + @echo begin pr-59073 parallel + @MAKEFLAGS= ${MAKE} -r -f ${MAKEFILE} -j1 pr-59703-mode + @echo end pr-59073 parallel + @rm -rf pr-59073 + +pr-59703-mode: pr-59073/file.o59703 + +.SUFFIXES: .c59703 .o59703 + +.c59703.o59703: + @echo '$$@ is $@' + @echo '$$< is $<' + @echo '$$* is $*' + +# end https://gnats.netbsd.org/59073 diff --git a/unit-tests/varmisc.exp b/unit-tests/varmisc.exp index 44b3c8e759cb..4d09e691de42 100644 --- a/unit-tests/varmisc.exp +++ b/unit-tests/varmisc.exp @@ -46,36 +46,36 @@ parse-dynamic: parse-dynamic parse-dynamic after varerror-unclosed-1:begin make: Unclosed variable "" in command "@echo $(" - in target "varerror-unclosed-2" + in target "varerror-unclosed-2" from varmisc.mk:195 make: Unclosed variable "UNCLOSED" in command "@echo $(UNCLOSED" - in target "varerror-unclosed-3" + in target "varerror-unclosed-3" from varmisc.mk:198 make: Unclosed variable "UNCLOSED" in command "@echo ${UNCLOSED" - in target "varerror-unclosed-4" + in target "varerror-unclosed-4" from varmisc.mk:201 make: Unclosed variable "PATTERN" while evaluating variable "UNCLOSED" with value "" in command "@echo ${UNCLOSED:M${PATTERN" - in target "varerror-unclosed-5" + in target "varerror-unclosed-5" from varmisc.mk:204 make: Unclosed expression, expecting "}" for modifier "M${PATTERN" while evaluating variable "UNCLOSED" with value "" in command "@echo ${UNCLOSED:M${PATTERN" - in target "varerror-unclosed-5" + in target "varerror-unclosed-5" from varmisc.mk:204 make: Unclosed variable "param" in command "@echo ${UNCLOSED.${param" - in target "varerror-unclosed-6" + in target "varerror-unclosed-6" from varmisc.mk:208 make: Unclosed variable "UNCLOSED." in command "@echo ${UNCLOSED.${param" - in target "varerror-unclosed-6" + in target "varerror-unclosed-6" from varmisc.mk:208 make: Unclosed variable "UNCLOSED.1" in command "@echo ${UNCLOSED.${:U1}" - in target "varerror-unclosed-7" + in target "varerror-unclosed-7" from varmisc.mk:213 make: Unclosed variable "UNCLOSED_ORIG" while evaluating variable "UNCLOSED_INDIR_1" with value "${UNCLOSED_ORIG" while evaluating variable "UNCLOSED_INDIR_2" with value "${UNCLOSED_INDIR_1}" in command "@echo ${UNCLOSED_INDIR_2}" - in target "varerror-unclosed-8" + in target "varerror-unclosed-8" from varmisc.mk:217 target1-flags: we have: one two target2-flags: we have: one two three four exit status 2 diff --git a/unit-tests/varmod-assign.exp b/unit-tests/varmod-assign.exp index ae7f6787d124..2cbd7e525449 100644 --- a/unit-tests/varmod-assign.exp +++ b/unit-tests/varmod-assign.exp @@ -40,30 +40,30 @@ Global: .MAKEFLAGS = -r -k -d v -d 0 -d v -d 0 make: Invalid attempt to assign "value" to variable "" via modifier "::=" while evaluating "${::=value}" with value "" in command "@echo $@: ${::=value}" - in target "mod-assign-empty-1" + in target "mod-assign-empty-1" from varmod-assign.mk:78 make: Invalid attempt to assign "overwritten" to variable "" via modifier "::=" while evaluating "${:Uvalue::=overwritten}" with value "value" in command "@echo $@: ${:Uvalue::=overwritten}" - in target "mod-assign-empty-2" + in target "mod-assign-empty-2" from varmod-assign.mk:84 make: Invalid attempt to assign "appended" to variable "" via modifier "::+=" while evaluating "${:Uvalue::+=appended}" with value "value" in command "@echo $@: ${:Uvalue::+=appended}" - in target "mod-assign-empty-3" + in target "mod-assign-empty-3" from varmod-assign.mk:90 mod-assign-empty-4: VAR=overwritten make: Unknown modifier "::x" while evaluating variable "ASSIGN" with value "" in command "@echo ${ASSIGN::x}" - in target "mod-assign-parse-1" + in target "mod-assign-parse-1" from varmod-assign.mk:103 sysv:y make: Unfinished modifier after "value # missing closing brace", expecting "}" while evaluating variable "ASSIGN" with value "" in command "@echo ${ASSIGN::=value # missing closing brace" - in target "mod-assign-parse-3" + in target "mod-assign-parse-3" from varmod-assign.mk:112 ok=word make: warning: Command " echo word; (exit 13) " exited with status 13 while evaluating variable "SH_ERR" with value "previous" in command "@${SH_ERR::!= echo word; (exit 13) } echo err=${SH_ERR}" - in target "mod-assign-shell-error" + in target "mod-assign-shell-error" from varmod-assign.mk:120 err=previous Command: TARGET_CMD_VAR = cmd-value Global: TARGET_GLOBAL_VAR = global-value diff --git a/unit-tests/varmod-hash.exp b/unit-tests/varmod-hash.exp index 1abc6bc92a9f..eb2490d27c3f 100644 --- a/unit-tests/varmod-hash.exp +++ b/unit-tests/varmod-hash.exp @@ -1,15 +1,15 @@ make: Unknown modifier ":has" while evaluating variable "12345" with value "12345" in command "@echo ${12345:L:has} # modifier name too short" - in target "step-1" + in target "step-1" from varmod-hash.mk:61 26bb0f5f 12345 make: Unknown modifier ":hasX" while evaluating variable "12345" with value "12345" in command "@echo ${12345:L:hasX} # misspelled" - in target "step-4" + in target "step-4" from varmod-hash.mk:67 make: Unknown modifier ":hashed" while evaluating variable "12345" with value "12345" in command "@echo ${12345:L:hashed} # modifier name too long" - in target "step-5" + in target "step-5" from varmod-hash.mk:69 exit status 2 diff --git a/unit-tests/varmod-loop-delete.exp b/unit-tests/varmod-loop-delete.exp index daacafc35561..7f31a606c10c 100644 --- a/unit-tests/varmod-loop-delete.exp +++ b/unit-tests/varmod-loop-delete.exp @@ -1,6 +1,12 @@ -make: varmod-loop-delete.mk:20: Cannot delete variable "VAR" while it is used +make -f varmod-loop-delete.mk delete-active-variable || true +make: varmod-loop-delete.mk:31: Cannot delete variable "VAR" while it is used while evaluating "${:U:@VAR@@} rest of the value" with value "" while evaluating variable "VAR" with value "${:U:@VAR@@} rest of the value" + in make[1] in directory "<curdir>" make: Fatal errors encountered -- cannot continue -make: stopped making "all" in unit-tests -exit status 1 +make: stopped making "delete-active-variable" in unit-tests + +make -f varmod-loop-delete.mk delete-active-variable-in-target || true +: delete-active-variable-in-target: ' rest of the value' + +exit status 0 diff --git a/unit-tests/varmod-loop-delete.mk b/unit-tests/varmod-loop-delete.mk index 478a25e91f6e..7b7dc0a77b25 100644 --- a/unit-tests/varmod-loop-delete.mk +++ b/unit-tests/varmod-loop-delete.mk @@ -1,4 +1,4 @@ -# $NetBSD: varmod-loop-delete.mk,v 1.7 2024/08/29 20:20:36 rillig Exp $ +# $NetBSD: varmod-loop-delete.mk,v 1.9 2026/02/09 22:04:54 rillig Exp $ # # Tests for the variable modifier ':@', which as a side effect allows to # delete an arbitrary variable. @@ -11,6 +11,17 @@ # # See Var_Parse, comment 'the value of the variable must not change'. +all: .PHONY + ${MAKE} -f ${MAKEFILE} delete-active-variable || true + @echo + ${MAKE} -f ${MAKEFILE} delete-active-variable-in-target || true + @echo + # Disabled since the details of the crash depend on the execution + # environment. + #${MAKE} -f ${MAKEFILE} use-after-free + +delete-active-variable: .PHONY +.if make(delete-active-variable) # Set up the variable that deletes itself when it is evaluated. VAR= ${:U:@VAR@@} rest of the value @@ -18,12 +29,16 @@ VAR= ${:U:@VAR@@} rest of the value # defined in the global scope, it deletes itself. # expect+1: Cannot delete variable "VAR" while it is used EVAL:= ${VAR} -.if ${EVAL} != " rest of the value" -. error +. if ${EVAL} != " rest of the value" +. error +. endif .endif +delete-active-variable-in-target: .PHONY +.if make(delete-active-variable-in-target) VAR= ${:U:@VAR@@} rest of the value -all: .PHONY + +delete-active-variable-in-target: # In the command that is associated with a target, the scope is the # one from the target. That scope only contains a few variables like # '.TARGET', '.ALLSRC', '.IMPSRC'. Make does not expect that these @@ -32,3 +47,28 @@ all: .PHONY # There is no variable named 'VAR' in the local scope, so nothing # happens. : $@: '${VAR}' +# expect: : delete-active-variable-in-target: ' rest of the value' +.endif + + +# On NetBSD 11.99.x with jemalloc and MALLOC_CONF=junk:true, the output is: +# make: varmod-loop-delete.mk:72: Unknown modifier ":Z2" +# while evaluating "${:U 333 :@v@...${:Z1}@:Z2}" with value "...${:Z1}" +# while evaluating variable "INNER.1" with value "${:U 333 :@v@...${:Z1}@:Z2}" +# while evaluating variable "ZZZZZZZZZZZZ...${:Z1}" with value "ZZZZZZZZ" +# while evaluating "${:U 111 222 :@v@${v:S,^,${INNER.1},}@}" with value " 111 222 " +# while evaluating variable "OUTER" with value "${:U 111 222 :@v@${v:S,^,${INNER.1},}@}" +# in make in directory "<curdir>" +# Modifier part: "" +# ModifyWords: split "ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ" into 1 word +# Result of ${ZZZZZZZZZZZZ:S,^,${INNER.1},} is "ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ" (eval-keep-undefined, regular) +# Segmentation fault (core dumped) +use-after-free: .PHONY +.if make(use-after-free) +OUTER= ${:U 111 222 :@v@${v:S,^,${INNER.1},}@} +INNER.1= ${:U 333 :@v@...${:Z1}@:Z2} + +.MAKEFLAGS: -dcpv +_:= ${OUTER} +.MAKEFLAGS: -d0 +.endif diff --git a/unit-tests/varmod-select-words.exp b/unit-tests/varmod-select-words.exp index 4ac95ead0852..b731baf8869f 100644 --- a/unit-tests/varmod-select-words.exp +++ b/unit-tests/varmod-select-words.exp @@ -1,7 +1,7 @@ make: Invalid modifier ":[]" while evaluating variable "LIST" with value "one two three four five six" in command "@echo 'LIST:[]="${LIST:[]}" is an error'" - in target "mod-squarebrackets-empty" + in target "mod-squarebrackets-empty" from varmod-select-words.mk:54 LIST:[0]="one two three four five six" LIST:[0x0]="one two three four five six" LIST:[000]="one two three four five six" @@ -42,11 +42,11 @@ LIST:[1]="one" make: Invalid modifier ":[1.]" while evaluating variable "LIST" with value "one two three four five six" in command "@echo 'LIST:[1.]="${LIST:[1.]}" is an error'" - in target "mod-squarebrackets-n-error-1" + in target "mod-squarebrackets-n-error-1" from varmod-select-words.mk:100 make: Extra text after "[1]" while evaluating variable "LIST" with value "one two three four five six" in command "@echo 'LIST:[1].="${LIST:[1].}" is an error'" - in target "mod-squarebrackets-n-error-2" + in target "mod-squarebrackets-n-error-2" from varmod-select-words.mk:103 LIST:[2]="two" LIST:[6]="six" LIST:[7]="" @@ -54,11 +54,11 @@ LIST:[999]="" make: Invalid modifier ":[-]" while evaluating variable "LIST" with value "one two three four five six" in command "@echo 'LIST:[-]="${LIST:[-]}" is an error'" - in target "mod-squarebrackets-n-error-3" + in target "mod-squarebrackets-n-error-3" from varmod-select-words.mk:111 make: Invalid modifier ":[--]" while evaluating variable "LIST" with value "one two three four five six" in command "@echo 'LIST:[--]="${LIST:[--]}" is an error'" - in target "mod-squarebrackets-n-error-4" + in target "mod-squarebrackets-n-error-4" from varmod-select-words.mk:114 LIST:[-1]="six" LIST:[-2]="five" LIST:[-6]="one" @@ -80,20 +80,20 @@ LONGLIST:[012..0x12]="10 11 12 13 14 15 16 17 18" make: Invalid modifier ":[1.]" while evaluating variable "LIST" with value "one two three four five six" in command "@echo 'LIST:[1.]="${LIST:[1.]}" is an error'" - in target "mod-squarebrackets-start-end-error-1" + in target "mod-squarebrackets-start-end-error-1" from varmod-select-words.mk:137 make: Invalid modifier ":[1..]" while evaluating variable "LIST" with value "one two three four five six" in command "@echo 'LIST:[1..]="${LIST:[1..]}" is an error'" - in target "mod-squarebrackets-start-end-error-2" + in target "mod-squarebrackets-start-end-error-2" from varmod-select-words.mk:140 make: Invalid modifier ":[1.. ]" while evaluating variable "LIST" with value "one two three four five six" in command "@echo 'LIST:[1.. ]="${LIST:[1.. ]}" is an error'" - in target "mod-squarebrackets-start-end-error-3" + in target "mod-squarebrackets-start-end-error-3" from varmod-select-words.mk:143 LIST:[1..1]="one" make: Invalid modifier ":[1..1.]" while evaluating variable "LIST" with value "one two three four five six" in command "@echo 'LIST:[1..1.]="${LIST:[1..1.]}" is an error'" - in target "mod-squarebrackets-start-end-error-4" + in target "mod-squarebrackets-start-end-error-4" from varmod-select-words.mk:148 LIST:[1..2]="one two" LIST:[2..1]="two one" LIST:[3..-2]="three four five" @@ -101,11 +101,11 @@ LIST:[-4..4]="three four" make: Invalid modifier ":[0..1]" while evaluating variable "LIST" with value "one two three four five six" in command "@echo 'LIST:[0..1]="${LIST:[0..1]}" is an error'" - in target "mod-squarebrackets-start-end-error-5" + in target "mod-squarebrackets-start-end-error-5" from varmod-select-words.mk:156 make: Invalid modifier ":[-1..0]" while evaluating variable "LIST" with value "one two three four five six" in command "@echo 'LIST:[-1..0]="${LIST:[-1..0]}" is an error'" - in target "mod-squarebrackets-start-end-error-6" + in target "mod-squarebrackets-start-end-error-6" from varmod-select-words.mk:159 LIST:[-1..1]="six five four three two one" LIST:[0..0]="one two three four five six" LIST:[3..99]="three four five six" @@ -122,7 +122,7 @@ LIST:[${AT}]="one two three four five six" make: Invalid modifier ":[]" while evaluating variable "LIST" with value "one two three four five six" in command "@echo 'LIST:[$${EMPTY}]="${LIST:[${EMPTY}]}" is an error'" - in target "mod-squarebrackets-nested-error-1" + in target "mod-squarebrackets-nested-error-1" from varmod-select-words.mk:178 LIST:[${LONGLIST:[21]:S/2//}]="one" LIST:[${LIST:[#]}]="six" LIST:[${LIST:[${HASH}]}]="six" diff --git a/unit-tests/varmod-subst-regex.exp b/unit-tests/varmod-subst-regex.exp index 816b02248591..c8bc2ac035ea 100644 --- a/unit-tests/varmod-subst-regex.exp +++ b/unit-tests/varmod-subst-regex.exp @@ -1,67 +1,67 @@ make: Regex compilation error: (details omitted) while evaluating "${:Uword1 word2:C,****,____,g:C,word,____,:Q}." with value "word1 word2" in command "@echo $@: ${:Uword1 word2:C,****,____,g:C,word,____,:Q}." - in target "mod-regex-compile-error" + in target "mod-regex-compile-error" from varmod-subst-regex.mk:154 make: No subexpression \1 while evaluating "${:U1 23 456:C,..,\1\1,:Q}" with value "1 23 456" in command "@echo $@:11-missing:${:U1 23 456:C,..,\1\1,:Q}" - in target "mod-regex-limits-1" + in target "mod-regex-limits-1" from varmod-subst-regex.mk:159 make: No subexpression \1 while evaluating "${:U1 23 456:C,..,\1\1,:Q}" with value "1 23 456" in command "@echo $@:11-missing:${:U1 23 456:C,..,\1\1,:Q}" - in target "mod-regex-limits-1" + in target "mod-regex-limits-1" from varmod-subst-regex.mk:159 make: No subexpression \1 while evaluating "${:U1 23 456:C,..,\1\1,:Q}" with value "1 23 456" in command "@echo $@:11-missing:${:U1 23 456:C,..,\1\1,:Q}" - in target "mod-regex-limits-1" + in target "mod-regex-limits-1" from varmod-subst-regex.mk:159 make: No subexpression \1 while evaluating "${:U1 23 456:C,..,\1\1,:Q}" with value "1 23 456" in command "@echo $@:11-missing:${:U1 23 456:C,..,\1\1,:Q}" - in target "mod-regex-limits-1" + in target "mod-regex-limits-1" from varmod-subst-regex.mk:159 mod-regex-limits-2:11-ok:1 22 446 make: No subexpression \2 while evaluating "${:U1 23 456:C,..,\2\2,:Q}" with value "1 23 456" in command "@echo $@:22-missing:${:U1 23 456:C,..,\2\2,:Q}" - in target "mod-regex-limits-3" + in target "mod-regex-limits-3" from varmod-subst-regex.mk:163 make: No subexpression \2 while evaluating "${:U1 23 456:C,..,\2\2,:Q}" with value "1 23 456" in command "@echo $@:22-missing:${:U1 23 456:C,..,\2\2,:Q}" - in target "mod-regex-limits-3" + in target "mod-regex-limits-3" from varmod-subst-regex.mk:163 make: No subexpression \2 while evaluating "${:U1 23 456:C,..,\2\2,:Q}" with value "1 23 456" in command "@echo $@:22-missing:${:U1 23 456:C,..,\2\2,:Q}" - in target "mod-regex-limits-3" + in target "mod-regex-limits-3" from varmod-subst-regex.mk:163 make: No subexpression \2 while evaluating "${:U1 23 456:C,..,\2\2,:Q}" with value "1 23 456" in command "@echo $@:22-missing:${:U1 23 456:C,..,\2\2,:Q}" - in target "mod-regex-limits-3" + in target "mod-regex-limits-3" from varmod-subst-regex.mk:163 make: No subexpression \2 while evaluating "${:U1 23 456:C,(.).,\2\2,:Q}" with value "1 23 456" in command "@echo $@:22-missing:${:U1 23 456:C,(.).,\2\2,:Q}" - in target "mod-regex-limits-4" + in target "mod-regex-limits-4" from varmod-subst-regex.mk:165 make: No subexpression \2 while evaluating "${:U1 23 456:C,(.).,\2\2,:Q}" with value "1 23 456" in command "@echo $@:22-missing:${:U1 23 456:C,(.).,\2\2,:Q}" - in target "mod-regex-limits-4" + in target "mod-regex-limits-4" from varmod-subst-regex.mk:165 make: No subexpression \2 while evaluating "${:U1 23 456:C,(.).,\2\2,:Q}" with value "1 23 456" in command "@echo $@:22-missing:${:U1 23 456:C,(.).,\2\2,:Q}" - in target "mod-regex-limits-4" + in target "mod-regex-limits-4" from varmod-subst-regex.mk:165 make: No subexpression \2 while evaluating "${:U1 23 456:C,(.).,\2\2,:Q}" with value "1 23 456" in command "@echo $@:22-missing:${:U1 23 456:C,(.).,\2\2,:Q}" - in target "mod-regex-limits-4" + in target "mod-regex-limits-4" from varmod-subst-regex.mk:165 mod-regex-limits-5:22-ok:1 33 556 mod-regex-limits-6:capture:ihgfedcbaabcdefghijABCDEFGHIJa0a1a2rest make: Regex compilation error: (details omitted) while evaluating variable "UNDEF" with value "value" in command "@echo $@: ${UNDEF:Uvalue:C,[,,}" - in target "mod-regex-errors-1" + in target "mod-regex-errors-1" from varmod-subst-regex.mk:174 make: Unknown modifier ":Z" while evaluating "${:U:Z}y,W}" with value "" while evaluating variable "word" with value "word" in command "@echo $@: ${word:L:C,.*,x${:U:Z}y,W}" - in target "mod-regex-errors-2" + in target "mod-regex-errors-2" from varmod-subst-regex.mk:179 unmatched-subexpression.ok: one one 2 3 5 8 one3 2one 34 make: No match for subexpression \2 unmatched-subexpression.1: ()() diff --git a/unit-tests/varmod-subst-regex.mk b/unit-tests/varmod-subst-regex.mk index bc04bc5fffb9..5af0236975bb 100644 --- a/unit-tests/varmod-subst-regex.mk +++ b/unit-tests/varmod-subst-regex.mk @@ -1,6 +1,6 @@ -# $NetBSD: varmod-subst-regex.mk,v 1.12 2024/07/20 11:05:12 rillig Exp $ +# $NetBSD: varmod-subst-regex.mk,v 1.13 2026/01/03 22:40:38 rillig Exp $ # -# Tests for the :C,from,to, variable modifier. +# Tests for the :C,from,to, modifier. # report unmatched subexpressions .MAKEFLAGS: -dL @@ -23,7 +23,7 @@ all: unmatched-subexpression . error .endif -# The 'W' modifier treats the whole variable value as a single big word, +# The 'W' modifier treats the whole expression value as a single big word, # containing whitespace. This big word matches the regular expression, # therefore it gets replaced. Whitespace is preserved after replacing. .if ${:Ua b b c:C,a b,,W} != " b c" @@ -60,14 +60,16 @@ all: unmatched-subexpression # The modifier '1' applies the replacement at most once, across the whole # expression value, no matter whether it is a single big word or many small # words. -# -# Up to 2020-08-28, the manual page said that the modifiers '1' and 'g' -# were orthogonal, which was wrong. It doesn't make sense to specify both -# 'g' and '1' at the same time. .if ${:U12345 12345:C,.,\0\0,1} != "112345 12345" . error .endif +# When both '1' and 'g' are given, this means to replace all occurrences, +# but only in the first word where they are found, not in any remaining words. +.if ${:U 11111 22222 22222 :C,2,0,g1} != "11111 00000 22222" +. error +.endif + # A regular expression that matches the empty string applies before every # single character of the word. # XXX: Most other places where regular expression are used match at the end @@ -129,16 +131,30 @@ all: unmatched-subexpression .endif +# Just as in the ":S" modifier and the sed(1) utility, an "&" in the +# replacement part stands for the whole matched string. It can be escaped +# using a backslash. +.if ${:U 123 234 345 :C,2,&\&&,} != "12&23 2&234 345" +. error +.endif + +# When the ":C" modifier uses "&" as the delimiter for its parts, the "&" +# needs to be escaped. To get a literal "&" in the replacement, it needs +# to be written as "\\\&". When parsing the modifier part, the "\\" and "\&" +# result in "\" and "&", which then form the replacement "\&", and that is +# interpreted as a literal "&". +.if ${:U 123 234 345 :C&2&\&\\\&\&&} != "12&23 2&234 345" +. error +.endif + + # Multiple asterisks form an invalid regular expression. This produces an -# error message and (as of 2020-08-28) stops parsing in the middle of the -# expression. The unparsed part of the expression is then copied -# verbatim to the output, which is unexpected and can lead to strange shell -# commands being run. +# error message, and due to this error message, the shell command is not run. mod-regex-compile-error: @echo $@: ${:Uword1 word2:C,****,____,g:C,word,____,:Q}. -# These tests generate error messages but as of 2020-08-28 just continue -# parsing and execution as if nothing bad had happened. +# These tests generate error messages for the missing capturing groups. +# Due to these error messages, the echo commands are not executed. mod-regex-limits-1: @echo $@:11-missing:${:U1 23 456:C,..,\1\1,:Q} mod-regex-limits-2: @@ -158,9 +174,8 @@ mod-regex-errors-1: @echo $@: ${UNDEF:Uvalue:C,[,,} mod-regex-errors-2: - # If the replacement pattern produces a parse error because of an - # unknown modifier, the parse error is ignored in ParseModifierPart - # and the faulty expression expands to "". + # If the replacement pattern produces a parse error due to an + # unknown modifier, the faulty expression expands to "". @echo $@: ${word:L:C,.*,x${:U:Z}y,W} # In regular expressions with alternatives, not all capturing groups are diff --git a/unit-tests/varmod-subst.exp b/unit-tests/varmod-subst.exp index 8eec26e33ef5..fcd5ab4cd856 100644 --- a/unit-tests/varmod-subst.exp +++ b/unit-tests/varmod-subst.exp @@ -43,12 +43,17 @@ mod-subst-delimiter: 1 two 3 vertical line 1 two 3 right curly bracket 1 two 3 tilde +123 two34 345 circumflex accent +make: Regex compilation error: (details omitted) + while evaluating "${:U 123 234 345 :C^^2^two^:Q} circumflex accent" with value " 123 234 345 " + in command "@echo ${:U 123 234 345 :C^^2^two^:Q} circumflex accent" + in target "mod-subst-delimiter-circumflex" from varmod-subst.mk:250 mod-subst-chain: A B c. make: Unknown modifier ":i" while evaluating "${:Uvalue:S,a,x,i}." with value "vxlue" in command "@echo ${:Uvalue:S,a,x,i}." - in target "mod-subst-chain" + in target "mod-subst-chain" from varmod-subst.mk:268 mod-subst-dollar:$1: mod-subst-dollar:$2: mod-subst-dollar:$3: diff --git a/unit-tests/varmod-subst.mk b/unit-tests/varmod-subst.mk index e9da303515b2..ef7ad2358951 100644 --- a/unit-tests/varmod-subst.mk +++ b/unit-tests/varmod-subst.mk @@ -1,9 +1,10 @@ -# $NetBSD: varmod-subst.mk,v 1.17 2025/03/29 19:08:53 rillig Exp $ +# $NetBSD: varmod-subst.mk,v 1.18 2026/01/03 20:48:35 rillig Exp $ # # Tests for the :S,from,to, variable modifier. all: mod-subst all: mod-subst-delimiter +all: mod-subst-delimiter-circumflex all: mod-subst-chain all: mod-subst-dollar @@ -237,11 +238,22 @@ mod-subst-delimiter: @echo ${:U1 2 3:S}2}two}:Q} right curly bracket @echo ${:U1 2 3:S~2~two~:Q} tilde + +# When the ":S" modifier uses "^" to separate its parts, and when the first +# part starts with another "^", that "^" is interpreted as an anchor, not as +# the delimiter between the parts. +mod-subst-delimiter-circumflex: .PHONY + @echo ${:U 123 234 345 :S^^2^two^:Q} circumflex accent + # In the ":C" modifier, the "^" is not interpreted as an anchor, + # instead it is interpreted as the delimiter of the regular + # expression, thus making the regular expression empty and invalid. + @echo ${:U 123 234 345 :C^^2^two^:Q} circumflex accent + + # The :S and :C modifiers can be chained without a separating ':'. # This is not documented in the manual page. # It works because ApplyModifier_Subst scans for the known modifiers g1W -# and then just returns to ApplyModifiers. There, the colon is optionally -# skipped (see the *st.next == ':' at the end of the loop). +# and then just returns to ApplySingleModifier. There, the colon is skipped. # # Most other modifiers cannot be chained since their parsers skip until # the next ':' or '}' or ')'. diff --git a/unit-tests/varname-dot-make-save_dollars.mk b/unit-tests/varname-dot-make-save_dollars.mk index 31f228c220b2..a2134af51330 100644 --- a/unit-tests/varname-dot-make-save_dollars.mk +++ b/unit-tests/varname-dot-make-save_dollars.mk @@ -1,4 +1,4 @@ -# $NetBSD: varname-dot-make-save_dollars.mk,v 1.7 2021/12/03 18:43:52 rillig Exp $ +# $NetBSD: varname-dot-make-save_dollars.mk,v 1.8 2026/03/13 04:22:03 sjg Exp $ # # Tests for the special .MAKE.SAVE_DOLLARS variable, which controls whether # the assignment operator ':=' converts '$$' to a single '$' or keeps it @@ -8,11 +8,11 @@ # var-op-expand.mk for ':=' in general # varmisc.mk for parsing the boolean values -# Initially, the variable .MAKE.SAVE_DOLLARS is undefined. At this point the -# behavior of the assignment operator ':=' depends. NetBSD's usr.bin/make -# preserves the '$$' as-is, while the bmake distribution replaces '$$' with -# '$'. -.if ${.MAKE.SAVE_DOLLARS:Uundefined} != "undefined" +# The variable .MAKE.SAVE_DOLLARS is a boolean that controls the handling +# of '$$' during ':=' +# If "yes" (default for NetBSD's usr.bin/make) '$$' is left as-is. +# If "no" (default for bmake), '$$' is replaced with '$'. +.if ${.MAKE.SAVE_DOLLARS:Uundefined} == "undefined" . error .endif diff --git a/unit-tests/varname-make_stack_trace.exp b/unit-tests/varname-make_stack_trace.exp index c0f46cc5aa1e..5de66aa8bb8f 100644 --- a/unit-tests/varname-make_stack_trace.exp +++ b/unit-tests/varname-make_stack_trace.exp @@ -1,7 +1,7 @@ make: Unknown modifier ":Z" while evaluating "${:Z}" with value "" in command "@echo ${:Z}" - in target "provoke-error" + in target "provoke-error" from varname-make_stack_trace.mk:42 in make[2] in directory "<curdir>" *** Error code 2 (continuing) @@ -10,7 +10,7 @@ make: stopped making "disabled-compat" in unit-tests make: Unknown modifier ":Z" while evaluating "${:Z}" with value "" in command "@echo ${:Z}" - in target "provoke-error" + in target "provoke-error" from varname-make_stack_trace.mk:42 in make[2] in directory "<curdir>" *** [disabled-parallel] Error code 2 @@ -18,10 +18,10 @@ make: stopped making "disabled-parallel" in unit-tests make: Unknown modifier ":Z" while evaluating "${:Z}" with value "" in command "@echo ${:Z}" - in target "provoke-error" + in target "provoke-error" from varname-make_stack_trace.mk:42 in make[2] in directory "<curdir>" in command "make -f varname-make_stack_trace.mk provoke-error" - in target "enabled-compat" + in target "enabled-compat" from varname-make_stack_trace.mk:35 in make[1] in directory "<curdir>" *** Error code 2 (continuing) @@ -30,11 +30,21 @@ make: stopped making "enabled-compat" in unit-tests make: Unknown modifier ":Z" while evaluating "${:Z}" with value "" in command "@echo ${:Z}" - in target "provoke-error" + in target "provoke-error" from varname-make_stack_trace.mk:42 in make[2] in directory "<curdir>" - in target "enabled-parallel" + in target "enabled-parallel" from varname-make_stack_trace.mk:39 in make[1] in directory "<curdir>" *** [enabled-parallel] Error code 2 make: stopped making "enabled-parallel" in unit-tests +.make[5]: warning: Invalid internal option "-J" in "<curdir>"; see the manual page + in .make[5] in directory "<curdir>" + in target "multi-stage-4" from varname-make_stack_trace.mk:56 + in make[4] in directory "<curdir>" + in target "multi-stage-3" from varname-make_stack_trace.mk:54 + in make[3] in directory "<curdir>" + in target "multi-stage-2" from varname-make_stack_trace.mk:52 + in make[2] in directory "<curdir>" + in target "multi-stage-1" from varname-make_stack_trace.mk:50 + in make[1] in directory "<curdir>" exit status 0 diff --git a/unit-tests/varname-make_stack_trace.mk b/unit-tests/varname-make_stack_trace.mk index cba02559bafe..26b06448d583 100644 --- a/unit-tests/varname-make_stack_trace.mk +++ b/unit-tests/varname-make_stack_trace.mk @@ -1,4 +1,4 @@ -# $NetBSD: varname-make_stack_trace.mk,v 1.1 2025/06/13 03:51:18 rillig Exp $ +# $NetBSD: varname-make_stack_trace.mk,v 1.8 2026/03/10 05:02:00 sjg Exp $ # # Tests for the MAKE_STACK_TRACE environment variable, which controls whether # to print inter-process stack traces that are useful to narrow down where an @@ -11,27 +11,53 @@ # with the space for the command line arguments, and long command lines are # already written to a temporary file by Cmd_Exec to not overwhelm this space. +_make ?= .make${.MAKE.PID} +.export _make + all: .PHONY @${MAKE} -f ${MAKEFILE} disabled-compat || : @${MAKE} -f ${MAKEFILE} -j1 disabled-parallel || : @MAKE_STACK_TRACE=yes ${MAKE} -f ${MAKEFILE} enabled-compat || : @MAKE_STACK_TRACE=yes ${MAKE} -f ${MAKEFILE} -j1 enabled-parallel || : + @MAKE_STACK_TRACE=yes ${MAKE} -f ${MAKEFILE} -j1 multi-stage-1 + @rm -f ${_make} -# expect-not: in target "disabled-compat" +# expect-not-matches: in target "disabled%-compat" disabled-compat: .PHONY @${MAKE} -f ${MAKEFILE} provoke-error -# expect-not: in target "disabled-parallel" +# expect-not-matches: in target "disabled%-parallel" disabled-parallel: .PHONY @${MAKE} -f ${MAKEFILE} provoke-error -# expect: in target "enabled-compat" +# expect: in target "enabled-compat" from varname-make_stack_trace.mk:35 enabled-compat: .PHONY @${MAKE} -f ${MAKEFILE} provoke-error -# expect: in target "enabled-parallel" +# expect: in target "enabled-parallel" from varname-make_stack_trace.mk:39 enabled-parallel: .PHONY @${MAKE} -f ${MAKEFILE} provoke-error provoke-error: .PHONY @echo ${:Z} + +# The stack trace must be printed exactly once. +# expect: in target "multi-stage-4" from varname-make_stack_trace.mk:56 +# expect: in target "multi-stage-1" from varname-make_stack_trace.mk:50 +# expect-not-matches: in target "multi%-stage%-4" +# expect-not-matches: in target "multi%-stage%-1" +multi-stage-1: .PHONY ${_make} + @${MAKE} -f ${MAKEFILE} -j1 multi-stage-2 +multi-stage-2: .PHONY + @${MAKE} -f ${MAKEFILE} -j1 multi-stage-3 +multi-stage-3: .PHONY + @${MAKE} -f ${MAKEFILE} -j1 multi-stage-4 +multi-stage-4: .PHONY + @./${_make} -f ${MAKEFILE} -j1 multi-stage-5 +multi-stage-5: .PHONY + +${_make}: + @ln -s ${MAKE} ${.TARGET} + +# for FreeBSD and similar make sure we get the expected errors. +.MAKE.ALWAYS_PASS_JOB_QUEUE= no @@ -1,4 +1,4 @@ -/* $NetBSD: var.c,v 1.1173 2025/11/12 22:14:07 sjg Exp $ */ +/* $NetBSD: var.c,v 1.1179 2026/03/13 04:22:03 sjg Exp $ */ /* * Copyright (c) 1988, 1989, 1990, 1993 @@ -93,7 +93,9 @@ * Var_Value Return the unexpanded value of a variable, or NULL if * the variable is undefined. * - * Var_Subst Substitute all expressions in a string. + * Var_Subst Copy a string, expanding expressions on the way. + * + * Var_Expand Expand all expressions in a string, in-place. * * Var_Parse Parse an expression such as ${VAR:Mpattern}. * @@ -143,7 +145,7 @@ #endif /* "@(#)var.c 8.3 (Berkeley) 3/19/94" */ -MAKE_RCSID("$NetBSD: var.c,v 1.1173 2025/11/12 22:14:07 sjg Exp $"); +MAKE_RCSID("$NetBSD: var.c,v 1.1179 2026/03/13 04:22:03 sjg Exp $"); /* * Variables are defined using one of the VAR=value assignments. Their @@ -319,31 +321,26 @@ static char varUndefined[] = ""; * Traditionally this make consumed $$ during := like any other expansion. * Other make's do not, and this make follows straight since 2016-01-09. * - * This knob allows controlling the behavior: + * This knob (.MAKE.SAVE_DOLLARS) allows controlling the behavior: * false to consume $$ during := assignment. * true to preserve $$ during := assignment. */ -#define MAKE_SAVE_DOLLARS ".MAKE.SAVE_DOLLARS" static bool save_dollars = false; /* * A scope collects variable names and their values. * - * The main scope is SCOPE_GLOBAL, which contains the variables that are set - * in the makefiles. SCOPE_INTERNAL acts as a fallback for SCOPE_GLOBAL and - * contains some internal make variables. These internal variables can thus - * be overridden, they can also be restored by undefining the overriding - * variable. + * Each target has its own scope, containing the 7 target-local variables + * .TARGET, .ALLSRC, etc. Variables set on dependency lines also go in + * this scope. * * SCOPE_CMDLINE contains variables from the command line arguments. These * override variables from SCOPE_GLOBAL. * + * SCOPE_GLOBAL contains the variables that are set in the makefiles. + * * There is no scope for environment variables, these are generated on-the-fly * whenever they are referenced. - * - * Each target has its own scope, containing the 7 target-local variables - * .TARGET, .ALLSRC, etc. Variables set on dependency lines also go in - * this scope. */ GNode *SCOPE_CMDLINE; @@ -415,6 +412,7 @@ EvalStack_Details(Buffer *buf) const char* value = elem->value != NULL && (kind == VSK_VARNAME || kind == VSK_EXPR) ? elem->value->str : NULL; + const GNode *gn; Buf_AddStr(buf, "\t"); Buf_AddStr(buf, descr[kind]); @@ -424,7 +422,16 @@ EvalStack_Details(Buffer *buf) Buf_AddStr(buf, "\" with value \""); Buf_AddStr(buf, value); } - Buf_AddStr(buf, "\"\n"); + if (kind == VSK_TARGET + && (gn = Targ_FindNode(elem->str)) != NULL + && gn->fname != NULL) { + Buf_AddStr(buf, "\" from "); + Buf_AddStr(buf, gn->fname); + Buf_AddStr(buf, ":"); + Buf_AddInt(buf, (int)gn->lineno); + Buf_AddStr(buf, "\n"); + } else + Buf_AddStr(buf, "\"\n"); } return evalStack.len > 0; } @@ -1282,12 +1289,8 @@ Var_Exists(GNode *scope, const char *name) } /* - * See if the given variable exists, in the given scope or in other - * fallback scopes. - * - * Input: - * scope scope in which to start search - * name name of the variable to find, is expanded once + * See if the given variable exists, in the given scope or in other fallback + * scopes. The variable name is expanded once. */ bool Var_ExistsExpand(GNode *scope, const char *name) @@ -2138,12 +2141,12 @@ typedef enum ApplyModifierResult { * backslashes. */ static bool -IsEscapedModifierPart(const char *p, char end1, char end2, +IsEscapedModifierPart(const char *p, char delim1, char delim2, struct ModifyWord_SubstArgs *subst) { if (p[0] != '\\' || p[1] == '\0') return false; - if (p[1] == end1 || p[1] == end2 || p[1] == '\\' || p[1] == '$') + if (p[1] == delim1 || p[1] == delim2 || p[1] == '\\' || p[1] == '$') return true; return p[1] == '&' && subst != NULL; } @@ -2224,10 +2227,10 @@ ParseModifierPart( * For the first part of the ':S' modifier, set anchorEnd if the last * character of the pattern is a $. */ - PatternFlags *out_pflags, + PatternFlags *pflags, /* - * For the second part of the ':S' modifier, allow ampersands to be - * escaped and replace unescaped ampersands with subst->lhs. + * For the second part of the ':S' modifier, allow '&' to be + * escaped and replace each unescaped '&' with subst->lhs. */ struct ModifyWord_SubstArgs *subst ) @@ -2246,8 +2249,8 @@ ParseModifierPart( LazyBuf_Add(part, *p); p++; } else if (p[1] == end2) { /* Unescaped '$' at end */ - if (out_pflags != NULL) - out_pflags->anchorEnd = true; + if (pflags != NULL) + pflags->anchorEnd = true; else LazyBuf_Add(part, *p); p++; @@ -3044,9 +3047,16 @@ ApplyModifier_Regex(const char **pp, ModChain *ch) if (!ModChain_ShouldEval(ch)) goto done; + if (re.str[0] == '\0') { + /* not all regcomp() fail on this */ + Parse_Error(PARSE_FATAL, "Regex compilation error: empty"); + goto re_err; + } + error = regcomp(&args.re, re.str, REG_EXTENDED); if (error != 0) { RegexError(error, &args.re, "Regex compilation error"); + re_err: LazyBuf_Done(&replaceBuf); FStr_Done(&re); return AMR_CLEANUP; @@ -3829,7 +3839,7 @@ ApplyModifier_SunShell1(const char **pp, ModChain *ch) v = VarFind(cache_varname, SCOPE_GLOBAL, false); if (v == NULL) { char *output, *error; - + output = Cmd_Exec(Expr_Str(expr), &error); if (error != NULL) { Parse_Error(PARSE_WARNING, "%s", error); @@ -3846,7 +3856,7 @@ ApplyModifier_SunShell1(const char **pp, ModChain *ch) return AMR_OK; } - + /* * In cases where the evaluation mode and the definedness are the "standard" |
