Update to bmake-20220724

Merge commit '308a28d6cd2e87028e535eabccb89a9dc2fd9515'
This commit is contained in:
Simon J. Gerraty 2022-07-26 09:07:25 -07:00
commit 954401e68e
65 changed files with 1933 additions and 1369 deletions

View file

@ -1,3 +1,32 @@
2022-07-24 Simon J Gerraty <sjg@beast.crufty.net>
* VERSION (_MAKE_VERSION): 20220724
Merge with NetBSD make, pick up
o make.1: describe variable assignment and evaluation more precisely
o parse.c: fix out-of-bounds read when parsing an invalid line
o var.c: simplify return type of IsShortVarnameValid
2022-06-12 Simon J Gerraty <sjg@beast.crufty.net>
* VERSION (_MAKE_VERSION): 20220612
Merge with NetBSD make, pick up
o allow to randomize build order of targets
.MAKE.MODE += randomize-targets can help uncover dependency bugs
within a makefile.
o compat.c: rename Compat_Run to Compat_MakeAll
o make.c: inline MakeBuildParent
inline make_abort, improve error details
o parse.c: reorganize Parse_Error
fix memory leak in wildcard targets and sources
separate cases in HandleDependencyTargetMundane
extract HandleSingleDependencyTargetMundane
rename loadfile to LoadFile
split IncludeFile into separate functions
condense code for searching a file in the paths
fix off-by-one error in buffer for .WAIT nodes
o str.c: condense Str_Match
make code for string matching syntactically more consistent
2022-04-18 Simon J Gerraty <sjg@beast.crufty.net>
* VERSION (_MAKE_VERSION): 20220418

View file

@ -158,8 +158,6 @@ unit-tests/cond-token-var.exp
unit-tests/cond-token-var.mk
unit-tests/cond-undef-lint.exp
unit-tests/cond-undef-lint.mk
unit-tests/cond1.exp
unit-tests/cond1.mk
unit-tests/counter-append.exp
unit-tests/counter-append.mk
unit-tests/counter.exp
@ -324,6 +322,8 @@ unit-tests/directive-export-literal.exp
unit-tests/directive-export-literal.mk
unit-tests/directive-export.exp
unit-tests/directive-export.mk
unit-tests/directive-for-empty.exp
unit-tests/directive-for-empty.mk
unit-tests/directive-for-errors.exp
unit-tests/directive-for-errors.mk
unit-tests/directive-for-escape.exp
@ -864,8 +864,6 @@ unit-tests/varparse-mod.exp
unit-tests/varparse-mod.mk
unit-tests/varparse-undef-partial.exp
unit-tests/varparse-undef-partial.mk
unit-tests/varquote.exp
unit-tests/varquote.mk
util.c
var.c
wait.h

View file

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

View file

@ -1,4 +1,4 @@
.\" $NetBSD: make.1,v 1.308 2022/04/18 15:06:27 rillig Exp $
.\" $NetBSD: make.1,v 1.315 2022/07/12 23:47:00 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 April 18, 2022
.Dd July 12, 2022
.Dt BMAKE 1
.Os
.Sh NAME
@ -61,12 +61,12 @@ If no
makefile option is given,
.Nm
will try to open
.Ql Pa makefile
.Sq Pa makefile
then
.Ql Pa Makefile
.Sq Pa Makefile
in order to find the specifications.
If the file
.Ql Pa .depend
.Sq Pa .depend
exists, it is read (see
.Xr mkdep 1 ) .
.Pp
@ -229,11 +229,11 @@ Specify that environment variables override macro assignments within
makefiles.
.It Fl f Ar makefile
Specify a makefile to read instead of the default
.Ql Pa makefile .
.Sq Pa makefile .
If
.Ar makefile
is
.Ql Fl ,
.Sq Fl ,
standard input is read.
Multiple makefiles may be specified, and are read in the order specified.
.It Fl I Ar directory
@ -244,7 +244,7 @@ option) is automatically included as part of this list.
.It Fl i
Ignore non-zero exit of shell commands in the makefile.
Equivalent to specifying
.Ql Fl
.Sq Fl
before each command line in the makefile.
.It Fl J Ar private
This option should
@ -252,7 +252,7 @@ This option should
be specified by the user.
.Pp
When the
.Ar j
.Fl j
option is in use in a recursive build, this option is passed by a make
to child makes to allow all the make processes in the build to
cooperate to avoid overloading the system.
@ -263,8 +263,8 @@ may have running at any one time.
The value is saved in
.Va .MAKE.JOBS .
Turns compatibility mode off, unless the
.Ar B
flag is also specified.
.Fl B
option is also specified.
When compatibility mode is off, all commands associated with a
target are executed in a single shell invocation as opposed to the
traditional one shell invocation per line.
@ -319,7 +319,7 @@ as an argument).
Display the commands that would have been executed, but do not
actually execute them unless the target depends on the .MAKE special
source (see below) or the command is prefixed with
.Ql Ic + .
.Sq Ic + .
.It Fl N
Display the commands which would have been executed, but do not
actually execute any of them; useful for debugging top-level makefiles
@ -336,7 +336,7 @@ This is the default behavior and the opposite of
.It Fl s
Do not echo any commands as they are executed.
Equivalent to specifying
.Ql Ic @
.Sq Ic @
before each command line in the makefile.
.It Fl T Ar tracefile
When used with the
@ -493,7 +493,7 @@ While targets can appear in many dependency lines if desired, by
default only one of these rules may be followed by a creation
script.
If the
.Ql Ic \&::
.Sq Ic \&::
operator is used, however, all rules may include scripts and the
scripts are executed in the order found.
.Pp
@ -505,23 +505,23 @@ in which case that line and the next are combined.
.\" normally ignores it.
.\" However, the tab at the beginning of the following line is removed.
If the first characters of the command are any combination of
.Ql Ic @ ,
.Ql Ic + ,
.Sq Ic @ ,
.Sq Ic + ,
or
.Ql Ic \- ,
.Sq Ic \- ,
the command is treated specially.
A
.Ql Ic @
.Sq Ic @
causes the command not to be echoed before it is executed.
A
.Ql Ic +
.Sq Ic +
causes the command to be executed even when
.Fl n
is given.
This is similar to the effect of the .MAKE special source,
except that the effect can be limited to a single line of a script.
A
.Ql Ic \-
.Sq Ic \-
in compatibility mode
causes any non-zero exit status of the command line to be ignored.
.Pp
@ -538,11 +538,11 @@ it will be passed to the shell; otherwise
.Nm
will attempt direct execution.
If a line starts with
.Ql Ic \-
.Sq Ic \-
and the shell has ErrCtl enabled then failure of the command line
will be ignored as in compatibility mode.
Otherwise
.Ql Ic \-
.Sq Ic \-
affects the entire job;
the script will stop at the first command line that fails,
but the target will not be deemed to have failed.
@ -576,27 +576,47 @@ Since
will
.Xr chdir 2
to
.Ql Va .OBJDIR
.Sq Va .OBJDIR
before executing any targets, each child process
starts with that as its current working directory.
.Sh VARIABLE ASSIGNMENTS
Variables in make are much like variables in the shell, and, by tradition,
consist of all upper-case letters.
.Ss Variable assignment modifiers
The five operators that can be used to assign values to variables are as
follows:
Variables in make behave much like macros in the C preprocessor.
.Pp
Variable assignments have the form
.Sq Ar NAME Ar op Ar value ,
where:
.Bl -tag -width Ds
.It Ar NAME
is a single-word variable name,
consisting, by tradition, of all upper-case letters,
.It Ar op
is one of the five variable assignment operators described below, and
.It Ar value
is interpreted according to the variable assignment operator.
.El
.Pp
Whitespace around
.Ar NAME ,
.Ar op
and
.Ar value
is discarded.
.Ss Variable assignment operators
The five operators that can be used to assign values to variables are:
.Bl -tag -width Ds
.It Ic \&=
Assign the value to the variable.
Any previous value is overridden.
Any previous value is overwritten.
.It Ic \&+=
Append the value to the current value of the variable.
Append the value to the current value of the variable,
separating them by a single space.
.It Ic \&?=
Assign the value to the variable if it is not already defined.
.It Ic \&:=
Assign with expansion, i.e. expand the value before assigning it
to the variable.
Normally, expansion is not done until the variable is referenced.
.Pp
.Em NOTE :
References to undefined variables are
.Em not
@ -607,45 +627,42 @@ Expand the value and pass it to the shell for execution and assign
the result to the variable.
Any newlines in the result are replaced with spaces.
.El
.Pp
Any white-space before the assigned
.Ar value
is removed; if the value is being appended, a single space is inserted
between the previous contents of the variable and the appended value.
.Pp
Variables are expanded by surrounding the variable name with either
curly braces
.Pq Ql {}
or parentheses
.Pq Ql ()
and preceding it with
a dollar sign
.Pq Ql \&$ .
If the variable name contains only a single letter, the surrounding
braces or parentheses are not required.
.Ss Expansion of variables
In contexts where variables are expanded,
.Ql \&$$
expands to a single dollar sign.
References to variables have the form
.Ql \&${ Ns Ar name Ns Oo \&: Ns Ar modifiers Oc Ns }
or
.Ql \&$( Ns Ar name Ns Oo \&: Ns Ar modifiers Oc Ns ) .
If the variable name contains only a single character,
the surrounding curly braces or parentheses are not required.
This shorter form is not recommended.
.Pp
If the variable name contains a dollar, then the name itself is expanded first.
This allows almost arbitrary variable names, however names containing dollar,
braces, parentheses, or whitespace are really best avoided!
braces, parentheses, or whitespace are really best avoided.
.Pp
If the result of expanding a variable contains a dollar sign
.Pq Ql \&$
.Pq Ql \&$ ,
the string is expanded again.
.Pp
Variable substitution occurs at three distinct times, depending on where
Variable substitution occurs at four distinct times, depending on where
the variable is being used.
.Bl -enum
.It
Variables in dependency lines are expanded as the line is read.
.It
Variables in conditionals are expanded individually,
but only as far as necessary to determine the result of the conditional.
.It
Variables in shell commands are expanded when the shell command is
executed.
.It
.Dq .for
loop index variables are expanded on each loop iteration.
Note that other variables are not expanded inside loops so
the following example code:
Note that other variables are not expanded when composing the body of a loop,
so the following example code:
.Bd -literal -offset indent
.Dv .for i in 1 2 3
@ -726,34 +743,34 @@ The seven built-in local variables are as follows:
.Bl -tag -width ".ARCHIVE" -offset indent
.It Va .ALLSRC
The list of all sources for this target; also known as
.Ql Va \&> .
.Sq Va \&> .
.It Va .ARCHIVE
The name of the archive file; also known as
.Ql Va \&! .
.Sq Va \&! .
.It Va .IMPSRC
In suffix-transformation rules, the name/path of the source from which the
target is to be transformed (the
.Dq implied
source); also known as
.Ql Va \&< .
.Sq Va \&< .
It is not defined in explicit rules.
.It Va .MEMBER
The name of the archive member; also known as
.Ql Va % .
.Sq Va % .
.It Va .OODATE
The list of sources for this target that were deemed out-of-date; also
known as
.Ql Va \&? .
.Sq Va \&? .
.It Va .PREFIX
The file prefix of the target, containing only the file portion, no suffix
or preceding directory components; also known as
.Ql Va * .
.Sq Va * .
The suffix must be one of the known suffixes declared with
.Ic .SUFFIXES
or it will not be recognized.
.It Va .TARGET
The name of the target; also known as
.Ql Va @ .
.Sq Va @ .
For compatibility with other makes this is an alias for
.Ic .ARCHIVE
in archive member rules.
@ -761,13 +778,13 @@ in archive member rules.
.Pp
The shorter forms
.Ql ( Va > ,
.Ql Va \&! ,
.Ql Va < ,
.Ql Va % ,
.Ql Va \&? ,
.Ql Va * ,
.Sq Va \&! ,
.Sq Va < ,
.Sq Va % ,
.Sq Va \&? ,
.Sq Va * ,
and
.Ql Va @ )
.Sq Va @ )
are permitted for backward
compatibility with historical makefiles and legacy POSIX make and are
not recommended.
@ -776,8 +793,8 @@ Variants of these variables with the punctuation followed immediately by
.Ql D
or
.Ql F ,
e.g.
.Ql Va $(@D) ,
e.g.\&
.Sq Va $(@D) ,
are legacy forms equivalent to using the
.Ql :H
and
@ -790,23 +807,16 @@ makefiles and POSIX but are not recommended.
Four of the local variables may be used in sources on dependency lines
because they expand to the proper value for each target on the line.
These variables are
.Ql Va .TARGET ,
.Ql Va .PREFIX ,
.Ql Va .ARCHIVE ,
.Sq Va .TARGET ,
.Sq Va .PREFIX ,
.Sq Va .ARCHIVE ,
and
.Ql Va .MEMBER .
.Sq Va .MEMBER .
.Ss Additional built-in variables
In addition,
.Nm
sets or knows about the following variables:
.Bl -tag -width .MAKEOVERRIDES
.It Va \&$
A single dollar sign
.Ql \&$ ,
i.e.
.Ql \&$$
expands to a single dollar
sign.
.It Va .ALLTARGETS
The list of all targets encountered in the Makefile.
If evaluated during
@ -816,7 +826,7 @@ A path to the directory where
.Nm
was executed.
Refer to the description of
.Ql Ev PWD
.Sq Ev PWD
for more details.
.It Va .INCLUDEDFROMDIR
The directory of the file this Makefile was included from.
@ -839,7 +849,7 @@ because it is more compatible with other versions of
and cannot be confused with the special target with the same name.
.It Va .MAKE.DEPENDFILE
Names the makefile (default
.Ql Pa .depend )
.Sq Pa .depend )
from which generated dependencies are read.
.It Va .MAKE.EXPAND_VARIABLES
A boolean that controls the default behavior of the
@ -860,17 +870,18 @@ option.
If
.Nm
is run with
.Ar j
then output for each target is prefixed with a token
.Fl j ,
the output for each target is prefixed with a token
.Ql --- target ---
the first part of which can be controlled via
.Va .MAKE.JOB.PREFIX .
If
.Va .MAKE.JOB.PREFIX
is empty, no token is printed.
.br
For example:
.Li .MAKE.JOB.PREFIX=${.newline}---${.MAKE:T}[${.MAKE.PID}]
For example, setting
.Va .MAKE.JOB.PREFIX
to
.Li ${.newline}---${.MAKE:T}[${.MAKE.PID}]
would produce tokens like
.Ql ---make[1234] target ---
making it easier to track the degree of parallelism being achieved.
@ -881,7 +892,7 @@ apparent variable assignments in dependency lines are
treated as normal sources.
.It Ev MAKEFLAGS
The environment variable
.Ql Ev MAKEFLAGS
.Sq Ev MAKEFLAGS
may contain anything that
may be specified on
.Nm Ns 's
@ -889,7 +900,7 @@ command line.
Anything specified on
.Nm Ns 's
command line is appended to the
.Ql Ev MAKEFLAGS
.Sq Ev MAKEFLAGS
variable which is then
entered into the environment for all programs which
.Nm
@ -908,8 +919,8 @@ to protect things which should only be evaluated in the initial instance of
.It Va .MAKE.MAKEFILE_PREFERENCE
The ordered list of makefile names
(default
.Ql Pa makefile ,
.Ql Pa Makefile )
.Sq Pa makefile ,
.Sq Pa Makefile )
that
.Nm
will look for.
@ -944,7 +955,7 @@ The captured output can be very useful when diagnosing errors.
Normally
.Nm
will not create .meta files in
.Ql Va .CURDIR .
.Sq Va .CURDIR .
This can be overridden by setting
.Va bf
to a value which represents True.
@ -978,6 +989,10 @@ If
.Va bf
is True, when a .meta file is created, mark the target
.Ic .SILENT .
.It Pa randomize-targets
In both compat and parallel mode, do not make the targets in the usual order,
but instead randomize their order.
This mode can be used to detect undeclared dependencies between files.
.El
.It Va .MAKE.META.BAILIWICK
In "meta" mode, provides a list of prefixes which
@ -1007,7 +1022,7 @@ information.
Provides a list of path prefixes that should be ignored;
because the contents are expected to change over time.
The default list includes:
.Ql Pa /dev /etc /proc /tmp /var/run /var/tmp
.Sq Pa /dev /etc /proc /tmp /var/run /var/tmp
.It Va .MAKE.META.IGNORE_PATTERNS
Provides a list of patterns to match against pathnames.
Ignore any that match.
@ -1021,16 +1036,16 @@ The default value is:
.It Va .MAKEOVERRIDES
This variable is used to record the names of variables assigned to
on the command line, so that they may be exported as part of
.Ql Ev MAKEFLAGS .
.Sq Ev MAKEFLAGS .
This behavior can be disabled by assigning an empty value to
.Ql Va .MAKEOVERRIDES
.Sq Va .MAKEOVERRIDES
within a makefile.
Extra variables can be exported from a makefile
by appending their names to
.Ql Va .MAKEOVERRIDES .
.Ql Ev MAKEFLAGS
.Sq Va .MAKEOVERRIDES .
.Sq Ev MAKEFLAGS
is re-exported whenever
.Ql Va .MAKEOVERRIDES
.Sq Va .MAKEOVERRIDES
is modified.
.It Va .MAKE.PATH_FILEMON
If
@ -1068,21 +1083,21 @@ The group-id running
When
.Nm
stops due to an error, it sets
.Ql Va .ERROR_TARGET
.Sq Va .ERROR_TARGET
to the name of the target that failed,
.Ql Va .ERROR_CMD
.Sq Va .ERROR_CMD
to the commands of the failed target,
and in "meta" mode, it also sets
.Ql Va .ERROR_CWD
.Sq Va .ERROR_CWD
to the
.Xr getcwd 3 ,
and
.Ql Va .ERROR_META_FILE
.Sq Va .ERROR_META_FILE
to the path of the meta file (if any) describing the failed target.
It then prints its name and the value of
.Ql Va .CURDIR
.Sq Va .CURDIR
as well as the value of any variables named in
.Ql Va MAKE_PRINT_VAR_ON_ERROR .
.Sq Va MAKE_PRINT_VAR_ON_ERROR .
.It Va .newline
This variable is simply assigned a newline character as its value.
This allows expansions using the
@ -1090,7 +1105,7 @@ This allows expansions using the
modifier to put a newline between
iterations of the loop rather than a space.
For example, the printing of
.Ql Va MAKE_PRINT_VAR_ON_ERROR
.Sq Va MAKE_PRINT_VAR_ON_ERROR
could be done as ${MAKE_PRINT_VAR_ON_ERROR:@v@$v='${$v}'${.newline}@}.
.It Va .OBJDIR
A path to the directory where the targets are built.
@ -1102,13 +1117,13 @@ to the following directories in order and using the first match:
.Ev ${MAKEOBJDIRPREFIX}${.CURDIR}
.Pp
(Only if
.Ql Ev MAKEOBJDIRPREFIX
.Sq Ev MAKEOBJDIRPREFIX
is set in the environment or on the command line.)
.It
.Ev ${MAKEOBJDIR}
.Pp
(Only if
.Ql Ev MAKEOBJDIR
.Sq Ev MAKEOBJDIR
is set in the environment or on the command line.)
.It
.Ev ${.CURDIR} Ns Pa /obj. Ns Ev ${MACHINE}
@ -1125,77 +1140,77 @@ so expressions such as
.Dl ${.CURDIR:S,^/usr/src,/var/obj,}
may be used.
This is especially useful with
.Ql Ev MAKEOBJDIR .
.Sq Ev MAKEOBJDIR .
.Pp
.Ql Va .OBJDIR
.Sq Va .OBJDIR
may be modified in the makefile via the special target
.Ql Ic .OBJDIR .
.Sq Ic .OBJDIR .
In all cases,
.Nm
will
.Xr chdir 2
to the specified directory if it exists, and set
.Ql Va .OBJDIR
.Sq Va .OBJDIR
and
.Ql Ev PWD
.Sq Ev PWD
to that directory before executing any targets.
.Pp
Except in the case of an explicit
.Ql Ic .OBJDIR
.Sq Ic .OBJDIR
target,
.Nm
will check that the specified directory is writable and ignore it if not.
This check can be skipped by setting the environment variable
.Ql Ev MAKE_OBJDIR_CHECK_WRITABLE
.Sq Ev MAKE_OBJDIR_CHECK_WRITABLE
to "no".
.
.It Va .PARSEDIR
A path to the directory of the current
.Ql Pa Makefile
.Sq Pa Makefile
being parsed.
.It Va .PARSEFILE
The basename of the current
.Ql Pa Makefile
.Sq Pa Makefile
being parsed.
This variable and
.Ql Va .PARSEDIR
.Sq Va .PARSEDIR
are both set only while the
.Ql Pa Makefiles
.Sq Pa Makefiles
are being parsed.
If you want to retain their current values, assign them to a variable
using assignment with expansion:
.Pq Ql Cm \&:= .
using assignment with expansion
.Sq Cm \&:= .
.It Va .PATH
A variable that represents the list of directories that
.Nm
will search for files.
The search list should be updated using the target
.Ql Va .PATH
.Sq Va .PATH
rather than the variable.
.It Ev PWD
Alternate path to the current directory.
.Nm
normally sets
.Ql Va .CURDIR
.Sq Va .CURDIR
to the canonical path given by
.Xr getcwd 3 .
However, if the environment variable
.Ql Ev PWD
.Sq Ev PWD
is set and gives a path to the current directory, then
.Nm
sets
.Ql Va .CURDIR
.Sq Va .CURDIR
to the value of
.Ql Ev PWD
.Sq Ev PWD
instead.
This behavior is disabled if
.Ql Ev MAKEOBJDIRPREFIX
.Sq Ev MAKEOBJDIRPREFIX
is set or
.Ql Ev MAKEOBJDIR
.Sq Ev MAKEOBJDIR
contains a variable transform.
.Ql Ev PWD
.Sq Ev PWD
is set to the value of
.Ql Va .OBJDIR
.Sq Va .OBJDIR
for all programs which
.Nm
executes.
@ -1215,7 +1230,7 @@ lists of directories that
will search for files.
The variable is supported for compatibility with old make programs only,
use
.Ql Va .PATH
.Sq Va .PATH
instead.
.El
.Ss Variable modifiers
@ -1249,14 +1264,14 @@ The supported modifiers are:
Replaces each word in the variable with its suffix.
.It Cm \&:H
Replaces each word in the variable with everything but the last component.
.It Cm \&:M Ns Ar pattern
.It Cm \&:M\| Ns Ar pattern
Selects only those words that match
.Ar pattern .
The standard shell wildcard characters
.Pf ( Ql * ,
.Ql \&? ,
and
.Ql Oo Oc )
.Ql \&[] )
may
be used.
The wildcard characters may be escaped with a backslash
@ -1268,9 +1283,9 @@ will normalize the inter-word spacing, removing all leading and
trailing space, and converting multiple consecutive spaces
to single spaces.
.
.It Cm \&:N Ns Ar pattern
.It Cm \&:N\| Ns Ar pattern
This is identical to
.Ql Cm \&:M ,
.Sq Cm \&:M ,
but selects all words which do not match
.Ar pattern .
.It Cm \&:O
@ -1293,7 +1308,7 @@ Orders every word in variable in reverse numerical order.
Shuffles the words in variable.
The results will be different each time you are referring to the
modified variable; use the assignment with expansion
.Pq Ql Cm \&:=
.Sq Cm \&:=
to prevent such behavior.
For example,
.Bd -literal -offset indent
@ -1327,11 +1342,11 @@ This is equivalent to:
.Sq \&:S/\e\&$/&&/g:Q .
.It Cm \&:R
Replaces each word in the variable with everything but its suffix.
.It Cm \&:range[=count]
.It Cm \&:range Ns Oo = Ns Ar count Oc
The value is an integer sequence representing the words of the original
value, or the supplied
.Va count .
.It Cm \&:gmtime[=utc]
.It Cm \&:gmtime Ns Oo = Ns Ar utc Oc
The value is a format string for
.Xr strftime 3 ,
using
@ -1341,7 +1356,7 @@ If a
value is not provided or is 0, the current time is used.
.It Cm \&:hash
Computes a 32-bit hash of the value and encode it as hex digits.
.It Cm \&:localtime[=utc]
.It Cm \&:localtime Ns Oo = Ns Ar utc Oc
The value is a format string for
.Xr strftime 3 ,
using
@ -1369,14 +1384,14 @@ Converts variable to upper-case letters.
Causes the value to be treated as a single word
(possibly containing embedded white space).
See also
.Ql Cm \&:[*] .
.Sq Cm \&:[*] .
.It Cm \&:tw
Causes the value to be treated as a sequence of
words delimited by white space.
See also
.Ql Cm \&:[@] .
.Sq Cm \&:[@] .
.Sm off
.It Cm \&:S No \&/ Ar old_string No \&/ Ar new_string No \&/ Op Cm 1gW
.It Cm \&:S\| No \&/ Ar old_string\| No \&/ Ar new_string\| No \&/ Op Cm 1gW
.Sm on
Modifies the first occurrence of
.Ar old_string
@ -1431,7 +1446,7 @@ of a dollar sign
.Pq Ql \&$ ,
not a preceding dollar sign as is usual.
.Sm off
.It Cm \&:C No \&/ Ar pattern No \&/ Ar replacement No \&/ Op Cm 1gW
.It Cm \&:C\| No \&/ Ar pattern\| No \&/ Ar replacement\| No \&/ Op Cm 1gW
.Sm on
The
.Cm \&:C
@ -1476,7 +1491,7 @@ Replaces each word in the variable with its last path component.
Removes adjacent duplicate words (like
.Xr uniq 1 ) .
.Sm off
.It Cm \&:\&? Ar true_string Cm \&: Ar false_string
.It Cm \&:\&?\| Ar true_string\| Cm \&: Ar false_string
.Sm on
If the variable name (not its value), when parsed as a .if conditional
expression, evaluates to true, return as its value the
@ -1491,7 +1506,7 @@ A common error is trying to use expressions like
which actually tests defined(NUMBERS),
to determine if any words match "42" you need to use something like:
.Dl ${"${NUMBERS:M42}" != \&"\&":?match:no} .
.It Ar :old_string=new_string
.It Cm :\| Ns Ar old_string\| Ns Cm = Ns Ar new_string
This is the
.At V
style variable substitution.
@ -1544,7 +1559,7 @@ expansion of a dollar sign
.Pq Ql \&$ ,
not a preceding dollar sign as is usual.
.Sm off
.It Cm \&:@ Ar temp Cm @ Ar string Cm @
.It Cm \&:@ Ar temp\| Cm @ Ar string\| Cm @
.Sm on
This is the loop expansion mechanism from the OSF Development
Environment (ODE) make.
@ -1563,7 +1578,7 @@ For example.
.Pp
However a single character variable is often more readable:
.Dl ${MAKE_PRINT_VAR_ON_ERROR:@v@$v='${$v}'${.newline}@}
.It Cm \&:_[=var]
.It Cm \&:_ Ns Oo Cm = Ns Ar var Oc
Saves the current variable value in
.Ql $_
or the named
@ -1584,7 +1599,7 @@ is used to save the result of the
.Ql :S
modifier which is later referenced using the index values from
.Ql :range .
.It Cm \&:U Ns Ar newval
.It Cm \&:U\| Ns Ar newval
If the variable is undefined,
.Ar newval
is the value.
@ -1594,7 +1609,7 @@ It is handy for setting per-target CFLAGS for instance:
.Dl ${_${.TARGET:T}_CFLAGS:U${DEF_CFLAGS}}
If a value is only required if the variable is undefined, use:
.Dl ${VAR:D:Unewval}
.It Cm \&:D Ns Ar newval
.It Cm \&:D\| Ns Ar newval
If the variable is defined,
.Ar newval
is the value.
@ -1608,7 +1623,7 @@ name of the variable is used.
In order for this modifier to work, the name (node) must at least have
appeared on the rhs of a dependency.
.Sm off
.It Cm \&:\&! Ar cmd Cm \&!
.It Cm \&:\&! Ar cmd\| Cm \&!
.Sm on
The output of running
.Ar cmd
@ -1630,7 +1645,7 @@ preceded with something to keep
happy.
.Pp
The
.Ql Cm \&::
.Sq Cm \&::
helps avoid false matches with the
.At V
style
@ -1663,7 +1678,7 @@ causing a value to be treated as a single word
An empty value, or a value that consists entirely of white-space,
is treated as a single word.
For the purposes of the
.Ql Cm \&:[]
.Sq Cm \&:[]
modifier, the words are indexed both forwards using positive integers
(where index 1 represents the first word),
and backwards using negative integers
@ -1685,7 +1700,7 @@ to
.Ar end ,
inclusive.
For example,
.Ql Cm \&:[2..-1]
.Sq Cm \&:[2..-1]
selects all words from the second word to the last word.
If
.Ar start
@ -1693,13 +1708,13 @@ is greater than
.Ar end ,
then the words are output in reverse order.
For example,
.Ql Cm \&:[-1..1]
.Sq Cm \&:[-1..1]
selects all the words from last to first.
If the list is already ordered, then this effectively reverses
the list, but it is more efficient to use
.Ql Cm \&:Or
.Sq Cm \&:Or
instead of
.Ql Cm \&:O:[-1..1] .
.Sq Cm \&:O:[-1..1] .
.\" :[*]
.It Cm \&*
Causes subsequent modifiers to treat the value as a single word
@ -1710,7 +1725,7 @@ in Bourne shell.
.\" :[0]
.It 0
Means the same as
.Ql Cm \&:[*] .
.Sq Cm \&:[*] .
.\" :[*]
.It Cm \&@
Causes subsequent modifiers to treat the value as a sequence of words
@ -1837,14 +1852,14 @@ PATH := ${PATH}
.Pp
.Ed
Would result in an environment containing only
.Ql Ev PATH ,
.Sq Ev PATH ,
which is the minimal useful environment.
Actually
.Ql Ev .MAKE.LEVEL
.Sq Ev .MAKE.LEVEL
will also be pushed into the new environment.
.It Ic .warning Ar message
The message prefixed by
.Ql Pa warning:
.Sq Pa warning:
is printed along with the name of the makefile and line number.
.It Ic \&.if Oo \&! Oc Ns Ar expression Op Ar operator expression ...
Test the value of an expression.
@ -1860,29 +1875,29 @@ Test the target being built.
Reverse the sense of the last conditional.
.It Ic .elif Oo \&! Ns Oc Ar expression Op Ar operator expression ...
A combination of
.Ql Ic .else
.Sq Ic .else
followed by
.Ql Ic .if .
.Sq Ic .if .
.It Ic .elifdef Oo \&! Oc Ns Ar variable Op Ar operator variable ...
A combination of
.Ql Ic .else
.Sq Ic .else
followed by
.Ql Ic .ifdef .
.Sq Ic .ifdef .
.It Ic .elifndef Oo \&! Oc Ns Ar variable Op Ar operator variable ...
A combination of
.Ql Ic .else
.Sq Ic .else
followed by
.Ql Ic .ifndef .
.Sq Ic .ifndef .
.It Ic .elifmake Oo \&! Oc Ns Ar target Op Ar operator target ...
A combination of
.Ql Ic .else
.Sq Ic .else
followed by
.Ql Ic .ifmake .
.Sq Ic .ifmake .
.It Ic .elifnmake Oo \&! Oc Ns Ar target Op Ar operator target ...
A combination of
.Ql Ic .else
.Sq Ic .else
followed by
.Ql Ic .ifnmake .
.Sq Ic .ifnmake .
.It Ic .endif
End the body of the conditional.
.El
@ -1906,11 +1921,11 @@ will only evaluate a conditional as far as is necessary to determine
its value.
Parentheses may be used to change the order of evaluation.
The boolean operator
.Ql Ic \&!
.Sq Ic \&!
may be used to logically negate an entire
conditional.
It is of higher precedence than
.Ql Ic \&&& .
.Sq Ic \&&& .
.Pp
The value of
.Ar expression
@ -1952,9 +1967,9 @@ preceded by 0x, otherwise it is decimal; octal numbers are not supported.
The standard C relational operators are all supported.
If after
variable expansion, either the left or right hand side of a
.Ql Ic ==
.Sq Ic ==
or
.Ql Ic "!="
.Sq Ic "!="
operator is not a numerical value, then
string comparison is performed between the expanded
variables.
@ -1971,17 +1986,17 @@ or
.Dq defined
expression is applied to it, depending on the form of the conditional.
If the form is
.Ql Ic .ifdef ,
.Ql Ic .ifndef ,
.Sq Ic .ifdef ,
.Sq Ic .ifndef ,
or
.Ql Ic .if
.Sq Ic .if
the
.Dq defined
expression is applied.
Similarly, if the form is
.Ql Ic .ifmake
.Sq Ic .ifmake
or
.Ql Ic .ifnmake ,
.Sq Ic .ifnmake ,
the
.Dq make
expression is applied.
@ -1990,9 +2005,9 @@ If the conditional evaluates to true the parsing of the makefile continues
as before.
If it evaluates to false, the following lines are skipped.
In both cases this continues until a
.Ql Ic .else
.Sq Ic .else
or
.Ql Ic .endif
.Sq Ic .endif
is found.
.Pp
For loops are typically used to apply a set of rules to a list of files.
@ -2243,16 +2258,17 @@ Synonym for
for compatibility with other pmake variants.
.It Ic .OBJDIR
The source is a new value for
.Ql Va .OBJDIR .
.Sq Va .OBJDIR .
If it exists,
.Nm
will
.Xr chdir 2
to it and update the value of
.Ql Va .OBJDIR .
.Sq Va .OBJDIR .
.It Ic .ORDER
The named targets are made in sequence.
In parallel mode, the named targets are made in sequence.
This ordering does not add targets to the list of targets to be made.
.Pp
Since the dependents of a target do not get built until the target itself
could be built, unless
.Ql a
@ -2263,9 +2279,6 @@ the following is a dependency loop:
b: a
.Ed
.Pp
The ordering imposed by
.Ic .ORDER
is only relevant for parallel makes.
.\" XXX: NOT YET!!!!
.\" .It Ic .PARALLEL
.\" The named targets are executed in parallel mode.
@ -2409,7 +2422,7 @@ may only be set in the environment or on the command line to
.Nm
and not as makefile variables;
see the description of
.Ql Va .OBJDIR
.Sq Va .OBJDIR
for more details.
.Sh FILES
.Bl -tag -width /usr/share/mk -compact

