Compare commits

...

15 Commits

Author SHA1 Message Date
Paul Smith
e4b3bf7f97 Release GNU Make 4.3.92
* configure.ac: Modify the release version.
* NEWS: Update the version and date.
2022-10-24 02:14:42 -04:00
Paul Smith
d18a87d0a4 [SV 63260] Don't recurse forever if setup_tmpfile() fails
If we fail during setup_tmpfile() we'll try to write an error, which
will invoke setup_tmpfile() again, etc.  Avoid infinite recursion.
Original patch by Dmitry Goncharov <dgoncharov@users.sf.net>

* src/output.c (setup_tmpfile): Remember we're in this function and
return immediately if we enter it during recursion.
(message): Remember the starting location and use that instead of
fmtbuf.buffer.
(error): Ditto.
(fatal): Ditto.
2022-10-24 01:50:12 -04:00
Paul Smith
41c35f2ffe * src/output.c (_outputs): Don't use invalid output sync FDs
Just write to stdout/stderr in this situation.
2022-10-24 01:50:12 -04:00
Paul Smith
deb4a42c3e * src/misc.c (get_tmpdir): Report errors if tmpdirs are invalid
* src/main.c (main): Set up initial temporary directories.
2022-10-24 01:50:12 -04:00
Dmitry Goncharov
252c26bd20 * src/posixos.c (os_anontmp): If O_TMPFILE fails try dup() method. 2022-10-23 18:41:50 -04:00
Paul Smith
6f8da5f4b8 * src/rule.c (get_rule_defn): Don't use STRING_SIZE_TUPLE in mempcpy
If mempcpy() is a macro then STRING_SIZE_TUPLE won't compile.
2022-10-23 18:41:50 -04:00
Paul Smith
c46b5a9e0e Provide a maintainer-only debug method
Generating debug logs to stdout or stderr makes it impossible to
run tests etc. so create a dumb DBG facility to log to a temp file.
This exists only in maintainer mode and the DBG macro gives a
compile error if it's used in non-maintainer mode.

* src/makeint.h (DBG): Call dbg() in maintainer mode, else error.
(dbg): Define it in maintainer mode.
* src/misc.c (dbg): Open a log file for append, write, then close.
2022-10-23 18:41:50 -04:00
Paul Smith
b4157d2ff4 * configure.ac: Check that we can link with Guile
On multi-arch systems we may be able to find the header file but
not successfully link the library.
2022-10-22 22:40:26 -04:00
Paul Smith
f364e0d8d6 Set PATH_MAX on systems without a default value
Some systems (HURD) use fully-dynamic pathnames, with no limit.
We can't support this without significant effort so for now set
PATH_MAX to a large value.

* src/makeint.h: Set PATH_MAX to 4096 if not set and MAXPATHLEN
is also not set.  Remove MAXPATHLEN setting: we won't use it.
* src/misc.c (get_path_max): If we can't get the path max via
pathconf() use the default PATH_MAX.
* src/dir.c (find_directory) [W32]: Use MAX_PATH not MAXPATHLEN.
(local_stat) [W32]: Ditto.
* src/job.c (create_batch_file) [W32]: Ditto.
* src/remake.c (name_mtime) [W32]: Ditto.
* src/w32/w32os.c (os_anontmp) [W32]: Ditto.
2022-10-22 22:40:26 -04:00
Paul Smith
bb0c05a7f0 [SV 63098] Enhance detection of missing peer also-make targets
The previous attempt to detect missing peer targets for implicit
rules had some holes.  Move the detection to notice_finished_file().

* src/remake.c (check_also_make): If we don't have the current mtime
for the file, obtain it.
(update_goal_chain): Don't call check_also_make() here.
(check_dep): Ditto.
(notice_finished_file): If we finished running an implicit rule that
has also_make targets, invoke check_also_make().
2022-10-22 22:40:26 -04:00
Paul Smith
f987d181c4 Collect failure details when the regression tests fail
* README.in: Add a section on running regression tests.
* Makefile.am (check-regression): Capture the test run output, and
on failure collect configure and test results into a tar file.
2022-10-22 22:40:26 -04:00
Paul Smith
cad3ddd165 Enhance tests to work on different systems
The GNU platform testers reported a number of test errors on
different systems; try to address them.

* tests/thelp.pl: A number of tests timed out with a 4-second
timeout.  Increase the default timeout to 10 seconds.
* tests/run_make_tests.pl: Executing directories on cygwin behaves
differently in Perl than make so skip these tests there.
* tests/scripts/options/symlinks: Check for the symlink feature
in make, rather than whether the system supports them.
* tests/scripts/features/implicit_search: On some systems "false"
exits with a different exit code.  Use the helper instead.
* tests/scripts/features/loadapi: Ditto.
* tests/scripts/features/output-sync: Sleep before make -f bar in
the first test as well as the second one.
* tests/scripts/features/exec: Skip on cygwin, which seems to
be "UNIX" but where scripts don't run normally.
* tests/scripts/misc/fopen-fail: Skip on cygwin, where make
eventually exits with exit code 0 and no error messages.
2022-10-22 22:37:49 -04:00
Dmitry Goncharov
54214176b1 [SV 63243] tests: Avoid SIGTERM racing with make error messages
Original patch from Frank Heckenbach <f.heckenbach@fh-soft.de>.

* tests/scripts/features/output-sync: Introduce a sleep to let make
write its error message.  Some systems use different names for
SIGTERM so match with a regex.
* tests/scripts/features/temp_stdin: Ditto.
2022-10-22 10:02:41 -04:00
Dmitry Goncharov
c2f92c980f [SV 63236] Fix getloadavg related error message on AIX
On AIX getloadavg keeps errno intact when it fails, resulting in a
bogus error message from make.

* src/job.c (load_too_high): Reset errno before calling getloadavg.
2022-10-22 09:45:40 -04:00
Dmitry Goncharov
5b1ca277ca [SV 63248] Ignore SIGPIPE
Don't terminate when make's output is redirected to a pipe and the
reader exits early; e.g.:
  $ echo 'all:; sleep 2' | make -f- -j2 -O |:

This lets us unlink temporary files, and tell the user that make was
not able to write its output.
Reported by Frank Heckenbach <f.heckenbach@fh-soft.de>.

* src/main.c (main): Ignore SIGPIPE.
* src/posixos.c (osync_clear): Fix a memory leak.
2022-10-22 09:45:40 -04:00
27 changed files with 300 additions and 128 deletions

4
.gitignore vendored
View File

@@ -60,6 +60,10 @@ WinRel/
GccDebug/
GccRel/
# Test artifacts
makeerror-*.tar.gz
test-suite.log
# Distribution artifacts
.dep_segment
.check-git-HEAD

View File

@@ -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
View File

@@ -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

View File

@@ -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
-------------

View File

@@ -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"
])
])

View File

@@ -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;
}

View File

@@ -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;

View File

@@ -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

View File

@@ -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,

View File

@@ -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;

View File

@@ -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);
}

View File

@@ -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;

View File

@@ -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

View File

@@ -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';

View File

@@ -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
View File

@@ -1,2 +1,3 @@
.test-result
config-flags.pm
work

View File

@@ -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');

View File

@@ -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 := .

View File

@@ -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");

View File

@@ -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);
}
}

View File

@@ -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");

View File

@@ -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);

View File

@@ -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.

View File

@@ -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);

View File

@@ -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.

View File

@@ -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;

View File

@@ -24,7 +24,7 @@
$| = 1;
my $quiet = 0;
my $timeout = 4;
my $timeout = 10;
sub op {
my ($op, $nm) = @_;