Import GNU Make 4.4.1

Landlock Make hasn't been working well on AARCH64 systems. Let's do this
over the right way, using our new build tools.
This commit is contained in:
Justine Tunney 2023-11-30 20:50:10 -08:00
parent 9315ebbfd9
commit 14bf57180f
No known key found for this signature in database
GPG key ID: BE714B4575D6E328
88 changed files with 13931 additions and 16191 deletions

View file

@ -1,5 +1,5 @@
/* Output to stdout / stderr for GNU make
Copyright (C) 2013-2020 Free Software Foundation, Inc.
/* Output to stdout / stderr for GNU Make
Copyright (C) 2013-2023 Free Software Foundation, Inc.
This file is part of GNU Make.
GNU Make is free software; you can redistribute it and/or modify it under the
@ -12,15 +12,27 @@ WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
A PARTICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License along with
this program. If not, see <http://www.gnu.org/licenses/>. */
this program. If not, see <https://www.gnu.org/licenses/>. */
#include "third_party/make/makeint.inc"
#include "third_party/make/os.h"
#include "third_party/make/output.h"
#include "libc/runtime/runtime.h"
#include "libc/calls/struct/flock.h"
#include "makeint.h"
#include "os.h"
#include "output.h"
/* GNU make no longer supports pre-ANSI89 environments. */
/* GNU Make no longer supports pre-ANSI89 environments. */
#include <assert.h>
#include <stdio.h>
#include <stdarg.h>
#ifdef HAVE_UNISTD_H
# include <unistd.h>
#endif
#ifdef HAVE_FCNTL_H
# include <fcntl.h>
#else
# include <sys/file.h>
#endif
struct output *output_context = NULL;
unsigned int stdio_traced = 0;
@ -29,30 +41,28 @@ unsigned int stdio_traced = 0;
#define OUTPUT_ISSET(_out) ((_out)->out >= 0 || (_out)->err >= 0)
#ifdef HAVE_FCNTL_H
# define STREAM_OK(_s) ((fcntl (fileno (_s), F_GETFD) != -1) || (errno != EBADF))
#else
# define STREAM_OK(_s) 1
#endif
/* Write a string to the current STDOUT or STDERR. */
static void
_outputs (struct output *out, int is_err, const char *msg)
{
if (! out || ! out->syncout)
{
FILE *f = is_err ? stderr : stdout;
fputs (msg, f);
fflush (f);
}
else
FILE *f;
if (out && out->syncout)
{
int fd = is_err ? out->err : out->out;
size_t len = strlen (msg);
int r;
EINTRLOOP (r, lseek (fd, 0, SEEK_END));
writebuf (fd, msg, len);
if (fd != OUTPUT_NONE)
{
size_t len = strlen (msg);
int r;
EINTRLOOP (r, lseek (fd, 0, SEEK_END));
writebuf (fd, msg, len);
return;
}
}
f = is_err ? stderr : stdout;
fputs (msg, f);
fflush (f);
}
/* Write a message indicating that we've just entered or
@ -125,73 +135,10 @@ log_working_directory (int entering)
return 1;
}
/* Set a file descriptor to be in O_APPEND mode.
If it fails, just ignore it. */
static void
set_append_mode (int fd)
{
#if defined(F_GETFL) && defined(F_SETFL) && defined(O_APPEND)
int flags = fcntl (fd, F_GETFL, 0);
if (flags >= 0)
{
int r;
EINTRLOOP(r, fcntl (fd, F_SETFL, flags | O_APPEND));
}
#endif
}
#ifndef NO_OUTPUT_SYNC
/* Semaphore for use in -j mode with output_sync. */
static sync_handle_t sync_handle = -1;
#define FD_NOT_EMPTY(_f) ((_f) != OUTPUT_NONE && lseek ((_f), 0, SEEK_END) > 0)
/* Set up the sync handle. Disables output_sync on error. */
static int
sync_init (void)
{
int combined_output = 0;
#ifdef WINDOWS32
if ((!STREAM_OK (stdout) && !STREAM_OK (stderr))
|| (sync_handle = create_mutex ()) == -1)
{
perror_with_name ("output-sync suppressed: ", "stderr");
output_sync = 0;
}
else
{
combined_output = same_stream (stdout, stderr);
prepare_mutex_handle_string (sync_handle);
}
#else
if (STREAM_OK (stdout))
{
struct stat stbuf_o, stbuf_e;
sync_handle = fileno (stdout);
combined_output = (fstat (fileno (stdout), &stbuf_o) == 0
&& fstat (fileno (stderr), &stbuf_e) == 0
&& stbuf_o.st_dev == stbuf_e.st_dev
&& stbuf_o.st_ino == stbuf_e.st_ino);
}
else if (STREAM_OK (stderr))
sync_handle = fileno (stderr);
else
{
perror_with_name ("output-sync suppressed: ", "stderr");
output_sync = 0;
}
#endif
return combined_output;
}
/* Support routine for output_sync() */
static void
pump_from_tmp (int from, FILE *to)
@ -232,55 +179,13 @@ pump_from_tmp (int from, FILE *to)
#endif
}
/* Obtain the lock for writing output. */
static void *
acquire_semaphore (void)
{
static struct flock fl;
fl.l_type = F_WRLCK;
fl.l_whence = SEEK_SET;
fl.l_start = 0;
fl.l_len = 1;
if (fcntl (sync_handle, F_SETLKW, &fl) != -1)
return &fl;
perror ("fcntl()");
return NULL;
}
/* Release the lock for writing output. */
static void
release_semaphore (void *sem)
{
struct flock *flp = (struct flock *)sem;
flp->l_type = F_UNLCK;
if (fcntl (sync_handle, F_SETLKW, flp) == -1)
perror ("fcntl()");
}
/* Returns a file descriptor to a temporary file. The file is automatically
closed/deleted on exit. Don't use a FILE* stream. */
/* Returns a file descriptor to a temporary file, that will be automatically
deleted on exit. */
int
output_tmpfd (void)
{
mode_t mask = umask (0077);
int fd = -1;
FILE *tfile = tmpfile ();
if (! tfile)
pfatal_with_name ("tmpfile");
/* Create a duplicate so we can close the stream. */
fd = dup (fileno (tfile));
if (fd < 0)
pfatal_with_name ("dup");
fclose (tfile);
set_append_mode (fd);
umask (mask);
int fd = get_tmpfd (NULL);
fd_set_append (fd);
return fd;
}
@ -291,13 +196,25 @@ output_tmpfd (void)
static void
setup_tmpfile (struct output *out)
{
/* Is make's stdout going to the same place as stderr? */
static int combined_output = -1;
static unsigned int in_setup = 0;
unsigned int io_state;
if (combined_output < 0)
combined_output = sync_init ();
/* If something fails during setup we might recurse back into this function
while writing errors. Make sure we don't do so infinitely. */
if (in_setup)
return;
in_setup = 1;
if (STREAM_OK (stdout))
io_state = check_io_state ();
if (NONE_SET (io_state, IO_STDOUT_OK|IO_STDERR_OK))
{
/* This is probably useless since stdout/stderr aren't working. */
perror_with_name ("output-sync suppressed: ", "stderr");
goto error;
}
if (ANY_SET (io_state, IO_STDOUT_OK))
{
int fd = output_tmpfd ();
if (fd < 0)
@ -306,9 +223,9 @@ setup_tmpfile (struct output *out)
out->out = fd;
}
if (STREAM_OK (stderr))
if (ANY_SET (io_state, IO_STDERR_OK))
{
if (out->out != OUTPUT_NONE && combined_output)
if (out->out != OUTPUT_NONE && ANY_SET (io_state, IO_COMBINED_OUTERR))
out->err = out->out;
else
{
@ -320,12 +237,18 @@ setup_tmpfile (struct output *out)
}
}
in_setup = 0;
return;
/* If we failed to create a temp file, disable output sync going forward. */
error:
O (error, NILF,
_("cannot open output-sync lock file, suppressing output-sync."));
output_close (out);
output_sync = OUTPUT_SYNC_NONE;
osync_clear ();
in_setup = 0;
}
/* Synchronize the output of jobs in -j mode to keep the results of
@ -336,6 +259,8 @@ setup_tmpfile (struct output *out)
void
output_dump (struct output *out)
{
#define FD_NOT_EMPTY(_f) ((_f) != OUTPUT_NONE && lseek ((_f), 0, SEEK_END) > 0)
int outfd_not_empty = FD_NOT_EMPTY (out->out);
int errfd_not_empty = FD_NOT_EMPTY (out->err);
@ -346,10 +271,16 @@ output_dump (struct output *out)
/* Try to acquire the semaphore. If it fails, dump the output
unsynchronized; still better than silently discarding it.
We want to keep this lock for as little time as possible. */
void *sem = acquire_semaphore ();
if (!osync_acquire ())
{
O (error, NILF,
_("warning: Cannot acquire output lock, disabling output sync."));
osync_clear ();
}
/* Log the working directory for this dump. */
if (print_directory_flag && output_sync != OUTPUT_SYNC_RECURSE)
if (output_sync != OUTPUT_SYNC_RECURSE && should_print_dir ())
traced = log_working_directory (1);
if (outfd_not_empty)
@ -361,8 +292,7 @@ output_dump (struct output *out)
log_working_directory (0);
/* Exit the critical section. */
if (sem)
release_semaphore (sem);
osync_release ();
/* Truncate and reset the output, in case we use it again. */
if (out->out != OUTPUT_NONE)
@ -382,53 +312,6 @@ output_dump (struct output *out)
#endif /* NO_OUTPUT_SYNC */
/* This code is stolen from gnulib.
If/when we abandon the requirement to work with K&R compilers, we can
remove this (and perhaps other parts of GNU make!) and migrate to using
gnulib directly.
This is called only through atexit(), which means die() has already been
invoked. So, call exit() here directly. Apparently that works...?
*/
/* Close standard output, exiting with status 'exit_failure' on failure.
If a program writes *anything* to stdout, that program should close
stdout and make sure that it succeeds before exiting. Otherwise,
suppose that you go to the extreme of checking the return status
of every function that does an explicit write to stdout. The last
printf can succeed in writing to the internal stream buffer, and yet
the fclose(stdout) could still fail (due e.g., to a disk full error)
when it tries to write out that buffered data. Thus, you would be
left with an incomplete output file and the offending program would
exit successfully. Even calling fflush is not always sufficient,
since some file systems (NFS and CODA) buffer written/flushed data
until an actual close call.
Besides, it's wasteful to check the return value from every call
that writes to stdout -- just let the internal stream state record
the failure. That's what the ferror test is checking below.
It's important to detect such failures and exit nonzero because many
tools (most notably 'make' and other build-management systems) depend
on being able to detect failure in other tools via their exit status. */
static void
close_stdout (void)
{
int prev_fail = ferror (stdout);
int fclose_fail = fclose (stdout);
if (prev_fail || fclose_fail)
{
if (fclose_fail)
perror_with_name (_("write error: stdout"), "");
else
O (error, NILF, _("write error: stdout"));
exit (MAKE_TROUBLE);
}
}
void
output_init (struct output *out)
{
@ -439,28 +322,10 @@ output_init (struct output *out)
return;
}
/* Configure this instance of make. Be sure stdout is line-buffered. */
#ifdef HAVE_SETVBUF
# ifdef SETVBUF_REVERSED
setvbuf (stdout, _IOLBF, xmalloc (BUFSIZ), BUFSIZ);
# else /* setvbuf not reversed. */
/* Some buggy systems lose if we pass 0 instead of allocating ourselves. */
setvbuf (stdout, 0, _IOLBF, BUFSIZ);
# endif /* setvbuf reversed. */
#elif HAVE_SETLINEBUF
setlinebuf (stdout);
#endif /* setlinebuf missing. */
/* Force stdout/stderr into append mode. This ensures parallel jobs won't
lose output due to overlapping writes. */
set_append_mode (fileno (stdout));
set_append_mode (fileno (stderr));
#ifdef HAVE_ATEXIT
if (STREAM_OK (stdout))
atexit (close_stdout);
#endif
/* Force stdout/stderr into append mode (if they are files) to ensure
parallel jobs won't lose output due to overlapping writes. */
fd_set_append (fileno (stdout));
fd_set_append (fileno (stderr));
}
void
@ -499,7 +364,7 @@ output_start (void)
/* If we're not syncing this output per-line or per-target, make sure we emit
the "Entering..." message where appropriate. */
if (output_sync == OUTPUT_SYNC_NONE || output_sync == OUTPUT_SYNC_RECURSE)
if (! stdio_traced && print_directory_flag)
if (! stdio_traced && should_print_dir ())
stdio_traced = log_working_directory (1);
}
@ -542,10 +407,11 @@ void
message (int prefix, size_t len, const char *fmt, ...)
{
va_list args;
char *start;
char *p;
len += strlen (fmt) + strlen (program) + INTSTR_LENGTH + 4 + 1 + 1;
p = get_buffer (len);
start = p = get_buffer (len);
if (prefix)
{
@ -562,8 +428,8 @@ message (int prefix, size_t len, const char *fmt, ...)
strcat (p, "\n");
assert (fmtbuf.buffer[len-1] == '\0');
outputs (0, fmtbuf.buffer);
assert (start[len-1] == '\0');
outputs (0, start);
}
/* Print an error message. */
@ -572,12 +438,13 @@ void
error (const floc *flocp, size_t len, const char *fmt, ...)
{
va_list args;
char *start;
char *p;
len += (strlen (fmt) + strlen (program)
+ (flocp && flocp->filenm ? strlen (flocp->filenm) : 0)
+ INTSTR_LENGTH + 4 + 1 + 1);
p = get_buffer (len);
start = p = get_buffer (len);
if (flocp && flocp->filenm)
sprintf (p, "%s:%lu: ", flocp->filenm, flocp->lineno + flocp->offset);
@ -593,8 +460,8 @@ error (const floc *flocp, size_t len, const char *fmt, ...)
strcat (p, "\n");
assert (fmtbuf.buffer[len-1] == '\0');
outputs (1, fmtbuf.buffer);
assert (start[len-1] == '\0');
outputs (1, start);
}
/* Print an error message and exit. */
@ -604,12 +471,13 @@ fatal (const floc *flocp, size_t len, const char *fmt, ...)
{
va_list args;
const char *stop = _(". Stop.\n");
char *start;
char *p;
len += (strlen (fmt) + strlen (program)
+ (flocp && flocp->filenm ? strlen (flocp->filenm) : 0)
+ INTSTR_LENGTH + 8 + strlen (stop) + 1);
p = get_buffer (len);
start = p = get_buffer (len);
if (flocp && flocp->filenm)
sprintf (p, "%s:%lu: *** ", flocp->filenm, flocp->lineno + flocp->offset);
@ -625,8 +493,8 @@ fatal (const floc *flocp, size_t len, const char *fmt, ...)
strcat (p, stop);
assert (fmtbuf.buffer[len-1] == '\0');
outputs (1, fmtbuf.buffer);
assert (start[len-1] == '\0');
outputs (1, start);
die (MAKE_FAILURE);
}