File diff suppressed because it is too large Load diff

Before

Width:  |  Height:  |  Size: 83 KiB

After

Width:  |  Height:  |  Size: 85 KiB

View file

@ -1,4 +1,4 @@
/* $NetBSD: compat.c,v 1.238 2022/01/22 18:59:23 rillig Exp $ */
/* $NetBSD: compat.c,v 1.240 2022/05/07 17:49:47 rillig Exp $ */
/*
* Copyright (c) 1988, 1989, 1990 The Regents of the University of California.
@ -70,16 +70,11 @@
*/
/*
* compat.c --
* The routines in this file implement the full-compatibility
* mode of PMake. Most of the special functionality of PMake
* is available in this mode. Things not supported:
* - different shells.
* - friendly variable substitution.
* This file implements the full-compatibility mode of make, which makes the
* targets without parallelism and without a custom shell.
*
* Interface:
* Compat_Run Initialize things for this module and recreate
* thems as need creatin'
* Compat_MakeAll Initialize this module and make the given targets.
*/
#ifdef HAVE_CONFIG_H
@ -99,7 +94,7 @@
#include "pathnames.h"
/* "@(#)compat.c 8.2 (Berkeley) 3/19/94" */
MAKE_RCSID("$NetBSD: compat.c,v 1.238 2022/01/22 18:59:23 rillig Exp $");
MAKE_RCSID("$NetBSD: compat.c,v 1.240 2022/05/07 17:49:47 rillig Exp $");
static GNode *curTarg = NULL;
static pid_t compatChild;
@ -466,14 +461,66 @@ RunCommands(GNode *gn)
}
}
static void
MakeInRandomOrder(GNode **gnodes, GNode **end, GNode *pgn)
{
GNode **it;
size_t r;
for (r = (size_t)(end - gnodes); r >= 2; r--) {
/* Biased, but irrelevant in practice. */
size_t i = (size_t)random() % r;
GNode *t = gnodes[r - 1];
gnodes[r - 1] = gnodes[i];
gnodes[i] = t;
}
for (it = gnodes; it != end; it++)
Compat_Make(*it, pgn);
}
static void
MakeWaitGroupsInRandomOrder(GNodeList *gnodes, GNode *pgn)
{
Vector vec;
GNodeListNode *ln;
GNode **nodes;
size_t i, n, start;
Vector_Init(&vec, sizeof(GNode *));
for (ln = gnodes->first; ln != NULL; ln = ln->next)
*(GNode **)Vector_Push(&vec) = ln->datum;
nodes = vec.items;
n = vec.len;
start = 0;
for (i = 0; i < n; i++) {
if (nodes[i]->type & OP_WAIT) {
MakeInRandomOrder(nodes + start, nodes + i, pgn);
Compat_Make(nodes[i], pgn);
start = i + 1;
}
}
MakeInRandomOrder(nodes + start, nodes + i, pgn);
Vector_Done(&vec);
}
static void
MakeNodes(GNodeList *gnodes, GNode *pgn)
{
GNodeListNode *ln;
if (Lst_IsEmpty(gnodes))
return;
if (opts.randomizeTargets) {
MakeWaitGroupsInRandomOrder(gnodes, pgn);
return;
}
for (ln = gnodes->first; ln != NULL; ln = ln->next) {
GNode *cohort = ln->datum;
Compat_Make(cohort, pgn);
GNode *cgn = ln->datum;
Compat_Make(cgn, pgn);
}
}
@ -692,14 +739,8 @@ InitSignals(void)
bmake_signal(SIGQUIT, CompatInterrupt);
}
/*
* Initialize this module and start making.
*
* Input:
* targs The target nodes to re-create
*/
void
Compat_Run(GNodeList *targs)
Compat_MakeAll(GNodeList *targs)
{
GNode *errorNode = NULL;

View file

@ -1,4 +1,4 @@
/* $NetBSD: dir.c,v 1.278 2022/02/04 23:22:19 rillig Exp $ */
/* $NetBSD: dir.c,v 1.279 2022/05/07 21:19:43 rillig Exp $ */
/*
* Copyright (c) 1988, 1989, 1990 The Regents of the University of California.
@ -138,7 +138,7 @@
#include "job.h"
/* "@(#)dir.c 8.2 (Berkeley) 1/2/94" */
MAKE_RCSID("$NetBSD: dir.c,v 1.278 2022/02/04 23:22:19 rillig Exp $");
MAKE_RCSID("$NetBSD: dir.c,v 1.279 2022/05/07 21:19:43 rillig Exp $");
/*
* A search path is a list of CachedDir structures. A CachedDir has in it the
@ -1035,7 +1035,7 @@ DirLookupAbs(CachedDir *dir, const char *name, const char *cp)
}
/*
* Find the file given on "." or curdir.
* Find the given file in "." or curdir.
* Return the freshly allocated path to the file, or NULL.
*/
static char *

View file

@ -1,4 +1,4 @@
/* $NetBSD: for.c,v 1.167 2022/02/04 23:22:19 rillig Exp $ */
/* $NetBSD: for.c,v 1.168 2022/06/12 16:09:21 rillig Exp $ */
/*
* Copyright (c) 1992, The Regents of the University of California.
@ -58,7 +58,7 @@
#include "make.h"
/* "@(#)for.c 8.1 (Berkeley) 6/6/93" */
MAKE_RCSID("$NetBSD: for.c,v 1.167 2022/02/04 23:22:19 rillig Exp $");
MAKE_RCSID("$NetBSD: for.c,v 1.168 2022/06/12 16:09:21 rillig Exp $");
typedef struct ForLoop {
@ -269,7 +269,14 @@ For_Accum(const char *line, int *forLevel)
return true;
}
/*
* When the body of a '.for i' loop is prepared for an iteration, each
* occurrence of $i in the body is replaced with ${:U...}, inserting the
* value of the item. If this item contains a '$', it may be the start of a
* variable expression. This expression is copied verbatim, its length is
* determined here, in a rather naive way, ignoring escape characters and
* funny delimiters in modifiers like ':S}from}to}'.
*/
static size_t
ExprLen(const char *s, const char *e)
{

View file

@ -1,4 +1,4 @@
/* $NetBSD: job.c,v 1.452 2022/02/12 11:14:48 rillig Exp $ */
/* $NetBSD: job.c,v 1.453 2022/05/07 08:01:20 rillig Exp $ */
/*
* Copyright (c) 1988, 1989, 1990 The Regents of the University of California.
@ -155,7 +155,7 @@
#include "trace.h"
/* "@(#)job.c 8.2 (Berkeley) 3/19/94" */
MAKE_RCSID("$NetBSD: job.c,v 1.452 2022/02/12 11:14:48 rillig Exp $");
MAKE_RCSID("$NetBSD: job.c,v 1.453 2022/05/07 08:01:20 rillig Exp $");
/*
* A shell defines how the commands are run. All commands for a target are
@ -2346,7 +2346,7 @@ Job_Init(void)
(void)Job_RunTarget(".BEGIN", NULL);
/*
* Create the .END node now, even though no code in the unit tests
* depends on it. See also Targ_GetEndNode in Compat_Run.
* depends on it. See also Targ_GetEndNode in Compat_MakeAll.
*/
(void)Targ_GetEndNode();
}

View file

@ -1,4 +1,4 @@
/* $NetBSD: main.c,v 1.580 2022/04/18 15:06:27 rillig Exp $ */
/* $NetBSD: main.c,v 1.582 2022/05/07 17:49:47 rillig Exp $ */
/*
* Copyright (c) 1988, 1989, 1990, 1993
@ -111,7 +111,7 @@
#include "trace.h"
/* "@(#)main.c 8.3 (Berkeley) 3/19/94" */
MAKE_RCSID("$NetBSD: main.c,v 1.580 2022/04/18 15:06:27 rillig Exp $");
MAKE_RCSID("$NetBSD: main.c,v 1.582 2022/05/07 17:49:47 rillig Exp $");
#if defined(MAKE_NATIVE) && !defined(lint)
__COPYRIGHT("@(#) Copyright (c) 1988, 1989, 1990, 1993 "
"The Regents of the University of California. "
@ -817,6 +817,8 @@ MakeMode(void)
if (strstr(mode, "meta") != NULL)
meta_mode_init(mode);
#endif
if (strstr(mode, "randomize-targets") != NULL)
opts.randomizeTargets = true;
}
free(mode);
@ -921,11 +923,7 @@ runTargets(void)
/* Traverse the graph, checking on all the targets */
outOfDate = Make_Run(&targs);
} else {
/*
* Compat_Init will take care of creating all the
* targets as well as initializing the module.
*/
Compat_Run(&targs);
Compat_MakeAll(&targs);
outOfDate = false;
}
Lst_Done(&targs); /* Don't free the targets themselves. */

