In function names, the word "get" was not used consistently to look up
or compute data, in several cases "get" was a synonym for "read", just
like in the standard C library (fgetc).
The really confusing part is that there are two functions now, called
ParseGetLine and ParseReadLine, and both were underdocumented.
At that point, the variable expression has already been expanded. To
avoid the impression that the token might be relevant, pass FALSE
instead of TRUE. No change of behavior.
This is needed to compile bmake with GCC 2.8.1 on SunOS 5.9.
To support ancient systems like this, the whole code of usr.bin/make is
supposed to use only ISO C90 features, except for filemon, which is not
used on these systems.
There is no use case for accessing or even modifying the capacity of a
vector, therefore there is no need to hide it using the prefix "priv_".
This way, the member names are aligned between Buffer and Vector.
The function basename from POSIX has a few unfortunate properties, it is
allowed to return a pointer to static memory. This is too unreliable,
therefore this trivial own implementation.
The comment "execute the commands" had once been correct but not
anymore. Since a few years, not only the commands of the .BEGIN and
.END nodes are executed, instead the nodes are made as usual, including
their dependencies.
A race between child and parent means that we cannot
guarantee whether all child output is seen before we call
JobClosePipes, thus intervening debug output can appear
before or after the last child output.
Now that the parsing of the directives is unified and strict, there is
no need anymore for the dispatched functions to check for unknown
directives. These functions don't even get the information to decide
that since this decision is already done.
Since a line is not an iterator and since the expression *line typically
means "the current element", not "the first character", replacing *line
with line[0] more directly expresses the idea of accessing the first
character of a string.
Before, make accepted misspellings like .warnings, .export-literally and
a few others, all of which are unlikely to occur in practice. See the
test directive-misspellings.mk for further details.
This test allows the other directive-* tests to focus on the purpose of
the individual directive, allowing these tests to continue after
parsing, without errors.
It had been conceptually wrong to modify cmdFlags.echo just to suppress
echoing while enabling error checking.
Now the code in JobPrintCommand speaks for itself and no longer needs
any comments. The few lines at the end have the sole purpose of
restoring the default state (echo + errChk) in the shell file.
The field job->echo is initialized in JobStart (and in JobOpenTmpFile).
After that, it is not modified anymore. Therefore it is not necessary
to run these test cases redundantly.
The field job->ignerr, on the other hand, is modified later on. For
these cases, the many remaining test cases are still needed.
This flag was placed wrong in the Job since it is only necessary as long
as the shell commands are written to the shell file.
Resetting it in JobStart and JobExec was completely misguided since that
is far away from writing the shell commands; this should have been done
in JobPrintCommands instead.
The status of this flag doesn't need to be printed in debugging mode
since it is controlled by a single command line option (-dx) and does
not interact with all the other switches.
Right now, the test sh-flags.mk demonstrates many variants to configure
echoing of the shell commands (-s, .SILENT, '@'), error handling (-i,
.IGNORE, '-') and whether the commands are run (-n, -N, .MAKE,
.RECURSIVE, '+').
Even more variants are possible by configuring the shell to have error
control. None of the built-in shell definitions has error control, so
it is unlikely that anybody uses them, but who knows.
Being able to configure these details at 3 levels is good, but what
makes all this really hard to understand is that some of these switches
interact in non-obvious ways. For example, in jobs mode, a single
command can change job->ignerr (in JobPrintSpecialsEchoCtl), which will
affect all further commands of that job.
The goal of this refactoring is to make the code easier to understand by
making the switches on the job level constant and by moving all
modifications to them to the ShellWriter.
In other places, the exit status of make is carefully chosen to be 0
(success), 1 (did not make everything), 2 (other error). Using a signal
number is not guaranteed to be consistent among operating systems and is
therefore a weird choice.
They are all templates with a single %s placeholder, so embed this
unambiguously in the variable name. The previous variable names didn't
provide any clue that echoCmd, execIgnore and errExit had a lot in
common.
Flags of similar names are also available in CmdOpts (global command
line options) and Job. The new name CommandFlags emphasizes that these
flags apply to the smallest scope possible, which is a single command,
as opposed to the whole GNode/Job.
They have never been related. Furthermore, Job.errOn is really tricky
to reach at all. To do that, one has to define a custom shell and set
hasErrCtl=true. The manual page has an example for that, but it's
probably not use in practice, just like the possibility to use the C
shell for all commands.
Having all these flags in a single bitmask makes it harder to see where
exactly they can possibly be used since their state could also be
modified using the unsuspicious job->flags = 0. Using individual names
just leaves the single memset, and that is only used during
initialization.
The "false" is supposed to be run not only if the command has the '-'
flag, but also if the target is marked as .IGNORE or if the command line
option -i is given.
After the failed command, the remaining commands are skipped, therefore
the final echo for the empty line had to be moved up, at the beginning
of the target.
The code in JobPrintSpecials is rather complicated and contains
surprising interaction between some of the switches.
To see the exact effects of the switches, record the current state and
its output, to prevent accidental breakage during the upcoming
refactorings.
The manual page says that in -j mode when the shell does not have ErrCtl
(and none of the default shells has that), the command prefix '-'
"affects the entire job", but this seems to be wrong. At least, there
is no change in the output from before, when all commands had been in
the same target.
The first parameter of the macro was always stdout, and there was no
apparent reason to pass anything else there.
Let the compiler decide whether to inline this or not, it's not
time-critical.
Since Var_Export1 is neither exported by the module nor does it belong
to the Var type, the previous function name was misleading. The 1 in
the function name was not as expressive as possible. The new name
aligns nicely with UnexportVar, which is a very young name as well.
Now that errors in the main targets and in their dependencies have the
same effect on the .END node and its dependencies, the two variables can
be merged.
Whether in -k mode or not, the exit status tells whether all requested
targets were made or not. If a dependency could not be made, the main
target was not made as well, therefore the exit status must be nonzero
in such a case.
This part of the code lacked proper unit tests until today. The unit
test deptgt-end-fail.mk is compatible with make>=2003 at least, allowing
to compare the output over time.
In 2003, in the ok-ok-ok-ok case, "Making all from all-dep." was printed
twice in a row, for whatever reason ... (40 minutes later) ... If I had
just made the two commands for 'all' and '.END' more distinguishable.
Back in 2003, the local variables for .END had not been initialized,
instead the .END node was run with the local variables of the last
preceding node. In this case, that node was 'all', therefore ${.TARGET}
had obviously expanded to 'all'.
Somewhere in 2004, the shell commands were no longer run with the -e
flag, which resulted in the "exit status $?" line to be printed in cases
that had stopped early before.
Somewhere in 2005, the local variables for the .END node had been fixed.
The variable ${.TARGET} now had the value '.END', just as expected. In
addition, the dependencies for the .END node were made, although without
getting their proper local variables. This resulted in the output
"Making out of nothing" instead of the expected "Making end-dep out of
nothing".
Still in 2005, in the test case "all=ok all-dep=ok end=ok end-dep=ERR",
the error code of the failed 'end-dep' was first reported as "*** Error
code 1 (continuing)". To compensate for this improvement, a new bug had
been introduced. The test case "all=ok all-dep=ok end=ERR end-dep=ERR"
had properly exited with status 1 on 2005-01-01, but on 2006-01-01 it
exited with status 0, thereby ignoring errors in the .END node.
Somewhere in 2008, some of the error messages (but not all) were
directed to stderr instead of stdout. The actual output stayed the same
though.
Somewhere in 2011, the dependency of the .END node got its own local
variables, and ${.TARGET} now expanded to 'end-dep', as expected.
Somewhere in 2016, the two empty lines between the "*** Error code 1
(continuing)" and the "Stop." got compressed into a single empty line.
On 2020-12-07 (that is, today), the exit status 1 has been restored in
the error cases, after it had been wrong for at least 14 years.
Adding an individual test for each of the 16 combinations would have
been too much manual work, and it's not easy to come up with a good
naming scheme for all the tests, keeping them short and expressive at
the same time.
Earlier versions of make didn't know the -v option to print the expanded
value of a variable. To make the test runnable by older makes as well,
switch to -V instead, which has been available much longer.
Makefiles are text files, they must not contain null bytes.
The previous code in this area was rotten anyway. It assumed that
buf_end could be NULL even if buf_ptr was a valid pointer, which is no
longer true, probably since a few years already.
Continuing parsing after a null byte does not make sense. If there's a
null byte in a text file, that file is corrupted, and parsing it leads
to unintended effects easily. Therefore the only sensible action is to
stop parsing immediately.
The check whether cf->readMore could be null was outdated as well, which
previously made the fatal error impossible to reach. Because of the
missing unit tests, nobody noticed this though.
The "exit status 0" in opt-file.exp is worring but that's due to another
bug and will be fixed in a follow-up commit.