* New feature: -L option
authorPaul Smith <psmith@gnu.org>
Mon, 28 Feb 2005 07:48:22 +0000 (07:48 +0000)
committerPaul Smith <psmith@gnu.org>
Mon, 28 Feb 2005 07:48:22 +0000 (07:48 +0000)
* 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)

26 files changed:
ChangeLog
NEWS
configure.in
dir.c
doc/make.texi
file.c
filedef.h
function.c
implicit.c
main.c
make.h
misc.c
read.c
remake.c
tests/ChangeLog
tests/run_make_tests.pl
tests/scripts/features/patspecific_vars
tests/scripts/functions/eval
tests/scripts/misc/general4
tests/scripts/options/symlinks [new file with mode: 0644]
tests/scripts/variables/MAKE
tests/scripts/variables/MAKEFILE_LIST [deleted file]
tests/scripts/variables/MFILE_LIST [new file with mode: 0644]
tests/test_driver.pl
variable.c
w32/subproc/NMakefile

index becece8878b03d1267897e6d383f93c76ee78064..46964204675009a3241c7bffaae64dc0f37ebb20 100644 (file)
--- 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 219ffb3f9477cf481fcf2edb26de2412fd250ca4..eb5a22612f58871c70e66c5c93e20bdfa348ee80 100644 (file)
--- 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.
index 7e4d54527e1a90735fa7844d42bccf1067c58af7..4bd77efbc0d928e0e49e1bd2f17f0e1ed58f9572 100644 (file)
@@ -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 976e0b49f62d3f3c6c41b2ea64c8539cb30b2e48..832b5622569d35d73a675c0273b977cff4f3f7a9 100644 (file)
--- 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
index 9b6f9d8a5a72dcb9ccf75df37c37e358dae62a56..c6f4c1a346f97f3ccb44ebc8801104a59938a456 100644 (file)
@@ -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 62a6a687060498f10b5dea7606dc4aae57400178..45bcaef28f765d5f38ab1f5c5c9f60c503041b6c 100644 (file)
--- 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;
 }
 \f
 /* Set the `command_state' member of FILE and all its `also_make's.  */
index 2822e8a782ae1ace93e43ce3cae640f755f7da71..ae45f892fe350287d08128c8cd29475885d03287 100644 (file)
--- 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;
index b344e66aae367f56f912cdfcba060569b2757751..66d23fd5d1d3c8cf2169787f94491033d1039c2a 100644 (file)
@@ -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},
index 7c1f4b73bbabadccd7cbbee16471e23bf247cb62..b844419b741decb79a2eef58a5f40276af438f23 100644 (file)
@@ -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 1035b8c2a4e553a1e75094f8605e6145b9683f3c..c20be9b04dd398f9ff3f4b703e021d3c1651dee1 100644 (file)
--- 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 e9ea18a9360d4fd16bd883738a5be7edaf0baea2..5696965fd31eaadfad12f6fe1d0bcf255729dceb 100644 (file)
--- 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 53c1923ee85402b597725dd0c6e2d7f85ea8260d..63936f76ce3e99ffad7dae5810ee404aad7046f0 100644 (file)
--- 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 0862b482df1aea0f79450410e4c8dae6c5b94d7a..d235c6aae9f343d77ab6001d25c22bd081a3e871 100644 (file)
--- 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 ("");
 
index 70acad3361d5d0ede502b91b3f570194b3e491cc..e1def6480a389fe96ddb30973e64fe90674c617d 100644 (file)
--- 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;
 }
 
 