View file

@ -1,4 +1,4 @@
.\" $NetBSD: make.1,v 1.308 2022/04/18 15:06:27 rillig Exp $
.\" $NetBSD: make.1,v 1.315 2022/07/12 23:47:00 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 April 18, 2022
.Dd July 12, 2022
.Dt MAKE 1
.Os
.Sh NAME
@ -61,12 +61,12 @@ If no
makefile option is given,
.Nm
will try to open
.Ql Pa makefile
.Sq Pa makefile
then
.Ql Pa Makefile
.Sq Pa Makefile
in order to find the specifications.
If the file
.Ql Pa .depend
.Sq Pa .depend
exists, it is read (see
.Xr mkdep 1 ) .
.Pp
@ -229,11 +229,11 @@ Specify that environment variables override macro assignments within
makefiles.
.It Fl f Ar makefile
Specify a makefile to read instead of the default
.Ql Pa makefile .
.Sq Pa makefile .
If
.Ar makefile
is
.Ql Fl ,
.Sq Fl ,
standard input is read.
Multiple makefiles may be specified, and are read in the order specified.
.It Fl I Ar directory
@ -244,7 +244,7 @@ option) is automatically included as part of this list.
.It Fl i
Ignore non-zero exit of shell commands in the makefile.
Equivalent to specifying
.Ql Fl
.Sq Fl
before each command line in the makefile.
.It Fl J Ar private
This option should
@ -252,7 +252,7 @@ This option should
be specified by the user.
.Pp
When the
.Ar j
.Fl j
option is in use in a recursive build, this option is passed by a make
to child makes to allow all the make processes in the build to
cooperate to avoid overloading the system.
@ -263,8 +263,8 @@ may have running at any one time.
The value is saved in
.Va .MAKE.JOBS .
Turns compatibility mode off, unless the
.Ar B
flag is also specified.
.Fl B
option is also specified.
When compatibility mode is off, all commands associated with a
target are executed in a single shell invocation as opposed to the
traditional one shell invocation per line.
@ -319,7 +319,7 @@ as an argument).
Display the commands that would have been executed, but do not
actually execute them unless the target depends on the .MAKE special
source (see below) or the command is prefixed with
.Ql Ic + .
.Sq Ic + .
.It Fl N
Display the commands which would have been executed, but do not
actually execute any of them; useful for debugging top-level makefiles
@ -336,7 +336,7 @@ This is the default behavior and the opposite of
.It Fl s
Do not echo any commands as they are executed.
Equivalent to specifying
.Ql Ic @
.Sq Ic @
before each command line in the makefile.
.It Fl T Ar tracefile
When used with the
@ -493,7 +493,7 @@ While targets can appear in many dependency lines if desired, by
default only one of these rules may be followed by a creation
script.
If the
.Ql Ic \&::
.Sq Ic \&::
operator is used, however, all rules may include scripts and the
scripts are executed in the order found.
.Pp
@ -505,23 +505,23 @@ in which case that line and the next are combined.
.\" normally ignores it.
.\" However, the tab at the beginning of the following line is removed.
If the first characters of the command are any combination of
.Ql Ic @ ,
.Ql Ic + ,
.Sq Ic @ ,
.Sq Ic + ,
or
.Ql Ic \- ,
.Sq Ic \- ,
the command is treated specially.
A
.Ql Ic @
.Sq Ic @
causes the command not to be echoed before it is executed.
A
.Ql Ic +
.Sq Ic +
causes the command to be executed even when
.Fl n
is given.
This is similar to the effect of the .MAKE special source,
except that the effect can be limited to a single line of a script.
A
.Ql Ic \-
.Sq Ic \-
in compatibility mode
causes any non-zero exit status of the command line to be ignored.
.Pp
@ -538,11 +538,11 @@ it will be passed to the shell; otherwise
.Nm
will attempt direct execution.
If a line starts with
.Ql Ic \-
.Sq Ic \-
and the shell has ErrCtl enabled then failure of the command line
will be ignored as in compatibility mode.
Otherwise
.Ql Ic \-
.Sq Ic \-
affects the entire job;
the script will stop at the first command line that fails,
but the target will not be deemed to have failed.
@ -576,27 +576,47 @@ Since
will
.Xr chdir 2
to
.Ql Va .OBJDIR
.Sq Va .OBJDIR
before executing any targets, each child process
starts with that as its current working directory.
.Sh VARIABLE ASSIGNMENTS
Variables in make are much like variables in the shell, and, by tradition,
consist of all upper-case letters.
.Ss Variable assignment modifiers
The five operators that can be used to assign values to variables are as
follows:
Variables in make behave much like macros in the C preprocessor.
.Pp
Variable assignments have the form
.Sq Ar NAME Ar op Ar value ,
where:
.Bl -tag -width Ds
.It Ar NAME
is a single-word variable name,
consisting, by tradition, of all upper-case letters,
.It Ar op
is one of the five variable assignment operators described below, and
.It Ar value
is interpreted according to the variable assignment operator.
.El
.Pp
Whitespace around
.Ar NAME ,
.Ar op
and
.Ar value
is discarded.
.Ss Variable assignment operators
The five operators that can be used to assign values to variables are:
.Bl -tag -width Ds
.It Ic \&=
Assign the value to the variable.
Any previous value is overridden.
Any previous value is overwritten.
.It Ic \&+=
Append the value to the current value of the variable.
Append the value to the current value of the variable,
separating them by a single space.
.It Ic \&?=
Assign the value to the variable if it is not already defined.
.It Ic \&:=
Assign with expansion, i.e. expand the value before assigning it
to the variable.
Normally, expansion is not done until the variable is referenced.
.Pp
.Em NOTE :
References to undefined variables are
.Em not
@ -607,45 +627,42 @@ Expand the value and pass it to the shell for execution and assign
the result to the variable.
Any newlines in the result are replaced with spaces.
.El
.Pp
Any white-space before the assigned
.Ar value
is removed; if the value is being appended, a single space is inserted
between the previous contents of the variable and the appended value.
.Pp
Variables are expanded by surrounding the variable name with either
curly braces
.Pq Ql {}
or parentheses
.Pq Ql ()
and preceding it with
a dollar sign
.Pq Ql \&$ .
If the variable name contains only a single letter, the surrounding
braces or parentheses are not required.
.Ss Expansion of variables
In contexts where variables are expanded,
.Ql \&$$
expands to a single dollar sign.
References to variables have the form
.Ql \&${ Ns Ar name Ns Oo \&: Ns Ar modifiers Oc Ns }
or
.Ql \&$( Ns Ar name Ns Oo \&: Ns Ar modifiers Oc Ns ) .
If the variable name contains only a single character,
the surrounding curly braces or parentheses are not required.
This shorter form is not recommended.
.Pp
If the variable name contains a dollar, then the name itself is expanded first.
This allows almost arbitrary variable names, however names containing dollar,
braces, parentheses, or whitespace are really best avoided!
braces, parentheses, or whitespace are really best avoided.
.Pp
If the result of expanding a variable contains a dollar sign
.Pq Ql \&$
.Pq Ql \&$ ,
the string is expanded again.
.Pp
Variable substitution occurs at three distinct times, depending on where
Variable substitution occurs at four distinct times, depending on where
the variable is being used.
.Bl -enum
.It
Variables in dependency lines are expanded as the line is read.
.It
Variables in conditionals are expanded individually,
but only as far as necessary to determine the result of the conditional.
.It
Variables in shell commands are expanded when the shell command is
executed.
.It
.Dq .for
loop index variables are expanded on each loop iteration.
Note that other variables are not expanded inside loops so
the following example code:
Note that other variables are not expanded when composing the body of a loop,
so the following example code:
.Bd -literal -offset indent
.Dv .for i in 1 2 3
@ -726,34 +743,34 @@ The seven built-in local variables are as follows:
.Bl -tag -width ".ARCHIVE" -offset indent
.It Va .ALLSRC
The list of all sources for this target; also known as
.Ql Va \&> .
.Sq Va \&> .
.It Va .ARCHIVE
The name of the archive file; also known as
.Ql Va \&! .
.Sq Va \&! .
.It Va .IMPSRC
In suffix-transformation rules, the name/path of the source from which the
target is to be transformed (the
.Dq implied
source); also known as
.Ql Va \&< .
.Sq Va \&< .
It is not defined in explicit rules.
.It Va .MEMBER
The name of the archive member; also known as
.Ql Va % .
.Sq Va % .
.It Va .OODATE
The list of sources for this target that were deemed out-of-date; also
known as
.Ql Va \&? .
.Sq Va \&? .
.It Va .PREFIX
The file prefix of the target, containing only the file portion, no suffix
or preceding directory components; also known as
.Ql Va * .
.Sq Va * .
The suffix must be one of the known suffixes declared with
.Ic .SUFFIXES
or it will not be recognized.
.It Va .TARGET
The name of the target; also known as
.Ql Va @ .
.Sq Va @ .
For compatibility with other makes this is an alias for
.Ic .ARCHIVE
in archive member rules.
@ -761,13 +778,13 @@ in archive member rules.
.Pp
The shorter forms
.Ql ( Va > ,
.Ql Va \&! ,
.Ql Va < ,
.Ql Va % ,
.Ql Va \&? ,
.Ql Va * ,
.Sq Va \&! ,
.Sq Va < ,
.Sq Va % ,
.Sq Va \&? ,
.Sq Va * ,
and
.Ql Va @ )
.Sq Va @ )
are permitted for backward
compatibility with historical makefiles and legacy POSIX make and are
not recommended.
@ -776,8 +793,8 @@ Variants of these variables with the punctuation followed immediately by
.Ql D
or
.Ql F ,
e.g.
.Ql Va $(@D) ,
e.g.\&
.Sq Va $(@D) ,
are legacy forms equivalent to using the
.Ql :H
and
@ -790,23 +807,16 @@ makefiles and POSIX but are not recommended.
Four of the local variables may be used in sources on dependency lines
because they expand to the proper value for each target on the line.
These variables are
.Ql Va .TARGET ,
.Ql Va .PREFIX ,
.Ql Va .ARCHIVE ,
.Sq Va .TARGET ,
.Sq Va .PREFIX ,
.Sq Va .ARCHIVE ,
and
.Ql Va .MEMBER .
.Sq Va .MEMBER .
.Ss Additional built-in variables
In addition,
.Nm
sets or knows about the following variables:
.Bl -tag -width .MAKEOVERRIDES
.It Va \&$
A single dollar sign
.Ql \&$ ,
i.e.
.Ql \&$$
expands to a single dollar
sign.
.It Va .ALLTARGETS
The list of all targets encountered in the Makefile.
If evaluated during
@ -816,7 +826,7 @@ A path to the directory where
.Nm
was executed.
Refer to the description of
.Ql Ev PWD
.Sq Ev PWD
for more details.
.It Va .INCLUDEDFROMDIR
The directory of the file this Makefile was included from.
@ -850,7 +860,7 @@ for backwards compatability with
and earlier.
.It Va .MAKE.DEPENDFILE
Names the makefile (default
.Ql Pa .depend )
.Sq Pa .depend )
from which generated dependencies are read.
.It Va .MAKE.EXPAND_VARIABLES
A boolean that controls the default behavior of the
@ -871,17 +881,18 @@ option.
If
.Nm
is run with
.Ar j
then output for each target is prefixed with a token
.Fl j ,
the output for each target is prefixed with a token
.Ql --- target ---
the first part of which can be controlled via
.Va .MAKE.JOB.PREFIX .
If
.Va .MAKE.JOB.PREFIX
is empty, no token is printed.
.br
For example:
.Li .MAKE.JOB.PREFIX=${.newline}---${.MAKE:T}[${.MAKE.PID}]
For example, setting
.Va .MAKE.JOB.PREFIX
to
.Li ${.newline}---${.MAKE:T}[${.MAKE.PID}]
would produce tokens like
.Ql ---make[1234] target ---
making it easier to track the degree of parallelism being achieved.
@ -892,7 +903,7 @@ apparent variable assignments in dependency lines are
treated as normal sources.
.It Ev MAKEFLAGS
The environment variable
.Ql Ev MAKEFLAGS
.Sq Ev MAKEFLAGS
may contain anything that
may be specified on
.Nm Ns 's
@ -900,7 +911,7 @@ command line.
Anything specified on
.Nm Ns 's
command line is appended to the
.Ql Ev MAKEFLAGS
.Sq Ev MAKEFLAGS
variable which is then
entered into the environment for all programs which
.Nm
@ -919,8 +930,8 @@ to protect things which should only be evaluated in the initial instance of
.It Va .MAKE.MAKEFILE_PREFERENCE
The ordered list of makefile names
(default
.Ql Pa makefile ,
.Ql Pa Makefile )
.Sq Pa makefile ,
.Sq Pa Makefile )
that
.Nm
will look for.
@ -955,7 +966,7 @@ The captured output can be very useful when diagnosing errors.
Normally
.Nm
will not create .meta files in
.Ql Va .CURDIR .
.Sq Va .CURDIR .
This can be overridden by setting
.Va bf
to a value which represents True.
@ -989,6 +1000,10 @@ If
.Va bf
is True, when a .meta file is created, mark the target
.Ic .SILENT .
.It Pa randomize-targets
In both compat and parallel mode, do not make the targets in the usual order,
but instead randomize their order.
This mode can be used to detect undeclared dependencies between files.
.El
.It Va .MAKE.META.BAILIWICK
In "meta" mode, provides a list of prefixes which
@ -1018,7 +1033,7 @@ information.
Provides a list of path prefixes that should be ignored;
because the contents are expected to change over time.
The default list includes:
.Ql Pa /dev /etc /proc /tmp /var/run /var/tmp
.Sq Pa /dev /etc /proc /tmp /var/run /var/tmp
.It Va .MAKE.META.IGNORE_PATTERNS
Provides a list of patterns to match against pathnames.
Ignore any that match.
@ -1032,16 +1047,16 @@ The default value is:
.It Va .MAKEOVERRIDES
This variable is used to record the names of variables assigned to
on the command line, so that they may be exported as part of
.Ql Ev MAKEFLAGS .
.Sq Ev MAKEFLAGS .
This behavior can be disabled by assigning an empty value to
.Ql Va .MAKEOVERRIDES
.Sq Va .MAKEOVERRIDES
within a makefile.
Extra variables can be exported from a makefile
by appending their names to
.Ql Va .MAKEOVERRIDES .
.Ql Ev MAKEFLAGS
.Sq Va .MAKEOVERRIDES .
.Sq Ev MAKEFLAGS
is re-exported whenever
.Ql Va .MAKEOVERRIDES
.Sq Va .MAKEOVERRIDES
is modified.
.It Va .MAKE.PATH_FILEMON
If
@ -1079,21 +1094,21 @@ The group-id running
When
.Nm
stops due to an error, it sets
.Ql Va .ERROR_TARGET
.Sq Va .ERROR_TARGET
to the name of the target that failed,
.Ql Va .ERROR_CMD
.Sq Va .ERROR_CMD
to the commands of the failed target,
and in "meta" mode, it also sets
.Ql Va .ERROR_CWD
.Sq Va .ERROR_CWD
to the
.Xr getcwd 3 ,
and
.Ql Va .ERROR_META_FILE
.Sq Va .ERROR_META_FILE
to the path of the meta file (if any) describing the failed target.
It then prints its name and the value of
.Ql Va .CURDIR
.Sq Va .CURDIR
as well as the value of any variables named in
.Ql Va MAKE_PRINT_VAR_ON_ERROR .
.Sq Va MAKE_PRINT_VAR_ON_ERROR .
.It Va .newline
This variable is simply assigned a newline character as its value.
This allows expansions using the
@ -1101,7 +1116,7 @@ This allows expansions using the
modifier to put a newline between
iterations of the loop rather than a space.
For example, the printing of
.Ql Va MAKE_PRINT_VAR_ON_ERROR
.Sq Va MAKE_PRINT_VAR_ON_ERROR
could be done as ${MAKE_PRINT_VAR_ON_ERROR:@v@$v='${$v}'${.newline}@}.
.It Va .OBJDIR
A path to the directory where the targets are built.
@ -1113,13 +1128,13 @@ to the following directories in order and using the first match:
.Ev ${MAKEOBJDIRPREFIX}${.CURDIR}
.Pp
(Only if
.Ql Ev MAKEOBJDIRPREFIX
.Sq Ev MAKEOBJDIRPREFIX
is set in the environment or on the command line.)
.It
.Ev ${MAKEOBJDIR}
.Pp
(Only if
.Ql Ev MAKEOBJDIR
.Sq Ev MAKEOBJDIR
is set in the environment or on the command line.)
.It
.Ev ${.CURDIR} Ns Pa /obj. Ns Ev ${MACHINE}
@ -1136,77 +1151,77 @@ so expressions such as
.Dl ${.CURDIR:S,^/usr/src,/var/obj,}
may be used.
This is especially useful with
.Ql Ev MAKEOBJDIR .
.Sq Ev MAKEOBJDIR .
.Pp
.Ql Va .OBJDIR
.Sq Va .OBJDIR
may be modified in the makefile via the special target
.Ql Ic .OBJDIR .
.Sq Ic .OBJDIR .
In all cases,
.Nm
will
.Xr chdir 2
to the specified directory if it exists, and set
.Ql Va .OBJDIR
.Sq Va .OBJDIR
and
.Ql Ev PWD
.Sq Ev PWD
to that directory before executing any targets.
.Pp
Except in the case of an explicit
.Ql Ic .OBJDIR
.Sq Ic .OBJDIR
target,
.Nm
will check that the specified directory is writable and ignore it if not.
This check can be skipped by setting the environment variable
.Ql Ev MAKE_OBJDIR_CHECK_WRITABLE
.Sq Ev MAKE_OBJDIR_CHECK_WRITABLE
to "no".
.
.It Va .PARSEDIR
A path to the directory of the current
.Ql Pa Makefile
.Sq Pa Makefile
being parsed.
.It Va .PARSEFILE
The basename of the current
.Ql Pa Makefile
.Sq Pa Makefile
being parsed.
This variable and
.Ql Va .PARSEDIR
.Sq Va .PARSEDIR
are both set only while the
.Ql Pa Makefiles
.Sq Pa Makefiles
are being parsed.
If you want to retain their current values, assign them to a variable
using assignment with expansion:
.Pq Ql Cm \&:= .
using assignment with expansion
.Sq Cm \&:= .
.It Va .PATH
A variable that represents the list of directories that
.Nm
will search for files.
The search list should be updated using the target
.Ql Va .PATH
.Sq Va .PATH
rather than the variable.
.It Ev PWD
Alternate path to the current directory.
.Nm
normally sets
.Ql Va .CURDIR
.Sq Va .CURDIR
to the canonical path given by
.Xr getcwd 3 .
However, if the environment variable
.Ql Ev PWD
.Sq Ev PWD
is set and gives a path to the current directory, then
.Nm
sets
.Ql Va .CURDIR
.Sq Va .CURDIR
to the value of
.Ql Ev PWD
.Sq Ev PWD
instead.
This behavior is disabled if
.Ql Ev MAKEOBJDIRPREFIX
.Sq Ev MAKEOBJDIRPREFIX
is set or
.Ql Ev MAKEOBJDIR
.Sq Ev MAKEOBJDIR
contains a variable transform.
.Ql Ev PWD
.Sq Ev PWD
is set to the value of
.Ql Va .OBJDIR
.Sq Va .OBJDIR
for all programs which
.Nm
executes.
@ -1226,7 +1241,7 @@ lists of directories that
will search for files.
The variable is supported for compatibility with old make programs only,
use
.Ql Va .PATH
.Sq Va .PATH
instead.
.El
.Ss Variable modifiers
@ -1260,14 +1275,14 @@ The supported modifiers are:
Replaces each word in the variable with its suffix.
.It Cm \&:H
Replaces each word in the variable with everything but the last component.
.It Cm \&:M Ns Ar pattern
.It Cm \&:M\| Ns Ar pattern
Selects only those words that match
.Ar pattern .
The standard shell wildcard characters
.Pf ( Ql * ,
.Ql \&? ,
and
.Ql Oo Oc )
.Ql \&[] )
may
be used.
The wildcard characters may be escaped with a backslash
@ -1279,9 +1294,9 @@ will normalize the inter-word spacing, removing all leading and
trailing space, and converting multiple consecutive spaces
to single spaces.
.
.It Cm \&:N Ns Ar pattern
.It Cm \&:N\| Ns Ar pattern
This is identical to
.Ql Cm \&:M ,
.Sq Cm \&:M ,
but selects all words which do not match
.Ar pattern .
.It Cm \&:O
@ -1304,7 +1319,7 @@ Orders every word in variable in reverse numerical order.
Shuffles the words in variable.
The results will be different each time you are referring to the
modified variable; use the assignment with expansion
.Pq Ql Cm \&:=
.Sq Cm \&:=
to prevent such behavior.
For example,
.Bd -literal -offset indent
@ -1338,11 +1353,11 @@ This is equivalent to:
.Sq \&:S/\e\&$/&&/g:Q .
.It Cm \&:R
Replaces each word in the variable with everything but its suffix.
.It Cm \&:range[=count]
.It Cm \&:range Ns Oo = Ns Ar count Oc
The value is an integer sequence representing the words of the original
value, or the supplied
.Va count .
.It Cm \&:gmtime[=utc]
.It Cm \&:gmtime Ns Oo = Ns Ar utc Oc
The value is a format string for
.Xr strftime 3 ,
using
@ -1352,7 +1367,7 @@ If a
value is not provided or is 0, the current time is used.
.It Cm \&:hash
Computes a 32-bit hash of the value and encode it as hex digits.
.It Cm \&:localtime[=utc]
.It Cm \&:localtime Ns Oo = Ns Ar utc Oc
The value is a format string for
.Xr strftime 3 ,
using
@ -1380,14 +1395,14 @@ Converts variable to upper-case letters.
Causes the value to be treated as a single word
(possibly containing embedded white space).
See also
.Ql Cm \&:[*] .
.Sq Cm \&:[*] .
.It Cm \&:tw
Causes the value to be treated as a sequence of
words delimited by white space.
See also
.Ql Cm \&:[@] .
.Sq Cm \&:[@] .
.Sm off
.It Cm \&:S No \&/ Ar old_string No \&/ Ar new_string No \&/ Op Cm 1gW
.It Cm \&:S\| No \&/ Ar old_string\| No \&/ Ar new_string\| No \&/ Op Cm 1gW
.Sm on
Modifies the first occurrence of
.Ar old_string
@ -1442,7 +1457,7 @@ of a dollar sign
.Pq Ql \&$ ,
not a preceding dollar sign as is usual.
.Sm off
.It Cm \&:C No \&/ Ar pattern No \&/ Ar replacement No \&/ Op Cm 1gW
.It Cm \&:C\| No \&/ Ar pattern\| No \&/ Ar replacement\| No \&/ Op Cm 1gW
.Sm on
The
.Cm \&:C
@ -1487,7 +1502,7 @@ Replaces each word in the variable with its last path component.
Removes adjacent duplicate words (like
.Xr uniq 1 ) .
.Sm off
.It Cm \&:\&? Ar true_string Cm \&: Ar false_string
.It Cm \&:\&?\| Ar true_string\| Cm \&: Ar false_string
.Sm on
If the variable name (not its value), when parsed as a .if conditional
expression, evaluates to true, return as its value the
@ -1502,7 +1517,7 @@ A common error is trying to use expressions like
which actually tests defined(NUMBERS),
to determine if any words match "42" you need to use something like:
.Dl ${"${NUMBERS:M42}" != \&"\&":?match:no} .
.It Ar :old_string=new_string
.It Cm :\| Ns Ar old_string\| Ns Cm = Ns Ar new_string
This is the
.At V
style variable substitution.
@ -1555,7 +1570,7 @@ expansion of a dollar sign
.Pq Ql \&$ ,
not a preceding dollar sign as is usual.
.Sm off
.It Cm \&:@ Ar temp Cm @ Ar string Cm @
.It Cm \&:@ Ar temp\| Cm @ Ar string\| Cm @
.Sm on
This is the loop expansion mechanism from the OSF Development
Environment (ODE) make.
@ -1574,7 +1589,7 @@ For example.
.Pp
However a single character variable is often more readable:
.Dl ${MAKE_PRINT_VAR_ON_ERROR:@v@$v='${$v}'${.newline}@}
.It Cm \&:_[=var]
.It Cm \&:_ Ns Oo Cm = Ns Ar var Oc
Saves the current variable value in
.Ql $_
or the named
@ -1595,7 +1610,7 @@ is used to save the result of the
.Ql :S
modifier which is later referenced using the index values from
.Ql :range .
.It Cm \&:U Ns Ar newval
.It Cm \&:U\| Ns Ar newval
If the variable is undefined,
.Ar newval
is the value.
@ -1605,7 +1620,7 @@ It is handy for setting per-target CFLAGS for instance:
.Dl ${_${.TARGET:T}_CFLAGS:U${DEF_CFLAGS}}
If a value is only required if the variable is undefined, use:
.Dl ${VAR:D:Unewval}
.It Cm \&:D Ns Ar newval
.It Cm \&:D\| Ns Ar newval
If the variable is defined,
.Ar newval
is the value.
@ -1619,7 +1634,7 @@ name of the variable is used.
In order for this modifier to work, the name (node) must at least have
appeared on the rhs of a dependency.
.Sm off
.It Cm \&:\&! Ar cmd Cm \&!
.It Cm \&:\&! Ar cmd\| Cm \&!
.Sm on
The output of running
.Ar cmd
@ -1641,7 +1656,7 @@ preceded with something to keep
happy.
.Pp
The
.Ql Cm \&::
.Sq Cm \&::
helps avoid false matches with the
.At V
style
@ -1674,7 +1689,7 @@ causing a value to be treated as a single word
An empty value, or a value that consists entirely of white-space,
is treated as a single word.
For the purposes of the
.Ql Cm \&:[]
.Sq Cm \&:[]
modifier, the words are indexed both forwards using positive integers
(where index 1 represents the first word),
and backwards using negative integers
@ -1696,7 +1711,7 @@ to
.Ar end ,
inclusive.
For example,
.Ql Cm \&:[2..-1]
.Sq Cm \&:[2..-1]
selects all words from the second word to the last word.
If
.Ar start
@ -1704,13 +1719,13 @@ is greater than
.Ar end ,
then the words are output in reverse order.
For example,
.Ql Cm \&:[-1..1]
.Sq Cm \&:[-1..1]
selects all the words from last to first.
If the list is already ordered, then this effectively reverses
the list, but it is more efficient to use
.Ql Cm \&:Or
.Sq Cm \&:Or
instead of
.Ql Cm \&:O:[-1..1] .
.Sq Cm \&:O:[-1..1] .
.\" :[*]
.It Cm \&*
Causes subsequent modifiers to treat the value as a single word
@ -1721,7 +1736,7 @@ in Bourne shell.
.\" :[0]
.It 0
Means the same as
.Ql Cm \&:[*] .
.Sq Cm \&:[*] .
.\" :[*]
.It Cm \&@
Causes subsequent modifiers to treat the value as a sequence of words
@ -1848,14 +1863,14 @@ PATH := ${PATH}
.Pp
.Ed
Would result in an environment containing only
.Ql Ev PATH ,
.Sq Ev PATH ,
which is the minimal useful environment.
Actually
.Ql Ev .MAKE.LEVEL
.Sq Ev .MAKE.LEVEL
will also be pushed into the new environment.
.It Ic .warning Ar message
The message prefixed by
.Ql Pa warning:
.Sq Pa warning:
is printed along with the name of the makefile and line number.
.It Ic \&.if Oo \&! Oc Ns Ar expression Op Ar operator expression ...
Test the value of an expression.
@ -1871,29 +1886,29 @@ Test the target being built.
Reverse the sense of the last conditional.
.It Ic .elif Oo \&! Ns Oc Ar expression Op Ar operator expression ...
A combination of
.Ql Ic .else
.Sq Ic .else
followed by
.Ql Ic .if .
.Sq Ic .if .
.It Ic .elifdef Oo \&! Oc Ns Ar variable Op Ar operator variable ...
A combination of
.Ql Ic .else
.Sq Ic .else
followed by
.Ql Ic .ifdef .
.Sq Ic .ifdef .
.It Ic .elifndef Oo \&! Oc Ns Ar variable Op Ar operator variable ...
A combination of
.Ql Ic .else
.Sq Ic .else
followed by
.Ql Ic .ifndef .
.Sq Ic .ifndef .
.It Ic .elifmake Oo \&! Oc Ns Ar target Op Ar operator target ...
A combination of
.Ql Ic .else
.Sq Ic .else
followed by
.Ql Ic .ifmake .
.Sq Ic .ifmake .
.It Ic .elifnmake Oo \&! Oc Ns Ar target Op Ar operator target ...
A combination of
.Ql Ic .else
.Sq Ic .else
followed by
.Ql Ic .ifnmake .
.Sq Ic .ifnmake .
.It Ic .endif
End the body of the conditional.
.El
@ -1917,11 +1932,11 @@ will only evaluate a conditional as far as is necessary to determine
its value.
Parentheses may be used to change the order of evaluation.
The boolean operator
.Ql Ic \&!
.Sq Ic \&!
may be used to logically negate an entire
conditional.
It is of higher precedence than
.Ql Ic \&&& .
.Sq Ic \&&& .
.Pp
The value of
.Ar expression
@ -1963,9 +1978,9 @@ preceded by 0x, otherwise it is decimal; octal numbers are not supported.
The standard C relational operators are all supported.
If after
variable expansion, either the left or right hand side of a
.Ql Ic ==
.Sq Ic ==
or
.Ql Ic "!="
.Sq Ic "!="
operator is not a numerical value, then
string comparison is performed between the expanded
variables.
@ -1982,17 +1997,17 @@ or
.Dq defined
expression is applied to it, depending on the form of the conditional.
If the form is
.Ql Ic .ifdef ,
.Ql Ic .ifndef ,
.Sq Ic .ifdef ,
.Sq Ic .ifndef ,
or
.Ql Ic .if
.Sq Ic .if
the
.Dq defined
expression is applied.
Similarly, if the form is
.Ql Ic .ifmake
.Sq Ic .ifmake
or
.Ql Ic .ifnmake ,
.Sq Ic .ifnmake ,
the
.Dq make
expression is applied.
@ -2001,9 +2016,9 @@ If the conditional evaluates to true the parsing of the makefile continues
as before.
If it evaluates to false, the following lines are skipped.
In both cases this continues until a
.Ql Ic .else
.Sq Ic .else
or
.Ql Ic .endif
.Sq Ic .endif
is found.
.Pp
For loops are typically used to apply a set of rules to a list of files.
@ -2254,16 +2269,17 @@ Synonym for
for compatibility with other pmake variants.
.It Ic .OBJDIR
The source is a new value for
.Ql Va .OBJDIR .
.Sq Va .OBJDIR .
If it exists,
.Nm
will
.Xr chdir 2
to it and update the value of
.Ql Va .OBJDIR .
.Sq Va .OBJDIR .
.It Ic .ORDER
The named targets are made in sequence.
In parallel mode, the named targets are made in sequence.
This ordering does not add targets to the list of targets to be made.
.Pp
Since the dependents of a target do not get built until the target itself
could be built, unless
.Ql a
@ -2274,9 +2290,6 @@ the following is a dependency loop:
b: a
.Ed
.Pp
The ordering imposed by
.Ic .ORDER
is only relevant for parallel makes.
.\" XXX: NOT YET!!!!
.\" .It Ic .PARALLEL
.\" The named targets are executed in parallel mode.
@ -2420,7 +2433,7 @@ may only be set in the environment or on the command line to
.Nm
and not as makefile variables;
see the description of
.Ql Va .OBJDIR
.Sq Va .OBJDIR
for more details.
.Sh FILES
.Bl -tag -width /usr/share/mk -compact

