summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPaul Smith <psmith@gnu.org>2005-02-28 07:48:22 +0000
committerPaul Smith <psmith@gnu.org>2005-02-28 07:48:22 +0000
commitd2516343bc5c105543b22eed3b073a8a4e14a659 (patch)
treeb33081457bdf9207b45add40ba56fdeccf63fe6f
parent93bd1bd93c1033352e5059ed721a0cc769449639 (diff)
downloadgunmake-d2516343bc5c105543b22eed3b073a8a4e14a659.tar.gz
* New feature: -L option
* New function: $(info ...) * Disallow $(eval ...) to create prereq relationships inside command scripts (caused core dumps) * Try to allow more tests to succeed in Windows/DOS by sanitizing CRLF and \ * Various bug fixes and code cleanups (see the ChangeLog entry)
-rw-r--r--ChangeLog73
-rw-r--r--NEWS20
-rw-r--r--configure.in13
-rw-r--r--dir.c12
-rw-r--r--doc/make.texi17
-rw-r--r--file.c12
-rw-r--r--filedef.h3
-rw-r--r--function.c38
-rw-r--r--implicit.c2
-rw-r--r--main.c48
-rw-r--r--make.h5
-rw-r--r--misc.c4
-rw-r--r--read.c9
-rw-r--r--remake.c75
-rw-r--r--tests/ChangeLog30
-rwxr-xr-xtests/run_make_tests.pl13
-rw-r--r--tests/scripts/features/patspecific_vars2
-rw-r--r--tests/scripts/functions/eval10
-rw-r--r--tests/scripts/misc/general45
-rw-r--r--tests/scripts/options/symlinks47
-rw-r--r--tests/scripts/variables/MAKE4
-rw-r--r--tests/scripts/variables/MFILE_LIST (renamed from tests/scripts/variables/MAKEFILE_LIST)0
-rw-r--r--tests/test_driver.pl49
-rw-r--r--variable.c2
-rw-r--r--w32/subproc/NMakefile1
25 files changed, 390 insertions, 104 deletions
diff --git a/ChangeLog b/ChangeLog
index becece8..4696420 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,29 +1,68 @@
-Mon Feb 28 00:18:20 2005 Boris Kolpackov <boris@kolpackov.net>
+2005-02-27 Paul D. Smith <psmith@gnu.org>
+
+ * misc.c (end_of_token): Make argument const.
+ * make.h: Update prototype.
+
+ * function.c (abspath, func_realpath, func_abspath): Use
+ PATH_VAR() and GET_PATH_MAX instead of PATH_MAX.
+ * dir.c (downcase): Use PATH_VAR() instead of PATH_MAX.
+ * read.c (record_files): Ditto.
+ * variable.c (do_variable_definition): Ditto.
+
+ * function.c (func_error): Create a new function $(info ...) that
+ simply prints the message to stdout with no extras.
+ (function_table_init): Add new function to the table.
+ * NEWS: Add $(info ...) reference.
+ * doc/make.texi (Make Control Functions): Document it.
+
+ New feature: if the system supports symbolic links, and the user
+ provides the -L/--check-symlink-time flag, then use the latest
+ mtime between the symlink(s) and the target file.
+
+ * configure.in (MAKE_SYMLINKS): Check for lstat() and
+ readlink(). If both are available, define MAKE_SYMLINKS.
+ * main.c: New variable: check_symlink_flag.
+ (usage): Add a line for -L/--check-symlink-times to the help string.
+ (switches): Add -L/--check-symlink-times command line argument.
+ (main): If MAKE_SYMLINKS is not defined but the user specified -L,
+ print a warning and disable it again.
+ * make.h: Declare check_symlink_flag.
+ * remake.c (name_mtime): If MAKE_SYMLINKS and check_symlink_flag,
+ if the file is a symlink then check each link in the chain and
+ choose the NEWEST mtime we find as the mtime for the file. The
+ newest mtime might be the file itself!
+ * NEWS: Add information about this new feature.
+ * doc/make.texi (Options Summary): Add -L/--check-symlink-times docs.
+
+ Avoid core dumps described in Savannah bug # 12124:
+
+ * file.c: New variable snapped_deps remember whether we've run
+ snap_deps().
+ (snap_deps): Set it.
+ * filedef.h: Extern it.
+ * read.c (record_files): Check snapped_deps; if it's set then
+ we're trying to eval a new target/prerequisite relationship from
+ within a command script, which we don't support. Fatal.
+
+2005-02-28 Boris Kolpackov <boris@kolpackov.net>
Implementation of the .DEFAULT_TARGET special variable.
- * read.c (eval): If necessary, update default_target_name
- when reading rules.
-
+ * read.c (eval): If necessary, update default_target_name when
+ reading rules.
* read.c (record_files): Update default_target_file if
default_target_name has changed.
-
* main.c (default_target_name): Define.
-
* main.c (main): Enter .DEFAULT_TARGET as make variable. If
default_target_name is set use default_target_file as a root
target to make.
-
* filedef.h (default_target_name): Declare.
-
* dep.h (free_dep_chain):
* misc.c (free_dep_chain): Change to operate on struct nameseq
and change name to free_ns_chain.
-
* file.c (snap_deps): Update to use free_ns_chain.
-
-Sun Feb 27 22:03:36 2005 Boris Kolpackov <boris@kolpackov.net>
+2005-02-27 Boris Kolpackov <boris@kolpackov.net>
Implementation of the second expansion in explicit rules,
static pattern rules and implicit rules.
@@ -69,6 +108,12 @@ Sun Feb 27 22:03:36 2005 Boris Kolpackov <boris@kolpackov.net>
* make.h (strip_whitespace): Declare.
* function.c (strip_whitespace): Remove static specifier.
+2005-02-26 Paul D. Smith <psmith@gnu.org>
+
+ * main.c (main): Check for ferror() when reading makefiles from stdin.
+ Apparently some shells in Windows don't close pipes properly and
+ require this check.
+
2005-02-24 Jonathan Grant <jg@jguk.org>
* configure.in: Add MinGW configuration options, and extra w32 code
@@ -83,6 +128,12 @@ Sun Feb 27 22:03:36 2005 Boris Kolpackov <boris@kolpackov.net>
* tests/run_make_tests.pl, tests/test_driver.pl: MSYS testing
environment support.
+2004-04-16 Dmitry V. Levin <ldv@altlinux.org>
+
+ * function.c (func_shell): When initializing error_prefix, check
+ that reading file name is not null. This fixes long-standing
+ segfault in cases like "make 'a1=$(shell :)' 'a2:=$(a1)'".
+
2005-02-09 Paul D. Smith <psmith@gnu.org>
* maintMakefile: Update the CVS download URL to simplify them.
diff --git a/NEWS b/NEWS
index 219ffb3..eb5a226 100644
--- a/NEWS
+++ b/NEWS
@@ -13,7 +13,14 @@ reporting bugs.
Version 3.81beta2
* GNU make is ported to OS/2.
- Port provided by Andreas Buening <andreas.buening@nexgo.de>.
+
+* GNU make is ported to MinGW.
+
+* New command-line option: -L (--check-symlink-times). On systems that
+ support symbolic links, if this option is given then GNU make will
+ use the most recent modification time of any symbolic links that are
+ used to resolve target files. The default behavior remains as it
+ always has: use the modification time of the actual target file only.
* All pattern-specific variables that match a given target are now used
(previously only the first match was used).
@@ -27,8 +34,13 @@ Version 3.81beta2
* Implemented a solution for the "thundering herd" problem with "-j -l".
This version of GNU make uses an algorithm suggested by Thomas Riedl
<thomas.riedl@siemens.com> to track the number of jobs started in the
- last second and adjust GNU make's view of the system's load average
- accordingly.
+ last second and artificially adjust GNU make's view of the system's
+ load average accordingly.
+
+* New special variables available in this release:
+ - .DEFAULT_TARGET: Contains the name of the default target make will
+ use if no targets are provided on the command line. It can be set
+ to change the default target.
* New functions available in this release:
- $(lastword ...) returns the last word in the list. This gives
@@ -39,6 +51,8 @@ Version 3.81beta2
- $(realpath ...) returns the canonical pathname for each path
provided. The canonical pathname is the absolute pathname, with
all symbolic links resolved as well.
+ - $(info ...) prints informative messages to stdout. No makefile
+ name or line number info, etc. is printed, just the message.
* Changes made for POSIX compatibility:
- Only touch targets (under -t) if they have at least one command.
diff --git a/configure.in b/configure.in
index 7e4d545..4bd77ef 100644
--- a/configure.in
+++ b/configure.in
@@ -1,6 +1,6 @@
# Process this file with autoconf to produce a configure script.
-AC_INIT([GNU make],[3.81beta2],[bug-make@gnu.org])
+AC_INIT([GNU make],[3.81rc1],[bug-make@gnu.org])
AC_PREREQ(2.59)
AC_REVISION([[$Id$]])
@@ -136,7 +136,8 @@ fi
AC_CHECK_FUNCS( memcpy memmove strchr strdup mkstemp mktemp fdopen \
bsd_signal dup2 getcwd realpath sigsetmask sigaction \
getgroups seteuid setegid setlinebuf setreuid setregid \
- getrlimit setrlimit setvbuf pipe strerror strsignal)
+ getrlimit setrlimit setvbuf pipe strerror strsignal \
+ lstat readlink)
AC_FUNC_SETVBUF_REVERSED
@@ -280,6 +281,14 @@ case "$ac_cv_func_pipe/$ac_cv_func_sigaction/$make_cv_sa_restart/$has_wait_nohan
[Define this to enable job server support in GNU make.]);;
esac
+# if we have both lstat() and readlink() then we can support symlink
+# timechecks.
+case "$ac_cv_func_lstat/$ac_cv_func_readlink" in
+ yes/yes)
+ AC_DEFINE(MAKE_SYMLINKS, 1,
+ [Define this to enable symbolic link timestamp checking.]);;
+esac
+
# Find the SCCS commands, so we can include them in our default rules.
AC_CACHE_CHECK(for location of SCCS get command, make_cv_path_sccs_get, [
diff --git a/dir.c b/dir.c
index 976e0b4..832b562 100644
--- a/dir.c
+++ b/dir.c
@@ -122,11 +122,7 @@ dosify (char *filename)
static char *
downcase (char *filename)
{
-#ifdef _AMIGA
- static char new_filename[136];
-#else
- static char new_filename[PATH_MAX];
-#endif
+ static PATH_VAR (new_filename);
char *df;
int i;
@@ -1152,10 +1148,10 @@ read_dirstream (__ptr_t stream)
}
static void
-ansi_free(void *p)
+ansi_free (void *p)
{
- if (p)
- free(p);
+ if (p)
+ free(p);
}
/* On 64 bit ReliantUNIX (5.44 and above) in LFS mode, stat() is actually a
diff --git a/doc/make.texi b/doc/make.texi
index 9b6f9d8..c6f4c1a 100644
--- a/doc/make.texi
+++ b/doc/make.texi
@@ -6750,6 +6750,13 @@ and the resulting message is displayed, but processing of the makefile
continues.
The result of the expansion of this function is the empty string.
+
+@item $(info @var{text}@dots{})
+@findex info
+@cindex printing messages
+This function does nothing more than print its (expanded) argument(s)
+to standard output. No makefile name or line number is added. The
+result of the expansion of this function is the empty string.
@end table
@node Running, Implicit Rules, Functions, Top
@@ -7366,6 +7373,16 @@ other jobs running and the load average is at least @var{load} (a
floating-point number). With no argument, removes a previous load
limit. @xref{Parallel, ,Parallel Execution}.
+@item -L
+@cindex @code{-L}
+@itemx --check-symlink-times
+@cindex @code{--check-symlink-times}
+On systems that support symbolic links, this option causes @code{make}
+to consider the timestamps on any symbolic links in addition to the
+timestamp on the file referenced by those links. When this option is
+provided, the most recent timestamp among the file and the symbolic
+links is taken as the modification time for this target file.
+
@item -n
@cindex @code{-n}
@itemx --just-print
diff --git a/file.c b/file.c
index 62a6a68..45bcaef 100644
--- a/file.c
+++ b/file.c
@@ -31,6 +31,15 @@ Boston, MA 02111-1307, USA. */
#include "hash.h"
+/* Remember whether snap_deps has been invoked: we need this to be sure we
+ don't add new rules (via $(eval ...)) afterwards. In the future it would
+ be nice to support this, but it means we'd need to re-run snap_deps() or
+ at least its functionality... it might mean changing snap_deps() to be run
+ per-file, so we can invoke it after the eval... or remembering which files
+ in the hash have been snapped (a new boolean flag?) and having snap_deps()
+ only work on files which have not yet been snapped. */
+int snapped_deps = 0;
+
/* Hash table of files the makefile knows how to make. */
static unsigned long
@@ -611,6 +620,9 @@ snap_deps (void)
f = lookup_file (".NOTPARALLEL");
if (f != 0 && f->is_target)
not_parallel = 1;
+
+ /* Remember that we've done this. */
+ snapped_deps = 1;
}
/* Set the `command_state' member of FILE and all its `also_make's. */
diff --git a/filedef.h b/filedef.h
index 2822e8a..ae45f89 100644
--- a/filedef.h
+++ b/filedef.h
@@ -198,3 +198,6 @@ extern FILE_TIMESTAMP f_mtime PARAMS ((struct file *file, int search));
#define check_renamed(file) \
while ((file)->renamed != 0) (file) = (file)->renamed /* No ; here. */
+
+/* Have we snapped deps yet? */
+extern int snapped_deps;
diff --git a/function.c b/function.c
index b344e66..66d23fd 100644
--- a/function.c
+++ b/function.c
@@ -1082,12 +1082,23 @@ func_error (char *o, char **argv, const char *funcname)
}
strcpy (p, *argvp);
- if (*funcname == 'e')
- fatal (reading_file, "%s", msg);
+ switch (*funcname) {
+ case 'e':
+ fatal (reading_file, "%s", msg);
- /* The warning function expands to the empty string. */
- error (reading_file, "%s", msg);
+ case 'w':
+ error (reading_file, "%s", msg);
+ break;
+ case 'i':
+ printf ("%s\n", msg);
+ break;
+
+ default:
+ fatal (reading_file, "Internal error: func_error: '%s'", funcname);
+ }
+
+ /* The warning function expands to the empty string. */
return o;
}
@@ -1472,7 +1483,7 @@ func_shell (char *o, char **argv, const char *funcname UNUSED)
envp = environ;
/* For error messages. */
- if (reading_file != 0)
+ if (reading_file && reading_file->filenm)
{
error_prefix = (char *) alloca (strlen (reading_file->filenm)+11+4);
sprintf (error_prefix,
@@ -1752,7 +1763,7 @@ abspath (const char *name, char *apath)
if (name[0] == '\0' || apath == NULL)
return NULL;
- apath_limit = apath + PATH_MAX;
+ apath_limit = apath + GET_PATH_MAX;
if (name[0] != '/')
{
@@ -1826,13 +1837,12 @@ func_realpath (char *o, char **argv, const char *funcname UNUSED)
char *path = 0;
int doneany = 0;
unsigned int len = 0;
-
- char in[PATH_MAX];
- char out[PATH_MAX];
+ PATH_VAR (in);
+ PATH_VAR (out);
while ((path = find_next_token (&p, &len)) != 0)
{
- if (len < PATH_MAX)
+ if (len < GET_PATH_MAX)
{
strncpy (in, path, len);
in[len] = '\0';
@@ -1868,13 +1878,12 @@ func_abspath (char *o, char **argv, const char *funcname UNUSED)
char *path = 0;
int doneany = 0;
unsigned int len = 0;
-
- char in[PATH_MAX];
- char out[PATH_MAX];
+ PATH_VAR (in);
+ PATH_VAR (out);
while ((path = find_next_token (&p, &len)) != 0)
{
- if (len < PATH_MAX)
+ if (len < GET_PATH_MAX)
{
strncpy (in, path, len);
in[len] = '\0';
@@ -1939,6 +1948,7 @@ static struct function_table_entry function_table_init[] =
{ STRING_SIZE_TUPLE("origin"), 0, 1, 1, func_origin},
{ STRING_SIZE_TUPLE("foreach"), 3, 3, 0, func_foreach},
{ STRING_SIZE_TUPLE("call"), 1, 0, 1, func_call},
+ { STRING_SIZE_TUPLE("info"), 0, 1, 1, func_error},
{ STRING_SIZE_TUPLE("error"), 0, 1, 1, func_error},
{ STRING_SIZE_TUPLE("warning"), 0, 1, 1, func_error},
{ STRING_SIZE_TUPLE("if"), 2, 3, 0, func_if},
diff --git a/implicit.c b/implicit.c
index 7c1f4b7..b844419 100644
--- a/implicit.c
+++ b/implicit.c
@@ -1,5 +1,5 @@
/* Implicit rule searching for GNU Make.
-Copyright (C) 1988,89,90,91,92,93,94,97,2000 Free Software Foundation, Inc.
+Copyright (C) 1988,1989,1990,1991,1992,1993,1994,1997,2000,2004,2005 Free Software Foundation, Inc.
This file is part of GNU Make.
GNU Make is free software; you can redistribute it and/or modify
diff --git a/main.c b/main.c
index 1035b8c..c20be9b 100644
--- a/main.c
+++ b/main.c
@@ -193,6 +193,10 @@ int no_builtin_variables_flag = 0;
int keep_going_flag;
int default_keep_going_flag = 0;
+/* Nonzero means check symlink mtimes. */
+
+int check_symlink_flag = 0;
+
/* Nonzero means print directory before starting and when done (-w). */
int print_directory_flag = 0;
@@ -316,6 +320,8 @@ static const char *const usage[] =
-l [N], --load-average[=N], --max-load[=N]\n\
Don't start multiple jobs unless load is below N.\n"),
N_("\
+ -L, --check-symlink-times Use the latest mtime between symlinks and target.\n"),
+ N_("\
-n, --just-print, --dry-run, --recon\n\
Don't actually run any commands; just print them.\n"),
N_("\
@@ -363,50 +369,52 @@ static const struct command_switch switches[] =
{ 'D', flag, (char *) &suspend_flag, 1, 1, 0, 0, 0, "suspend-for-debug" },
#endif
{ 'e', flag, (char *) &env_overrides, 1, 1, 0, 0, 0,
- "environment-overrides", },
+ "environment-overrides", },
{ 'f', string, (char *) &makefiles, 0, 0, 0, 0, 0, "file" },
{ 'h', flag, (char *) &print_usage_flag, 0, 0, 0, 0, 0, "help" },
{ 'i', flag, (char *) &ignore_errors_flag, 1, 1, 0, 0, 0,
- "ignore-errors" },
+ "ignore-errors" },
{ 'I', string, (char *) &include_directories, 1, 1, 0, 0, 0,
- "include-dir" },
+ "include-dir" },
{ 'j', positive_int, (char *) &job_slots, 1, 1, 0, (char *) &inf_jobs,
- (char *) &default_job_slots, "jobs" },
+ (char *) &default_job_slots, "jobs" },
{ CHAR_MAX+2, string, (char *) &jobserver_fds, 1, 1, 0, 0, 0,
- "jobserver-fds" },
+ "jobserver-fds" },
{ 'k', flag, (char *) &keep_going_flag, 1, 1, 0, 0,
- (char *) &default_keep_going_flag, "keep-going" },
+ (char *) &default_keep_going_flag, "keep-going" },
#ifndef NO_FLOAT
{ 'l', floating, (char *) &max_load_average, 1, 1, 0,
- (char *) &default_load_average, (char *) &default_load_average,
- "load-average" },
+ (char *) &default_load_average, (char *) &default_load_average,
+ "load-average" },
#else
{ 'l', positive_int, (char *) &max_load_average, 1, 1, 0,
- (char *) &default_load_average, (char *) &default_load_average,
- "load-average" },
+ (char *) &default_load_average, (char *) &default_load_average,
+ "load-average" },
#endif
+ { 'L', flag, (char *) &check_symlink_flag, 1, 1, 0, 0, 0,
+ "check-symlink-times" },
{ 'm', ignore, 0, 0, 0, 0, 0, 0, 0 },
{ 'n', flag, (char *) &just_print_flag, 1, 1, 1, 0, 0, "just-print" },
{ 'o', string, (char *) &old_files, 0, 0, 0, 0, 0, "old-file" },
{ 'p', flag, (char *) &print_data_base_flag, 1, 1, 0, 0, 0,
- "print-data-base" },
+ "print-data-base" },
{ 'q', flag, (char *) &question_flag, 1, 1, 1, 0, 0, "question" },
{ 'r', flag, (char *) &no_builtin_rules_flag, 1, 1, 0, 0, 0,
"no-builtin-rules" },
{ 'R', flag, (char *) &no_builtin_variables_flag, 1, 1, 0, 0, 0,
- "no-builtin-variables" },
+ "no-builtin-variables" },
{ 's', flag, (char *) &silent_flag, 1, 1, 0, 0, 0, "silent" },
{ 'S', flag_off, (char *) &keep_going_flag, 1, 1, 0, 0,
(char *) &default_keep_going_flag, "no-keep-going" },
{ 't', flag, (char *) &touch_flag, 1, 1, 1, 0, 0, "touch" },
{ 'v', flag, (char *) &print_version_flag, 1, 1, 0, 0, 0, "version" },
{ 'w', flag, (char *) &print_directory_flag, 1, 1, 0, 0, 0,
- "print-directory" },
+ "print-directory" },
{ CHAR_MAX+3, flag, (char *) &inhibit_print_directory_flag, 1, 1, 0, 0, 0,
- "no-print-directory" },
+ "no-print-directory" },
{ 'W', string, (char *) &new_files, 0, 0, 0, 0, 0, "what-if" },
{ CHAR_MAX+4, flag, (char *) &warn_undefined_variables_flag, 1, 1, 0, 0, 0,
- "warn-undefined-variables" },
+ "warn-undefined-variables" },
{ 0 }
};
@@ -1461,7 +1469,7 @@ main (int argc, char **argv, char **envp)
outfile = open_tmpfile (&stdin_nm, template);
if (outfile == 0)
pfatal_with_name (_("fopen (temporary file)"));
- while (!feof (stdin))
+ while (!feof (stdin) && ! ferror (stdin))
{
char buf[2048];
unsigned int n = fread (buf, 1, sizeof (buf), stdin);
@@ -1702,6 +1710,14 @@ main (int argc, char **argv, char **envp)
}
#endif
+#ifndef MAKE_SYMLINKS
+ if (check_symlink_flag)
+ {
+ error (NILF, _("Symbolic links not supported: disabling -L."));
+ check_symlink_flag = 0;
+ }
+#endif
+
/* Set up MAKEFLAGS and MFLAGS again, so they will be right. */
define_makeflags (1, 0);
diff --git a/make.h b/make.h
index e9ea18a..5696965 100644
--- a/make.h
+++ b/make.h
@@ -366,7 +366,6 @@ extern int strcmpi (const char *,const char *);
extern void sync_Path_environment(void);
extern int kill(int pid, int sig);
-extern int safe_stat(char *file, struct stat *sb);
extern char *end_of_token_w32(char *s, char stopchar);
extern int find_and_set_default_shell(char *token);
@@ -420,7 +419,7 @@ extern char *xrealloc PARAMS ((char *, unsigned int));
extern char *xstrdup PARAMS ((const char *));
extern char *find_next_token PARAMS ((char **, unsigned int *));
extern char *next_token PARAMS ((const char *));
-extern char *end_of_token PARAMS ((char *));
+extern char *end_of_token PARAMS ((const char *));
extern void collapse_continuations PARAMS ((char *));
extern void remove_comments PARAMS((char *));
extern char *lindex PARAMS ((const char *, const char *, int));
@@ -496,7 +495,7 @@ extern char **environ;
extern int just_print_flag, silent_flag, ignore_errors_flag, keep_going_flag;
extern int print_data_base_flag, question_flag, touch_flag, always_make_flag;
extern int env_overrides, no_builtin_rules_flag, no_builtin_variables_flag;
-extern int print_version_flag, print_directory_flag;
+extern int print_version_flag, print_directory_flag, check_symlink_flag;
extern int warn_undefined_variables_flag, posix_pedantic, not_parallel;
extern int clock_skew_detected, rebuilding_makefiles;
diff --git a/misc.c b/misc.c
index 53c1923..63936f7 100644
--- a/misc.c
+++ b/misc.c
@@ -432,11 +432,11 @@ lindex (const char *s, const char *limit, int c)
/* Return the address of the first whitespace or null in the string S. */
char *
-end_of_token (char *s)
+end_of_token (const char *s)
{
while (*s != '\0' && !isblank ((unsigned char)*s))
++s;
- return s;
+ return (char *)s;
}
#ifdef WINDOWS32
diff --git a/read.c b/read.c
index 0862b48..d235c6a 100644
--- a/read.c
+++ b/read.c
@@ -1822,6 +1822,13 @@ record_files (struct nameseq *filenames, char *pattern, char *pattern_percent,
char **targets = 0, **target_percents = 0;
struct commands *cmds;
+ /* If we've already snapped deps, that means we're in an eval being
+ resolved after the makefiles have been read in. We can't add more rules
+ at this time, since they won't get snapped and we'll get core dumps.
+ See Savannah bug # 12124. */
+ if (snapped_deps)
+ fatal (flocp, _("prerequisites cannot be defined in command scripts"));
+
if (commands_idx > 0)
{
cmds = (struct commands *) xmalloc (sizeof (struct commands));
@@ -1910,7 +1917,7 @@ record_files (struct nameseq *filenames, char *pattern, char *pattern_percent,
if (find_percent (this->name) != 0)
{
- char stem[PATH_MAX];
+ PATH_VAR (stem);
char *o;
char *buffer = variable_expand ("");
diff --git a/remake.c b/remake.c
index 70acad3..e1def64 100644
--- a/remake.c
+++ b/remake.c
@@ -1313,9 +1313,16 @@ f_mtime (struct file *file, int search)
/* Return the mtime of the file or archive-member reference NAME. */
+/* First, we check with stat(). If the file does not exist, then we return
+ NONEXISTENT_MTIME. If it does, and the symlink check flag is set, then
+ examine each indirection of the symlink and find the newest mtime.
+ This causes one duplicate stat() when -L is being used, but the code is
+ much cleaner. */
+
static FILE_TIMESTAMP
name_mtime (char *name)
{
+ FILE_TIMESTAMP mtime;
struct stat st;
int e;
@@ -1326,8 +1333,74 @@ name_mtime (char *name)
perror_with_name ("stat:", name);
return NONEXISTENT_MTIME;
}
+ mtime = FILE_TIMESTAMP_STAT_MODTIME (name, st);
+
+#ifdef MAKE_SYMLINKS
+#ifndef S_ISLNK
+# define S_ISLNK(_m) (((_m)&S_IFMT)==S_IFLNK)
+#endif
+ if (check_symlink_flag)
+ {
+ PATH_VAR (lpath);
+
+ /* Check each symbolic link segment (if any). Find the latest mtime
+ amongst all of them (and the target file of course).
+ Note that we have already successfully dereferenced all the links
+ above. So, if we run into any error trying to lstat(), or
+ readlink(), or whatever, something bizarre-o happened. Just give up
+ and use whatever mtime we've already computed at that point. */
+ strcpy (lpath, name);
+ while (1)
+ {
+ FILE_TIMESTAMP ltime;
+ PATH_VAR (lbuf);
+ long llen;
+ char *p;
+
+ EINTRLOOP (e, lstat (lpath, &st));
+ if (e)
+ {
+ /* Eh? Just take what we have. */
+ perror_with_name ("lstat: ", lpath);
+ break;
+ }
+
+ /* If this is not a symlink, we're done (we started with the real
+ file's mtime so we don't need to test it again). */
+ if (!S_ISLNK (st.st_mode))
+ break;
- return FILE_TIMESTAMP_STAT_MODTIME (name, st);
+ /* If this mtime is newer than what we had, keep the new one. */
+ ltime = FILE_TIMESTAMP_STAT_MODTIME (lpath, st);
+ if (ltime > mtime)
+ mtime = ltime;
+
+ /* Set up to check the file pointed to by this link. */
+ EINTRLOOP (llen, readlink (lpath, lbuf, GET_PATH_MAX));
+ if (llen < 0)
+ {
+ /* Eh? Just take what we have. */
+ perror_with_name ("readlink: ", lpath);
+ break;
+ }
+ lbuf[llen] = '\0';
+
+ /* If the target is fully-qualified or the source is just a
+ filename, then the new path is the target. Otherwise it's the
+ source directory plus the target. */
+ if (lbuf[0] == '/' || (p = strrchr (lpath, '/')) == NULL)
+ strcpy (lpath, lbuf);
+ else if ((p - lpath) + llen + 2 > GET_PATH_MAX)
+ /* Eh? Path too long! Again, just go with what we have. */
+ break;
+ else
+ /* Create the next step in the symlink chain. */
+ strcpy (p+1, lbuf);
+ }
+ }
+#endif
+
+ return mtime;
}
diff --git a/tests/ChangeLog b/tests/ChangeLog
index 462c2e6..41c9b34 100644
--- a/tests/ChangeLog
+++ b/tests/ChangeLog
@@ -1,24 +1,42 @@
-Mon Feb 28 00:31:14 2005 Boris Kolpackov <boris@kolpackov.net>
+2005-02-28 Paul D. Smith <psmith@gnu.org>
+
+ * scripts/options/symlinks: New file to test checking of symlink
+ timestamps. Can't use filename dash-L because it conflicts with
+ dash-l on case-insensitive filesystems.
+
+ * scripts/variables/MAKEFILE_LIST, scripts/variables/MFILE_LIST:
+ Rename MAKEFILE_LIST test to MFILE_LIST, for systems that need 8.3
+ unique filenames.
+
+2005-02-28 Boris Kolpackov <boris@kolpackov.net>
* scripts/variables/DEFAULT_TARGET: Test the .DEFAULT_TARGET
special variable.
-Sun Feb 27 23:33:32 2005 Boris Kolpackov <boris@kolpackov.net>
+2005-02-27 Boris Kolpackov <boris@kolpackov.net>
* scripts/features/se_explicit: Test the second expansion in
explicit rules.
-
* scripts/features/se_implicit: Test the second expansion in
implicit rules.
-
* scripts/features/se_statpat: Test the second expansion in
static pattern rules.
-
- * tests/scripts/variables/automatic: Fix to work with the second
+ * scripts/variables/automatic: Fix to work with the second
expansion.
* scripts/misc/general4: Add a test for bug #12091.
+2005-02-27 Paul D. Smith <psmith@gnu.org>
+
+ * scripts/functions/eval: Check that eval of targets within
+ command scripts fails. See Savannah bug # 12124.
+
+2005-02-26 Paul D. Smith <psmith@gnu.org>
+
+ * test_driver.pl (compare_output): If a basic comparison of the
+ log and answer doesn't match, try harder: change all backslashes
+ to slashes and all CRLF to LF. This helps on DOS/Windows systems.
+
2005-02-09 Paul D. Smith <psmith@gnu.org>
* scripts/features/recursion: Test command line variable settings:
diff --git a/tests/run_make_tests.pl b/tests/run_make_tests.pl
index 5276d29..ca711b2 100755
--- a/tests/run_make_tests.pl
+++ b/tests/run_make_tests.pl
@@ -38,7 +38,7 @@ sub valid_option
return 1;
}
-# This doesn't work--it _should_! Someone needs to fix this badly.
+# This doesn't work--it _should_! Someone badly needs to fix this.
#
# elsif ($option =~ /^-work([-_]?dir)?$/)
# {
@@ -241,20 +241,15 @@ sub set_more_defaults
# On DOS/Windows system the filesystem apparently can't track
# timestamps with second granularity (!!). Change the sleep time
# needed to force a file to be considered "old".
- #
$wtime = $port_type eq 'UNIX' ? 1 : $port_type eq 'OS/2' ? 2 : 4;
print "Port type: $port_type\n" if $debug;
print "Make path: $make_path\n" if $debug;
# Find the full pathname of Make. For DOS systems this is more
- # complicated, so we ask make itself. The following shell code does not
- # work on W32 (MinGW/MSYS)
-
- if ($port_type ne 'W32') {
- $make_path = `sh -c 'echo "all:;\@echo \\\$(MAKE)" | $make_path -f-'`;
- chop $make_path;
- }
+ # complicated, so we ask make itself.
+ $make_path = `sh -c 'echo "all:;\@echo \\\$(MAKE)" | $make_path -f-'`;
+ chop $make_path;
print "Make\t= `$make_path'\n" if $debug;
$string = `$make_path -v -f /dev/null 2> /dev/null`;
diff --git a/tests/scripts/features/patspecific_vars b/tests/scripts/features/patspecific_vars
index 31359cf..9e98b43 100644
--- a/tests/scripts/features/patspecific_vars
+++ b/tests/scripts/features/patspecific_vars
@@ -67,7 +67,7 @@ run_make_test('
/%: export foo := foo
/bar:
- @test "$(foo)" == "$$foo"
+ @test "$(foo)" = "$$foo"
', '', '');
diff --git a/tests/scripts/functions/eval b/tests/scripts/functions/eval
index c69a110..bc43053 100644
--- a/tests/scripts/functions/eval
+++ b/tests/scripts/functions/eval
@@ -158,4 +158,14 @@ $(eval $(FOO))
', '', 'hello
world');
+
+# We don't allow new target/prerequisite relationships to be defined within a
+# command script, because these are evaluated after snap_deps() and that
+# causes lots of problems (like core dumps!)
+# See Savannah bug # 12124.
+
+run_make_test('deps: ; $(eval deps: foo)', '',
+ '#MAKEFILE#:1: *** prerequisites cannot be defined in command scripts. Stop.',
+ 512);
+
1;
diff --git a/tests/scripts/misc/general4 b/tests/scripts/misc/general4
index 3b4595f..63320e2 100644
--- a/tests/scripts/misc/general4
+++ b/tests/scripts/misc/general4
@@ -24,13 +24,10 @@ close(MAKEFILE);
$answer = "mkdir -p dir/subdir\ntouch dir/subdir/file.b\ncp dir/subdir/file.b dir/subdir/file.a\n";
&compare_output($answer,&get_logfile(1));
-
# Test implicit rules
&touch('foo.c');
-run_make_test('
-foo: foo.o
-',
+run_make_test('foo: foo.o',
'CC="@echo cc" OUTPUT_OPTION=',
'cc -c foo.c
cc foo.o -o foo');
diff --git a/tests/scripts/options/symlinks b/tests/scripts/options/symlinks
new file mode 100644
index 0000000..4dcc67a
--- /dev/null
+++ b/tests/scripts/options/symlinks
@@ -0,0 +1,47 @@
+# -*-perl-*-
+
+$description = "Test the -L option.";
+
+$details = "Verify that symlink handling with and without -L works properly.";
+
+# Only run these tests if the system sypports symlinks
+if (eval { symlink("",""); 1 }) {
+
+ # Set up a symlink sym -> dep
+ # We'll make both dep and targ older than sym
+ $pwd =~ m%/([^/]+)$%;
+ $dirnm = $1;
+ &utouch(-10, 'dep');
+ &utouch(-5, 'targ');
+ symlink("../$dirnm/dep", 'sym');
+
+ # Without -L, nothing should happen
+ # With -L, it should update targ
+ run_make_test('targ: sym ; @echo make $@ from $<', '',
+ "#MAKE#: `targ' is up to date.");
+ run_make_test(undef, '-L', "make targ from sym");
+
+ # Now update dep; in all cases targ should be out of date.
+ &touch('dep');
+ run_make_test(undef, '', "make targ from sym");
+ run_make_test(undef, '-L', "make targ from sym");
+
+ # Now update targ; in all cases targ should be up to date.
+ &touch('targ');
+ run_make_test(undef, '', "#MAKE#: `targ' is up to date.");
+ run_make_test(undef, '-L', "#MAKE#: `targ' is up to date.");
+
+ # Add in a new link between sym and dep. Be sure it's newer than targ.
+ sleep(1);
+ rename('dep', 'dep1');
+ symlink('dep1', 'dep');
+
+ # Without -L, nothing should happen
+ # With -L, it should update targ
+ run_make_test(undef, '', "#MAKE#: `targ' is up to date.");
+ run_make_test(undef, '-L', "make targ from sym");
+
+ rmfiles('targ', 'dep', 'sym', 'dep1');
+}
+
+1;
diff --git a/tests/scripts/variables/MAKE b/tests/scripts/variables/MAKE
index 7c4cf0a..079c57e 100644
--- a/tests/scripts/variables/MAKE
+++ b/tests/scripts/variables/MAKE
@@ -1,3 +1,5 @@
+# -*-perl-*-
+
$description = "The following test creates a makefile to test MAKE \n"
."(very generic)";
@@ -26,7 +28,7 @@ $answer = "$mkpath\n$mkpath -f $makefile foo\n"
&run_make_with_options($makefile,"",&get_logfile,0);
-&delete("foo");
+&rmfiles("foo");
# COMPARE RESULTS
&compare_output($answer,&get_logfile(1));
diff --git a/tests/scripts/variables/MAKEFILE_LIST b/tests/scripts/variables/MFILE_LIST
index 076e42d..076e42d 100644
--- a/tests/scripts/variables/MAKEFILE_LIST
+++ b/tests/scripts/variables/MFILE_LIST
diff --git a/tests/test_driver.pl b/tests/test_driver.pl
index 0698d26..7cd40b5 100644
--- a/tests/test_driver.pl
+++ b/tests/test_driver.pl
@@ -451,13 +451,13 @@ sub run_each_test
$status = "ok ($tests_passed passed)";
for ($i = $num_of_tmpfiles; $i; $i--)
{
- &delete ($tmp_filename . &num_suffix ($i) );
+ &rmfiles ($tmp_filename . &num_suffix ($i) );
}
for ($i = $num_of_logfiles ? $num_of_logfiles : 1; $i; $i--)
{
- &delete ($log_filename . &num_suffix ($i) );
- &delete ($base_filename . &num_suffix ($i) );
+ &rmfiles ($log_filename . &num_suffix ($i) );
+ &rmfiles ($base_filename . &num_suffix ($i) );
}
}
elsif ($code > 0) {
@@ -500,7 +500,7 @@ sub run_each_test
# If the keep flag is not set, this subroutine deletes all filenames that
# are sent to it.
-sub delete
+sub rmfiles
{
local(@files) = @_;
@@ -611,7 +611,7 @@ sub error
sub compare_output
{
local($answer,$logfile) = @_;
- local($slurp);
+ local($slurp, $answer_matched) = ('', 0);
print "Comparing Output ........ " if $debug;
@@ -624,14 +624,29 @@ sub compare_output
++$tests_run;
- if ($slurp eq $answer && $test_passed)
+ if ($slurp eq $answer) {
+ $answer_matched = 1;
+ } else {
+ # See if it is a slash or CRLF problem
+ local ($answer_mod) = $answer;
+
+ $answer_mod =~ tr,\\,/,;
+ $answer_mod =~ s,\r\n,\n,gs;
+
+ $slurp =~ tr,\\,/,;
+ $slurp =~ s,\r\n,\n,gs;
+
+ $answer_matched = ($slurp eq $answer_mod);
+ }
+
+ if ($answer_matched && $test_passed)
{
print "ok\n" if $debug;
++$tests_passed;
return 1;
}
- if ($slurp ne $answer) {
+ if (! $answer_matched) {
print "DIFFERENT OUTPUT\n" if $debug;
&create_file (&get_basefile, $answer);
@@ -639,9 +654,9 @@ sub compare_output
print "\nCreating Difference File ...\n" if $debug;
# Create the difference file
+
local($command) = "diff -c " . &get_basefile . " " . $logfile;
&run_command_with_output(&get_difffile,$command);
-
}
$suite_passed = 0;
@@ -729,15 +744,11 @@ sub run_command
{
local ($code);
- if ($debug)
- {
- print "\nrun_command: @_\n";
- $code = system @_;
- print "run_command: \"@_\" returned $code.\n";
- return $code;
- }
+ print "\nrun_command: @_\n" if $debug;
+ $code = system @_;
+ print "run_command: \"@_\" returned $code.\n" if $debug;
- return system @_;
+ return $code;
}
# run one command (passed as a list of arg 0 - n, with arg 0 being the
@@ -753,10 +764,8 @@ sub run_command_with_output
&attach_default_output ($filename);
$code = system @_;
&detach_default_output;
- if ($debug)
- {
- print "run_command_with_output: \"@_\" returned $code.\n";
- }
+
+ print "run_command_with_output: '@_' returned $code.\n" if $debug;
return $code;
}
diff --git a/variable.c b/variable.c
index 495aef4..4c38316 100644
--- a/variable.c
+++ b/variable.c
@@ -1048,7 +1048,7 @@ do_variable_definition (const struct floc *flocp, const char *varname,
if ((origin == o_file || origin == o_override)
&& strcmp (varname, "SHELL") == 0)
{
- char shellpath[PATH_MAX];
+ PATH_VAR (shellpath);
extern char * __dosexec_find_on_path (const char *, char *[], char *);
/* See if we can find "/bin/sh.exe", "/bin/sh.com", etc. */
diff --git a/w32/subproc/NMakefile b/w32/subproc/NMakefile
index 66afe65..d14fcc4 100644
--- a/w32/subproc/NMakefile
+++ b/w32/subproc/NMakefile
@@ -23,6 +23,7 @@
#
LIB = lib
CC = cl
+MAKE = nmake
OUTDIR=.
MAKEFILE=NMakefile