index 462c2e6219aa1c5cdedd58b0f5c55559544017bf..41c9b34b8f99adf24e78f539ff965dbc7d6eb39f 100644 (file)
@@ -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:
index 5276d29b9d4b511d65d1447e252106ea23d25c99..ca711b291354995b9252e3ec343b23acfe5714bc 100755 (executable)
@@ -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`;
index 31359cfb5bd399804e78edfe6aa062548edc37e4..9e98b437646adbb3b56b6620118b791c30ab2900 100644 (file)
@@ -67,7 +67,7 @@ run_make_test('
 /%: export foo := foo
 
 /bar:
-       @test "$(foo)" == "$$foo"
+       @test "$(foo)" = "$$foo"
 ', '', '');
 
 
index c69a1100792fa2c07aff1a6fc4ace86f25368565..bc430532dadf29894011df33dd780afe02e55114 100644 (file)
@@ -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;
index 3b4595f1833dcf59e7b0bc4de9371e490f8eb3de..63320e230a3771f94c5d3dbd852ef6ed83e43b8d 100644 (file)
@@ -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 (file)
index 0000000..4dcc67a
--- /dev/null
@@ -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;
index 7c4cf0a5038cdb8459d6b1d21474267d79512ed5..079c57eb5c24b908f04915d9685da3be66f60f81 100644 (file)
@@ -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/MAKEFILE_LIST
deleted file mode 100644 (file)
index 076e42d..0000000
+++ /dev/null
@@ -1,30 +0,0 @@
-#                                                                    -*-perl-*-
-
-$description = "Test the MAKEFILE_LIST variable.";
-
-$makefile2 = &get_tmpfile;
-
-open(MAKEFILE,"> $makefile");
-print MAKEFILE <<EOF;
-m1 := \$(MAKEFILE_LIST)
-include $makefile2
-m3 := \$(MAKEFILE_LIST)
-
-all:
-\t\@echo \$(m1)
-\t\@echo \$(m2)
-\t\@echo \$(m3)
-EOF
-close(MAKEFILE);
-
-
-open(MAKEFILE,"> $makefile2");
-print MAKEFILE "m2 := \$(MAKEFILE_LIST)\n";
-close(MAKEFILE);
-
-
-&run_make_with_options($makefile, "", &get_logfile);
-$answer = "$makefile\n$makefile $makefile2\n$makefile $makefile2\n";
-&compare_output($answer,&get_logfile(1));
-
-1;
diff --git a/tests/scripts/variables/MFILE_LIST b/tests/scripts/variables/MFILE_LIST
new file mode 100644 (file)
index 0000000..076e42d
--- /dev/null
@@ -0,0 +1,30 @@
+#                                                                    -*-perl-*-
+
+$description = "Test the MAKEFILE_LIST variable.";
+
+$makefile2 = &get_tmpfile;
+
+open(MAKEFILE,"> $makefile");
+print MAKEFILE <<EOF;
+m1 := \$(MAKEFILE_LIST)
+include $makefile2
+m3 := \$(MAKEFILE_LIST)
+
+all:
+\t\@echo \$(m1)
+\t\@echo \$(m2)
+\t\@echo \$(m3)
+EOF
+close(MAKEFILE);
+
+
+open(MAKEFILE,"> $makefile2");
+print MAKEFILE "m2 := \$(MAKEFILE_LIST)\n";
+close(MAKEFILE);
+
+
+&run_make_with_options($makefile, "", &get_logfile);
+$answer = "$makefile\n$makefile $makefile2\n$makefile $makefile2\n";
+&compare_output($answer,&get_logfile(1));
+
+1;
index 0698d2685487aed8e347fabb8bd537affe5bcdf5..7cd40b58dfc9376287f006730f7f390457318bdd 100644 (file)
@@ -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;
 }
index 495aef45ae37abbc0bc5aeeac9bb9297029017a8..4c383160abaa036a76493afdd1cec386f268daa0 100644 (file)
@@ -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.  */
index 66afe650a2fa81283941b9d3ad8b2eec7da4a276..d14fcc4951885ceab16988f90ac3ea6e648eb1b3 100644 (file)
@@ -23,6 +23,7 @@
 #
 LIB = lib
 CC = cl
+MAKE = nmake
 
 OUTDIR=.
 MAKEFILE=NMakefile