View file

@ -1,4 +1,4 @@
/* $NetBSD: make.c,v 1.252 2022/01/09 15:48:30 rillig Exp $ */
/* $NetBSD: make.c,v 1.255 2022/05/07 17:49:47 rillig Exp $ */
/*
* Copyright (c) 1988, 1989, 1990, 1993
@ -104,7 +104,7 @@
#include "job.h"
/* "@(#)make.c 8.1 (Berkeley) 6/6/93" */
MAKE_RCSID("$NetBSD: make.c,v 1.252 2022/01/09 15:48:30 rillig Exp $");
MAKE_RCSID("$NetBSD: make.c,v 1.255 2022/05/07 17:49:47 rillig Exp $");
/* Sequence # to detect recursion. */
static unsigned int checked_seqno = 1;
@ -127,17 +127,6 @@ debug_printf(const char *fmt, ...)
va_end(ap);
}
MAKE_ATTR_DEAD static void
make_abort(GNode *gn, int lineno)
{
debug_printf("make_abort from line %d\n", lineno);
Targ_PrintNode(gn, 2);
Targ_PrintNodes(&toBeMade, 2);
Targ_PrintGraph(3);
abort();
}
static const char *
GNodeType_ToString(GNodeType type, void **freeIt)
{
@ -644,7 +633,7 @@ IsWaitingForOrder(GNode *gn)
return false;
}
static void MakeBuildParent(GNode *, GNodeListNode *);
static bool MakeBuildChild(GNode *, GNodeListNode *);
static void
ScheduleOrderSuccessors(GNode *gn)
@ -652,8 +641,13 @@ ScheduleOrderSuccessors(GNode *gn)
GNodeListNode *toBeMadeNext = toBeMade.first;
GNodeListNode *ln;
for (ln = gn->order_succ.first; ln != NULL; ln = ln->next)
MakeBuildParent(ln->datum, toBeMadeNext);
for (ln = gn->order_succ.first; ln != NULL; ln = ln->next) {
GNode *succ = ln->datum;
if (succ->made == DEFERRED &&
!MakeBuildChild(succ, toBeMadeNext))
succ->flags.doneOrder = true;
}
}
/*
@ -938,6 +932,28 @@ GNode_SetLocalVars(GNode *gn)
gn->flags.doneAllsrc = true;
}
static void
ScheduleRandomly(GNode *gn)
{
GNodeListNode *ln;
size_t i, n;
n = 0;
for (ln = toBeMade.first; ln != NULL; ln = ln->next)
n++;
i = n > 0 ? (size_t)random() % (n + 1) : 0;
if (i == 0) {
Lst_Append(&toBeMade, gn);
return;
}
i--;
for (ln = toBeMade.first; i > 0; ln = ln->next)
i--;
Lst_InsertBefore(&toBeMade, ln, gn);
}
static bool
MakeBuildChild(GNode *cn, GNodeListNode *toBeMadeNext)
{
@ -963,7 +979,9 @@ MakeBuildChild(GNode *cn, GNodeListNode *toBeMadeNext)
cn->name, cn->cohort_num);
cn->made = REQUESTED;
if (toBeMadeNext == NULL)
if (opts.randomizeTargets && !(cn->type & OP_WAIT))
ScheduleRandomly(cn);
else if (toBeMadeNext == NULL)
Lst_Append(&toBeMade, cn);
else
Lst_InsertBefore(&toBeMade, toBeMadeNext, cn);
@ -983,19 +1001,6 @@ MakeBuildChild(GNode *cn, GNodeListNode *toBeMadeNext)
return cn->type & OP_WAIT && cn->unmade > 0;
}
/* When a .ORDER LHS node completes, we do this on each RHS. */
static void
MakeBuildParent(GNode *pn, GNodeListNode *toBeMadeNext)
{
if (pn->made != DEFERRED)
return;
if (!MakeBuildChild(pn, toBeMadeNext)) {
/* When this node is built, reschedule its parents. */
pn->flags.doneOrder = true;
}
}
static void
MakeChildren(GNode *gn)
{
@ -1033,13 +1038,12 @@ MakeStartJobs(void)
DEBUG2(MAKE, "Examining %s%s...\n", gn->name, gn->cohort_num);
if (gn->made != REQUESTED) {
/*
* XXX: Replace %d with string representation;
* see made_name.
*/
DEBUG1(MAKE, "state %d\n", gn->made);
make_abort(gn, __LINE__);
debug_printf("internal error: made = %s\n",
GNodeMade_Name(gn->made));
Targ_PrintNode(gn, 2);
Targ_PrintNodes(&toBeMade, 2);
Targ_PrintGraph(3);
abort();
}
if (gn->checked_seqno == checked_seqno) {

View file

@ -1,4 +1,4 @@
/* $NetBSD: make.h,v 1.300 2022/04/18 15:06:27 rillig Exp $ */
/* $NetBSD: make.h,v 1.303 2022/06/12 13:37:32 rillig Exp $ */
/*
* Copyright (c) 1988, 1989, 1990, 1993
@ -785,6 +785,11 @@ typedef struct CmdOpts {
*/
StringList create;
/*
* Randomize the order in which the targets from toBeMade are made,
* to catch undeclared dependencies.
*/
bool randomizeTargets;
} CmdOpts;
extern CmdOpts opts;
@ -804,7 +809,7 @@ bool Arch_IsLib(GNode *) MAKE_ATTR_USE;
/* compat.c */
bool Compat_RunCommand(const char *, GNode *, StringListNode *);
void Compat_Run(GNodeList *);
void Compat_MakeAll(GNodeList *);
void Compat_Make(GNode *, GNode *);
/* cond.c */
@ -863,7 +868,7 @@ bool GetBooleanExpr(const char *, bool);
void Parse_Init(void);
void Parse_End(void);
void PrintLocation(FILE *, bool, const char *, unsigned);
void PrintLocation(FILE *, bool, const GNode *);
void PrintStackTrace(bool);
void Parse_Error(ParseErrorLevel, const char *, ...) MAKE_ATTR_PRINTFLIKE(2, 3);
bool Parse_VarAssign(const char *, bool, GNode *) MAKE_ATTR_USE;

View file

@ -1,3 +1,23 @@
2022-07-20 Simon J Gerraty <sjg@beast.crufty.net>
* install-mk (MK_VERSION): 20220720
* prog.mk: handle PROG_CXX for more than just NetBSD
2022-06-20 Simon J Gerraty <sjg@beast.crufty.net>
* install-mk (MK_VERSION): 20220620
* yacc.mk: when we have *.y in SRCS used explicit rules and .ORDER
rather than just suffix rules
2022-04-23 Simon J Gerraty <sjg@beast.crufty.net>
* install-mk (MK_VERSION): 20220422
* gendirdeps.mk: If LOCAL_DEPENDS_GUARD is set to "no"
do not capture any local depends in Makefile.depend
2022-03-25 Simon J Gerraty <sjg@beast.crufty.net>
* install-mk (MK_VERSION): 20220323

View file

@ -1,4 +1,4 @@
# $Id: gendirdeps.mk,v 1.46 2020/08/19 17:51:53 sjg Exp $
# $Id: gendirdeps.mk,v 1.47 2022/04/23 21:37:03 sjg Exp $
# Copyright (c) 2011-2020, Simon J. Gerraty
# Copyright (c) 2010-2018, Juniper Networks, Inc.
@ -339,6 +339,8 @@ CAT_DEPEND ?= .depend
.PHONY: ${_DEPENDFILE}
.endif
# set this to 'no' and we will not capture any
# local depends
LOCAL_DEPENDS_GUARD ?= _{.MAKE.LEVEL} > 0
# 'cat .depend' should suffice, but if we are mixing build modes
@ -351,6 +353,7 @@ ${_DEPENDFILE}: .NOMETA ${CAT_DEPEND:M.depend} ${META_FILES:O:u:@m@${exists($m):
echo '${DIRDEPS:@d@ $d \\${.newline}@}'; echo; \
${_include_src_dirdeps} \
echo '.include <dirdeps.mk>'; \
[ "${LOCAL_DEPENDS_GUARD:[1]:tl}" != no ] || exit 0; \
echo; \
echo '.if ${LOCAL_DEPENDS_GUARD}'; \
echo '# local dependencies - needed for -jN in clean tree'; \

View file

@ -55,7 +55,7 @@
# Simon J. Gerraty <sjg@crufty.net>
# RCSid:
# $Id: install-mk,v 1.217 2022/03/25 23:43:43 sjg Exp $
# $Id: install-mk,v 1.220 2022/07/22 20:08:56 sjg Exp $
#
# @(#) Copyright (c) 1994 Simon J. Gerraty
#
@ -70,7 +70,7 @@
# sjg@crufty.net
#
MK_VERSION=20220323
MK_VERSION=20220720
OWNER=
GROUP=
MODE=444

View file

@ -1,8 +1,8 @@
#!/bin/sh
# $Id: mkopt.sh,v 1.13 2020/08/19 17:51:53 sjg Exp $
# $Id: mkopt.sh,v 1.15 2022/06/06 21:34:21 sjg Exp $
#
# @(#) Copyright (c) 2014, 2020, Simon J. Gerraty
# @(#) Copyright (c) 2014-2022, Simon J. Gerraty
#
# This file is provided in the hope that it will
# be of use. There is absolutely NO WARRANTY.
@ -84,9 +84,36 @@ _mk_opts_defaults() {
$OPTIONS_DEFAULT_DEPENDENT $__DEFAULT_DEPENDENT_OPTIONS
}
# _mk_cmdline_opts opt ...
# look at the command line (saved in _cmdline)
# to see any options we care about are being set with -DWITH*
# or MK_*= if 'opt' is '*' then all options are of interest.
_cmdline="$0 $@"
_mk_cmdline_opts() {
for _x in $_cmdline
do
case "$_x" in
-DWITH*|${_MKOPT_PREFIX:-MK_}*)
for _o in "$@"
do
case "$_x" in
-DWITH_$_o|-DWITHOUT_$_o) eval ${_x#-D}=1;;
-DWITH_$_o=*|-DWITHOUT_$_o=*) eval ${_x#-D};;
${_MKOPT_PREFIX:-MK_}$_o=*) eval "$_x";;
esac
done
;;
esac
done
}
case "/$0" in
*/mkopt*)
_list=no
_mk_cmdline_opts '*'
_mk_opts no DEBUG
[ $MK_DEBUG = no ] || set -x
while :
do
case "$1" in

View file

