diff options
| author | Paul Smith <psmith@gnu.org> | 2005-02-28 07:48:22 +0000 | 
|---|---|---|
| committer | Paul Smith <psmith@gnu.org> | 2005-02-28 07:48:22 +0000 | 
| commit | d2516343bc5c105543b22eed3b073a8a4e14a659 (patch) | |
| tree | b33081457bdf9207b45add40ba56fdeccf63fe6f | |
| parent | 93bd1bd93c1033352e5059ed721a0cc769449639 (diff) | |
| download | gunmake-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-- | ChangeLog | 73 | ||||
| -rw-r--r-- | NEWS | 20 | ||||
| -rw-r--r-- | configure.in | 13 | ||||
| -rw-r--r-- | dir.c | 12 | ||||
| -rw-r--r-- | doc/make.texi | 17 | ||||
| -rw-r--r-- | file.c | 12 | ||||
| -rw-r--r-- | filedef.h | 3 | ||||
| -rw-r--r-- | function.c | 38 | ||||
| -rw-r--r-- | implicit.c | 2 | ||||
| -rw-r--r-- | main.c | 48 | ||||
| -rw-r--r-- | make.h | 5 | ||||
| -rw-r--r-- | misc.c | 4 | ||||
| -rw-r--r-- | read.c | 9 | ||||
| -rw-r--r-- | remake.c | 75 | ||||
| -rw-r--r-- | tests/ChangeLog | 30 | ||||
| -rwxr-xr-x | tests/run_make_tests.pl | 13 | ||||
| -rw-r--r-- | tests/scripts/features/patspecific_vars | 2 | ||||
| -rw-r--r-- | tests/scripts/functions/eval | 10 | ||||
| -rw-r--r-- | tests/scripts/misc/general4 | 5 | ||||
| -rw-r--r-- | tests/scripts/options/symlinks | 47 | ||||
| -rw-r--r-- | tests/scripts/variables/MAKE | 4 | ||||
| -rw-r--r-- | tests/scripts/variables/MFILE_LIST (renamed from tests/scripts/variables/MAKEFILE_LIST) | 0 | ||||
| -rw-r--r-- | tests/test_driver.pl | 49 | ||||
| -rw-r--r-- | variable.c | 2 | ||||
| -rw-r--r-- | w32/subproc/NMakefile | 1 | 
25 files changed, 390 insertions, 104 deletions
| @@ -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. @@ -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, [ @@ -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 @@ -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.  */ @@ -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; @@ -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}, @@ -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 @@ -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); @@ -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; @@ -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 @@ -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 (""); @@ -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;  } @@ -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 | 
