mirror of
https://github.com/mirror/make.git
synced 2026-08-24 19:03:27 +08:00
Compare commits
15 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e4b3bf7f97 | ||
|
|
d18a87d0a4 | ||
|
|
41c35f2ffe | ||
|
|
deb4a42c3e | ||
|
|
252c26bd20 | ||
|
|
6f8da5f4b8 | ||
|
|
c46b5a9e0e | ||
|
|
b4157d2ff4 | ||
|
|
f364e0d8d6 | ||
|
|
bb0c05a7f0 | ||
|
|
f987d181c4 | ||
|
|
cad3ddd165 | ||
|
|
54214176b1 | ||
|
|
c2f92c980f | ||
|
|
5b1ca277ca |
4
.gitignore
vendored
4
.gitignore
vendored
@@ -60,6 +60,10 @@ WinRel/
|
||||
GccDebug/
|
||||
GccRel/
|
||||
|
||||
# Test artifacts
|
||||
makeerror-*.tar.gz
|
||||
test-suite.log
|
||||
|
||||
# Distribution artifacts
|
||||
.dep_segment
|
||||
.check-git-HEAD
|
||||
|
||||
24
Makefile.am
24
Makefile.am
@@ -137,8 +137,8 @@ src/gmk-default.h: $(top_srcdir)/src/gmk-default.scm
|
||||
dist-hook:
|
||||
(cd $(top_srcdir); \
|
||||
sub=`find tests/scripts -follow \( -name .git -o -name .deps -o -name work -o -name .gitignore -o -name \*.orig -o -name \*.rej -o -name \*~ -o -name \*.out -o -name Makefile \) -prune -o -type f -print`; \
|
||||
tar chf - $$sub) \
|
||||
| (cd $(distdir); tar xfBp -)
|
||||
$(AMTAR) chf - $$sub) \
|
||||
| (cd $(distdir); $(AMTAR) xfBp -)
|
||||
|
||||
|
||||
# --------------- Local CHECK Section
|
||||
@@ -162,9 +162,19 @@ MAKETESTFLAGS =
|
||||
|
||||
.PHONY: check-regression
|
||||
|
||||
GMK_OUTDIR=..
|
||||
GMK_OUTDIR = ..
|
||||
|
||||
testlog = test-suite.log
|
||||
testresult = tests/.test-result
|
||||
errorfile = makeerror-$(host_triplet).tar.gz
|
||||
|
||||
testfiles = $(testlog) $(testresult) $(errorfile)
|
||||
MOSTLYCLEANFILES = $(testfiles)
|
||||
|
||||
errordetails = config.status config.log src/config.h $(testlog) tests/work
|
||||
|
||||
check-regression: tests/config-flags.pm
|
||||
@rm -f $(testfiles)
|
||||
@if test -f '$(top_srcdir)/tests/run_make_tests'; then \
|
||||
ulimit -n 128; \
|
||||
if $(PERL) -v >/dev/null 2>&1; then \
|
||||
@@ -177,7 +187,13 @@ check-regression: tests/config-flags.pm
|
||||
done; fi ;; \
|
||||
esac; \
|
||||
echo "cd tests && $(PERL) $(PERLFLAGS) ./run_make_tests.pl -srcdir $(abs_top_srcdir) -make $(GMK_OUTDIR)/make$(EXEEXT) $(MAKETESTFLAGS)"; \
|
||||
cd tests && $(PERL) $(PERLFLAGS) ./run_make_tests.pl -srcdir '$(abs_top_srcdir)' -make '$(GMK_OUTDIR)/make$(EXEEXT)' $(MAKETESTFLAGS); \
|
||||
(cd tests && $(PERL) $(PERLFLAGS) ./run_make_tests.pl -srcdir '$(abs_top_srcdir)' -make '$(GMK_OUTDIR)/make$(EXEEXT)' $(MAKETESTFLAGS); echo $$? >.test-result) 2>&1 | tee $(testlog); \
|
||||
er=$$(cat $(testresult)); if test "$$er" -ne 0; then \
|
||||
$(AMTAR) chf - $(errordetails) | eval GZIP= gzip $(GZIP_ENV) -c >$(errorfile); \
|
||||
echo '*** Testing failed! Details saved in: $(errorfile)'; \
|
||||
echo '*** Please report to <$(PACKAGE_BUGREPORT)>'; echo; \
|
||||
exit $$er; \
|
||||
fi; \
|
||||
else \
|
||||
echo "Can't find a working Perl ($(PERL)); the test suite requires Perl."; \
|
||||
fi; \
|
||||
|
||||
12
NEWS
12
NEWS
@@ -1,6 +1,6 @@
|
||||
GNU Make NEWS -*-indented-text-*-
|
||||
History of user-visible changes.
|
||||
18 October 2022
|
||||
24 October 2022
|
||||
|
||||
See the end of this file for copyrights and conditions.
|
||||
|
||||
@@ -9,7 +9,7 @@ which is contained in this distribution as the file doc/make.texi.
|
||||
See the README file and the GNU Make manual for instructions for
|
||||
reporting bugs.
|
||||
|
||||
Version 4.3.91 (18 Oct 2022)
|
||||
Version 4.3.92 (24 Oct 2022)
|
||||
|
||||
A complete list of bugs fixed in this version is available here:
|
||||
|
||||
@@ -100,7 +100,7 @@ https://sv.gnu.org/bugs/index.php?group=make&report_id=111&fix_release_id=109&se
|
||||
each prerequisite).
|
||||
|
||||
* New feature: The .NOTINTERMEDIATE special target
|
||||
.NOTINTERMEDIATE Disables intermediate behavior for specific files, for all
|
||||
.NOTINTERMEDIATE disables intermediate behavior for specific files, for all
|
||||
files built using a pattern, or for the entire makefile.
|
||||
Implementation provided by Dmitry Goncharov <dgoncharov@users.sf.net>
|
||||
|
||||
@@ -186,9 +186,9 @@ https://sv.gnu.org/bugs/index.php?group=make&report_id=111&fix_release_id=109&se
|
||||
* Special targets like .POSIX are detected upon definition, ensuring that any
|
||||
change in behavior takes effect immediately, before the next line is parsed.
|
||||
|
||||
* When the jobserver is enabled and GNU Make decides it is invoking a non-make
|
||||
sub-process and closes the jobserver pipes, it will now add a new option to
|
||||
the MAKEFLAGS environment variable that disables the jobserver.
|
||||
* When the pipe-based jobserver is enabled and GNU Make decides it is invoking
|
||||
a non-make sub-process and closes the jobserver pipes, it will now add a new
|
||||
option to the MAKEFLAGS environment variable that disables the jobserver.
|
||||
This prevents sub-processes that invoke make from accidentally using other
|
||||
open file descriptors as jobserver pipes. For more information see
|
||||
https://savannah.gnu.org/bugs/?57242 and https://savannah.gnu.org/bugs/?62397
|
||||
|
||||
13
README.in
13
README.in
@@ -66,6 +66,19 @@ You can find most information concerning the development of GNU Make at
|
||||
this site.
|
||||
|
||||
|
||||
Regression Tests
|
||||
----------------
|
||||
|
||||
GNU Make contains a suite of regression tests. To run them use "make check"
|
||||
after building GNU Make. If they fail a tar package will be created
|
||||
containing useful information, which can be emailed (as an attachment) to
|
||||
the <bug-make@gnu.org> mailing list.
|
||||
|
||||
Please note that since these tests rely on known-good-output comparisons,
|
||||
they can show spurious failures on some systems (particularly non-POSIX systems
|
||||
such as Windows).
|
||||
|
||||
|
||||
Bug Reporting
|
||||
-------------
|
||||
|
||||
|
||||
28
configure.ac
28
configure.ac
@@ -16,7 +16,7 @@
|
||||
# You should have received a copy of the GNU General Public License along with
|
||||
# this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
AC_INIT([GNU Make],[4.3.91],[bug-make@gnu.org])
|
||||
AC_INIT([GNU Make],[4.3.92],[bug-make@gnu.org])
|
||||
|
||||
AC_PREREQ([2.69])
|
||||
|
||||
@@ -175,15 +175,35 @@ AS_IF([test "x$with_guile" != xno],
|
||||
AC_MSG_RESULT([$guile_version])
|
||||
AS_IF([test "$have_guile" = yes],
|
||||
[ PKG_CHECK_MODULES(GUILE, [guile-$guile_version])
|
||||
# Unfortunately Guile requires a C99 compiler but GNU make doesn't, so
|
||||
# verify we can actually compile the header.
|
||||
# Unfortunately pkg doesn't help in multi-arch environments where the
|
||||
# package is installed for some architectures but not others; we need
|
||||
# to try to link.
|
||||
keep_CPPFLAGS="$CPPFLAGS"
|
||||
CPPFLAGS="$CPPFLAGS $pkg_cv_GUILE_CFLAGS"
|
||||
keep_LIBS="$LIBS"
|
||||
CPPFLAGS="$CPPFLAGS $GUILE_CFLAGS"
|
||||
LIBS="$LIBS $GUILE_LIBS"
|
||||
AC_CHECK_HEADER([libguile.h],
|
||||
[AC_DEFINE([HAVE_GUILE], [1], [Embed GNU Guile support])],
|
||||
[have_guile=no],
|
||||
[/* Avoid configuration error warnings. */])
|
||||
AS_IF([test "$have_guile" = yes],
|
||||
[ AC_MSG_CHECKING([whether we can link GNU Guile])
|
||||
AC_LINK_IFELSE([AC_LANG_PROGRAM([[
|
||||
#include <libguile.h>
|
||||
static void *
|
||||
guile_init (void *arg)
|
||||
{
|
||||
(void) arg;
|
||||
return 0;
|
||||
}
|
||||
]], [[
|
||||
scm_with_guile (guile_init, 0);
|
||||
]])],
|
||||
[have_guile=yes],
|
||||
[have_guile=no])
|
||||
AC_MSG_RESULT([$have_guile])])
|
||||
CPPFLAGS="$keep_CPPFLAGS"
|
||||
LIBS="$keep_LIBS"
|
||||
])
|
||||
])
|
||||
|
||||
|
||||
@@ -521,7 +521,7 @@ find_directory (const char *name)
|
||||
/* See if the directory exists. */
|
||||
#if defined(WINDOWS32)
|
||||
{
|
||||
char tem[MAXPATHLEN], *tstart, *tend;
|
||||
char tem[MAX_PATH+1], *tstart, *tend;
|
||||
size_t len = strlen (name);
|
||||
|
||||
/* Remove any trailing slashes. Windows32 stat fails even on
|
||||
@@ -1314,10 +1314,10 @@ local_stat (const char *path, struct stat *buf)
|
||||
foo/. => foo without checking first that foo is a directory. */
|
||||
if (plen > 2 && path[plen - 1] == '.' && ISDIRSEP (path[plen - 2]))
|
||||
{
|
||||
char parent[MAXPATHLEN+1];
|
||||
char parent[MAX_PATH+1];
|
||||
|
||||
strncpy (parent, path, MAXPATHLEN);
|
||||
parent[MIN(plen - 2, MAXPATHLEN)] = '\0';
|
||||
strncpy (parent, path, MAX_PATH);
|
||||
parent[MIN(plen - 2, MAX_PATH)] = '\0';
|
||||
if (stat (parent, buf) < 0 || !_S_ISDIR (buf->st_mode))
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -283,7 +283,7 @@ create_batch_file (char const *base, int unixy, int *fd)
|
||||
{
|
||||
const char *const ext = unixy ? "sh" : "bat";
|
||||
const char *error_string = NULL;
|
||||
char temp_path[MAXPATHLEN]; /* need to know its length */
|
||||
char temp_path[MAX_PATH+1]; /* need to know its length */
|
||||
unsigned path_size = GetTempPath (sizeof temp_path, temp_path);
|
||||
int path_is_dot = 0;
|
||||
/* The following variable is static so we won't try to reuse a name
|
||||
@@ -2092,6 +2092,7 @@ load_too_high (void)
|
||||
}
|
||||
|
||||
/* Find the real system load average. */
|
||||
errno = 0;
|
||||
if (getloadavg (&load, 1) != 1)
|
||||
{
|
||||
static int lossage = -1;
|
||||
|
||||
@@ -1182,6 +1182,11 @@ main (int argc, char **argv, char **envp)
|
||||
/* Useful for attaching debuggers, etc. */
|
||||
SPIN ("main-entry");
|
||||
|
||||
/* Don't die if our stdout sends us SIGPIPE. */
|
||||
#ifdef SIGPIPE
|
||||
bsd_signal (SIGPIPE, SIG_IGN);
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_ATEXIT
|
||||
if (ANY_SET (check_io_state (), IO_STDOUT_OK))
|
||||
atexit (close_stdout);
|
||||
@@ -1385,6 +1390,10 @@ main (int argc, char **argv, char **envp)
|
||||
|
||||
initialize_global_hash_tables ();
|
||||
|
||||
/* Ensure the temp directory is set up: we don't want the first time we use
|
||||
it to be in a forked process. */
|
||||
get_tmpdir ();
|
||||
|
||||
/* Figure out where we are. */
|
||||
|
||||
#ifdef WINDOWS32
|
||||
|
||||
@@ -152,13 +152,14 @@ extern int errno;
|
||||
#endif
|
||||
|
||||
#ifndef PATH_MAX
|
||||
# ifndef POSIX
|
||||
# ifdef MAXPATHLEN
|
||||
# define PATH_MAX MAXPATHLEN
|
||||
# else
|
||||
/* Some systems (HURD) have fully dynamic pathnames with no maximum.
|
||||
Ideally we'd support this but it will take some work. */
|
||||
# define PATH_MAX 4096
|
||||
# endif
|
||||
#endif
|
||||
#ifndef MAXPATHLEN
|
||||
# define MAXPATHLEN 1024
|
||||
#endif
|
||||
|
||||
#ifdef PATH_MAX
|
||||
# define GET_PATH_MAX PATH_MAX
|
||||
@@ -494,6 +495,8 @@ extern struct rlimit stack_limit;
|
||||
|
||||
/* Number of characters in a string constant. Does NOT include the \0 byte. */
|
||||
#define CSTRLEN(_s) (sizeof (_s)-1)
|
||||
|
||||
/* Only usable when NOT calling a macro: only use it for local functions. */
|
||||
#define STRING_SIZE_TUPLE(_s) (_s), CSTRLEN(_s)
|
||||
|
||||
/* The number of bytes needed to represent the largest signed and unsigned
|
||||
@@ -657,8 +660,12 @@ int unload_file (const char *name);
|
||||
#ifdef MAKE_MAINTAINER_MODE
|
||||
# define SPIN(_s) spin (_s)
|
||||
void spin (const char* suffix);
|
||||
# define DBG(_f) dbg _f
|
||||
void dbg (const char *fmt, ...);
|
||||
#else
|
||||
# define SPIN(_s)
|
||||
/* Never put this code into Git or a release. */
|
||||
# define DBG(_f) compile-error
|
||||
#endif
|
||||
|
||||
/* We omit these declarations on non-POSIX systems which define _POSIX_VERSION,
|
||||
|
||||
56
src/misc.c
56
src/misc.c
@@ -530,6 +530,22 @@ spin (const char* type)
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
dbg (const char *fmt, ...)
|
||||
{
|
||||
FILE *fp = fopen ("/tmp/gmkdebug.log", "a+");
|
||||
va_list args;
|
||||
char buf[4096];
|
||||
|
||||
va_start (args, fmt);
|
||||
vsprintf (buf, fmt, args);
|
||||
va_end (args);
|
||||
|
||||
fprintf(fp, "%u: %s\n", (unsigned) make_pid (), buf);
|
||||
fflush (fp);
|
||||
fclose (fp);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
@@ -552,7 +568,6 @@ umask (mode_t mask)
|
||||
}
|
||||
#endif
|
||||
|
||||
#define MAKE_TMPDIR "MAKE_TMPDIR"
|
||||
#ifdef VMS
|
||||
# define DEFAULT_TMPFILE "sys$scratch:gnv$make_cmdXXXXXX.com"
|
||||
#else
|
||||
@@ -566,13 +581,36 @@ get_tmpdir ()
|
||||
|
||||
if (!tmpdir)
|
||||
{
|
||||
if (((tmpdir = getenv (MAKE_TMPDIR)) == NULL || *tmpdir == '\0')
|
||||
#if defined (__MSDOS__) || defined (WINDOWS32) || defined (__EMX__)
|
||||
&& ((tmpdir = getenv ("TMP")) == NULL || *tmpdir == '\0')
|
||||
&& ((tmpdir = getenv ("TEMP")) == NULL || *tmpdir == '\0')
|
||||
# define TMP_EXTRAS "TMP", "TEMP",
|
||||
#else
|
||||
# define TMP_EXTRAS
|
||||
#endif
|
||||
&& ((tmpdir = getenv ("TMPDIR")) == NULL || *tmpdir == '\0'))
|
||||
tmpdir = DEFAULT_TMPDIR;
|
||||
const char *tlist[] = { "MAKE_TMPDIR", "TMPDIR", TMP_EXTRAS NULL };
|
||||
const char **tp;
|
||||
unsigned int found = 0;
|
||||
|
||||
for (tp = tlist; *tp; ++tp)
|
||||
if ((tmpdir = getenv (*tp)) && *tmpdir != '\0')
|
||||
{
|
||||
struct stat st;
|
||||
int r;
|
||||
found = 1;
|
||||
EINTRLOOP(r, stat (tmpdir, &st));
|
||||
if (r < 0)
|
||||
OSSS (error, NILF,
|
||||
_("%s value %s: %s"), *tp, tmpdir, strerror (errno));
|
||||
else if (! S_ISDIR (st.st_mode))
|
||||
OSS (error, NILF,
|
||||
_("%s value %s: not a directory"), *tp, tmpdir);
|
||||
else
|
||||
return tmpdir;
|
||||
}
|
||||
|
||||
tmpdir = DEFAULT_TMPDIR;
|
||||
|
||||
if (found)
|
||||
OS (error, NILF, _("using default temporary directory '%s'"), tmpdir);
|
||||
}
|
||||
|
||||
return tmpdir;
|
||||
@@ -769,11 +807,11 @@ get_path_max (void)
|
||||
|
||||
if (value == 0)
|
||||
{
|
||||
long int x = pathconf ("/", _PC_PATH_MAX);
|
||||
long x = pathconf ("/", _PC_PATH_MAX);
|
||||
if (x > 0)
|
||||
value = x;
|
||||
value = (unsigned int) x;
|
||||
else
|
||||
return MAXPATHLEN;
|
||||
value = PATH_MAX;
|
||||
}
|
||||
|
||||
return value;
|
||||
|
||||
60
src/output.c
60
src/output.c
@@ -51,20 +51,24 @@ unsigned int stdio_traced = 0;
|
||||
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
|
||||
@@ -198,7 +202,16 @@ output_tmpfd (void)
|
||||
static void
|
||||
setup_tmpfile (struct output *out)
|
||||
{
|
||||
unsigned int io_state = check_io_state ();
|
||||
static unsigned int in_setup = 0;
|
||||
unsigned int io_state;
|
||||
|
||||
/* 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;
|
||||
|
||||
io_state = check_io_state ();
|
||||
|
||||
if (NONE_SET (io_state, IO_STDOUT_OK|IO_STDERR_OK))
|
||||
{
|
||||
@@ -230,6 +243,7 @@ setup_tmpfile (struct output *out)
|
||||
}
|
||||
}
|
||||
|
||||
in_setup = 0;
|
||||
return;
|
||||
|
||||
/* If we failed to create a temp file, disable output sync going forward. */
|
||||
@@ -237,6 +251,7 @@ setup_tmpfile (struct output *out)
|
||||
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
|
||||
@@ -394,10 +409,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)
|
||||
{
|
||||
@@ -414,8 +430,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. */
|
||||
@@ -424,12 +440,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);
|
||||
@@ -445,8 +462,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. */
|
||||
@@ -456,12 +473,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);
|
||||
@@ -477,8 +495,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);
|
||||
}
|
||||
|
||||
@@ -699,6 +699,7 @@ osync_clear ()
|
||||
int r;
|
||||
|
||||
EINTRLOOP (r, unlink (osync_tmpfile));
|
||||
free (osync_tmpfile);
|
||||
osync_tmpfile = NULL;
|
||||
}
|
||||
}
|
||||
@@ -838,17 +839,22 @@ fd_set_append (int fd)
|
||||
int
|
||||
os_anontmp ()
|
||||
{
|
||||
const char *tdir = get_tmpdir ();
|
||||
int fd = -1;
|
||||
|
||||
#ifdef O_TMPFILE
|
||||
EINTRLOOP (fd, open (get_tmpdir (), O_RDWR | O_TMPFILE | O_EXCL, 0600));
|
||||
if (fd < 0)
|
||||
pfatal_with_name ("open(O_TMPFILE)");
|
||||
#elif HAVE_DUP
|
||||
/* We don't have O_TMPFILE but we can dup: if we are creating temp files in
|
||||
the default location then try tmpfile() + dup() + fclose() to avoid ever
|
||||
having a name for a file. */
|
||||
if (streq (get_tmpdir (), DEFAULT_TMPDIR))
|
||||
EINTRLOOP (fd, open (tdir, O_RDWR | O_TMPFILE | O_EXCL, 0600));
|
||||
if (fd >= 0)
|
||||
return fd;
|
||||
|
||||
DB (DB_BASIC, (_("Cannot open '%s' with O_TMPFILE: %s.\n"),
|
||||
tdir, strerror (errno)));
|
||||
#endif
|
||||
|
||||
#if HAVE_DUP
|
||||
/* If we can dup and we are creating temp files in the default location then
|
||||
try tmpfile() + dup() + fclose() to avoid ever having a named file. */
|
||||
if (streq (tdir, DEFAULT_TMPDIR))
|
||||
{
|
||||
mode_t mask = umask (0077);
|
||||
FILE *tfile;
|
||||
|
||||
70
src/remake.c
70
src/remake.c
@@ -34,6 +34,7 @@ this program. If not, see <https://www.gnu.org/licenses/>. */
|
||||
#include <starlet.h>
|
||||
#endif
|
||||
#ifdef WINDOWS32
|
||||
#include <windows.h>
|
||||
#include <io.h>
|
||||
#include <sys/stat.h>
|
||||
#if defined(_MSC_VER) && _MSC_VER > 1200
|
||||
@@ -81,19 +82,20 @@ static const char *library_search (const char *lib, FILE_TIMESTAMP *mtime_ptr);
|
||||
static void
|
||||
check_also_make (const struct file *file)
|
||||
{
|
||||
/* If the target was created by an implicit rule, and it exists and was
|
||||
updated, warn about any of its also_make targets that don't exist. */
|
||||
if (file->tried_implicit && is_ordinary_mtime (file->last_mtime)
|
||||
&& file->last_mtime > file->mtime_before_update)
|
||||
{
|
||||
struct dep *ad;
|
||||
struct dep *ad;
|
||||
FILE_TIMESTAMP mtime = file->last_mtime;
|
||||
|
||||
for (ad = file->also_make; ad; ad = ad->next)
|
||||
if (ad->file->last_mtime == NONEXISTENT_MTIME)
|
||||
OS (error, file->cmds ? &file->cmds->fileinfo : NILF,
|
||||
_("warning: pattern recipe did not update peer target '%s'."),
|
||||
ad->file->name);
|
||||
}
|
||||
if (mtime == UNKNOWN_MTIME)
|
||||
mtime = name_mtime (file->name);
|
||||
|
||||
/* If we updated the file, check its also-make files. */
|
||||
|
||||
if (is_ordinary_mtime (mtime) && mtime > file->mtime_before_update)
|
||||
for (ad = file->also_make; ad; ad = ad->next)
|
||||
if (ad->file->last_mtime == NONEXISTENT_MTIME)
|
||||
OS (error, file->cmds ? &file->cmds->fileinfo : NILF,
|
||||
_("warning: pattern recipe did not update peer target '%s'."),
|
||||
ad->file->name);
|
||||
}
|
||||
|
||||
/* Remake all the goals in the 'struct dep' chain GOALS. Return update_status
|
||||
@@ -205,8 +207,6 @@ update_goal_chain (struct goaldep *goaldeps)
|
||||
FILE_TIMESTAMP mtime = MTIME (file);
|
||||
check_renamed (file);
|
||||
|
||||
check_also_make (file);
|
||||
|
||||
if (file->updated && mtime != file->mtime_before_update)
|
||||
{
|
||||
/* Updating was done. If this is a makefile and
|
||||
@@ -1039,23 +1039,30 @@ notice_finished_file (struct file *file)
|
||||
}
|
||||
|
||||
if (ran && file->update_status != us_none)
|
||||
/* We actually tried to update FILE, which has
|
||||
updated its also_make's as well (if it worked).
|
||||
If it didn't work, it wouldn't work again for them.
|
||||
So mark them as updated with the same status. */
|
||||
for (d = file->also_make; d != 0; d = d->next)
|
||||
{
|
||||
d->file->command_state = cs_finished;
|
||||
d->file->updated = 1;
|
||||
d->file->update_status = file->update_status;
|
||||
{
|
||||
/* We actually tried to update FILE, which has
|
||||
updated its also_make's as well (if it worked).
|
||||
If it didn't work, it wouldn't work again for them.
|
||||
So mark them as updated with the same status. */
|
||||
for (d = file->also_make; d != 0; d = d->next)
|
||||
{
|
||||
d->file->command_state = cs_finished;
|
||||
d->file->updated = 1;
|
||||
d->file->update_status = file->update_status;
|
||||
|
||||
if (ran && !d->file->phony)
|
||||
/* Fetch the new modification time.
|
||||
We do this instead of just invalidating the cached time
|
||||
so that a vpath_search can happen. Otherwise, it would
|
||||
never be done because the target is already updated. */
|
||||
f_mtime (d->file, 0);
|
||||
}
|
||||
if (ran && !d->file->phony)
|
||||
/* Fetch the new modification time.
|
||||
We do this instead of just invalidating the cached time
|
||||
so that a vpath_search can happen. Otherwise, it would
|
||||
never be done because the target is already updated. */
|
||||
f_mtime (d->file, 0);
|
||||
}
|
||||
|
||||
/* If the target was created by an implicit rule, and it was updated,
|
||||
warn about any of its also_make targets that don't exist. */
|
||||
if (file->tried_implicit && file->also_make)
|
||||
check_also_make (file);
|
||||
}
|
||||
else if (file->update_status == us_none)
|
||||
/* Nothing was done for FILE, but it needed nothing done.
|
||||
So mark it now as "succeeded". */
|
||||
@@ -1094,7 +1101,6 @@ check_dep (struct file *file, unsigned int depth,
|
||||
check_renamed (file);
|
||||
if (mtime == NONEXISTENT_MTIME || mtime > this_mtime)
|
||||
*must_make_ptr = 1;
|
||||
check_also_make (file);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -1546,7 +1552,7 @@ name_mtime (const char *name)
|
||||
|
||||
#if defined(WINDOWS32)
|
||||
{
|
||||
char tem[MAXPATHLEN], *tstart, *tend;
|
||||
char tem[MAX_PATH+1], *tstart, *tend;
|
||||
const char *p = name + strlen (name);
|
||||
|
||||
/* Remove any trailing slashes and "."/"..". MS-Windows stat
|
||||
|
||||
@@ -94,7 +94,7 @@ get_rule_defn (struct rule *r)
|
||||
if (dep->ignore_mtime == 0)
|
||||
{
|
||||
if (dep->wait_here)
|
||||
p = mempcpy (p, STRING_SIZE_TUPLE (" .WAIT"));
|
||||
p = mempcpy (p, " .WAIT", CSTRLEN (" .WAIT"));
|
||||
p = mempcpy (mempcpy (p, " ", 1), dep_name (dep),
|
||||
strlen (dep_name (dep)));
|
||||
}
|
||||
@@ -107,7 +107,7 @@ get_rule_defn (struct rule *r)
|
||||
{
|
||||
p = mempcpy (p, sep, strlen (sep));
|
||||
if (ood->wait_here)
|
||||
p = mempcpy (p, STRING_SIZE_TUPLE (".WAIT "));
|
||||
p = mempcpy (p, ".WAIT ", CSTRLEN (".WAIT "));
|
||||
p = mempcpy (p, dep_name (ood), strlen (dep_name (ood)));
|
||||
}
|
||||
*p = '\0';
|
||||
|
||||
@@ -115,7 +115,7 @@ check_io_state ()
|
||||
int
|
||||
os_anontmp ()
|
||||
{
|
||||
char temp_path[MAXPATHLEN];
|
||||
char temp_path[MAX_PATH+1];
|
||||
unsigned path_size = GetTempPath (sizeof (temp_path), temp_path);
|
||||
int using_cwd = 0;
|
||||
|
||||
|
||||
1
tests/.gitignore
vendored
1
tests/.gitignore
vendored
@@ -1,2 +1,3 @@
|
||||
.test-result
|
||||
config-flags.pm
|
||||
work
|
||||
|
||||
@@ -148,11 +148,16 @@ $ERR_command_not_found = undef;
|
||||
$ERR_nonexe_file = "$!";
|
||||
}
|
||||
|
||||
$_ = `./. 2>&1`;
|
||||
if ($? == 0) {
|
||||
print "Executed directory! Skipping related tests.\n";
|
||||
if ($^O =~ /cygwin/i) {
|
||||
# For some reason the execute here gives a different answer than make's
|
||||
print "Skipping directory execution on $^O\n";
|
||||
} else {
|
||||
$ERR_exe_dir = "$!";
|
||||
$_ = `./. 2>&1`;
|
||||
if ($? == 0) {
|
||||
print "Executed directory! Skipping related tests.\n";
|
||||
} else {
|
||||
$ERR_exe_dir = "$!";
|
||||
}
|
||||
}
|
||||
|
||||
chmod(0000, 'file.out');
|
||||
|
||||
@@ -99,7 +99,7 @@ if ($ERR_nonexe_file) {
|
||||
# Try failing by "running" a directory
|
||||
|
||||
if ($ERR_exe_dir) {
|
||||
mkdir('sd', 0775);
|
||||
mkdir('sd', 0775) or print "mkdir: sd: $!\n";
|
||||
|
||||
run_make_test(q!
|
||||
PATH := .
|
||||
|
||||
@@ -13,6 +13,7 @@ my $details = "The various shells that this test uses are the default"
|
||||
|
||||
# Only bother with this on UNIX systems
|
||||
$port_type eq 'UNIX' or return -1;
|
||||
$^O =~ /cygwin/ and return -1;
|
||||
|
||||
my $usersh = $origENV{SHELL};
|
||||
my $answer = 'hello, world';
|
||||
@@ -36,7 +37,7 @@ for my $shbang (@shbangs) {
|
||||
close(CMD);
|
||||
chmod 0700, $cmd;
|
||||
|
||||
run_make_test("# $shbang\n# $shell" . q!
|
||||
run_make_test("# shbang=$shbang\n# shell=$shell" . q!
|
||||
all:; @$(CMD)
|
||||
!, "$shell CMD=$cmd", "$answer\n");
|
||||
|
||||
|
||||
@@ -55,8 +55,8 @@ run_make_test("
|
||||
all: hello$s
|
||||
%$s:$r %.c; \$(info hello.c)
|
||||
%$s:$r %.f; \$(info hello.f)
|
||||
hello.c:; false
|
||||
", '-r', "false\n#MAKE#: *** [#MAKEFILE#:5: hello.c] Error 1\n", 512);
|
||||
hello.c:; @#HELPER# fail 1
|
||||
", '-r', "fail 1\n#MAKE#: *** [#MAKEFILE#:5: hello.c] Error 1\n", 512);
|
||||
|
||||
# Test that make finds the intended implicit rule based on existence of a
|
||||
# prerequisite in the filesystem, even when the prerequisite of another
|
||||
@@ -115,9 +115,9 @@ run_make_test("
|
||||
all: hello$s
|
||||
%$s:$r %.c; \$(info \$<)
|
||||
%$s:$r %.f; \$(info \$<)
|
||||
.DEFAULT:; \$(info \$\@) false
|
||||
.DEFAULT:; \@\$(info \$\@) #HELPER# fail 1
|
||||
unrelated: hello.c
|
||||
", '-r', "hello.c\nfalse\n#MAKE#: *** [#MAKEFILE#:5: hello.c] Error 1\n", 512);
|
||||
", '-r', "hello.c\nfail 1\n#MAKE#: *** [#MAKEFILE#:5: hello.c] Error 1\n", 512);
|
||||
|
||||
# hello.f is missing.
|
||||
# No rule is found, because hello.c is not mentioned explicitly.
|
||||
@@ -125,8 +125,8 @@ run_make_test("
|
||||
all: hello$s
|
||||
%$s:$r %.c; \$(info \$<)
|
||||
%$s:$r %.f; \$(info \$<)
|
||||
.DEFAULT:; \@\$(info \$\@) false
|
||||
", '-r', "hello$s\n#MAKE#: *** [#MAKEFILE#:5: hello$s] Error 1\n", 512);
|
||||
.DEFAULT:; \@\$(info \$\@) #HELPER# fail 1
|
||||
", '-r', "hello$s\nfail 1\n#MAKE#: *** [#MAKEFILE#:5: hello$s] Error 1\n", 512);
|
||||
|
||||
}
|
||||
}
|
||||
@@ -202,7 +202,7 @@ for my $r (@rules) {
|
||||
|
||||
my $result = "#MAKE#: *** No rule to make target 'hello.tsk', needed by 'all'. Stop.\n";
|
||||
if ($s or $r) {
|
||||
$result = "false\n#MAKE#: *** [#MAKEFILE#:6: hello.c] Error 1\n";
|
||||
$result = "fail 1\n#MAKE#: *** [#MAKEFILE#:6: hello.c] Error 1\n";
|
||||
}
|
||||
|
||||
run_make_test("
|
||||
@@ -210,7 +210,7 @@ all: hello.tsk
|
||||
%.tsk: %$s; \$(info hello.tsk)
|
||||
%$s:$r %.c; \$(info hello.c)
|
||||
%$s:$r %.f; \$(info hello.f)
|
||||
hello.c:; false
|
||||
hello.c:; @#HELPER# fail 1
|
||||
", '-r', $result, 512);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -190,10 +190,10 @@ run_make_test("
|
||||
load testapi.so
|
||||
$extra_loads
|
||||
all:; \$(info \$(test-expand hello))
|
||||
testapi.so: force; false
|
||||
testapi.so: force; @#HELPER# fail 1
|
||||
force:;
|
||||
.PHONY: force
|
||||
", '', "testapi_gmk_setup\nfalse\n#MAKE#: *** [#MAKEFILE#:$n: testapi.so] Error 1\n", 512);
|
||||
", '', "testapi_gmk_setup\nfail 1\n#MAKE#: *** [#MAKEFILE#:$n: testapi.so] Error 1\n", 512);
|
||||
|
||||
# sv 63045.
|
||||
# Same as above, but testapi_gmk_setup returned -1.
|
||||
@@ -203,7 +203,7 @@ run_make_test("
|
||||
load testapi.so
|
||||
$extra_loads
|
||||
all:; \$(info \$(test-expand hello))
|
||||
testapi.so: force; false
|
||||
testapi.so: force; @#HELPER# fail 1
|
||||
force:;
|
||||
.PHONY: force
|
||||
", '', "testapi_gmk_setup\nhello\n#MAKE#: 'all' is up to date.\n");
|
||||
|
||||
@@ -116,20 +116,24 @@ EOF
|
||||
close(MAKEFILE);
|
||||
|
||||
# Test per-make synchronization.
|
||||
# Note we have to sleep again here after starting the foo makefile before
|
||||
# starting the bar makefile, otherwise the "entering/leaving" messages for the
|
||||
# submakes might be ordered differently than we expect.
|
||||
|
||||
unlink(@syncfiles);
|
||||
run_make_test(qq!
|
||||
all: make-foo make-bar
|
||||
|
||||
make-foo: ; \$(MAKE) -C foo
|
||||
|
||||
make-bar: ; \$(MAKE) -C bar!,
|
||||
make-bar: ; #HELPER# -q sleep 1 ; \$(MAKE) -C bar!,
|
||||
'-j -Orecurse',
|
||||
"#MAKEPATH# -C foo
|
||||
#MAKE#[1]: Entering directory '#PWD#/foo'
|
||||
foo: start
|
||||
foo: end
|
||||
#MAKE#[1]: Leaving directory '#PWD#/foo'
|
||||
#MAKEPATH# -C bar
|
||||
#HELPER# -q sleep 1 ; #MAKEPATH# -C bar
|
||||
#MAKE#[1]: Entering directory '#PWD#/bar'
|
||||
bar: start
|
||||
bar: end
|
||||
@@ -352,10 +356,12 @@ use POSIX ();
|
||||
# Test that make removes temporary files, even when a signal is received.
|
||||
# The general test_driver postprocessing will ensure the temporary file used
|
||||
# to synchronize output and the jobserver fifo are both removed.
|
||||
# sleep is needed to let make write its "... Terminated" message to the log
|
||||
# file.
|
||||
run_make_test(q!
|
||||
pid:=$(shell echo $$PPID)
|
||||
all:; @kill -TERM $(pid)
|
||||
!, '-O -j2', "", POSIX::SIGTERM);
|
||||
all:; @kill -TERM $(pid) && sleep 16
|
||||
!, '-O -j2', '/#MAKE#: \*\*\* \[#MAKEFILE#:3: all] Terminated/', POSIX::SIGTERM);
|
||||
}
|
||||
|
||||
unlink($fout);
|
||||
|
||||
@@ -478,6 +478,20 @@ run_make_test(q!
|
||||
'gta', "touch gta\n#MAKEFILE#:2: warning: pattern recipe did not update peer target 'gtb'.\n");
|
||||
unlink(qw(gta));
|
||||
|
||||
# We don't warn if we didn't update the file
|
||||
utouch(-10, qw(gta));
|
||||
run_make_test(q!
|
||||
%a %b : xyzzy ; $(OP)
|
||||
xyzzy: ;
|
||||
ifdef RUN
|
||||
OP = @echo no
|
||||
endif
|
||||
!,
|
||||
'-rR gta', "#MAKE#: 'gta' is up to date.\n");
|
||||
|
||||
run_make_test(undef, '-rR gta RUN=1', "no\n");
|
||||
unlink(qw(gta));
|
||||
|
||||
run_make_test(q!
|
||||
all:;
|
||||
include gta
|
||||
@@ -486,6 +500,14 @@ include gta
|
||||
'', "touch gta\n#MAKEFILE#:4: warning: pattern recipe did not update peer target 'gtb'.\n#MAKE#: 'all' is up to date.");
|
||||
unlink(qw(gta));
|
||||
|
||||
run_make_test(q!
|
||||
%.c %.h : %.y; touch $*.c
|
||||
%.o: %.c; touch $@
|
||||
foo.y: ; touch $@
|
||||
!,
|
||||
'foo.o', "touch foo.y\ntouch foo.c\n#MAKEFILE#:2: warning: pattern recipe did not update peer target 'foo.h'.\ntouch foo.o\nrm foo.c");
|
||||
unlink(qw(foo.y foo.c foo.o));
|
||||
|
||||
if (0) {
|
||||
# SV 12078: Missing grouped pattern peer causes remake regardless of which
|
||||
# target caused the rule to run.
|
||||
|
||||
@@ -62,6 +62,8 @@ use POSIX ();
|
||||
# include bye.mk and bye.mk: rule is needed to cause make to keep the temporary
|
||||
# file for re-exec. Without re-exec make will remove the file before the signal
|
||||
# arrives.
|
||||
# sleep is needed to let make write its "... Terminated" message to the log
|
||||
# file.
|
||||
&utouch(-600, 'bye.mk');
|
||||
close(STDIN);
|
||||
open(STDIN, "<", 'input.mk') || die "$0: cannot open input.mk for reading: $!";
|
||||
@@ -69,9 +71,9 @@ run_make_test(q!
|
||||
include bye.mk
|
||||
pid:=$(shell echo $$PPID)
|
||||
all:;
|
||||
bye.mk: force; @kill -TERM $(pid)
|
||||
bye.mk: force; @kill -TERM $(pid) && sleep 16
|
||||
force:
|
||||
!, '-f-', "", POSIX::SIGTERM);
|
||||
!, '-f-', '/#MAKE#: \*\*\* \[#MAKEFILE#:5: bye.mk] Terminated/', POSIX::SIGTERM);
|
||||
}
|
||||
unlink($fout);
|
||||
|
||||
|
||||
@@ -2,6 +2,10 @@
|
||||
|
||||
$description = "Make sure make exits with an error if fopen fails.";
|
||||
|
||||
# For some reason on Cygwin, make exits with no error message after
|
||||
# it recurses for a while.
|
||||
$^O =~ /cygwin/ and return -1;
|
||||
|
||||
# Recurse infinitely until we run out of open files, and ensure we
|
||||
# fail with a non-zero exit code. Don't bother to test the output
|
||||
# since it's hard to know what it will be, exactly.
|
||||
|
||||
@@ -6,14 +6,7 @@ $details = "Verify that symlink handling with and without -L works properly.";
|
||||
|
||||
# Only run these tests if the system sypports symlinks
|
||||
|
||||
# Apparently the Windows port of Perl reports that it does support symlinks
|
||||
# (in that the symlink() function doesn't fail) but it really doesn't, so
|
||||
# check for it explicitly.
|
||||
|
||||
if ($port_type eq 'W32' || !( eval { symlink("",""); 1 })) {
|
||||
# This test is N/A
|
||||
return -1;
|
||||
}
|
||||
exists $FEATURES{'check-symlink'} or return -1;
|
||||
|
||||
use File::Spec;
|
||||
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
$| = 1;
|
||||
|
||||
my $quiet = 0;
|
||||
my $timeout = 4;
|
||||
my $timeout = 10;
|
||||
|
||||
sub op {
|
||||
my ($op, $nm) = @_;
|
||||
|
||||
Reference in New Issue
Block a user