@ -1,4 +1,4 @@
# $Id: prog.mk,v 1.37 2021/12/08 05:56:50 sjg Exp $
# $Id: prog.mk,v 1.38 2022/07/22 20:08:56 sjg Exp $
.if !target(__${.PARSEFILE}__)
__${.PARSEFILE}__: .NOTMAIN
@ -73,6 +73,13 @@ ${CXX_SUFFIXES:%=%.o}:
@rm -f x.cc
.endif
.if defined(PROG_CXX)
PROG= ${PROG_CXX}
_CCLINK= ${CXX}
_SUPCXX?= -lstdc++ -lm
.endif
_CCLINK?= ${CC}
.if defined(PROG)
BINDIR ?= ${prefix}/bin
@ -100,15 +107,8 @@ _PROGLDOPTS+= -Wl,-rpath-link,${DESTDIR}${SHLIBDIR}:${DESTDIR}/usr/lib \
-L${DESTDIR}${SHLIBDIR}
.endif
_PROGLDOPTS+= -Wl,-rpath,${SHLIBDIR}:/usr/lib
.if defined(PROG_CXX)
_CCLINK= ${CXX}
_SUPCXX= -lstdc++ -lm
.endif
.endif # NetBSD
_CCLINK?= ${CC}
.if ${MK_PROG_LDORDER_MK} != "no"
${PROG}: ldorder

View file

@ -1,4 +1,4 @@
# $Id: yacc.mk,v 1.7 2020/08/19 17:51:53 sjg Exp $
# $Id: yacc.mk,v 1.8 2022/06/22 04:51:06 sjg Exp $
#
# @(#) Copyright (c) 1999-2011, Simon J. Gerraty
@ -23,6 +23,28 @@ RM?= rm
YACC.y?= ${YACC} ${YFLAGS}
# first deal with explicit *.y in SRCS
.for y in ${SRCS:M*.y}
.if ${YACC.y:M-d} == "" || defined(NO_RENAME_Y_TAB_H)
.ORDER: ${y:T:R}.c y.tab.h
y.tab.h: .NOMETA
${y:T:R}.c y.tab.h: $y
${YACC.y} ${.IMPSRC}
[ ! -s y.tab.c ] || mv y.tab.c ${.TARGET}
${RM} -f y.tab.[!h]
.else
.ORDER: ${y:T:R}.c ${y:T:R}.h
${y:T:R}.h: .NOMETA
${y:T:R}.c ${y:T:R}.h: $y
${YACC.y} ${.IMPSRC}
[ ! -s y.tab.c ] || mv y.tab.c ${.TARGET:T:R}.c
[ ! -s y.tab.h ] || cmp -s y.tab.h ${.TARGET:T:R}.h \
|| mv y.tab.h ${.TARGET:T:R}.h
${RM} -f y.tab.*
.endif
.endfor
.if ${SRCS:M*.y} == ""
.if ${YACC.y:M-d} == "" || defined(NO_RENAME_Y_TAB_H)
.y.c:
@ -50,8 +72,10 @@ YACC.y?= ${YACC} ${YFLAGS}
{ [ ! -s y.tab.c ] || mv y.tab.c ${.TARGET}; \
${RM} y.tab.*; }; }
.endif
.endif
beforedepend: ${SRCS:T:M*.y:S/.y/.c/g}
CLEANFILES+= ${SRCS:T:M*.y:S/.y/.[ch]/g}
CLEANFILES+= y.tab.[ch]

View file

@ -1,4 +1,4 @@
/* $NetBSD: parse.c,v 1.670 2022/04/18 16:09:05 sjg Exp $ */
/* $NetBSD: parse.c,v 1.681 2022/07/24 20:25:23 rillig Exp $ */
/*
* Copyright (c) 1988, 1989, 1990, 1993
@ -121,7 +121,7 @@
#include "pathnames.h"
/* "@(#)parse.c 8.3 (Berkeley) 3/19/94" */
MAKE_RCSID("$NetBSD: parse.c,v 1.670 2022/04/18 16:09:05 sjg Exp $");
MAKE_RCSID("$NetBSD: parse.c,v 1.681 2022/07/24 20:25:23 rillig Exp $");
/*
* A file being read.
@ -325,7 +325,7 @@ CurFile(void)
}
static Buffer
loadfile(const char *path, int fd)
LoadFile(const char *path, int fd)
{
ssize_t n;
Buffer buf;
@ -452,10 +452,22 @@ FindKeyword(const char *str)
}
void
PrintLocation(FILE *f, bool useVars, const char *fname, unsigned lineno)
PrintLocation(FILE *f, bool useVars, const GNode *gn)
{
char dirbuf[MAXPATHLEN + 1];
FStr dir, base;
const char *fname;
unsigned lineno;
if (gn != NULL) {
fname = gn->fname;
lineno = gn->lineno;
} else if (includes.len > 0) {
IncludedFile *curFile = CurFile();
fname = curFile->name.str;
lineno = curFile->lineno;
} else
return;
if (!useVars || fname[0] == '/' || strcmp(fname, "(stdin)") == 0) {
(void)fprintf(f, "\"%s\" line %u: ", fname, lineno);
@ -478,16 +490,15 @@ PrintLocation(FILE *f, bool useVars, const char *fname, unsigned lineno)
FStr_Done(&dir);
}
static void MAKE_ATTR_PRINTFLIKE(6, 0)
ParseVErrorInternal(FILE *f, bool useVars, const char *fname, unsigned lineno,
static void MAKE_ATTR_PRINTFLIKE(5, 0)
ParseVErrorInternal(FILE *f, bool useVars, const GNode *gn,
ParseErrorLevel level, const char *fmt, va_list ap)
{
static bool fatal_warning_error_printed = false;
(void)fprintf(f, "%s: ", progname);
if (fname != NULL)
PrintLocation(f, useVars, fname, lineno);
PrintLocation(f, useVars, gn);
if (level == PARSE_WARNING)
(void)fprintf(f, "warning: ");
(void)vfprintf(f, fmt, ap);
@ -508,20 +519,20 @@ ParseVErrorInternal(FILE *f, bool useVars, const char *fname, unsigned lineno,
PrintStackTrace(false);
}
static void MAKE_ATTR_PRINTFLIKE(4, 5)
ParseErrorInternal(const char *fname, unsigned lineno,
static void MAKE_ATTR_PRINTFLIKE(3, 4)
ParseErrorInternal(const GNode *gn,
ParseErrorLevel level, const char *fmt, ...)
{
va_list ap;
(void)fflush(stdout);
va_start(ap, fmt);
ParseVErrorInternal(stderr, false, fname, lineno, level, fmt, ap);
ParseVErrorInternal(stderr, false, gn, level, fmt, ap);
va_end(ap);
if (opts.debug_file != stdout && opts.debug_file != stderr) {
va_start(ap, fmt);
ParseVErrorInternal(opts.debug_file, false, fname, lineno,
ParseVErrorInternal(opts.debug_file, false, gn,
level, fmt, ap);
va_end(ap);
}
@ -539,26 +550,15 @@ void
Parse_Error(ParseErrorLevel level, const char *fmt, ...)
{
va_list ap;
const char *fname;
unsigned lineno;
if (includes.len == 0) {
fname = NULL;
lineno = 0;
} else {
IncludedFile *curFile = CurFile();
fname = curFile->name.str;
lineno = curFile->lineno;
}
(void)fflush(stdout);
va_start(ap, fmt);
ParseVErrorInternal(stderr, true, fname, lineno, level, fmt, ap);
ParseVErrorInternal(stderr, true, NULL, level, fmt, ap);
va_end(ap);
if (opts.debug_file != stdout && opts.debug_file != stderr) {
va_start(ap, fmt);
ParseVErrorInternal(opts.debug_file, true, fname, lineno,
ParseVErrorInternal(opts.debug_file, true, NULL,
level, fmt, ap);
va_end(ap);
}
@ -714,11 +714,11 @@ static void
ApplyDependencySourceWait(bool isSpecial)
{
static unsigned wait_number = 0;
char wait_src[16];
char name[6 + 10 + 1];
GNode *gn;
snprintf(wait_src, sizeof wait_src, ".WAIT_%u", ++wait_number);
gn = Targ_NewInternalNode(wait_src);
snprintf(name, sizeof name, ".WAIT_%u", ++wait_number);
gn = Targ_NewInternalNode(name);
if (doing_depend)
RememberLocation(gn);
gn->type = OP_WAIT | OP_PHONY | OP_DEPENDS | OP_NOTMAIN;
@ -1037,27 +1037,34 @@ HandleDependencyTarget(const char *targetName,
}
static void
HandleDependencyTargetMundane(char *targetName)
HandleSingleDependencyTargetMundane(const char *name)
{
StringList targetNames = LST_INIT;
GNode *gn = Suff_IsTransform(name)
? Suff_AddTransform(name)
: Targ_GetNode(name);
if (doing_depend)
RememberLocation(gn);
Lst_Append(targets, gn);
}
static void
HandleDependencyTargetMundane(const char *targetName)
{
if (Dir_HasWildcards(targetName)) {
StringList targetNames = LST_INIT;
SearchPath *emptyPath = SearchPath_New();
SearchPath_Expand(emptyPath, targetName, &targetNames);
SearchPath_Free(emptyPath);
while (!Lst_IsEmpty(&targetNames)) {
char *targName = Lst_Dequeue(&targetNames);
HandleSingleDependencyTargetMundane(targName);
free(targName);
}
} else
Lst_Append(&targetNames, targetName);
while (!Lst_IsEmpty(&targetNames)) {
char *targName = Lst_Dequeue(&targetNames);
GNode *gn = Suff_IsTransform(targName)
? Suff_AddTransform(targName)
: Targ_GetNode(targName);
if (doing_depend)
RememberLocation(gn);
Lst_Append(targets, gn);
}
HandleSingleDependencyTargetMundane(targetName);
}
static void
@ -1113,10 +1120,12 @@ ParseDependencyOp(char **pp)
{
if (**pp == '!')
return (*pp)++, OP_FORCE;
if ((*pp)[1] == ':')
if (**pp == ':' && (*pp)[1] == ':')
return *pp += 2, OP_DOUBLEDEP;
else
else if (**pp == ':')
return (*pp)++, OP_DEPENDS;
else
return OP_NONE;
}
static void
@ -1131,6 +1140,56 @@ ClearPaths(SearchPathList *paths)
Dir_SetPATH();
}
static char *
FindInDirOfIncludingFile(const char *file)
{
char *fullname, *incdir, *slash, *newName;
int i;
fullname = NULL;
incdir = bmake_strdup(CurFile()->name.str);
slash = strrchr(incdir, '/');
if (slash != NULL) {
*slash = '\0';
/*
* Now do lexical processing of leading "../" on the
* filename.
*/
for (i = 0; strncmp(file + i, "../", 3) == 0; i += 3) {
slash = strrchr(incdir + 1, '/');
if (slash == NULL || strcmp(slash, "/..") == 0)
break;
*slash = '\0';
}
newName = str_concat3(incdir, "/", file + i);
fullname = Dir_FindFile(newName, parseIncPath);
if (fullname == NULL)
fullname = Dir_FindFile(newName, &dirSearchPath);
free(newName);
}
free(incdir);
return fullname;
}
static char *
FindInQuotPath(const char *file)
{
const char *suff;
SearchPath *suffPath;
char *fullname;
fullname = FindInDirOfIncludingFile(file);
if (fullname == NULL &&
(suff = strrchr(file, '.')) != NULL &&
(suffPath = Suff_GetPath(suff)) != NULL)
fullname = Dir_FindFile(file, suffPath);
if (fullname == NULL)
fullname = Dir_FindFile(file, parseIncPath);
if (fullname == NULL)
fullname = Dir_FindFile(file, &dirSearchPath);
return fullname;
}
/*
* Handle one of the .[-ds]include directives by remembering the current file
* and pushing the included file on the stack. After the included file has
@ -1146,77 +1205,14 @@ IncludeFile(const char *file, bool isSystem, bool depinc, bool silent)
{
Buffer buf;
char *fullname; /* full pathname of file */
char *newName;
char *slash, *incdir;
int fd;
int i;
fullname = file[0] == '/' ? bmake_strdup(file) : NULL;
if (fullname == NULL && !isSystem) {
/*
* Include files contained in double-quotes are first searched
* relative to the including file's location. We don't want to
* cd there, of course, so we just tack on the old file's
* leading path components and call Dir_FindFile to see if
* we can locate the file.
*/
if (fullname == NULL && !isSystem)
fullname = FindInQuotPath(file);
incdir = bmake_strdup(CurFile()->name.str);
slash = strrchr(incdir, '/');
if (slash != NULL) {
*slash = '\0';
/*
* Now do lexical processing of leading "../" on the
* filename.
*/
for (i = 0; strncmp(file + i, "../", 3) == 0; i += 3) {
slash = strrchr(incdir + 1, '/');
if (slash == NULL || strcmp(slash, "/..") == 0)
break;
*slash = '\0';
}
newName = str_concat3(incdir, "/", file + i);
fullname = Dir_FindFile(newName, parseIncPath);
if (fullname == NULL)
fullname = Dir_FindFile(newName,
&dirSearchPath);
free(newName);
}
free(incdir);
if (fullname == NULL) {
/*
* Makefile wasn't found in same directory as included
* makefile.
*
* Search for it first on the -I search path, then on
* the .PATH search path, if not found in a -I
* directory. If we have a suffix-specific path, we
* should use that.
*/
const char *suff;
SearchPath *suffPath = NULL;
if ((suff = strrchr(file, '.')) != NULL) {
suffPath = Suff_GetPath(suff);
if (suffPath != NULL)
fullname = Dir_FindFile(file, suffPath);
}
if (fullname == NULL) {
fullname = Dir_FindFile(file, parseIncPath);
if (fullname == NULL)
fullname = Dir_FindFile(file,
&dirSearchPath);
}
}
}
/* Looking for a system file or file still not found */
if (fullname == NULL) {
/*
* Look for it on the system path
*/
SearchPath *path = Lst_IsEmpty(&sysIncPath->dirs)
? defSysIncPath : sysIncPath;
fullname = Dir_FindFile(file, path);
@ -1228,16 +1224,14 @@ IncludeFile(const char *file, bool isSystem, bool depinc, bool silent)
return;
}
/* Actually open the file... */
fd = open(fullname, O_RDONLY);
if (fd == -1) {
if ((fd = open(fullname, O_RDONLY)) == -1) {
if (!silent)
Parse_Error(PARSE_FATAL, "Cannot open %s", fullname);
free(fullname);
return;
}
buf = loadfile(fullname, fd);
buf = LoadFile(fullname, fd);
(void)close(fd);
Parse_PushInput(fullname, 1, 0, buf, NULL);
@ -1586,6 +1580,7 @@ ParseDependency(char *line)
ParseSpecial special; /* in special targets, the children are
* linked as children of the parent but not
* vice versa */
GNodeType op;
DEBUG1(PARSE, "ParseDependency(%s)\n", line);
p = line;
@ -1599,7 +1594,12 @@ ParseDependency(char *line)
if (!Lst_IsEmpty(targets))
CheckSpecialMundaneMixture(special);
ApplyDependencyOperator(ParseDependencyOp(&p));
op = ParseDependencyOp(&p);
if (op == OP_NONE) {
InvalidLineType(line);
goto out;
}
ApplyDependencyOperator(op);
pp_skip_whitespace(&p);
@ -1945,7 +1945,7 @@ GNode_AddCommand(GNode *gn, char *cmd)
Parse_Error(PARSE_WARNING,
"duplicate script for target \"%s\" ignored",
gn->name);
ParseErrorInternal(gn->fname, gn->lineno, PARSE_WARNING,
ParseErrorInternal(gn, PARSE_WARNING,
"using previous script for \"%s\" defined here",
gn->name);
#endif
@ -2894,7 +2894,7 @@ Parse_File(const char *name, int fd)
char *line;
Buffer buf;
buf = loadfile(name, fd != -1 ? fd : STDIN_FILENO);
buf = LoadFile(name, fd != -1 ? fd : STDIN_FILENO);
if (fd != -1)
(void)close(fd);

View file

@ -1,4 +1,4 @@
/* $NetBSD: str.c,v 1.89 2022/03/03 19:50:01 rillig Exp $ */
/* $NetBSD: str.c,v 1.93 2022/06/11 09:24:07 rillig Exp $ */
/*
* Copyright (c) 1988, 1989, 1990, 1993
@ -71,7 +71,7 @@
#include "make.h"
/* "@(#)str.c 5.8 (Berkeley) 6/1/90" */
MAKE_RCSID("$NetBSD: str.c,v 1.89 2022/03/03 19:50:01 rillig Exp $");
MAKE_RCSID("$NetBSD: str.c,v 1.93 2022/06/11 09:24:07 rillig Exp $");
static HashTable interned_strings;
@ -219,7 +219,7 @@ Substring_Words(const char *str, bool expand)
if (word_start == NULL)
word_start = word_end;
*word_end++ = '\\';
/* catch '\' at end of line */
/* catch lonely '\' at end of string */
if (str_p[1] == '\0')
continue;
ch = *++str_p;
@ -292,55 +292,57 @@ Str_Words(const char *str, bool expand)
return words;
}
/*
* XXX: In the extreme edge case that one of the characters is from the basic
* execution character set and the other isn't, the result of the comparison
* differs depending on whether plain char is signed or unsigned.
*
* An example is the character range from \xE4 to 'a', where \xE4 may come
* from U+00E4 'Latin small letter A with diaeresis'.
*
* If char is signed, \xE4 evaluates to -28, the first half of the condition
* becomes -28 <= '0' && '0' <= 'a', which evaluates to true.
*
* If char is unsigned, \xE4 evaluates to 228, the second half of the
* condition becomes 'a' <= '0' && '0' <= 228, which evaluates to false.
*/
static bool
in_range(char e1, char c, char e2)
{
return (e1 <= c && c <= e2) || (e2 <= c && c <= e1);
}
/*
* Str_Match -- Test if a string matches a pattern like "*.[ch]".
* The following special characters are known *?\[] (as in fnmatch(3)).
*
* XXX: this function does not detect or report malformed patterns.
*
* See varmod-match.mk for examples and edge cases.
*/
bool
Str_Match(const char *str, const char *pat)
{
for (;;) {
/*
* See if we're at the end of both the pattern and the
* string. If so, we succeeded. If we're at the end of the
* pattern but not at the end of the string, we failed.
*/
if (*pat == '\0')
return *str == '\0';
if (*str == '\0' && *pat != '*')
return false;
/*
* A '*' in the pattern matches any substring. We handle this
* by calling ourselves for each suffix of the string.
*/
if (*pat == '*') {
for (; *pat != '\0'; pat++, str++) {
if (*pat == '*') { /* match any substring */
pat++;
while (*pat == '*')
pat++;
if (*pat == '\0')
return true;
while (*str != '\0') {
for (; *str != '\0'; str++)
if (Str_Match(str, pat))
return true;
str++;
}
return false;
}
/* A '?' in the pattern matches any single character. */
if (*pat == '?')
goto thisCharOK;
if (*str == '\0')
return false;
/*
* A '[' in the pattern matches a character from a list.
* The '[' is followed by the list of acceptable characters,
* or by ranges (two characters separated by '-'). In these
* character lists, the backslash is an ordinary character.
*/
if (*pat == '[') {
if (*pat == '?') /* match any single character */
continue;
if (*pat == '[') { /* match a character from a list */
bool neg = pat[1] == '^';
pat += neg ? 2 : 1;
@ -350,23 +352,12 @@ Str_Match(const char *str, const char *pat)
break;
return false;
}
/*
* XXX: This naive comparison makes the
* control flow of the pattern parser
* dependent on the actual value of the
* string. This is unpredictable. It may be
* though that the code only looks wrong but
* actually all code paths result in the same
* behavior. This needs further tests.
*/
if (*pat == *str)
break;
if (pat[1] == '-') {
if (pat[2] == '\0')
return neg;
if (pat[0] <= *str && *str <= pat[2])
break;
if (pat[2] <= *str && *str <= pat[0])
if (in_range(pat[0], *str, pat[2]))
break;
pat += 2;
}
@ -378,26 +369,16 @@ Str_Match(const char *str, const char *pat)
pat++;
if (*pat == '\0')
pat--;
goto thisCharOK;
continue;
}
/*
* A backslash in the pattern matches the character following
* it exactly.
*/
if (*pat == '\\') {
if (*pat == '\\') /* match the next character exactly */
pat++;
if (*pat == '\0')
return false;
}
if (*pat != *str)
return false;
thisCharOK:
pat++;
str++;
}
return *str == '\0';
}
void

View file

@ -1,6 +1,6 @@
# $Id: Makefile,v 1.180 2022/04/18 21:25:37 sjg Exp $
# $Id: Makefile,v 1.181 2022/06/13 00:18:20 sjg Exp $
#
# $NetBSD: Makefile,v 1.312 2022/04/18 15:06:28 rillig Exp $
# $NetBSD: Makefile,v 1.318 2022/06/10 21:28:50 rillig Exp $
#
# Unit tests for make(1)
#
@ -83,7 +83,6 @@ TESTS+= cond-token-plain
TESTS+= cond-token-string
TESTS+= cond-token-var
TESTS+= cond-undef-lint
TESTS+= cond1
TESTS+= counter
TESTS+= counter-append
TESTS+= dep
@ -168,6 +167,7 @@ TESTS+= directive-export-impl
TESTS+= directive-export-gmake
TESTS+= directive-export-literal
TESTS+= directive-for
TESTS+= directive-for-empty
TESTS+= directive-for-errors
TESTS+= directive-for-escape
TESTS+= directive-for-generating-endif
@ -439,7 +439,6 @@ TESTS+= varparse-dynamic
TESTS+= varparse-errors
TESTS+= varparse-mod
TESTS+= varparse-undef-partial
TESTS+= varquote
# some shells have quirks
_shell := ${.SHELL:tA:T}
@ -579,8 +578,10 @@ SED_CMDS.varname-dot-shell+= -e 's,\[/[^] ]*\],[(details omitted)],g'
SED_CMDS.varname-empty= ${.OBJDIR .PARSEDIR .PATH .SHELL:L:@v@-e '/\\$v/d'@}
# 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 '/Input graph/, /^$$/'
POSTPROC.varname-dot-make-mode= sed 's,^\(: Making [abc]\)[123]$$,\1,'
# Some tests reuse other tests, which makes them unnecessarily fragile.
export-all.rawout: export.mk
@ -724,7 +725,7 @@ MAKE_TEST_ENV+= MALLOC_CONF="junk:true" # for jemalloc 510
MAKE_TEST_ENV+= TMPDIR=${TMPDIR}
.if ${.MAKE.OS} == "NetBSD"
LIMIT_RESOURCES?= ulimit -v 200000
LIMIT_RESOURCES?= ulimit -v 300000
.endif
LIMIT_RESOURCES?= :
@ -746,7 +747,7 @@ LIMIT_RESOURCES?= :
echo $$status > ${.TARGET:R}.status
@mv ${.TARGET}.tmp ${.TARGET}
# Postprocess the test output so that the results can be compared.
# Postprocess the test output to make the output platform-independent.
#
# always pretend .MAKE was called 'make'
_SED_CMDS+= -e 's,^${TEST_MAKE:T:S,.,\\.,g}[][0-9]*:,make:,'

View file

@ -2,4 +2,7 @@ makeobjdir-direct:
show-objdir: <tmpdir>/6a8899d2-d227-4b55-9b6b-f3c8eeb83fd5
makeobjdir-indirect:
show-objdir: <tmpdir>/a7b41170-53f8-4cc2-bc5c-e4c3dd93ec45/
space-and-comment:
value # no comment $
value # no comment $
exit status 0

View file

@ -1,4 +1,4 @@
# $NetBSD: cmdline.mk,v 1.3 2021/02/06 18:26:03 sjg Exp $
# $NetBSD: cmdline.mk,v 1.4 2022/06/10 18:58:07 rillig Exp $
#
# Tests for command line parsing and related special variables.
@ -11,6 +11,7 @@ DIR12= ${TMPBASE}/${SUB1}/${SUB2}
all: prepare-dirs
all: makeobjdir-direct makeobjdir-indirect
all: space-and-comment
prepare-dirs:
@rm -rf ${DIR2} ${DIR12}
@ -34,3 +35,24 @@ makeobjdir-indirect:
show-objdir:
@echo $@: ${.OBJDIR:Q}
# Variable assignments in the command line are handled differently from
# variable assignments in makefiles. In the command line, trailing whitespace
# is preserved, and the '#' does not start a comment. This is because the
# low-level parsing from ParseRawLine does not take place.
#
# Preserving '#' and trailing whitespace has the benefit that when passing
# such values to sub-makes via MAKEFLAGS, no special encoding is needed.
# Leading whitespace in the variable value is discarded though, which makes
# the behavior inconsistent.
space-and-comment: .PHONY
@echo $@:
@env -i \
${MAKE} -r -f /dev/null ' VAR= value # no comment ' -v VAR \
| sed 's,$$,$$,'
@env -i MAKEFLAGS="' VAR= value # no comment '" \
${MAKE} -r -f /dev/null -v VAR \
| sed 's,$$,$$,'

View file

@ -1,4 +1,4 @@
# $NetBSD: comment.mk,v 1.4 2022/01/23 18:00:53 rillig Exp $
# $NetBSD: comment.mk,v 1.5 2022/05/08 06:51:27 rillig Exp $
#
# Demonstrate how comments are written in makefiles.
@ -23,7 +23,7 @@ on and on.
.endif # And after the closing directive.
VAR= # This comment makes the variable value empty.
# ParseGetLine removes any whitespace before the
# ParseRawLine removes any whitespace before the
# comment.
.if ${VAR} != ""
. error

View file

@ -1,17 +1,24 @@
# $NetBSD: compat-error.mk,v 1.3 2020/12/13 19:33:53 rillig Exp $
# $NetBSD: compat-error.mk,v 1.5 2022/05/08 06:51:27 rillig Exp $
#
# Test detailed error handling in compat mode.
#
# Until 2020-12-13, .ERROR_TARGET was success3, which was wrong.
# Since compat.c 1.215 from 2020-12-13, it is 'fail1', which is the first
# failed top-level target. XXX: Even better would be if .ERROR_TARGET were
# the smallest target that caused the build to fail, even if it were a
# sub-sub-sub-dependency of a top-level target.
# Make several targets that alternately succeed and fail.
#
# XXX: As of 2020-12-13, .ERROR_CMD is empty, which is wrong.
# The first failing top-level target is recorded in '.ERROR_TARGET'. While
# this information may give a hint as to which target failed, it would be more
# useful at that point to know the actual target that failed, or the complete
# chain from root cause to top-level target.
#
# Historic bugs
# Before compat.c 1.215 from 2020-12-13, '.ERROR_TARGET' was 'success3',
# which was obviously wrong.
#
# Bugs
# As of 2020-12-13, '.ERROR_CMD' is empty, which does not provide any
# insight into the command that actually failed.
#
# See also:
# Compat_Run
# Compat_MakeAll
#
# The commit that added the NULL command to gn->commands:
# CVS: 1994.06.06.22.45.??
@ -20,10 +27,10 @@
# 2020: LstNode_SetNull(cmdNode);
#
# The commit that skipped NULL commands for .ERROR_CMD:
# CVS: 2016.08.11.19.53.??
# CVS: 2016.08.11.19.53.17
# Git: 58b23478b7353d46457089e726b07a49197388e4
.MAKEFLAGS: success1 fail1 success2 fail2 success3
.MAKEFLAGS: -k success1 fail1 success2 fail2 success3
success1 success2 success3:
: Making ${.TARGET} out of nothing.

View file

@ -1,4 +1,4 @@
# $NetBSD: cond-cmp-string.mk,v 1.15 2021/12/11 09:53:53 rillig Exp $
# $NetBSD: cond-cmp-string.mk,v 1.16 2022/05/08 06:51:27 rillig Exp $
#
# Tests for string comparisons in .if conditions.
@ -136,3 +136,11 @@
.else
. error
.endif
# Two variables with different values compare unequal.
VAR1= value1
VAR2= value2
.if ${VAR1} != ${VAR2}
.else
. error
.endif

View file

@ -1,4 +1,4 @@
# $NetBSD: cond-func-defined.mk,v 1.8 2021/12/12 08:55:28 rillig Exp $
# $NetBSD: cond-func-defined.mk,v 1.9 2022/05/08 06:51:27 rillig Exp $
#
# Tests for the defined() function in .if conditions.
@ -48,5 +48,10 @@ ${:UA B}= variable name with spaces
. endif
.endfor
all:
@:;
# Neither of the conditions is true. Before July 2020, the right-hand
# condition was evaluated even though it was irrelevant.
.if defined(UNDEF) && ${UNDEF:Mx} != ""
. error
.endif
all: .PHONY

View file

@ -13,6 +13,9 @@ CondParser_Eval: "${:Uvalue}"
make: "cond-token-string.mk" line 68: A nonempty variable expression evaluates to true.
CondParser_Eval: "${:U}"
make: "cond-token-string.mk" line 76: An empty variable evaluates to false.
CondParser_Eval: ("${VAR}")
CondParser_Eval: "quoted" == quoted
Comparing "quoted" == "quoted"
make: Fatal errors encountered -- cannot continue
make: stopped in unit-tests
exit status 1

View file

@ -1,4 +1,4 @@
# $NetBSD: cond-token-string.mk,v 1.4 2021/01/21 00:38:28 rillig Exp $
# $NetBSD: cond-token-string.mk,v 1.6 2022/05/08 06:57:00 rillig Exp $
#
# Tests for quoted string literals in .if conditions.
#
@ -76,7 +76,24 @@
. info An empty variable evaluates to false.
.endif
# A non-empty string evaluates to true, no matter if it's a literal string or
# if it contains variable expressions. The parentheses are not necessary for
# the parser, in this case their only purpose is to make the code harder to
# read for humans.
VAR= value
.if ("${VAR}")
.else
. error
.endif
# In the conditions in .if directives, the left-hand side of a comparison must
# be enclosed in quotes. The right-hand side does not need to be enclosed in
# quotes.
.if "quoted" == quoted
.else
. error
.endif
.MAKEFLAGS: -d0
all:
@:;
all: .PHONY

View file

@ -1,23 +0,0 @@
make: "cond1.mk" line 80: warning: extra else
make: "cond1.mk" line 90: warning: extra else
2 is prime
A='other' B='unknown' C='clever' o='no,no'
Passed:
var
("var")
(var != var)
var != var
!((var != var) && defined(name))
var == quoted
1 is not prime
2 is prime
3 is prime
4 is not prime
5 is prime
make: String comparison operator must be either == or !=
make: Bad conditional expression '"0" > 0' in '"0" > 0?OK:No'
OK
exit status 0

View file

@ -1,114 +0,0 @@
# $NetBSD: cond1.mk,v 1.3 2020/11/15 14:58:14 rillig Exp $
# TODO: Convert these tests into tutorial form.
# TODO: Split these tests by topic.
# TODO: Use better variable names and expression values that actually express
# the intended behavior. uname(1) has nothing to do with conditions.
# hard code these!
TEST_UNAME_S= NetBSD
TEST_UNAME_M= sparc
TEST_MACHINE= i386
.if ${TEST_UNAME_S}
Ok=var,
.endif
.if ("${TEST_UNAME_S}")
Ok+=(\"var\"),
.endif
.if (${TEST_UNAME_M} != ${TEST_MACHINE})
Ok+=(var != var),
.endif
.if ${TEST_UNAME_M} != ${TEST_MACHINE}
Ok+= var != var,
.endif
.if !((${TEST_UNAME_M} != ${TEST_MACHINE}) && defined(X))
Ok+= !((var != var) && defined(name)),
.endif
# from bsd.obj.mk
MKOBJ?=no
.if ${MKOBJ} == "no"
o= no
Ok+= var == "quoted",
.else
.if defined(notMAKEOBJDIRPREFIX) || defined(norMAKEOBJDIR)
.if defined(notMAKEOBJDIRPREFIX)
o=${MAKEOBJDIRPREFIX}${__curdir}
.else
o= ${MAKEOBJDIR}
.endif
.endif
o= o
.endif
# repeat the above to check we get the same result
.if ${MKOBJ} == "no"
o2= no
.else
.if defined(notMAKEOBJDIRPREFIX) || defined(norMAKEOBJDIR)
.if defined(notMAKEOBJDIRPREFIX)
o2=${MAKEOBJDIRPREFIX}${__curdir}
.else
o2= ${MAKEOBJDIR}
.endif
.endif
o2= o
.endif
PRIMES=2 3 5 7 11
NUMBERS=1 2 3 4 5
n=2
.if ${PRIMES:M$n} == ""
X=not
.else
X=
.endif
.if ${MACHINE_ARCH} == no-such
A=one
.else
.if ${MACHINE_ARCH} == not-this
.if ${MACHINE_ARCH} == something-else
A=unlikely
.else
A=no
.endif
.endif
A=other
# We expect an extra else warning - we're not skipping here
.else
A=this should be an error
.endif
.if $X != ""
.if $X == not
B=one
.else
B=other
# We expect an extra else warning - we are skipping here
.else
B=this should be an error
.endif
.else
B=unknown
.endif
.if "quoted" == quoted
C=clever
.else
C=dim
.endif
.if defined(nosuch) && ${nosuch:Mx} != ""
# this should not happen
.info nosuch is x
.endif
all:
@echo "$n is $X prime"
@echo "A='$A' B='$B' C='$C' o='$o,${o2}'"
@echo "Passed:${.newline} ${Ok:S/,/${.newline}/}"
@echo "${NUMBERS:@n@$n is ${("${PRIMES:M$n}" == ""):?not:} prime${.newline}@}"
@echo "${"${DoNotQuoteHere:U0}" > 0:?OK:No}"
@echo "${${NoSuchNumber:U42} > 0:?OK:No}"

View file

@ -1,13 +1,18 @@
--- a ---
echo a
a
--- b1 ---
echo b1
b1
--- b ---
echo b
b
--- x ---
echo x
x
: Making 3a
: Making 3a
: Making 3a
: Making 3b
: Making 3b
: Making 3b
: Making 3c
: Making 3c
: Making 3c
exit status 0

View file

@ -1,9 +1,15 @@
# $NetBSD: depsrc-wait.mk,v 1.3 2020/09/07 18:40:32 rillig Exp $
# $NetBSD: depsrc-wait.mk,v 1.4 2022/05/07 17:49:47 rillig Exp $
#
# Tests for the special source .WAIT in dependency declarations,
# which adds a sequence point between the nodes to its left and the nodes
# to its right.
all: .PHONY
@${MAKE} -r -f ${MAKEFILE} x
@${MAKE} -r -f ${MAKEFILE} three-by-three
.if make(x)
# Even though the build could run massively parallel, the .WAIT imposes a
# strict ordering in this example, which forces the targets to be made in
# exactly this order.
@ -19,3 +25,17 @@ b: b1
echo b
b1:
echo b1
.endif
# There are 3 groups of 3 targets, with .WAIT barriers in between. Each of
# these groups has to be made completely before starting the next group.
# See Makefile, POSTPROC for the postprocessing that takes place.
.if make(three-by-three)
.MAKEFLAGS: -j5
.MAKE.MODE+= randomize-targets
three-by-three: .WAIT 3a1 3a2 3a3 .WAIT 3b1 3b2 3b3 .WAIT 3c1 3c2 3c3 .WAIT
3a1 3a2 3a3 3b1 3b2 3b3 3c1 3c2 3c3:
: Making ${.TARGET}
.endif

View file

@ -1,4 +1,4 @@
# $NetBSD: deptgt-begin.mk,v 1.5 2020/11/15 22:28:08 rillig Exp $
# $NetBSD: deptgt-begin.mk,v 1.6 2022/05/07 08:01:20 rillig Exp $
#
# Tests for the special target .BEGIN in dependency declarations,
# which is a container for commands that are run before any other
@ -25,8 +25,8 @@ before-begin: .PHONY .NOTMAIN
# Another way is to define a custom target and make that a .USE dependency.
# For the .BEGIN target, .USE dependencies do not work though, since in
# Compat_Run, the .USE and .USEBEFORE nodes are expanded right after the
# .BEGIN target has been run, which is too late.
# Compat_MakeAll, the .USE and .USEBEFORE nodes are expanded right after the
# .BEGIN target has been made, which is too late.
.BEGIN: use
use: .USE .NOTMAIN
: Making $@ from a .USE dependency.
@ -35,8 +35,8 @@ use: .USE .NOTMAIN
# .BEGIN target.
#
# For the .BEGIN target, .USEBEFORE dependencies do not work though, since in
# Compat_Run, the .USE and .USEBEFORE nodes are expanded right after the
# .BEGIN target has been run, which is too late.
# Compat_MakeAll, the .USE and .USEBEFORE nodes are expanded right after the
# .BEGIN target has been made, which is too late.
.BEGIN: use-before
use-before: .USEBEFORE .NOTMAIN
: Making $@ from a .USEBEFORE dependency.

View file

@ -1,10 +1,10 @@
# $NetBSD: deptgt-end-fail-indirect.mk,v 1.2 2020/12/06 21:22:04 rillig Exp $
# $NetBSD: deptgt-end-fail-indirect.mk,v 1.3 2022/05/07 08:01:20 rillig Exp $
#
# Tests for an error in a dependency of the .END node.
#
# Before 2020-11-25, an error in the .END target did not print the "Stop."
# and exited with status 0. The cause for this was a missing condition in
# Compat_Run in the handling of the .END node.
# Compat_MakeAll in the handling of the .END node.
all:
: $@

View file

@ -1,11 +1,11 @@
# $NetBSD: deptgt-end-fail.mk,v 1.6 2020/12/07 01:04:07 rillig Exp $
# $NetBSD: deptgt-end-fail.mk,v 1.7 2022/05/07 08:01:20 rillig Exp $
#
# Tests for an errors in the main target, its dependencies,
# the .END node and its dependencies.
#
# Before 2020-11-25, an error in the .END target did not print the "Stop.",
# even though this was intended. The cause for this was a missing condition
# in Compat_Run, in the code handling the .END node.
# in Compat_MakeAll, in the code handling the .END node.
test: .PHONY

View file

@ -1,16 +1,22 @@
# $NetBSD: deptgt-posix.mk,v 1.2 2022/04/18 15:59:39 sjg Exp $
# $NetBSD: deptgt-posix.mk,v 1.4 2022/05/07 21:24:52 rillig Exp $
#
# Tests for the special target '.POSIX', which enables POSIX mode.
#
# As of 2022-04-18, this only means that the variable '%POSIX' is defined and
# that the variables and rules specified by POSIX replace the default ones.
# This is done by loading <posix.mk>, if available. That file is not included
# in NetBSD, but only in the bmake distribution. As of 2022-04-18, POSIX
# support is not complete.
# As of 2022-04-18, when parsing the dependency line '.POSIX', the variable
# '%POSIX' is defined and <posix.mk> is included, if it exists. Other than
# that, POSIX support is still incomplete, the exact set of supported features
# needs to be cross-checked with the POSIX specification.
#
# Implementation node: this test needs to be isolated from the usual test
# to prevent unit-tests/posix.mk from interfering with the posix.mk from the
# system directory that this test uses.
# At the point of '.POSIX:', <sys.mk> has been loaded already, unless the
# option '-r' was given. This means that an implementation of <posix.mk> must
# work both with and without the system rules from <sys.mk> being in effect.
#
# Implementation note: this test needs to run isolated from the usual tests
# directory to prevent unit-tests/posix.mk from interfering with the posix.mk
# from the system directory that this test uses; since at least 1997, the
# directive '.include <file>' has been looking in the current directory first
# before searching the file in the system search path, as described in
# https://gnats.netbsd.org/15163.
#
# See also:
# https://pubs.opengroup.org/onlinepubs/9699919799/utilities/make.html
@ -99,7 +105,8 @@ in-first-line: .PHONY set-up-sysdir check-is-posix run
'.POSIX:'
# The only allowed lines before switching to POSIX mode are comment lines.
# POSIX defines that empty and blank lines are called comment lines as well.
# POSIX defines comment lines as "blank lines, empty lines, and lines with
# <number-sign> ('#') as the first character".
all: after-comment-lines
after-comment-lines: .PHONY set-up-sysdir check-is-posix run
printf '%s\n' > ${MAIN_MK} \

View file

@ -0,0 +1,27 @@
make: "directive-for-empty.mk" line 21: 2
make: "directive-for-empty.mk" line 34: Missing argument for ".error"
make: "directive-for-empty.mk" line 34: Missing argument for ".error"
make: "directive-for-empty.mk" line 34: Missing argument for ".error"
For: end for 1
For: loop body:
# The identifier 'empty' can only be used in conditions such as .if, .ifdef or
# .elif. In other lines the string 'empty(' must be preserved.
CPPFLAGS+= -Dmessage="empty(i)"
# There may be whitespace between 'empty' and '('.
.if ! empty (i)
. error
.endif
# Even in conditions, the string 'empty(' is not always a function call, it
# can occur in a string literal as well.
.if "empty\(i)" != "empty(i)"
. error
.endif
# In comments like 'empty(i)', the text must be preserved as well.
#
# Conditions, including function calls to 'empty', can not only occur in
# condition directives, they can also occur in the modifier ':?', see
# varmod-ifelse.mk.
CPPFLAGS+= -Dmacro="${empty(i):?empty:not-empty}"
make: Fatal errors encountered -- cannot continue
make: stopped in unit-tests
exit status 1

View file

@ -0,0 +1,120 @@
# $NetBSD: directive-for-empty.mk,v 1.1 2022/05/23 22:33:56 rillig Exp $
#
# Tests for .for loops containing conditions of the form 'empty(var:...)'.
#
# When a .for loop is expanded, variable expressions in the body of the loop
# are replaced with expressions containing the variable values. This
# replacement is a bit naive but covers most of the practical cases. The one
# popular exception is the condition 'empty(var:Modifiers)', which does not
# look like a variable expression and is thus not replaced.
#
# See also:
# https://gnats.netbsd.org/43821
# In the body of the .for loop, the expression '${i:M*2*}' is replaced with
# '${:U11:M*2*}', '${:U12:M*2*}', '${:U13:M*2*}', one after another. This
# replacement creates the impression that .for variables were real variables,
# when in fact they aren't.
.for i in 11 12 13
. if ${i:M*2*}
.info 2
. endif
.endfor
# In conditions, the function call to 'empty' does not look like a variable
# expression, therefore it is not replaced. Since there is no global variable
# named 'i', this expression makes for a leaky abstraction. If the .for
# variables were real variables, calling 'empty' would work on them as well.
.for i in 11 12 13
# Asking for an empty iteration variable does not make sense as the .for loop
# splits the iteration items into words, and such a word cannot be empty.
. if empty(i)
. error # due to the leaky abstraction
. endif
# The typical way of using 'empty' with variables from .for loops is pattern
# matching using the modifiers ':M' or ':N'.
. if !empty(i:M*2*)
. if ${i} != "12"
. error
. endif
. endif
.endfor
# The idea of replacing every occurrences of 'empty(i' in the body of a .for
# loop would be naive and require many special cases, as there are many cases
# that need to be considered when deciding whether the token 'empty' is a
# function call or not, as demonstrated by the following examples. For
# variable expressions like '${i:Modifiers}', this is simpler as a single
# dollar almost always starts a variable expression. For counterexamples and
# edge cases, see directive-for-escape.mk. Adding another such tricky detail
# is out of the question.
.MAKEFLAGS: -df
.for i in value
# The identifier 'empty' can only be used in conditions such as .if, .ifdef or
# .elif. In other lines the string 'empty(' must be preserved.
CPPFLAGS+= -Dmessage="empty(i)"
# There may be whitespace between 'empty' and '('.
.if ! empty (i)
. error
.endif
# Even in conditions, the string 'empty(' is not always a function call, it
# can occur in a string literal as well.
.if "empty\(i)" != "empty(i)"
. error
.endif
# In comments like 'empty(i)', the text must be preserved as well.
#
# Conditions, including function calls to 'empty', can not only occur in
# condition directives, they can also occur in the modifier ':?', see
# varmod-ifelse.mk.
CPPFLAGS+= -Dmacro="${empty(i):?empty:not-empty}"
.endfor
.MAKEFLAGS: -d0
# An idea to work around the above problems is to collect the variables from
# the .for loops in a separate scope. To match the current behavior, there
# has to be one scope per included file. There may be .for loops using the
# same variable name in files that include each other:
#
# outer.mk: .for i in outer
# . info $i # outer
# . include "inner.mk"
# inner.mk: . info $i # (undefined)
# . for i in inner
# . info $i # inner
# . endfor
# . info $i # (undefined)
# outer.mk: . info $i # outer
# .endfor
#
# This might be regarded another leaky abstraction, but it is in fact useful
# that variables from .for loops can only affect expressions in the current
# file. If variables from .for loops were implemented as global variables,
# they might interact between files.
#
# To emulate this exact behavior for the function 'empty', each file in the
# stack of included files needs its own scope that is independent from the
# other files.
#
# Another tricky detail are nested .for loops in a single file that use the
# same variable name. These are generally avoided by developers, as they
# would be difficult to understand for humans as well. Technically, they are
# possible though. Assuming there are two nested .for loops, both using the
# variable 'i'. When the inner .for loop ends, the inner 'i' needs to be
# removed from the scope, which would need to make the outer 'i' visible
# again. This would suggest to use one variable scope per .for loop.
#
# Using a separate scope has the benefit that Var_Parse already allows for
# a custom scope to be passed as parameter. This would have another side
# effect though. There are several modifiers that actually modify variables,
# and these modifications happen in the scope that is passed to Var_Parse.
# This would mean that the combination of a .for variable and the modifiers
# '::=', '::+=', '::?=', '::!=' and ':_' would lead to different behavior than
# before.
# TODO: Add code that demonstrates the current interaction between variables
# from .for loops and the modifiers mentioned above.

View file

@ -26,30 +26,37 @@ For: loop body:
make: "directive-for-escape.mk" line 43: value-with-modifier
For: end for 1
For: loop body:
# ${:U\${UNDEF\:U\\$\\$}
For: loop body:
# ${:U{{\}\}}
For: loop body:
# ${:Uend\}}
For: end for 1
For: loop body:
. info ${:U\${UNDEF\:U\\$\\$}
make: "directive-for-escape.mk" line 72: ${UNDEF:U\backslash$
make: "directive-for-escape.mk" line 92: ${UNDEF:U\backslash$
For: loop body:
. info ${:U{{\}\}}
make: "directive-for-escape.mk" line 72: {{}}
make: "directive-for-escape.mk" line 92: {{}}
For: loop body:
. info ${:Uend\}}
make: "directive-for-escape.mk" line 72: end}
make: "directive-for-escape.mk" line 92: end}
For: end for 1
For: loop body:
. info ${:Ubegin<${UNDEF:Ufallback:N{{{}}}}>end}
make: "directive-for-escape.mk" line 84: begin<fallback>end
make: "directive-for-escape.mk" line 113: begin<fallback>end
For: end for 1
For: loop body:
. info ${:U\$}
make: "directive-for-escape.mk" line 92: $
make: "directive-for-escape.mk" line 121: $
For: end for 1
For: loop body:
. info ${NUMBERS} ${:Ureplaced}
make: "directive-for-escape.mk" line 100: one two three replaced
make: "directive-for-escape.mk" line 129: one two three replaced
For: end for 1
For: loop body:
. info ${:Ureplaced}
make: "directive-for-escape.mk" line 110: replaced
make: "directive-for-escape.mk" line 139: replaced
For: end for 1
For: loop body:
. info . $$i: ${:Uinner}
@ -62,46 +69,46 @@ For: loop body:
. info . $${i2}: ${i2}
. info . $${i,}: ${i,}
. info . adjacent: ${:Uinner}${:Uinner}${:Uinner:M*}${:Uinner}
make: "directive-for-escape.mk" line 118: . $i: inner
make: "directive-for-escape.mk" line 119: . ${i}: inner
make: "directive-for-escape.mk" line 120: . ${i:M*}: inner
make: "directive-for-escape.mk" line 121: . $(i): inner
make: "directive-for-escape.mk" line 122: . $(i:M*): inner
make: "directive-for-escape.mk" line 123: . ${i${:U}}: outer
make: "directive-for-escape.mk" line 124: . ${i\}}: inner}
make: "directive-for-escape.mk" line 125: . ${i2}: two
make: "directive-for-escape.mk" line 126: . ${i,}: comma
make: "directive-for-escape.mk" line 127: . adjacent: innerinnerinnerinner
make: "directive-for-escape.mk" line 147: . $i: inner
make: "directive-for-escape.mk" line 148: . ${i}: inner
make: "directive-for-escape.mk" line 149: . ${i:M*}: inner
make: "directive-for-escape.mk" line 150: . $(i): inner
make: "directive-for-escape.mk" line 151: . $(i:M*): inner
make: "directive-for-escape.mk" line 152: . ${i${:U}}: outer
make: "directive-for-escape.mk" line 153: . ${i\}}: inner}
make: "directive-for-escape.mk" line 154: . ${i2}: two
make: "directive-for-escape.mk" line 155: . ${i,}: comma
make: "directive-for-escape.mk" line 156: . adjacent: innerinnerinnerinner
For: end for 1
For: loop body:
. info eight $$$$$$$$ and no cents.
. info eight ${:Udollar}${:Udollar}${:Udollar}${:Udollar} and no cents.
make: "directive-for-escape.mk" line 135: eight $$$$ and no cents.
make: "directive-for-escape.mk" line 136: eight dollardollardollardollar and no cents.
make: "directive-for-escape.mk" line 145: eight and no cents.
make: "directive-for-escape.mk" line 164: eight $$$$ and no cents.
make: "directive-for-escape.mk" line 165: eight dollardollardollardollar and no cents.
make: "directive-for-escape.mk" line 174: eight and no cents.
For: end for 1
make: "directive-for-escape.mk" line 152: newline in .for value
make: "directive-for-escape.mk" line 152: newline in .for value
make: "directive-for-escape.mk" line 181: newline in .for value
make: "directive-for-escape.mk" line 181: newline in .for value
For: loop body:
. info short: ${:U" "}
. info long: ${:U" "}
make: "directive-for-escape.mk" line 153: short: " "
make: "directive-for-escape.mk" line 154: long: " "
make: "directive-for-escape.mk" line 182: short: " "
make: "directive-for-escape.mk" line 183: long: " "
For: end for 1
For: loop body:
For: end for 1
Parse_PushInput: .for loop in directive-for-escape.mk, line 167
make: "directive-for-escape.mk" line 167: newline in .for value
in .for loop from directive-for-escape.mk:167 with i = "
Parse_PushInput: .for loop in directive-for-escape.mk, line 196
make: "directive-for-escape.mk" line 196: newline in .for value
in .for loop from directive-for-escape.mk:196 with i = "
"
For: loop body:
: ${:U" "}
SetFilenameVars: ${.PARSEDIR} = <some-dir> ${.PARSEFILE} = `directive-for-escape.mk'
Parsing line 168: : ${:U" "}
Parsing line 197: : ${:U" "}
ParseDependency(: " ")
ParseEOF: returning to file directive-for-escape.mk, line 170
ParseEOF: returning to file directive-for-escape.mk, line 199
SetFilenameVars: ${.PARSEDIR} = <some-dir> ${.PARSEFILE} = `directive-for-escape.mk'
Parsing line 170: .MAKEFLAGS: -d0
Parsing line 199: .MAKEFLAGS: -d0
ParseDependency(.MAKEFLAGS: -d0)
For: end for 1
For: loop body:

View file

@ -1,4 +1,4 @@
# $NetBSD: directive-for-escape.mk,v 1.15 2022/01/27 20:15:14 rillig Exp $
# $NetBSD: directive-for-escape.mk,v 1.16 2022/06/12 16:09:21 rillig Exp $
#
# Test escaping of special characters in the iteration values of a .for loop.
# These values get expanded later using the :U variable modifier, and this
@ -43,38 +43,67 @@ VALUES= $$ $${V} $${V:=-with-modifier} $$(V) $$(V:=-with-modifier)
. info $i
.endfor
# Try to cover the code for nested '{}' in ExprLen, without success.
#
# The value of the variable VALUES is not meant to be a variable expression.
# Instead, it is meant to represent literal text, the only escaping mechanism
# being that each '$' is written as '$$'.
VALUES= $${UNDEF:U\$$\$$ {{}} end}
#
# The .for loop splits ${VALUES} into 3 words, at the space characters, since
# the '$$' is an ordinary character and the spaces are not escaped.
# Word 1 is '${UNDEF:U\$\$'
# Word 2 is '{{}}'
# Word 3 is 'end}'
# The first iteration expands the body of the .for loop to:
# expect: . info ${:U\${UNDEF\:U\\$\\$}
# The modifier ':U' unescapes the '\$' to a simple '$'.
# The modifier ':U' unescapes the '\:' to a simple ':'.
# The modifier ':U' unescapes the '\\' to a simple '\'.
# The modifier ':U' resolves the expression '$\' to the word 'backslash', due
# to the following variable definition.
#
# Each of these words is now inserted in the body of the .for loop.
.for i in ${VALUES}
# $i
.endfor
#
# When these words are injected into the body of the .for loop, each inside a
# '${:U...}' expression, the result is:
#
# expect: For: loop body:
# expect: # ${:U\${UNDEF\:U\\$\\$}
# expect: For: loop body:
# expect: # ${:U{{\}\}}
# expect: For: loop body:
# expect: # ${:Uend\}}
# expect: For: end for 1
#
# The first of these expressions is the most interesting one, due to its many
# special characters. This expression is properly balanced:
#
# Text Meaning Explanation
# \$ $ escaped
# { { ordinary text
# UNDEF UNDEF ordinary text
# \: : escaped
# U U ordinary text
# \\ \ escaped
# $\ (expr) an expression, the variable name is '\'
# \$ $ escaped
#
# To make the expression '$\' visible, define it to an actual word:
${:U\\}= backslash
# FIXME: There was no expression '$\' in the original text of the previous
# line, that's a surprise in the parser.
# The modifier ':U' unescapes the '\$' to a simple '$'.
# expect+4: ${UNDEF:U\backslash$
VALUES= $${UNDEF:U\$$\$$ {{}} end}
# XXX: Where in the code does the '\$\$' get converted into a single '\$'?
.for i in ${VALUES}
. info $i
.endfor
#
# expect-3: ${UNDEF:U\backslash$
# expect-4: {{}}
# expect-5: end}
#
# FIXME: There was no expression '$\' in the original text of the variable
# 'VALUES', that's a surprise in the parser.
# Second try to cover the code for nested '{}' in ExprLen.
#
# XXX: It is wrong that ExprLen requires the braces to be balanced.
# XXX: It is not the job of ExprLen to parse an expression, it is naive to
# expect ExprLen to get all the details right in just a few lines of code.
# Each variable modifier has its own inconsistent way of parsing nested
# variable expressions, braces and parentheses. (Compare ':M', ':S', and
# ':D' for details.) The only sensible thing to do is therefore to let

View file

@ -1,9 +1,9 @@
# $NetBSD: directive-for-lines.mk,v 1.3 2020/12/19 12:40:00 rillig Exp $
# $NetBSD: directive-for-lines.mk,v 1.4 2022/05/08 06:51:27 rillig Exp $
#
# Tests for the line numbers that are reported in .for loops.
#
# Between 2007-01-01 (git 4d3c468f96e1080e, parse.c 1.127) and 2020-12-19
# (parse.c 1.494), the line numbers for the .info directives and error
# Since parse.c 1.127 from 2007-01-01 and before parse.c 1.494 from
# 2020-12-19, the line numbers for the .info directives and error
# messages inside .for loops had been wrong since ParseGetLine skipped empty
# lines, even when collecting the lines for the .for loop body.

View file

@ -1,4 +1,4 @@
# $NetBSD: directive-for-null.mk,v 1.1 2020/12/19 16:00:17 rillig Exp $
# $NetBSD: directive-for-null.mk,v 1.3 2022/06/12 15:03:27 rillig Exp $
#
# Test for parsing a .for loop that accidentally contains a null byte.
#
@ -9,11 +9,15 @@
# make: "(stdin)" line 3: Zero byte read from file
#
# The one about "end of file" might be misleading but is due to the
# implementation. On both errors and EOF, ParseGetLine returns NULL.
# implementation. On both errors and EOF, ParseRawLine returns NULL.
#
# The one about the "zero byte" in line 3 is surprising since the only
# line that contains a null byte is line 2.
all: .PHONY
@printf '%s\n' '.for i in 1 2 3' 'VAR=value' '.endfor' | tr 'l' '\0' \
@printf '%s\n' \
'.for i in 1 2 3' \
'VAR=value' \
'.endfor' \
| tr 'l' '\0' \
| ${MAKE} -f -

View file

@ -1,4 +1,4 @@
# $NetBSD: directive-info.mk,v 1.9 2022/01/08 20:21:34 rillig Exp $
# $NetBSD: directive-info.mk,v 1.10 2022/05/08 06:51:27 rillig Exp $
#
# Tests for the .info directive.
#
@ -18,7 +18,7 @@
.info.man: # not a message, but possibly a suffix rule
# Even if lines would have trailing whitespace, this would be trimmed by
# ParseGetLine.
# ParseRawLine.
.info
.info # comment

View file

@ -1,19 +1,20 @@
# $NetBSD: hanoi-include.mk,v 1.2 2022/01/08 22:13:43 rillig Exp $
# $NetBSD: hanoi-include.mk,v 1.3 2022/05/08 07:27:50 rillig Exp $
#
# Implements the Towers of Hanoi puzzle, thereby demonstrating a bunch of
# more or less useful programming techniques:
# Implements the Towers of Hanoi puzzle, demonstrating a bunch of more or less
# useful programming techniques:
#
# * default assignment using the ?= assignment operator
# * including the same file recursively (rather unusual)
# * extracting the current value of a variable using the .for loop
# * using shell commands for calculations since make is a text processor
# * using the :: dependency operator for adding commands to a target
# * on-the-fly variable assignment expressions using the ::= modifier
# * default assignment using the ?= assignment operator
# * including the same file recursively (rather unusual)
# * extracting the current value of a variable using the .for loop
# * using shell commands for calculations since make is a text processor
# * using the :: dependency operator for adding commands to a target
# * on-the-fly variable assignment expressions using the ::= modifier
#
# usage:
# env N=3 make -f hanoi-include.mk
# endless loop:
# make -f hanoi-include.mk N=3
# env N=3 make -r -f hanoi-include.mk
#
# endless loop, since command line variables cannot be overridden:
# make -r -f hanoi-include.mk N=3
N?= 5 # Move this number of disks ...
FROM?= A # ... from this stack ...

View file

@ -1,4 +1,4 @@
# $NetBSD: opt-define.mk,v 1.3 2022/01/23 16:09:38 rillig Exp $
# $NetBSD: opt-define.mk,v 1.4 2022/06/12 14:27:06 rillig Exp $
#
# Tests for the -D command line option, which defines global variables to the
# value 1, like in the C preprocessor.
@ -19,10 +19,22 @@ VAR= overwritten
.endif
# The variable can be undefined. If the variable had been defined in the
# "Internal" scope instead, undefining it would have no effect.
# "Internal" or in the "Command" scope instead, undefining it would have no
# effect.
.undef VAR
.if defined(VAR)
. error
.endif
# The C preprocessor allows to define a macro with a specific value. Make
# behaves differently, it defines a variable with the name 'VAR=value' and the
# value 1.
.MAKEFLAGS: -DVAR=value
.if defined(VAR)
. error
.endif
.if ${VAR=value} != "1"
. error
.endif
all: .PHONY

View file

@ -1,4 +1,4 @@
# $NetBSD: opt-jobs-no-action.mk,v 1.9 2021/04/04 09:58:51 rillig Exp $
# $NetBSD: opt-jobs-no-action.mk,v 1.10 2022/05/08 06:51:27 rillig Exp $
#
# Tests for the combination of the options -j and -n, which prints the
# commands instead of actually running them.
@ -21,7 +21,7 @@
# The shell attributes are handled by Job_ParseShell.
# The shell attributes 'quiet' and 'echo' don't need a trailing newline,
# this is handled by the [0] != '\0' checks in Job_ParseShell.
# The '\#' is handled by ParseGetLine.
# The '\#' is handled by ParseRawLine.
# The '\n' is handled by Str_Words in Job_ParseShell.
# The '$$' is handled by Var_Subst in ParseDependencyLine.
.SHELL: \

View file

@ -1,8 +1,8 @@
# $NetBSD: opt-version.mk,v 1.1 2021/12/23 11:05:59 rillig Exp $
# $NetBSD: opt-version.mk,v 1.2 2022/05/08 07:27:50 rillig Exp $
#
# Tests for the command line option '--version', which outputs the version
# number of make. NetBSD's make does not have a version number, but the bmake
# distribution created from it has.
# Tests for the command line option '--version', which may be expected to
# output the version number of make. NetBSD's make does not have a version
# number, but the bmake distribution created from it has.
# As of 2021-12-23, the output is a single empty line since the '--' does not
# end the command line options. Command line parsing then continues as if

View file

@ -1 +1,5 @@
ordinary:
BEFORE=before
submake:
BEFORE=before
exit status 0

View file

@ -1,8 +1,20 @@
# $NetBSD: opt-x-reduce-exported.mk,v 1.2 2020/08/16 14:25:16 rillig Exp $
# $NetBSD: opt-x-reduce-exported.mk,v 1.3 2022/05/08 07:27:50 rillig Exp $
#
# Tests for the -x command line option.
# Tests for the -X command line option, which prevents variables passed on the
# command line from being exported to the environment of child commands.
# TODO: Implementation
# The variable 'BEFORE' is exported, the variable 'AFTER' isn't.
.MAKEFLAGS: BEFORE=before -X AFTER=after
all:
@:;
all: .PHONY ordinary submake
ordinary: .PHONY
@echo 'ordinary:'
@env | sort | grep -e '^BEFORE' -e '^AFTER'
submake: .PHONY
@echo 'submake:'
@${MAKE} -r -f ${MAKEFILE} show-env
show-env: .PHONY
@env | sort | grep -e '^BEFORE' -e '^AFTER'

View file

@ -1,5 +1,6 @@
make: "parse.mk" line 7: Makefile appears to contain unresolved CVS/RCS/??? merge conflicts
make: "parse.mk" line 14: Makefile appears to contain unresolved CVS/RCS/??? merge conflicts
make: "parse.mk" line 24: Invalid line type
make: Fatal errors encountered -- cannot continue
make: stopped in unit-tests
exit status 1

View file

@ -1,4 +1,4 @@
# $NetBSD: parse.mk,v 1.2 2022/01/22 17:10:51 rillig Exp $
# $NetBSD: parse.mk,v 1.3 2022/07/24 20:25:23 rillig Exp $
#
# Test those parts of the parsing that do not belong in any of the other
# categories.
@ -12,3 +12,13 @@
# expect+1: Makefile appears to contain unresolved CVS/RCS/??? merge conflicts
>>>>>> new
# Since parse.c 1.578 from 2021-12-14 and before parse.c 1.681 from
# 2022-07-24, if a line of a makefile could only be a dependency specification
# but didn't contain any of the dependency operators ':', '!', '::' and its
# expansion ended with a space, make read a single byte from the memory beyond
# the expanded line's terminating '\0'.
#
# https://bugs.freebsd.org/265119
one-target ${:U }

View file

@ -1,11 +1 @@
head (dirname) of 'a/b/c' is 'a/b'
head (dirname) of 'def' is '.'
head (dirname) of 'a.b.c' is '.'
head (dirname) of 'a.b/c' is 'a.b'
head (dirname) of 'a' is '.'
head (dirname) of 'a.a' is '.'
head (dirname) of '.gitignore' is '.'
head (dirname) of 'a' is '.'
head (dirname) of 'a.a' is '.'
head (dirname) of 'trailing/' is 'trailing'
exit status 0

View file

@ -1,9 +1,64 @@
# $NetBSD: varmod-head.mk,v 1.4 2020/12/20 22:57:40 rillig Exp $
# $NetBSD: varmod-head.mk,v 1.5 2022/07/10 21:11:49 rillig Exp $
#
# Tests for the :H variable modifier, which returns the dirname of
# each of the words in the variable value.
all:
.for path in a/b/c def a.b.c a.b/c a a.a .gitignore a a.a trailing/
@echo "head (dirname) of '"${path:Q}"' is '"${path:H:Q}"'"
.endfor
.if ${:U a/b/c :H} != "a/b"
. error
.endif
.if ${:U def :H} != "."
. error
.endif
.if ${:U a.b.c :H} != "."
. error
.endif
.if ${:U a.b/c :H} != "a.b"
. error
.endif
.if ${:U a :H} != "."
. error
.endif
.if ${:U a.a :H} != "."
. error
.endif
.if ${:U .gitignore :H} != "."
. error
.endif
.if ${:U trailing/ :H} != "trailing"
. error
.endif
.if ${:U /abs/dir/file :H} != "/abs/dir"
. error
.endif
.if ${:U rel/dir/file :H} != "rel/dir"
. error
.endif
# The head of "/" was an empty string before 2020.07.20.14.50.41, leading to
# the output "before after", with two spaces. Since 2020.07.20.14.50.41, the
# output is "before after", discarding the empty word.
.if ${:U before/ / after/ :H} == "before after"
# OK
.elif ${:U before/ / after/ :H} == "before after"
# No '.info' to keep the file compatible with old make versions.
_!= echo "The modifier ':H' generates an empty word." 1>&2; echo
.else
. error
.endif
# An empty list is split into a single empty word.
# The dirname of this empty word is ".".
.if ${:U :H} != "."
. error
.endif
all: .PHONY

View file

@ -1,4 +1,4 @@
# $NetBSD: varmod-ifelse.mk,v 1.18 2022/01/15 20:16:55 rillig Exp $
# $NetBSD: varmod-ifelse.mk,v 1.19 2022/05/08 06:51:27 rillig Exp $
#
# Tests for the ${cond:?then:else} variable modifier, which evaluates either
# the then-expression or the else-expression, depending on the condition.
@ -133,7 +133,7 @@ VAR= value
# When parsing such an expression, the parser used to be strict. It first
# evaluated the left-hand side of the operator '&&' and then started parsing
# the right-hand side 'no >= 10'. The word 'no' is obviously a string
# literal, not enclosed in quotes, which is ok, even on the left-hand side of
# literal, not enclosed in quotes, which is OK, even on the left-hand side of
# the comparison operator, but only because this is a condition in the
# modifier ':?'. In an ordinary directive '.if', this would be a parse error.
# For strings, only the comparison operators '==' and '!=' are defined,
@ -169,3 +169,16 @@ EMPTY= # empty
.info ${${ASTERISK} :?true:false}
# syntax error since the condition is completely blank.
.info ${${EMPTY} :?true:false}
# Since the condition of the '?:' modifier is expanded before being parsed and
# evaluated, it is common practice to enclose expressions in quotes, to avoid
# producing syntactically invalid conditions such as ' == value'. This only
# works if the expanded values neither contain quotes nor backslashes. For
# strings containing quotes or backslashes, the '?:' modifier should not be
# used.
PRIMES= 2 3 5 7 11
.if ${1 2 3 4 5:L:@n@$n:${ ("${PRIMES:M$n}" != "") :?prime:not_prime}@} != \
"1:not_prime 2:prime 3:prime 4:not_prime 5:prime"
. error
.endif

View file

@ -5,12 +5,13 @@ Comparing "five six seven" != "five six seven"
CondParser_Eval: ${NUMBERS:M[^s]*[ex]} != "One Three five"
Comparing "One Three five" != "One Three five"
CondParser_Eval: ${:U****************:M****************b}
CondParser_Eval: ${:U..................................................b:M*?*?*?*?*?a}
CondParser_Eval: ${:Ua \$ sign:M*$$*} != "\$"
Comparing "$" != "$"
CondParser_Eval: ${:Ua \$ sign any-asterisk:M*\$*} != "any-asterisk"
Comparing "any-asterisk" != "any-asterisk"
make: "varmod-match.mk" line 146: Unknown modifier "]"
make: "varmod-match.mk" line 146: Malformed conditional (${ ${:U\:} ${:U\:\:} :L:M[:]} != ":")
make: "varmod-match.mk" line 157: Unknown modifier "]"
make: "varmod-match.mk" line 157: Malformed conditional (${ ${:U\:} ${:U\:\:} :L:M[:]} != ":")
make: Fatal errors encountered -- cannot continue
make: stopped in unit-tests
exit status 1

View file

@ -1,4 +1,4 @@
# $NetBSD: varmod-match.mk,v 1.8 2022/03/27 18:39:01 rillig Exp $
# $NetBSD: varmod-match.mk,v 1.11 2022/06/11 09:15:49 rillig Exp $
#
# Tests for the :M variable modifier, which filters words that match the
# given pattern.
@ -28,11 +28,16 @@ NUMBERS= One Two Three Four five six seven
. error
.endif
# Before 2020-06-13, this expression took quite a long time in Str_Match,
# calling itself 601080390 times for 16 asterisks.
# Before 2020-06-13, this expression called Str_Match 601,080,390 times.
# Since 2020-06-13, this expression calls Str_Match 1 time.
.if ${:U****************:M****************b}
.endif
# As of 2022-06-11, this expression calls Str_Match 5,242,223 times.
# Adding another '*?' to the pattern calls Str_Match 41,261,143 times.
.if ${:U..................................................b:M*?*?*?*?*?a}
.endif
# To match a dollar sign in a word, double it.
#
# This is different from the :S and :C variable modifiers, where a '$'
@ -125,6 +130,12 @@ ${:U*}= asterisk
. error
.endif
# [\] matches a single backslash
WORDS= a\b a[\]b ab
.if ${WORDS:Ma[\]b} != "a\\b"
. error
.endif
# : terminates the pattern
.if ${ A * :L:M:} != ""
. error
@ -151,26 +162,95 @@ ${:U*}= asterisk
# [\] matches exactly a backslash; no escaping takes place in
# character ranges
# Without the 'a' in the below expressions, the backslash would end a word and
# thus influence how the string is split into words.
.if ${ ${:U\\a} ${:U\\\\a} :L:M[\]a} != "\\a"
# Without the 'a' in the below words, the backslash would end a word and thus
# influence how the string is split into words.
WORDS= 1\a 2\\a
.if ${WORDS:M?[\]a} != "1\\a"
. error
.endif
#.MAKEFLAGS: -dcv
# [[-]] May look like it would match a single '[', '\' or ']', but
# the inner ']' has two roles: it is the upper bound of the
# character range as well as the closing character of the
# character list. The outer ']' is just a regular character.
WORDS= [ ] [] \] ]]
.if ${WORDS:M[[-]]} != "[] \\] ]]"
. error
.endif
# [b[-]a]
# Same as for '[[-]]': the character list stops at the first
# ']', and the 'a]' is treated as a literal string.
WORDS= [a \a ]a []a \]a ]]a [a] \a] ]a] ba]
.if ${WORDS:M[b[-]a]} != "[a] \\a] ]a] ba]"
. error
.endif
# [-] Matches a single '-' since the '-' only becomes part of a
# character range if it is preceded and followed by another
# character.
WORDS= - -]
.if ${WORDS:M[-]} != "-"
. error
.endif
# [ Incomplete empty character list, never matches.
WORDS= a a[
.if ${WORDS:Ma[} != ""
. error
.endif
# [^ Incomplete negated empty character list, matches any single
# character.
WORDS= a a[ aX
.if ${WORDS:Ma[^} != "a[ aX"
. error
.endif
# [-x1-3 Incomplete character list, matches those elements that can be
# parsed without lookahead.
WORDS= - + x xx 0 1 2 3 4 [x1-3
.if ${WORDS:M[-x1-3} != "- x 1 2 3"
. error
.endif
# [^-x1-3
# Incomplete negated character list, matches any character
# except those elements that can be parsed without lookahead.
WORDS= - + x xx 0 1 2 3 4 [x1-3
.if ${WORDS:M[^-x1-3} != "+ 0 4"
. error
.endif
# [\ Incomplete character list containing a single '\'.
#
# Incomplete patterns:
# [ matches TODO
# [x matches TODO
# [^ matches TODO
# [- matches TODO
# [xy matches TODO
# [^x matches TODO
# [\ matches TODO
# A word can only end with a backslash if the preceding
# character is a backslash as well; in all other cases the final
# backslash would escape the following space, making the space
# part of the word. Only the very last word of a string can be
# '\', as there is no following space that could be escaped.
WORDS= \\ \a ${:Ux\\}
.if ${WORDS:M?[\]} != "\\\\ x\\"
. error
.endif
# [x- Incomplete character list containing an incomplete character
# range, matches only the 'x'.
WORDS= [x- x x- y
.if ${WORDS:M[x-} != "x"
. error
.endif
# [^x- Incomplete negated character list containing an incomplete
# character range; matches each word that does not have an 'x'
# at the position of the character list.
#
# [x- matches exactly 'x', doesn't match 'x-'
# [^x- matches TODO
# \ matches never
# XXX: Even matches strings that are longer than a single
# character.
WORDS= [x- x x- y yyyyy
.if ${WORDS:M[^x-} != "[x- y yyyyy"
. error
.endif
# The modifier ':tW' prevents splitting at whitespace. Even leading and
@ -184,3 +264,19 @@ ${:U*}= asterisk
.if ${ plain string :L:M*} != "plain string"
. error
.endif
# The pattern can come from a variable expression. For single-letter
# variables, either the short form or the long form can be used, just as
# everywhere else.
PRIMES= 2 3 5 7 11
n= 2
.if ${PRIMES:M$n} != "2"
. error
.endif
.if ${PRIMES:M${n}} != "2"
. error
.endif
.if ${PRIMES:M${:U2}} != "2"
. error
.endif

View file

@ -1,2 +1,4 @@
!"#$$%&'()*+,-./09:;<=>?@AZ[\]^_`az{|}~
!"#$$%&'()*+,-./09:;<=>?@AZ[\]^_`az{|}~
!"#$$%&'()*+,-./09:;<=>?@AZ[\]^_`az{|}~
exit status 0

View file

@ -1,10 +1,17 @@
# $NetBSD: varmod-quote-dollar.mk,v 1.3 2022/01/22 17:10:51 rillig Exp $
# $NetBSD: varmod-quote-dollar.mk,v 1.4 2022/05/08 10:14:40 rillig Exp $
#
# Tests for the :q variable modifier, which quotes the string for the shell
# and doubles dollar signs, to prevent them from being interpreted by a
# child process of make.
# The newline and space characters at the beginning of this string are passed
# to the child make. When the child make parses the variable assignment, it
# discards the leading space characters.
ASCII_CHARS= ${.newline} !"\#$$%&'()*+,-./09:;<=>?@AZ[\]^_`az{|}~
all:
@${MAKE} -r -f /dev/null CHARS=${ASCII_CHARS:q} -V CHARS
@${MAKE} -r -f /dev/null \
CHARS=${ASCII_CHARS:q} \
TWICE=${ASCII_CHARS:q}${ASCII_CHARS:q} \
-V CHARS \
-V TWICE

View file

@ -1 +1,31 @@
randomize compat mode:
: Making a
: Making a
: Making a
: Making b
: Making b
: Making b
: Making c
: Making c
: Making c
randomize jobs mode (-j1):
: Making a
: Making a
: Making a
: Making b
: Making b
: Making b
: Making c
: Making c
: Making c
randomize jobs mode (-j5):
: Making a
: Making a
: Making a
: Making b
: Making b
: Making b
: Making c
: Making c
: Making c
exit status 0

View file

@ -1,8 +1,41 @@
# $NetBSD: varname-dot-make-mode.mk,v 1.2 2020/08/16 14:25:16 rillig Exp $
# $NetBSD: varname-dot-make-mode.mk,v 1.3 2022/05/07 17:49:47 rillig Exp $
#
# Tests for the special .MAKE.MODE variable.
# TODO: Implementation
# TODO: test .MAKE.MODE "meta", or see meta mode tests.
# TODO: test .MAKE.MODE "compat"
all:
@:;
# See Makefile, POSTPROC for the postprocessing that takes place.
# See the .rawout file for the raw output before stripping the digits.
all: .PHONY make-mode-randomize-targets
# By adding the word "randomize-targets" to the variable .MAKE.MODE, the
# targets are not made in declaration order, but rather in random order. This
# mode helps to find undeclared dependencies between files.
#
# History
# Added on 2022-05-07.
#
# See also
# https://gnats.netbsd.org/45226
make-mode-randomize-targets: .PHONY
@echo "randomize compat mode:"
@${MAKE} -r -f ${MAKEFILE} randomize-targets
@echo "randomize jobs mode (-j1):"
@${MAKE} -r -f ${MAKEFILE} -j1 randomize-targets
@echo "randomize jobs mode (-j5):"
@${MAKE} -r -f ${MAKEFILE} -j5 randomize-targets | grep '^:'
.if make(randomize-targets)
randomize-targets: .WAIT a1 a2 a3 .WAIT b1 b2 b3 .WAIT c1 c2 c3 .WAIT
a1 a2 a3 b1 b2 b3 c1 c2 c3:
: Making ${.TARGET}
# .MAKE.MODE is evaluated after parsing all files, so it suffices to switch
# the mode after defining the targets.
.MAKE.MODE+= randomize-targets
.endif

View file

@ -1,3 +0,0 @@
-fdebug-prefix-map=$NETBSDSRCDIR=/usr/src -fdebug-regex-map=/usr/src/(.*)/obj$=/usr/obj/\1
-fdebug-prefix-map=$NETBSDSRCDIR=/usr/src -fdebug-regex-map=/usr/src/(.*)/obj$=/usr/obj/\1
exit status 0

View file

@ -1,14 +0,0 @@
# $NetBSD: varquote.mk,v 1.5 2021/12/28 10:47:00 rillig Exp $
#
# Test VAR:q modifier
.if !defined(REPROFLAGS)
REPROFLAGS+= -fdebug-prefix-map=\$$NETBSDSRCDIR=/usr/src
REPROFLAGS+= -fdebug-regex-map='/usr/src/(.*)/obj$$=/usr/obj/\1'
all:
@${MAKE} -f ${MAKEFILE} REPROFLAGS=${REPROFLAGS:S/\$/&&/g:Q}
@${MAKE} -f ${MAKEFILE} REPROFLAGS=${REPROFLAGS:q}
.else
all:
@printf "%s %s\n" ${REPROFLAGS}
.endif

View file

@ -1,4 +1,4 @@
/* $NetBSD: var.c,v 1.1019 2022/03/27 18:39:01 rillig Exp $ */
/* $NetBSD: var.c,v 1.1025 2022/06/14 19:57:56 rillig Exp $ */
/*
* Copyright (c) 1988, 1989, 1990, 1993
@ -147,7 +147,7 @@
#include "metachar.h"
/* "@(#)var.c 8.3 (Berkeley) 3/19/94" */
MAKE_RCSID("$NetBSD: var.c,v 1.1019 2022/03/27 18:39:01 rillig Exp $");
MAKE_RCSID("$NetBSD: var.c,v 1.1025 2022/06/14 19:57:56 rillig Exp $");
/*
* Variables are defined using one of the VAR=value assignments. Their
@ -460,7 +460,6 @@ VarFindSubstring(Substring name, GNode *scope, bool elsewhere)
return var;
}
/* TODO: Replace these calls with VarFindSubstring, as far as possible. */
static Var *
VarFind(const char *name, GNode *scope, bool elsewhere)
{
@ -4147,15 +4146,15 @@ ParseVarname(const char **pp, char startc, char endc,
*pp = p;
}
static VarParseResult
ValidShortVarname(char varname, const char *start)
static bool
IsShortVarnameValid(char varname, const char *start)
{
if (varname != '$' && varname != ':' && varname != '}' &&
varname != ')' && varname != '\0')
return VPR_OK;
return true;
if (!opts.strict)
return VPR_ERR; /* XXX: Missing error message */
return false; /* XXX: Missing error message */
if (varname == '$')
Parse_Error(PARSE_FATAL,
@ -4166,7 +4165,7 @@ ValidShortVarname(char varname, const char *start)
Parse_Error(PARSE_FATAL,
"Invalid variable name '%c', at \"%s\"", varname, start);
return VPR_ERR;
return false;
}
/*
@ -4181,12 +4180,11 @@ ParseVarnameShort(char varname, const char **pp, GNode *scope,
{
char name[2];
Var *v;
VarParseResult vpr;
const char *val;
vpr = ValidShortVarname(varname, *pp);
if (vpr != VPR_OK) {
(*pp)++;
*out_false_res = vpr;
if (!IsShortVarnameValid(varname, *pp)) {
(*pp)++; /* only skip the '$' */
*out_false_res = VPR_ERR;
*out_false_val = var_Error;
return false;
}
@ -4194,41 +4192,39 @@ ParseVarnameShort(char varname, const char **pp, GNode *scope,
name[0] = varname;
name[1] = '\0';
v = VarFind(name, scope, true);
if (v == NULL) {
const char *val;
*pp += 2;
if (v != NULL) {
/* No need to advance *pp, the calling code handles this. */
*out_true_var = v;
return true;
}
val = UndefinedShortVarValue(varname, scope);
if (val == NULL)
val = emode == VARE_UNDEFERR
? var_Error : varUndefined;
*pp += 2;
if (opts.strict && val == var_Error) {
Parse_Error(PARSE_FATAL,
"Variable \"%s\" is undefined", name);
*out_false_res = VPR_ERR;
*out_false_val = val;
return false;
}
val = UndefinedShortVarValue(varname, scope);
if (val == NULL)
val = emode == VARE_UNDEFERR ? var_Error : varUndefined;
/*
* XXX: This looks completely wrong.
*
* If undefined expressions are not allowed, this should
* rather be VPR_ERR instead of VPR_UNDEF, together with an
* error message.
*
* If undefined expressions are allowed, this should rather
* be VPR_UNDEF instead of VPR_OK.
*/
*out_false_res = emode == VARE_UNDEFERR
? VPR_UNDEF : VPR_OK;
if (opts.strict && val == var_Error) {
Parse_Error(PARSE_FATAL,
"Variable \"%s\" is undefined", name);
*out_false_res = VPR_ERR;
*out_false_val = val;
return false;
}
*out_true_var = v;
return true;
/*
* XXX: This looks completely wrong.
*
* If undefined expressions are not allowed, this should
* rather be VPR_ERR instead of VPR_UNDEF, together with an
* error message.
*
* If undefined expressions are allowed, this should rather
* be VPR_UNDEF instead of VPR_OK.
*/
*out_false_res = emode == VARE_UNDEFERR ? VPR_UNDEF : VPR_OK;
*out_false_val = val;
return false;
}
/* Find variables like @F or <D. */
@ -4453,9 +4449,8 @@ Var_Parse_FastLane(const char **pp, VarEvalMode emode, FStr *out_value)
*
* Input:
* *pp The string to parse.
* In CondParser_FuncCallEmpty, it may also point to the
* "y" of "empty(VARNAME:Modifiers)", which is
* syntactically the same.
* When called from CondParser_FuncCallEmpty, it can
* also point to the "y" of "empty(VARNAME:Modifiers)".
* scope The scope for finding variables
* emode Controls the exact details of parsing and evaluation
*
@ -4486,16 +4481,14 @@ Var_Parse(const char **pp, GNode *scope, VarEvalMode emode, FStr *out_val)
{
const char *p = *pp;
const char *const start = p;
/* true if have modifiers for the variable. */
bool haveModifier;
/* Starting character if variable in parens or braces. */
char startc;
/* Ending character if variable in parens or braces. */
char endc;
bool haveModifier; /* true for ${VAR:...}, false for ${VAR} */
char startc; /* the actual '{' or '(' or '\0' */
char endc; /* the expected '}' or ')' or '\0' */
/*
* true if the variable is local and we're expanding it in a
* non-local scope. This is done to support dynamic sources.
* The result is just the expression, unaltered.
* true if the expression is based on one of the 7 predefined
* variables that are local to a target, and the expression is
* expanded in a non-local scope. The result is the text of the
* expression, unaltered. This is needed to support dynamic sources.
*/
bool dynamic;
const char *extramodifiers;
@ -4512,11 +4505,7 @@ Var_Parse(const char **pp, GNode *scope, VarEvalMode emode, FStr *out_val)
extramodifiers = NULL; /* extra modifiers to apply first */
dynamic = false;
/*
* Appease GCC, which thinks that the variable might not be
* initialized.
*/
endc = '\0';
endc = '\0'; /* Appease GCC. */
startc = p[1];
if (startc != '(' && startc != '{') {
@ -4539,8 +4528,7 @@ Var_Parse(const char **pp, GNode *scope, VarEvalMode emode, FStr *out_val)
if (v->inUse) {
if (scope->fname != NULL) {
fprintf(stderr, "In a command near ");
PrintLocation(stderr, false,
scope->fname, scope->lineno);
PrintLocation(stderr, false, scope);
}
Fatal("Variable %s is recursive.", v->name.str);
}
@ -4549,7 +4537,9 @@ Var_Parse(const char **pp, GNode *scope, VarEvalMode emode, FStr *out_val)
* XXX: This assignment creates an alias to the current value of the
* variable. This means that as long as the value of the expression
* stays the same, the value of the variable must not change.
* Using the '::=' modifier, it could be possible to do exactly this.
* Using the '::=' modifier, it could be possible to trigger exactly
* this situation.
*
* At the bottom of this function, the resulting value is compared to
* the then-current value of the variable. This might also invoke
* undefined behavior.