diff --git a/src/bin/make/Jamfile b/src/bin/make/Jamfile index 004ad9795a..e96ff49965 100644 --- a/src/bin/make/Jamfile +++ b/src/bin/make/Jamfile @@ -33,6 +33,7 @@ BinCommand make : remote-stub.c rule.c signame.c + strcache.c variable.c version.c vpath.c diff --git a/src/bin/make/README b/src/bin/make/README index d237d65542..14277e5ca8 100644 --- a/src/bin/make/README +++ b/src/bin/make/README @@ -1,37 +1,189 @@ -GNU make 3.80 -ftp://ftp.gnu.org/gnu/make/make-3.80.tar.gz +This directory contains the 3.81 release of GNU Make. ---- make-3.80/dir.c Fri Oct 4 02:13:42 2002 -+++ make/dir.c Sun Jun 20 17:35:56 2004 -@@ -20,6 +20,7 @@ +See the file NEWS for the user-visible changes from previous releases. +In addition, there have been bugs fixed. - #include "make.h" - #include "hash.h" -+#include "glob.h" +Please check the system-specific notes below for any caveats related to +your operating system. - #ifdef HAVE_DIRENT_H - # include +For general building and installation instructions, see the file INSTALL. ---- make-3.80/glob/glob.c Sat Jan 22 05:43:03 2000 -+++ make/glob/glob.c Sun Jun 20 17:41:46 2004 -@@ -175,7 +175,7 @@ - # define strcoll strcmp - #endif +If you need to build GNU Make and have no other `make' program to use, +you can use the shell script `build.sh' instead. To do this, first run +`configure' as described in INSTALL. Then, instead of typing `make' to +build the program, type `sh build.sh'. This should compile the program +in the current directory. Then you will have a Make program that you can +use for `./make install', or whatever else. --#if !defined HAVE_MEMPCPY && __GLIBC__ - 0 == 2 && __GLIBC_MINOR__ >= 1 -+#if !defined __BEOS__ && !defined HAVE_MEMPCPY && __GLIBC__ - 0 == 2 && __GLIBC_MINOR__ >= 1 - # define HAVE_MEMPCPY 1 - # undef mempcpy - # define mempcpy(Dest, Src, Len) __mempcpy (Dest, Src, Len) +Some systems' Make programs are broken and cannot process the Makefile for +GNU Make. If you get errors from your system's Make when building GNU +Make, try using `build.sh' instead. ---- make-3.80/glob/glob.h Sat Jan 22 05:43:03 2000 -+++ make/glob/glob.h Sun Jun 20 17:40:22 2004 -@@ -24,7 +24,7 @@ - #undef __ptr_t - #if defined __cplusplus || (defined __STDC__ && __STDC__) || defined WINDOWS32 --# if !defined __GLIBC__ || !defined __P -+# if !defined __GLIBC__ || !defined __P || !defined __PMT - # undef __P - # undef __PMT - # define __P(protos) protos +GNU Make is free software. See the file COPYING for copying conditions. + + +Downloading +----------- + +GNU Make can be obtained in many different ways. See a description here: + + http://www.gnu.org/software/software.html + + +Documentation +------------- + +GNU make is fully documented in the GNU Make manual, which is contained +in this distribution as the file make.texinfo. You can also find +on-line and preformatted (PostScript and DVI) versions at the FSF's web +site. There is information there about ordering hardcopy documentation. + + http://www.gnu.org/ + http://www.gnu.org/doc/doc.html + http://www.gnu.org/manual/manual.html + + +Development +----------- + +GNU Make development is hosted by Savannah, the FSF's online development +management tool. Savannah is here: + + http://savannah.gnu.org + +And the GNU Make development page is here: + + http://savannah.gnu.org/projects/make/ + +You can find most information concerning the development of GNU Make at +this site. + + +Bug Reporting +------------- + +You can send GNU make bug reports to . Please see the +section of the GNU make manual entitled `Problems and Bugs' for +information on submitting useful and complete bug reports. + +You can also use the online bug tracking system in the Savannah GNU Make +project to submit new problem reports or search for existing ones: + + http://savannah.gnu.org/bugs/?group=make + +If you need help using GNU make, try these forums: + + help-make@gnu.org + help-utils@gnu.org + news:gnu.utils.help + news:gnu.utils.bug + + http://savannah.gnu.org/support/?group=make + +You may also find interesting patches to GNU Make available here: + + http://savannah.gnu.org/patch/?group=make + +Note these patches are provided by our users as a service and we make no +statements regarding their correctness. Please contact the authors +directly if you have a problem or suggestion for a patch available on +this page. + + +CVS Access +---------- + +The GNU make source repository is available via anonymous CVS from the +GNU Subversions CVS server; look here for details: + + http://savannah.gnu.org/cvs/?group=make + +Please note: you won't be able to build GNU make from CVS without +installing appropriate maintainer's tools, such as GNU m4, automake, +autoconf, Perl, GNU make, and GCC. See the README.cvs file for hints on +how to build GNU make once these tools are available. We make no +guarantees about the contents or quality of the latest code in the CVS +repository: it is not unheard of for code that is known to be broken to +be checked in. Use at your own risk. + + +System-specific Notes +--------------------- + +It has been reported that the XLC 1.2 compiler on AIX 3.2 is buggy such +that if you compile make with `cc -O' on AIX 3.2, it will not work +correctly. It is said that using `cc' without `-O' does work. + +The standard /bin/sh on SunOS 4.1.3_U1 and 4.1.4 is broken and cannot be +used to configure GNU make. Please install a different shell such as +bash or pdksh in order to run "configure". See this message for more +information: + http://mail.gnu.org/archive/html/bug-autoconf/2003-10/msg00190.html + +One area that is often a problem in configuration and porting is the code +to check the system's current load average. To make it easier to test and +debug this code, you can do `make check-loadavg' to see if it works +properly on your system. (You must run `configure' beforehand, but you +need not build Make itself to run this test.) + +Another potential source of porting problems is the support for large +files (LFS) in configure for those operating systems that provide it. +Please report any bugs that you find in this area. If you run into +difficulties, then as a workaround you should be able to disable LFS by +adding the `--disable-largefile' option to the `configure' script. + +On systems that support micro- and nano-second timestamp values and +where stat(2) provides this information, GNU make will use it when +comparing timestamps to get the most accurate possible result. However, +note that many current implementations of tools that *set* timestamps do +not preserve micro- or nano-second granularity. This means that "cp -p" +and other similar tools (tar, etc.) may not exactly duplicate timestamps +with micro- and nano-second granularity on some systems. If your build +system contains rules that depend on proper behavior of tools like "cp +-p", you should consider using the .LOW_RESOLUTION_TIME pseudo-target to +force make to treat them properly. See the manual for details. + + +Ports +----- + + - See README.customs for details on integrating GNU make with the + Customs distributed build environment from the Pmake distribution. + + - See readme.vms for details about GNU Make on OpenVMS. + + - See README.Amiga for details about GNU Make on AmigaDOS. + + - See README.W32 for details about GNU Make on Windows NT, 95, or 98. + + - See README.DOS for compilation instructions on MS-DOS and MS-Windows + using DJGPP tools. + + A precompiled binary of the MSDOS port of GNU Make is available as part + of DJGPP; see the WWW page http://www.delorie.com/djgpp/ for more + information. + +Please note there are two _separate_ ports of GNU make for Microsoft +systems: a native Windows tool built with (for example) MSVC or Cygwin, +and a DOS-based tool built with DJGPP. Please be sure you are looking +at the right README! + + +------------------------------------------------------------------------------- +Copyright (C) 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, +1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006 Free Software Foundation, +Inc. +This file is part of GNU Make. + +GNU Make is free software; you can redistribute it and/or modify it under the +terms of the GNU General Public License as published by the Free Software +Foundation; either version 2, or (at your option) any later version. + +GNU Make is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR +A PARTICULAR PURPOSE. See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License along with +GNU Make; see the file COPYING. If not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. diff --git a/src/bin/make/ar.c b/src/bin/make/ar.c index 286be55f48..4d9f1bb1dd 100644 --- a/src/bin/make/ar.c +++ b/src/bin/make/ar.c @@ -1,22 +1,20 @@ /* Interface to `ar' archives for GNU Make. -Copyright (C) 1988, 1989, 1990, 1991, 1992, 1993, 1997, -2002 Free Software Foundation, Inc. +Copyright (C) 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, +1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006 Free Software +Foundation, Inc. This file is part of GNU Make. -GNU Make is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 2, or (at your option) -any later version. +GNU Make is free software; you can redistribute it and/or modify it under the +terms of the GNU General Public License as published by the Free Software +Foundation; either version 2, or (at your option) any later version. -GNU Make is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. +GNU Make is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR +A PARTICULAR PURPOSE. See the GNU General Public License for more details. -You should have received a copy of the GNU General Public License -along with GNU Make; see the file COPYING. If not, write to -the Free Software Foundation, Inc., 59 Temple Place - Suite 330, -Boston, MA 02111-1307, USA. */ +You should have received a copy of the GNU General Public License along with +GNU Make; see the file COPYING. If not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. */ #include "make.h" @@ -39,8 +37,7 @@ extern int ar_member_touch PARAMS ((char *arname, char *memname)); the attempt to use this unsupported feature. */ int -ar_name (name) - char *name; +ar_name (char *name) { char *p = strchr (name, '('); char *end; @@ -64,8 +61,7 @@ ar_name (name) put the malloc'd member name in *MEMNAME_P if MEMNAME_P is non-nil. */ void -ar_parse_name (name, arname_p, memname_p) - char *name, **arname_p, **memname_p; +ar_parse_name (char *name, char **arname_p, char **memname_p) { char *p = strchr (name, '('), *end = name + strlen (name) - 1; @@ -82,8 +78,7 @@ static long int ar_member_date_1 PARAMS ((int desc, char *mem, int truncated, lo /* Return the modtime of NAME. */ time_t -ar_member_date (name) - char *name; +ar_member_date (char *name) { char *arname; int arname_used = 0; @@ -125,14 +120,10 @@ ar_member_date (name) /* ARGSUSED */ static long int -ar_member_date_1 (desc, mem, truncated, - hdrpos, datapos, size, date, uid, gid, mode, name) - int desc; - char *mem; - int truncated; - long int hdrpos, datapos, size, date; - int uid, gid, mode; - char *name; +ar_member_date_1 (int desc UNUSED, char *mem, int truncated, + long int hdrpos UNUSED, long int datapos UNUSED, + long int size UNUSED, long int date, + int uid UNUSED, int gid UNUSED, int mode UNUSED, char *name) { return ar_name_equal (name, mem, truncated) ? date : 0; } @@ -141,16 +132,14 @@ ar_member_date_1 (desc, mem, truncated, #ifdef VMS int -ar_touch (name) - char *name; +ar_touch (char *name) { error (NILF, _("touch archive member is not available on VMS")); return -1; } #else int -ar_touch (name) - char *name; +ar_touch (char *name) { char *arname, *memname; int arname_used = 0; @@ -219,15 +208,10 @@ struct ar_glob_state element against the pattern in STATE. */ static long int -ar_glob_match (desc, mem, truncated, - hdrpos, datapos, size, date, uid, gid, mode, - state) - int desc; - char *mem; - int truncated; - long int hdrpos, datapos, size, date; - int uid, gid, mode; - struct ar_glob_state *state; +ar_glob_match (int desc UNUSED, char *mem, int truncated UNUSED, + long int hdrpos UNUSED, long int datapos UNUSED, + long int size UNUSED, long int date UNUSED, int uid UNUSED, + int gid UNUSED, int mode UNUSED, struct ar_glob_state *state) { if (fnmatch (state->pattern, mem, FNM_PATHNAME|FNM_PERIOD) == 0) { @@ -245,11 +229,9 @@ ar_glob_match (desc, mem, truncated, /* Return nonzero if PATTERN contains any metacharacters. Metacharacters can be quoted with backslashes if QUOTE is nonzero. */ static int -glob_pattern_p (pattern, quote) - const char *pattern; - const int quote; +glob_pattern_p (const char *pattern, int quote) { - register const char *p; + const char *p; int open = 0; for (p = pattern; *p != '\0'; ++p) @@ -281,9 +263,7 @@ glob_pattern_p (pattern, quote) Return a malloc'd chain of matching elements (or nil if none). */ struct nameseq * -ar_glob (arname, member_pattern, size) - char *arname, *member_pattern; - unsigned int size; +ar_glob (char *arname, char *member_pattern, unsigned int size) { struct ar_glob_state state; char **names; diff --git a/src/bin/make/arscan.c b/src/bin/make/arscan.c index fc003e9953..dbc4afd038 100644 --- a/src/bin/make/arscan.c +++ b/src/bin/make/arscan.c @@ -1,20 +1,20 @@ /* Library function for scanning an archive file. -Copyright (C) 1987,89,91,92,93,94,95,97 Free Software Foundation, Inc. +Copyright (C) 1987, 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, +1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006 Free Software Foundation, +Inc. +This file is part of GNU Make. -This program is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 2, or (at your option) -any later version. +GNU Make is free software; you can redistribute it and/or modify it under the +terms of the GNU General Public License as published by the Free Software +Foundation; either version 2, or (at your option) any later version. -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. +GNU Make is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR +A PARTICULAR PURPOSE. See the GNU General Public License for more details. -You should have received a copy of the GNU General Public License -along with this program; if not, write to the Free Software -Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, -USA. */ +You should have received a copy of the GNU General Public License along with +GNU Make; see the file COPYING. If not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. */ #include "make.h" @@ -46,9 +46,7 @@ static time_t VMS_member_date; static long int (*VMS_function) (); static int -VMS_get_member_info (module, rfa) - struct dsc$descriptor_s *module; - unsigned long *rfa; +VMS_get_member_info (struct dsc$descriptor_s *module, unsigned long *rfa) { int status, i; long int fnval; @@ -136,10 +134,7 @@ VMS_get_member_info (module, rfa) Returns 0 if have scanned successfully. */ long int -ar_scan (archive, function, arg) - char *archive; - long int (*function) (); - long int arg; +ar_scan (char *archive, long int (*function) PARAMS ((void)), long int arg) { char *p; @@ -306,10 +301,7 @@ struct ar_hdr Returns 0 if have scanned successfully. */ long int -ar_scan (archive, function, arg) - char *archive; - long int (*function) (); - long int arg; +ar_scan (char *archive, long int (*function)(), long int arg) { #ifdef AIAMAG FL_HDR fl_header; @@ -714,9 +706,7 @@ ar_scan (archive, function, arg) sizeof (struct ar_hdr.ar_name) - 1. */ int -ar_name_equal (name, mem, truncated) - char *name, *mem; - int truncated; +ar_name_equal (char *name, char *mem, int truncated) { char *p; @@ -747,14 +737,10 @@ ar_name_equal (name, mem, truncated) #ifndef VMS /* ARGSUSED */ static long int -ar_member_pos (desc, mem, truncated, - hdrpos, datapos, size, date, uid, gid, mode, name) - int desc; - char *mem; - int truncated; - long int hdrpos, datapos, size, date; - int uid, gid, mode; - char *name; +ar_member_pos (int desc UNUSED, char *mem, int truncated, + long int hdrpos, long int datapos UNUSED, long int size UNUSED, + long int date UNUSED, int uid UNUSED, int gid UNUSED, + int mode UNUSED, char *name) { if (!ar_name_equal (name, mem, truncated)) return 0; @@ -769,13 +755,13 @@ ar_member_pos (desc, mem, truncated, 1 if valid but member MEMNAME does not exist. */ int -ar_member_touch (arname, memname) - char *arname, *memname; +ar_member_touch (char *arname, char *memname) { - register long int pos = ar_scan (arname, ar_member_pos, (long int) memname); - register int fd; + long int pos = ar_scan (arname, ar_member_pos, (long int) memname); + int fd; struct ar_hdr ar_hdr; - register int i; + int i; + unsigned int ui; struct stat statbuf; if (pos < 0) @@ -797,12 +783,13 @@ ar_member_touch (arname, memname) if (AR_HDR_SIZE != write (fd, (char *) &ar_hdr, AR_HDR_SIZE)) goto lose; /* The file's mtime is the time we we want. */ - if (fstat (fd, &statbuf) < 0) + EINTRLOOP (i, fstat (fd, &statbuf)); + if (i < 0) goto lose; #if defined(ARFMAG) || defined(ARFZMAG) || defined(AIAMAG) || defined(WINDOWS32) /* Advance member's time to that time */ - for (i = 0; i < sizeof ar_hdr.ar_date; i++) - ar_hdr.ar_date[i] = ' '; + for (ui = 0; ui < sizeof ar_hdr.ar_date; ui++) + ar_hdr.ar_date[ui] = ' '; sprintf (ar_hdr.ar_date, "%ld", (long int) statbuf.st_mtime); #ifdef AIAMAG ar_hdr.ar_date[strlen(ar_hdr.ar_date)] = ' '; @@ -829,13 +816,9 @@ ar_member_touch (arname, memname) #ifdef TEST long int -describe_member (desc, name, truncated, - hdrpos, datapos, size, date, uid, gid, mode) - int desc; - char *name; - int truncated; - long int hdrpos, datapos, size, date; - int uid, gid, mode; +describe_member (int desc, char *name, int truncated, + long int hdrpos, long int datapos, long int size, + long int date, int uid, int gid, int mode) { extern char *ctime (); @@ -848,14 +831,12 @@ describe_member (desc, name, truncated, return 0; } -main (argc, argv) - int argc; - char **argv; +int +main (int argc, char **argv) { ar_scan (argv[1], describe_member); return 0; } #endif /* TEST. */ - #endif /* NO_ARCHIVES. */ diff --git a/src/bin/make/commands.c b/src/bin/make/commands.c index 84b58de573..a0a7c5cf9d 100644 --- a/src/bin/make/commands.c +++ b/src/bin/make/commands.c @@ -1,21 +1,20 @@ /* Command processing for GNU Make. -Copyright (C) 1988,89,91,92,93,94,95,96,97 Free Software Foundation, Inc. +Copyright (C) 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, +1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006 Free Software +Foundation, Inc. This file is part of GNU Make. -GNU Make is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 2, or (at your option) -any later version. +GNU Make is free software; you can redistribute it and/or modify it under the +terms of the GNU General Public License as published by the Free Software +Foundation; either version 2, or (at your option) any later version. -GNU Make is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. +GNU Make is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR +A PARTICULAR PURPOSE. See the GNU General Public License for more details. -You should have received a copy of the GNU General Public License -along with GNU Make; see the file COPYING. If not, write to -the Free Software Foundation, Inc., 59 Temple Place - Suite 330, -Boston, MA 02111-1307, USA. */ +You should have received a copy of the GNU General Public License along with +GNU Make; see the file COPYING. If not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. */ #include "make.h" #include "dep.h" @@ -23,6 +22,10 @@ Boston, MA 02111-1307, USA. */ #include "variable.h" #include "job.h" #include "commands.h" +#ifdef WINDOWS32 +#include +#include "w32err.h" +#endif #if VMS # define FILE_LIST_SEPARATOR ',' @@ -38,10 +41,10 @@ extern int getpid (); /* Set FILE's automatic variables up. */ -static void -set_file_variables (file) - register struct file *file; +void +set_file_variables (struct file *file) { + struct dep *d; char *at, *percent, *star, *less; #ifndef NO_ARCHIVES @@ -106,8 +109,14 @@ set_file_variables (file) } star = file->stem; - /* $< is the first dependency. */ - less = file->deps != 0 ? dep_name (file->deps) : ""; + /* $< is the first not order-only dependency. */ + less = ""; + for (d = file->deps; d != 0; d = d->next) + if (!d->ignore_mtime) + { + less = dep_name (d); + break; + } if (file->cmds == default_file->cmds) /* This file got its commands from .DEFAULT. @@ -127,14 +136,14 @@ set_file_variables (file) /* Compute the values for $^, $+, $?, and $|. */ { + static char *plus_value=0, *bar_value=0, *qmark_value=0; + static unsigned int qmark_max=0, plus_max=0, bar_max=0; + unsigned int qmark_len, plus_len, bar_len; - char *caret_value, *plus_value; char *cp; - char *qmark_value; - char *bar_value; + char *caret_value; char *qp; char *bp; - struct dep *d; unsigned int len; /* Compute first the value for $+, which is supposed to contain @@ -147,7 +156,9 @@ set_file_variables (file) if (plus_len == 0) plus_len++; - cp = plus_value = (char *) alloca (plus_len); + if (plus_len > plus_max) + plus_value = xrealloc (plus_value, plus_max = plus_len); + cp = plus_value; qmark_len = plus_len + 1; /* Will be this or less. */ for (d = file->deps; d != 0; d = d->next) @@ -193,8 +204,14 @@ set_file_variables (file) /* Compute the values for $^, $?, and $|. */ cp = caret_value = plus_value; /* Reuse the buffer; it's big enough. */ - qp = qmark_value = (char *) alloca (qmark_len); - bp = bar_value = (char *) alloca (bar_len); + + if (qmark_len > qmark_max) + qmark_value = xrealloc (qmark_value, qmark_max = qmark_len); + qp = qmark_value; + + if (bar_len > bar_max) + bar_value = xrealloc (bar_value, bar_max = bar_len); + bp = bar_value; for (d = file->deps; d != 0; d = d->next) { @@ -249,8 +266,7 @@ set_file_variables (file) Also set the `lines_flags' and `any_recurse' members. */ void -chop_commands (cmds) - register struct commands *cmds; +chop_commands (struct commands *cmds) { register char *p; unsigned int nlines, idx; @@ -333,13 +349,11 @@ chop_commands (cmds) flags |= COMMANDS_NOERROR; break; } - if (!(flags & COMMANDS_RECURSE)) - { - unsigned int len = strlen (p); - if (sindex (p, len, "$(MAKE)", 7) != 0 - || sindex (p, len, "${MAKE}", 7) != 0) - flags |= COMMANDS_RECURSE; - } + + /* If no explicit '+' was given, look for MAKE variable references. */ + if (!(flags & COMMANDS_RECURSE) + && (strstr (p, "$(MAKE)") != 0 || strstr (p, "${MAKE}") != 0)) + flags |= COMMANDS_RECURSE; cmds->lines_flags[idx] = flags; cmds->any_recurse |= flags & COMMANDS_RECURSE; @@ -351,8 +365,7 @@ chop_commands (cmds) fork off a child process to run the first command line in the sequence. */ void -execute_file_commands (file) - struct file *file; +execute_file_commands (struct file *file) { register char *p; @@ -389,8 +402,7 @@ int handling_fatal_signal = 0; /* Handle fatal signals. */ RETSIGTYPE -fatal_error_signal (sig) - int sig; +fatal_error_signal (int sig) { #ifdef __MSDOS__ extern int dos_status, dos_command_running; @@ -411,6 +423,27 @@ fatal_error_signal (sig) exit (10); #else /* not Amiga */ +#ifdef WINDOWS32 + extern HANDLE main_thread; + + /* Windows creates a sperate thread for handling Ctrl+C, so we need + to suspend the main thread, or else we will have race conditions + when both threads call reap_children. */ + if (main_thread) + { + DWORD susp_count = SuspendThread (main_thread); + + if (susp_count != 0) + fprintf (stderr, "SuspendThread: suspend count = %ld\n", susp_count); + else if (susp_count == (DWORD)-1) + { + DWORD ierr = GetLastError (); + + fprintf (stderr, "SuspendThread: error %ld: %s\n", + ierr, map_windows32_error_to_string (ierr)); + } + } +#endif handling_fatal_signal = 1; /* Set the handling for this signal to the default. @@ -472,10 +505,18 @@ fatal_error_signal (sig) exit (EXIT_FAILURE); #endif +#ifdef WINDOWS32 + if (main_thread) + CloseHandle (main_thread); + /* Cannot call W32_kill with a pid (it needs a handle). The exit + status of 130 emulates what happens in Bash. */ + exit (130); +#else /* Signal the same code; this time it will really be fatal. The signal will be unblocked when we return and arrive then to kill us. */ if (kill (getpid (), sig) < 0) pfatal_with_name ("kill"); +#endif /* not WINDOWS32 */ #endif /* not Amiga */ #endif /* not __MSDOS__ */ } @@ -484,11 +525,10 @@ fatal_error_signal (sig) and it has changed on disk since we last stat'd it. */ static void -delete_target (file, on_behalf_of) - struct file *file; - char *on_behalf_of; +delete_target (struct file *file, char *on_behalf_of) { struct stat st; + int e; if (file->precious || file->phony) return; @@ -512,7 +552,8 @@ delete_target (file, on_behalf_of) } #endif - if (stat (file->name, &st) == 0 + EINTRLOOP (e, stat (file->name, &st)); + if (e == 0 && S_ISREG (st.st_mode) && FILE_TIMESTAMP_STAT_MODTIME (file->name, st) != file->last_mtime) { @@ -531,8 +572,7 @@ delete_target (file, on_behalf_of) Set the flag in CHILD to say they've been deleted. */ void -delete_child_targets (child) - struct child *child; +delete_child_targets (struct child *child) { struct dep *d; @@ -552,8 +592,7 @@ delete_child_targets (child) /* Print out the commands in CMDS. */ void -print_commands (cmds) - register struct commands *cmds; +print_commands (struct commands *cmds) { register char *s; diff --git a/src/bin/make/commands.h b/src/bin/make/commands.h index edec91032c..96a1a4db0b 100644 --- a/src/bin/make/commands.h +++ b/src/bin/make/commands.h @@ -1,21 +1,20 @@ /* Definition of data structures describing shell commands for GNU Make. -Copyright (C) 1988, 1989, 1991, 1993 Free Software Foundation, Inc. +Copyright (C) 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, +1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006 Free Software +Foundation, Inc. This file is part of GNU Make. -GNU Make is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 2, or (at your option) -any later version. +GNU Make is free software; you can redistribute it and/or modify it under the +terms of the GNU General Public License as published by the Free Software +Foundation; either version 2, or (at your option) any later version. -GNU Make is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. +GNU Make is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR +A PARTICULAR PURPOSE. See the GNU General Public License for more details. -You should have received a copy of the GNU General Public License -along with GNU Make; see the file COPYING. If not, write to -the Free Software Foundation, Inc., 59 Temple Place - Suite 330, -Boston, MA 02111-1307, USA. */ +You should have received a copy of the GNU General Public License along with +GNU Make; see the file COPYING. If not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. */ /* Structure that gives the commands to make a file and information about where these commands came from. */ @@ -40,3 +39,4 @@ extern void execute_file_commands PARAMS ((struct file *file)); extern void print_commands PARAMS ((struct commands *cmds)); extern void delete_child_targets PARAMS ((struct child *child)); extern void chop_commands PARAMS ((struct commands *cmds)); +extern void set_file_variables PARAMS ((struct file *file)); diff --git a/src/bin/make/debug.h b/src/bin/make/debug.h index 30c2d62768..9b6ac07210 100644 --- a/src/bin/make/debug.h +++ b/src/bin/make/debug.h @@ -1,22 +1,19 @@ /* Debugging macros and interface. -Copyright (C) 1999 Free Software Foundation, Inc. +Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006 Free Software +Foundation, Inc. This file is part of GNU Make. -GNU Make is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 2, or (at your option) -any later version. +GNU Make is free software; you can redistribute it and/or modify it under the +terms of the GNU General Public License as published by the Free Software +Foundation; either version 2, or (at your option) any later version. -GNU Make is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with GNU Make; see the file COPYING. If not, write to -the Free Software Foundation, Inc., 59 Temple Place - Suite 330, -Boston, MA 02111-1307, USA. */ +GNU Make is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR +A PARTICULAR PURPOSE. See the GNU General Public License for more details. +You should have received a copy of the GNU General Public License along with +GNU Make; see the file COPYING. If not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. */ #define DB_NONE (0x000) #define DB_BASIC (0x001) diff --git a/src/bin/make/default.c b/src/bin/make/default.c index 5d981b987d..86f719aa24 100644 --- a/src/bin/make/default.c +++ b/src/bin/make/default.c @@ -1,34 +1,33 @@ /* Data base of default implicit rules for GNU Make. -Copyright (C) 1988,89,90,91,92,93,94,95,96 Free Software Foundation, Inc. +Copyright (C) 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, +1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006 Free Software +Foundation, Inc. This file is part of GNU Make. -GNU Make is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 2, or (at your option) -any later version. +GNU Make is free software; you can redistribute it and/or modify it under the +terms of the GNU General Public License as published by the Free Software +Foundation; either version 2, or (at your option) any later version. -GNU Make is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. +GNU Make is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR +A PARTICULAR PURPOSE. See the GNU General Public License for more details. -You should have received a copy of the GNU General Public License -along with GNU Make; see the file COPYING. If not, write to -the Free Software Foundation, Inc., 59 Temple Place - Suite 330, -Boston, MA 02111-1307, USA. */ +You should have received a copy of the GNU General Public License along with +GNU Make; see the file COPYING. If not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. */ #include "make.h" +#include "filedef.h" +#include "variable.h" #include "rule.h" #include "dep.h" -#include "filedef.h" #include "job.h" #include "commands.h" -#include "variable.h" /* Define GCC_IS_NATIVE if gcc is the native development environment on your system (gcc/bison/flex vs cc/yacc/lex). */ -#ifdef __MSDOS__ -#define GCC_IS_NATIVE +#if defined(__MSDOS__) || defined(__EMX__) +# define GCC_IS_NATIVE #endif @@ -41,6 +40,10 @@ static char default_suffixes[] = ".exe .olb .ln .obj .c .cxx .cc .pas .p .for .f .r .y .l .mar \ .s .ss .i .ii .mod .sym .def .h .info .dvi .tex .texinfo .texi .txinfo \ .w .ch .cweb .web .com .sh .elc .el"; +#elif defined(__EMX__) + = ".out .a .ln .o .c .cc .C .cpp .p .f .F .r .y .l .s .S \ +.mod .sym .def .h .info .dvi .tex .texinfo .texi .txinfo \ +.w .ch .web .sh .elc .el .obj .exe .dll .lib"; #else = ".out .a .ln .o .c .cc .C .cpp .p .f .F .r .y .l .s .S \ .mod .sym .def .h .info .dvi .tex .texinfo .texi .txinfo \ @@ -153,6 +156,8 @@ static char *default_suffix_rules[] = "$(COMPILE.cc)/noprep/noobj/machine /list=$@ $<", ".cc.obj", "$(COMPILE.cc) /obj=$@ $<", + ".cxx.obj", + "$(COMPILE.cxx) /obj=$@ $<", ".for.obj", "$(COMPILE.for) /obj=$@ $<", ".pas.obj", @@ -302,7 +307,11 @@ static char *default_variables[] = #ifdef VMS #ifdef __ALPHA "ARCH", "ALPHA", -#else +#endif +#ifdef __ia64 + "ARCH", "IA64", +#endif +#ifdef __VAX "ARCH", "VAX", #endif "AR", "library/obj", @@ -511,7 +520,7 @@ static char *default_variables[] = /* Set up the default .SUFFIXES list. */ void -set_default_suffixes () +set_default_suffixes (void) { suffix_file = enter_file (".SUFFIXES"); @@ -533,7 +542,7 @@ set_default_suffixes () installed after. */ void -install_default_suffix_rules () +install_default_suffix_rules (void) { register char **s; @@ -558,7 +567,7 @@ install_default_suffix_rules () /* Install the default pattern rules. */ void -install_default_implicit_rules () +install_default_implicit_rules (void) { register struct pspec *p; @@ -573,7 +582,7 @@ install_default_implicit_rules () } void -define_default_variables () +define_default_variables (void) { register char **s; diff --git a/src/bin/make/dep.h b/src/bin/make/dep.h index 7f4380b71a..f0923cc2ed 100644 --- a/src/bin/make/dep.h +++ b/src/bin/make/dep.h @@ -1,21 +1,20 @@ /* Definitions of dependency data structures for GNU Make. -Copyright (C) 1988, 1989, 1991, 1992, 1993, 1996 Free Software Foundation, Inc. +Copyright (C) 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, +1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006 Free Software +Foundation, Inc. This file is part of GNU Make. -GNU Make is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 2, or (at your option) -any later version. +GNU Make is free software; you can redistribute it and/or modify it under the +terms of the GNU General Public License as published by the Free Software +Foundation; either version 2, or (at your option) any later version. -GNU Make is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. +GNU Make is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR +A PARTICULAR PURPOSE. See the GNU General Public License for more details. -You should have received a copy of the GNU General Public License -along with GNU Make; see the file COPYING. If not, write to -the Free Software Foundation, Inc., 59 Temple Place - Suite 330, -Boston, MA 02111-1307, USA. */ +You should have received a copy of the GNU General Public License along with +GNU Make; see the file COPYING. If not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. */ /* Flag bits for the second argument to `read_makefile'. These flags are saved in the `changed' field of each @@ -29,7 +28,8 @@ Boston, MA 02111-1307, USA. */ /* Structure representing one dependency of a file. Each struct file's `deps' points to a chain of these, - chained through the `next'. + chained through the `next'. `stem' is the stem for this + dep line of static pattern rule or NULL. Note that the first two words of this match a struct nameseq. */ @@ -37,9 +37,12 @@ struct dep { struct dep *next; char *name; + char *stem; struct file *file; unsigned int changed : 8; unsigned int ignore_mtime : 1; + unsigned int staticpattern : 1; + unsigned int need_2nd_expansion : 1; }; @@ -71,8 +74,12 @@ extern struct nameseq *ar_glob PARAMS ((char *arname, char *member_pattern, unsi extern char *dep_name (); #endif -extern struct dep *copy_dep_chain PARAMS ((struct dep *d)); +extern struct dep *alloc_dep PARAMS ((void)); +extern void free_dep PARAMS ((struct dep *d)); +extern struct dep *copy_dep_chain PARAMS ((const struct dep *d)); +extern void free_dep_chain PARAMS ((struct dep *d)); +extern void free_ns_chain PARAMS ((struct nameseq *n)); extern struct dep *read_all_makefiles PARAMS ((char **makefiles)); extern int eval_buffer PARAMS ((char *buffer)); -extern int update_goal_chain PARAMS ((struct dep *goals, int makefiles)); +extern int update_goal_chain PARAMS ((struct dep *goals)); extern void uniquize_deps PARAMS ((struct dep *)); diff --git a/src/bin/make/dir.c b/src/bin/make/dir.c index 3f1a9a44f5..f72ce42ac5 100644 --- a/src/bin/make/dir.c +++ b/src/bin/make/dir.c @@ -1,26 +1,23 @@ /* Directory hashing for GNU Make. -Copyright (C) 1988, 1989, 1991, 1992, 1993, 1994, 1995, 1996, 1997, -2002 Free Software Foundation, Inc. +Copyright (C) 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, +1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006 Free Software +Foundation, Inc. This file is part of GNU Make. -GNU Make is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 2, or (at your option) -any later version. +GNU Make is free software; you can redistribute it and/or modify it under the +terms of the GNU General Public License as published by the Free Software +Foundation; either version 2, or (at your option) any later version. -GNU Make is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. +GNU Make is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR +A PARTICULAR PURPOSE. See the GNU General Public License for more details. -You should have received a copy of the GNU General Public License -along with GNU Make; see the file COPYING. If not, write to -the Free Software Foundation, Inc., 59 Temple Place - Suite 330, -Boston, MA 02111-1307, USA. */ +You should have received a copy of the GNU General Public License along with +GNU Make; see the file COPYING. If not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. */ #include "make.h" #include "hash.h" -#include "glob.h" #ifdef HAVE_DIRENT_H # include @@ -71,8 +68,7 @@ extern char *vmsify PARAMS ((char *name, int type)); #endif static char * -dosify (filename) - char *filename; +dosify (char *filename) { static char dos_filename[14]; char *df; @@ -122,14 +118,9 @@ dosify (filename) #ifdef HAVE_CASE_INSENSITIVE_FS static char * -downcase (filename) - char *filename; +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; @@ -154,8 +145,7 @@ downcase (filename) #ifdef VMS static int -vms_hash (name) - char *name; +vms_hash (char *name) { int h = 0; int g; @@ -163,7 +153,11 @@ vms_hash (name) while (*name) { unsigned char uc = *name; +#ifdef HAVE_CASE_INSENSITIVE_FS h = (h << 4) + (isupper (uc) ? tolower (uc) : uc); +#else + h = (h << 4) + uc; +#endif name++; g = h & 0xf0000000; if (g) @@ -177,9 +171,7 @@ vms_hash (name) /* fake stat entry for a directory */ static int -vmsstat_dir (name, st) - char *name; - struct stat *st; +vmsstat_dir (char *name, struct stat *st) { char *s; int h; @@ -249,13 +241,13 @@ struct directory_contents }; static unsigned long -directory_contents_hash_1 (key_0) - const void *key_0; +directory_contents_hash_1 (const void *key_0) { struct directory_contents const *key = (struct directory_contents const *) key_0; unsigned long hash; #ifdef WINDOWS32 + hash = 0; ISTRING_HASH_1 (key->path_key, hash); hash ^= ((unsigned int) key->dev << 4) ^ (unsigned int) key->ctime; #else @@ -272,13 +264,13 @@ directory_contents_hash_1 (key_0) } static unsigned long -directory_contents_hash_2 (key_0) - const void *key_0; +directory_contents_hash_2 (const void *key_0) { struct directory_contents const *key = (struct directory_contents const *) key_0; unsigned long hash; #ifdef WINDOWS32 + hash = 0; ISTRING_HASH_2 (key->path_key, hash); hash ^= ((unsigned int) key->dev << 4) ^ (unsigned int) ~key->ctime; #else @@ -295,10 +287,19 @@ directory_contents_hash_2 (key_0) return hash; } +/* Sometimes it's OK to use subtraction to get this value: + result = X - Y; + But, if we're not sure of the type of X and Y they may be too large for an + int (on a 64-bit system for example). So, use ?: instead. + See Savannah bug #15534. + + NOTE! This macro has side-effects! +*/ + +#define MAKECMP(_x,_y) ((_x)<(_y)?-1:((_x)==(_y)?0:1)) + static int -directory_contents_hash_cmp (xv, yv) - const void *xv; - const void *yv; +directory_contents_hash_cmp (const void *xv, const void *yv) { struct directory_contents const *x = (struct directory_contents const *) xv; struct directory_contents const *y = (struct directory_contents const *) yv; @@ -308,28 +309,28 @@ directory_contents_hash_cmp (xv, yv) ISTRING_COMPARE (x->path_key, y->path_key, result); if (result) return result; - result = x->ctime - y->ctime; + result = MAKECMP(x->ctime, y->ctime); if (result) return result; #else # ifdef VMS - result = x->ino[0] - y->ino[0]; + result = MAKECMP(x->ino[0], y->ino[0]); if (result) return result; - result = x->ino[1] - y->ino[1]; + result = MAKECMP(x->ino[1], y->ino[1]); if (result) return result; - result = x->ino[2] - y->ino[2]; + result = MAKECMP(x->ino[2], y->ino[2]); if (result) return result; # else - result = x->ino - y->ino; + result = MAKECMP(x->ino, y->ino); if (result) return result; # endif #endif /* WINDOWS32 */ - return x->dev - y->dev; + return MAKECMP(x->dev, y->dev); } /* Table of directory contents hashed by device and inode number. */ @@ -346,23 +347,19 @@ struct directory }; static unsigned long -directory_hash_1 (key) - const void *key; +directory_hash_1 (const void *key) { return_ISTRING_HASH_1 (((struct directory const *) key)->name); } static unsigned long -directory_hash_2 (key) - const void *key; +directory_hash_2 (const void *key) { return_ISTRING_HASH_2 (((struct directory const *) key)->name); } static int -directory_hash_cmp (x, y) - const void *x; - const void *y; +directory_hash_cmp (const void *x, const void *y) { return_ISTRING_COMPARE (((struct directory const *) x)->name, ((struct directory const *) y)->name); @@ -388,23 +385,19 @@ struct dirfile }; static unsigned long -dirfile_hash_1 (key) - const void *key; +dirfile_hash_1 (const void *key) { return_ISTRING_HASH_1 (((struct dirfile const *) key)->name); } static unsigned long -dirfile_hash_2 (key) - const void *key; +dirfile_hash_2 (const void *key) { return_ISTRING_HASH_2 (((struct dirfile const *) key)->name); } static int -dirfile_hash_cmp (xv, yv) - const void *xv; - const void *yv; +dirfile_hash_cmp (const void *xv, const void *yv) { struct dirfile const *x = ((struct dirfile const *) xv); struct dirfile const *y = ((struct dirfile const *) yv); @@ -424,8 +417,7 @@ static struct directory *find_directory PARAMS ((char *name)); /* Find the directory named NAME and return its `struct directory'. */ static struct directory * -find_directory (name) - register char *name; +find_directory (char *name) { register char *p; register struct directory *dir; @@ -436,9 +428,9 @@ find_directory (name) char* w32_path; char fs_label[BUFSIZ]; char fs_type[BUFSIZ]; - long fs_serno; - long fs_flags; - long fs_len; + unsigned long fs_serno; + unsigned long fs_flags; + unsigned long fs_len; #endif #ifdef VMS if ((*name == '.') && (*(name+1) == 0)) @@ -474,7 +466,7 @@ find_directory (name) #ifdef VMS r = vmsstat_dir (name, &st); #else - r = stat (name, &st); + EINTRLOOP (r, stat (name, &st)); #endif #ifdef WINDOWS32 @@ -555,7 +547,7 @@ find_directory (name) # endif #endif /* WINDOWS32 */ hash_insert_at (&directory_contents, dc, dc_slot); - dc->dirstream = opendir (name); + ENULLLOOP (dc->dirstream, opendir (name)); if (dc->dirstream == 0) /* Couldn't open the directory. Mark this by setting the `files' member to a nil pointer. */ @@ -585,9 +577,7 @@ find_directory (name) FILENAME must contain no slashes. */ static int -dir_contents_file_exists_p (dir, filename) - register struct directory_contents *dir; - register char *filename; +dir_contents_file_exists_p (struct directory_contents *dir, char *filename) { unsigned int hash; struct dirfile *df; @@ -610,6 +600,11 @@ dir_contents_file_exists_p (dir, filename) filename = downcase (filename); #endif +#ifdef __EMX__ + if (filename != 0) + _fnlwr (filename); /* lower case for FAT drives */ +#endif + #ifdef VMS filename = vmsify (filename,0); #endif @@ -644,21 +639,28 @@ dir_contents_file_exists_p (dir, filename) * filesystems force a rehash always as mtime does not change * on directories (ugh!). */ - if (dir->path_key - && (dir->fs_flags & FS_FAT - || (stat(dir->path_key, &st) == 0 - && st.st_mtime > dir->mtime))) + if (dir->path_key) { - /* reset date stamp to show most recent re-process */ - dir->mtime = st.st_mtime; + if ((dir->fs_flags & FS_FAT) != 0) + { + dir->mtime = time ((time_t *) 0); + rehash = 1; + } + else if (stat(dir->path_key, &st) == 0 && st.st_mtime > dir->mtime) + { + /* reset date stamp to show most recent re-process. */ + dir->mtime = st.st_mtime; + rehash = 1; + } - /* make sure directory can still be opened */ - dir->dirstream = opendir(dir->path_key); + /* If it has been already read in, all done. */ + if (!rehash) + return 0; - if (dir->dirstream) - rehash = 1; - else - return 0; /* couldn't re-read - fail */ + /* make sure directory can still be opened; if not return. */ + dir->dirstream = opendir(dir->path_key); + if (!dir->dirstream) + return 0; } else #endif @@ -666,13 +668,17 @@ dir_contents_file_exists_p (dir, filename) return 0; } - while ((d = readdir (dir->dirstream)) != 0) + while (1) { /* Enter the file in the hash table. */ unsigned int len; struct dirfile dirfile_key; struct dirfile **dirfile_slot; + ENULLLOOP (d, readdir (dir->dirstream)); + if (d == 0) + break; + #if defined(VMS) && defined(HAVE_DIRENT_H) /* In VMS we get file versions too, which have to be stripped off */ { @@ -725,9 +731,7 @@ dir_contents_file_exists_p (dir, filename) FILENAME must contain no slashes. */ int -dir_file_exists_p (dirname, filename) - register char *dirname; - register char *filename; +dir_file_exists_p (char *dirname, char *filename) { return dir_contents_file_exists_p (find_directory (dirname)->contents, filename); @@ -736,8 +740,7 @@ dir_file_exists_p (dirname, filename) /* Return 1 if the file named NAME exists. */ int -file_exists_p (name) - register char *name; +file_exists_p (char *name) { char *dirend; char *dirname; @@ -752,8 +755,7 @@ file_exists_p (name) dirend = strrchr (name, ']'); if (dirend == 0) dirend = strrchr (name, ':'); - dirend++; - if (dirend == (char *)1) + if (dirend == (char *)0) return dir_file_exists_p ("[]", name); #else /* !VMS */ dirend = strrchr (name, '/'); @@ -799,8 +801,7 @@ file_exists_p (name) as an intermediate file, and it has failed. */ void -file_impossible (filename) - register char *filename; +file_impossible (char *filename) { char *dirend; register char *p = filename; @@ -883,8 +884,7 @@ file_impossible (filename) /* Return nonzero if FILENAME has been marked impossible. */ int -file_impossible_p (filename) - char *filename; +file_impossible_p (char *filename) { char *dirend; register char *p = filename; @@ -965,8 +965,7 @@ file_impossible_p (filename) directory hash table that matches DIR. */ char * -dir_name (dir) - char *dir; +dir_name (char *dir) { return find_directory (dir)->name; } @@ -974,7 +973,7 @@ dir_name (dir) /* Print the data base of directories. */ void -print_dir_data_base () +print_dir_data_base (void) { register unsigned int files; register unsigned int impossible; @@ -1097,8 +1096,7 @@ static __ptr_t open_dirstream PARAMS ((const char *)); static struct dirent *read_dirstream PARAMS ((__ptr_t)); static __ptr_t -open_dirstream (directory) - const char *directory; +open_dirstream (const char *directory) { struct dirstream *new; struct directory *dir = find_directory ((char *)directory); @@ -1121,8 +1119,7 @@ open_dirstream (directory) } static struct dirent * -read_dirstream (stream) - __ptr_t stream; +read_dirstream (__ptr_t stream) { struct dirstream *const ds = (struct dirstream *) stream; struct directory_contents *dc = ds->contents; @@ -1149,6 +1146,12 @@ read_dirstream (stream) buf = xmalloc (bufsz); } d = (struct dirent *) buf; +#ifdef __MINGW32__ +# if __MINGW32_MAJOR_VERSION < 3 || (__MINGW32_MAJOR_VERSION == 3 && \ + __MINGW32_MINOR_VERSION == 0) + d->d_name = xmalloc(len); +# endif +#endif FAKE_DIR_ENTRY (d); #ifdef _DIRENT_HAVE_D_NAMLEN d->d_namlen = len - 1; @@ -1165,11 +1168,10 @@ read_dirstream (stream) } static void -ansi_free(p) - 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 @@ -1178,21 +1180,22 @@ ansi_free(p) */ #ifndef stat # ifndef VMS -extern int stat (); +extern int stat PARAMS ((const char *path, struct stat *sbuf)); # endif # define local_stat stat #else -static int local_stat (path, buf) - char *path; - struct stat *buf; +static int +local_stat (const char *path, struct stat *buf) { - return stat (path, buf); + int e; + + EINTRLOOP (e, stat (path, buf)); + return e; } #endif void -dir_setup_glob (gl) - glob_t *gl; +dir_setup_glob (glob_t *gl) { /* Bogus sunos4 compiler complains (!) about & before functions. */ gl->gl_opendir = open_dirstream; @@ -1204,7 +1207,7 @@ dir_setup_glob (gl) } void -hash_init_directories () +hash_init_directories (void) { hash_init (&directories, DIRECTORY_BUCKETS, directory_hash_1, directory_hash_2, directory_hash_cmp); diff --git a/src/bin/make/expand.c b/src/bin/make/expand.c index 6722e1b38a..993e6d4f08 100644 --- a/src/bin/make/expand.c +++ b/src/bin/make/expand.c @@ -1,21 +1,20 @@ /* Variable expansion functions for GNU Make. -Copyright (C) 1988, 89, 91, 92, 93, 95 Free Software Foundation, Inc. +Copyright (C) 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, +1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006 Free Software +Foundation, Inc. This file is part of GNU Make. -GNU Make is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 2, or (at your option) -any later version. +GNU Make is free software; you can redistribute it and/or modify it under the +terms of the GNU General Public License as published by the Free Software +Foundation; either version 2, or (at your option) any later version. -GNU Make is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. +GNU Make is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR +A PARTICULAR PURPOSE. See the GNU General Public License for more details. -You should have received a copy of the GNU General Public License -along with GNU Make; see the file COPYING. If not, write to -the Free Software Foundation, Inc., 59 Temple Place - Suite 330, -Boston, MA 02111-1307, USA. */ +You should have received a copy of the GNU General Public License along with +GNU Make; see the file COPYING. If not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. */ #include "make.h" @@ -27,6 +26,10 @@ Boston, MA 02111-1307, USA. */ #include "variable.h" #include "rule.h" +/* Initially, any errors reported when expanding strings will be reported + against the file where the error appears. */ +const struct floc **expanding_var = &reading_file; + /* The next two describe the variable output buffer. This buffer is used to hold the variable-expansion of a line of the makefile. It is made bigger with realloc whenever it is too small. @@ -52,9 +55,7 @@ char *variable_buffer; the following call. */ char * -variable_buffer_output (ptr, string, length) - char *ptr, *string; - unsigned int length; +variable_buffer_output (char *ptr, char *string, unsigned int length) { register unsigned int newlen = length + (ptr - variable_buffer); @@ -76,7 +77,7 @@ variable_buffer_output (ptr, string, length) /* Return a pointer to the beginning of the variable buffer. */ static char * -initialize_variable_output () +initialize_variable_output (void) { /* If we don't have a variable output buffer yet, get one. */ @@ -95,18 +96,35 @@ initialize_variable_output () static char *allocated_variable_append PARAMS ((const struct variable *v)); char * -recursively_expand_for_file (v, file) - struct variable *v; - struct file *file; +recursively_expand_for_file (struct variable *v, struct file *file) { char *value; + const struct floc *this_var; + const struct floc **saved_varp; struct variable_set_list *save = 0; + int set_reading = 0; + + /* Don't install a new location if this location is empty. + This can happen for command-line variables, builtin variables, etc. */ + saved_varp = expanding_var; + if (v->fileinfo.filenm) + { + this_var = &v->fileinfo; + expanding_var = &this_var; + } + + /* If we have no other file-reading context, use the variable's context. */ + if (!reading_file) + { + set_reading = 1; + reading_file = &v->fileinfo; + } if (v->expanding) { if (!v->exp_count) /* Expanding V causes infinite recursion. Lose. */ - fatal (reading_file, + fatal (*expanding_var, _("Recursive variable `%s' references itself (eventually)"), v->name); --v->exp_count; @@ -125,9 +143,14 @@ recursively_expand_for_file (v, file) value = allocated_variable_expand (v->value); v->expanding = 0; + if (set_reading) + reading_file = 0; + if (file) current_variable_set_list = save; + expanding_var = saved_varp; + return value; } @@ -137,10 +160,7 @@ recursively_expand_for_file (v, file) __inline #endif static char * -reference_variable (o, name, length) - char *o; - char *name; - unsigned int length; +reference_variable (char *o, char *name, unsigned int length) { register struct variable *v; char *value; @@ -150,7 +170,8 @@ reference_variable (o, name, length) if (v == 0) warn_undefined (name, length); - if (v == 0 || *v->value == '\0') + /* If there's no variable by that name or it has no value, stop now. */ + if (v == 0 || (*v->value == '\0' && !v->append)) return o; value = (v->recursive ? recursively_expand (v) : v->value); @@ -173,10 +194,7 @@ reference_variable (o, name, length) NULL. */ char * -variable_expand_string (line, string, length) - register char *line; - char *string; - long length; +variable_expand_string (char *line, char *string, long length) { register struct variable *v; register char *p, *o, *p1; @@ -204,7 +222,7 @@ variable_expand_string (line, string, length) p1 = strchr (p, '$'); - o = variable_buffer_output (o, p, p1 != 0 ? p1 - p : strlen (p) + 1); + o = variable_buffer_output (o, p, p1 != 0 ? (unsigned int)(p1 - p) : strlen (p) + 1); if (p1 == 0) break; @@ -245,7 +263,7 @@ variable_expand_string (line, string, length) end = strchr (beg, closeparen); if (end == 0) /* Unterminated variable reference. */ - fatal (reading_file, _("unterminated variable reference")); + fatal (*expanding_var, _("unterminated variable reference")); p1 = lindex (beg, end, '$'); if (p1 != 0) { @@ -286,7 +304,7 @@ variable_expand_string (line, string, length) char *subst_beg, *subst_end, *replace_beg, *replace_end; subst_beg = colon + 1; - subst_end = strchr (subst_beg, '='); + subst_end = lindex (subst_beg, end, '='); if (subst_end == 0) /* There is no = in sight. Punt on the substitution reference and treat this as a variable name containing @@ -303,51 +321,49 @@ variable_expand_string (line, string, length) if (v == 0) warn_undefined (beg, colon - beg); + /* If the variable is not empty, perform the + substitution. */ if (v != 0 && *v->value != '\0') { - char *value = (v->recursive ? recursively_expand (v) + char *pattern, *replace, *ppercent, *rpercent; + char *value = (v->recursive + ? recursively_expand (v) : v->value); - char *pattern, *percent; - if (free_beg) - { - *subst_end = '\0'; - pattern = subst_beg; - } - else - { - pattern = (char *) alloca (subst_end - subst_beg - + 1); - bcopy (subst_beg, pattern, subst_end - subst_beg); - pattern[subst_end - subst_beg] = '\0'; - } - percent = find_percent (pattern); - if (percent != 0) - { - char *replace; - if (free_beg) - { - *replace_end = '\0'; - replace = replace_beg; - } - else - { - replace = (char *) alloca (replace_end - - replace_beg - + 1); - bcopy (replace_beg, replace, - replace_end - replace_beg); - replace[replace_end - replace_beg] = '\0'; - } - o = patsubst_expand (o, value, pattern, replace, - percent, (char *) 0); - } + /* Copy the pattern and the replacement. Add in an + extra % at the beginning to use in case there + isn't one in the pattern. */ + pattern = (char *) alloca (subst_end - subst_beg + 2); + *(pattern++) = '%'; + bcopy (subst_beg, pattern, subst_end - subst_beg); + pattern[subst_end - subst_beg] = '\0'; + + replace = (char *) alloca (replace_end + - replace_beg + 2); + *(replace++) = '%'; + bcopy (replace_beg, replace, + replace_end - replace_beg); + replace[replace_end - replace_beg] = '\0'; + + /* Look for %. Set the percent pointers properly + based on whether we find one or not. */ + ppercent = find_percent (pattern); + if (ppercent) + { + ++ppercent; + rpercent = 0; + } else - o = subst_expand (o, value, - pattern, replace_beg, - strlen (pattern), - end - replace_beg, - 0, 1); + { + ppercent = pattern; + rpercent = replace; + --pattern; + --replace; + } + + o = patsubst_expand (o, value, pattern, replace, + ppercent, rpercent); + if (v->recursive) free (value); } @@ -373,19 +389,7 @@ variable_expand_string (line, string, length) /* A $ followed by a random char is a variable reference: $a is equivalent to $(a). */ - { - /* We could do the expanding here, but this way - avoids code repetition at a small performance cost. */ - char name[5]; - name[0] = '$'; - name[1] = '('; - name[2] = *p; - name[3] = ')'; - name[4] = '\0'; - p1 = allocated_variable_expand (name); - o = variable_buffer_output (o, p1, strlen (p1)); - free (p1); - } + o = reference_variable (o, p, 1); break; } @@ -409,8 +413,7 @@ variable_expand_string (line, string, length) and is valid only until the next time this function is called. */ char * -variable_expand (line) - char *line; +variable_expand (char *line) { return variable_expand_string(NULL, line, (long)-1); } @@ -422,8 +425,7 @@ variable_expand (line) variable-expansion that is in progress. */ char * -expand_argument (str, end) - char *str, *end; +expand_argument (const char *str, const char *end) { char *tmp; @@ -431,13 +433,11 @@ expand_argument (str, end) return xstrdup(""); if (!end || *end == '\0') - tmp = str; - else - { - tmp = (char *) alloca (end - str + 1); - bcopy (str, tmp, end - str); - tmp[end - str] = '\0'; - } + return allocated_variable_expand ((char *)str); + + tmp = (char *) alloca (end - str + 1); + bcopy (str, tmp, end - str); + tmp[end - str] = '\0'; return allocated_variable_expand (tmp); } @@ -445,10 +445,8 @@ expand_argument (str, end) /* Expand LINE for FILE. Error messages refer to the file and line where FILE's commands were found. Expansion uses FILE's variable set list. */ -static char * -variable_expand_for_file (line, file) - char *line; - register struct file *file; +char * +variable_expand_for_file (char *line, struct file *file) { char *result; struct variable_set_list *save; @@ -474,10 +472,8 @@ variable_expand_for_file (line, file) any upper variable sets. Then expand the resulting value. */ static char * -variable_append (name, length, set) - const char *name; - unsigned int length; - const struct variable_set_list *set; +variable_append (const char *name, unsigned int length, + const struct variable_set_list *set) { const struct variable *v; char *buf = 0; @@ -505,15 +501,19 @@ variable_append (name, length, set) if (buf > variable_buffer) buf = variable_buffer_output (buf, " ", 1); - return variable_buffer_output (buf, v->value, strlen (v->value)); + /* Either expand it or copy it, depending. */ + if (! v->recursive) + return variable_buffer_output (buf, v->value, strlen (v->value)); + + buf = variable_expand_string (buf, v->value, strlen (v->value)); + return (buf + strlen (buf)); } static char * -allocated_variable_append (v) - const struct variable *v; +allocated_variable_append (const struct variable *v) { - char *val, *retval; + char *val; /* Construct the appended variable value. */ @@ -529,21 +529,14 @@ allocated_variable_append (v) variable_buffer = obuf; variable_buffer_length = olen; - /* Now expand it and return that. */ - - retval = allocated_variable_expand (val); - - free (val); - return retval; + return val; } /* Like variable_expand_for_file, but the returned string is malloc'd. This function is called a lot. It wants to be efficient. */ char * -allocated_variable_expand_for_file (line, file) - char *line; - struct file *file; +allocated_variable_expand_for_file (char *line, struct file *file) { char *value; @@ -564,3 +557,28 @@ allocated_variable_expand_for_file (line, file) return value; } + +/* Install a new variable_buffer context, returning the current one for + safe-keeping. */ + +void +install_variable_buffer (char **bufp, unsigned int *lenp) +{ + *bufp = variable_buffer; + *lenp = variable_buffer_length; + + variable_buffer = 0; + initialize_variable_output (); +} + +/* Restore a previously-saved variable_buffer setting (free the current one). + */ + +void +restore_variable_buffer (char *buf, unsigned int len) +{ + free (variable_buffer); + + variable_buffer = buf; + variable_buffer_length = len; +} diff --git a/src/bin/make/file.c b/src/bin/make/file.c index ce1a0f9f6c..90dd123058 100644 --- a/src/bin/make/file.c +++ b/src/bin/make/file.c @@ -1,22 +1,20 @@ -/* Target file hash table management for GNU Make. +/* Target file management for GNU Make. Copyright (C) 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, -2002 Free Software Foundation, Inc. +1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006 Free Software +Foundation, Inc. This file is part of GNU Make. -GNU Make is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 2, or (at your option) -any later version. +GNU Make is free software; you can redistribute it and/or modify it under the +terms of the GNU General Public License as published by the Free Software +Foundation; either version 2, or (at your option) any later version. -GNU Make is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. +GNU Make is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR +A PARTICULAR PURPOSE. See the GNU General Public License for more details. -You should have received a copy of the GNU General Public License -along with GNU Make; see the file COPYING. If not, write to -the Free Software Foundation, Inc., 59 Temple Place - Suite 330, -Boston, MA 02111-1307, USA. */ +You should have received a copy of the GNU General Public License along with +GNU Make; see the file COPYING. If not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. */ #include "make.h" @@ -31,26 +29,31 @@ 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 -file_hash_1 (key) - const void *key; +file_hash_1 (const void *key) { return_ISTRING_HASH_1 (((struct file const *) key)->hname); } static unsigned long -file_hash_2 (key) - const void *key; +file_hash_2 (const void *key) { return_ISTRING_HASH_2 (((struct file const *) key)->hname); } static int -file_hash_cmp (x, y) - const void *x; - const void *y; +file_hash_cmp (const void *x, const void *y) { return_ISTRING_COMPARE (((struct file const *) x)->hname, ((struct file const *) y)->hname); @@ -70,8 +73,7 @@ static int all_secondary = 0; enter_file similar, but create one if there is none. */ struct file * -lookup_file (name) - char *name; +lookup_file (char *name) { register struct file *f; struct file file_key; @@ -86,14 +88,15 @@ lookup_file (name) on the command line. */ #ifdef VMS # ifndef WANT_CASE_SENSITIVE_TARGETS - { - register char *n; - lname = (char *) malloc (strlen (name) + 1); - for (n = name, ln = lname; *n != '\0'; ++n, ++ln) - *ln = isupper ((unsigned char)*n) ? tolower ((unsigned char)*n) : *n; - *ln = '\0'; - name = lname; - } + if (*name != '.') + { + register char *n; + lname = (char *) malloc (strlen (name) + 1); + for (n = name, ln = lname; *n != '\0'; ++n, ++ln) + *ln = isupper ((unsigned char)*n) ? tolower ((unsigned char)*n) : *n; + *ln = '\0'; + name = lname; + } # endif while (name[0] == '[' && name[1] == ']' && name[2] != '\0') @@ -122,14 +125,14 @@ lookup_file (name) file_key.hname = name; f = (struct file *) hash_find_item (&files, &file_key); #if defined(VMS) && !defined(WANT_CASE_SENSITIVE_TARGETS) - free (lname); + if (*name != '.') + free (lname); #endif return f; } struct file * -enter_file (name) - char *name; +enter_file (char *name) { register struct file *f; register struct file *new; @@ -142,22 +145,23 @@ enter_file (name) assert (*name != '\0'); #if defined(VMS) && !defined(WANT_CASE_SENSITIVE_TARGETS) - { - register char *n; - lname = (char *) malloc (strlen (name) + 1); - for (n = name, ln = lname; *n != '\0'; ++n, ++ln) - { - if (isupper ((unsigned char)*n)) - *ln = tolower ((unsigned char)*n); - else - *ln = *n; - } + if (*name != '.') + { + register char *n; + lname = (char *) malloc (strlen (name) + 1); + for (n = name, ln = lname; *n != '\0'; ++n, ++ln) + { + if (isupper ((unsigned char)*n)) + *ln = tolower ((unsigned char)*n); + else + *ln = *n; + } - *ln = 0; - /* Creates a possible leak, old value of name is unreachable, but I - currently don't know how to fix it. */ - name = lname; - } + *ln = 0; + /* Creates a possible leak, old value of name is unreachable, but I + currently don't know how to fix it. */ + name = lname; + } #endif file_key.hname = name; @@ -166,7 +170,8 @@ enter_file (name) if (! HASH_VACANT (f) && !f->double_colon) { #if defined(VMS) && !defined(WANT_CASE_SENSITIVE_TARGETS) - free(lname); + if (*name != '.') + free (lname); #endif return f; } @@ -177,14 +182,16 @@ enter_file (name) new->update_status = -1; if (HASH_VACANT (f)) - hash_insert_at (&files, new, file_slot); + { + new->last = new; + hash_insert_at (&files, new, file_slot); + } else { /* There is already a double-colon entry for this file. */ new->double_colon = f; - while (f->prev != 0) - f = f->prev; - f->prev = new; + f->last->prev = new; + f->last = new; } return new; @@ -195,9 +202,7 @@ enter_file (name) and possibly merged with an existing file called NAME. */ void -rename_file (from_file, to_hname) - register struct file *from_file; - char *to_hname; +rename_file (struct file *from_file, char *to_hname) { rehash_file (from_file, to_hname); while (from_file) @@ -212,9 +217,7 @@ rename_file (from_file, to_hname) and possibly merged with an existing file called NAME. */ void -rehash_file (from_file, to_hname) - register struct file *from_file; - char *to_hname; +rehash_file (struct file *from_file, char *to_hname) { struct file file_key; struct file **file_slot; @@ -333,8 +336,7 @@ rehash_file (from_file, to_hname) the message will go to stderr rather than stdout. */ void -remove_intermediates (sig) - int sig; +remove_intermediates (int sig) { register struct file **file_slot; register struct file **file_end; @@ -353,6 +355,10 @@ remove_intermediates (sig) if (! HASH_VACANT (*file_slot)) { register struct file *f = *file_slot; + /* Is this file eligible for automatic deletion? + Yes, IFF: it's marked intermediate, it's not secondary, it wasn't + given on the command-line, and it's either a -include makefile or + it's not precious. */ if (f->intermediate && (f->dontcare || !f->precious) && !f->secondary && !f->cmd_target) { @@ -403,6 +409,216 @@ remove_intermediates (sig) } } +struct dep * +parse_prereqs (char *p) +{ + struct dep *new = (struct dep *) + multi_glob (parse_file_seq (&p, '|', sizeof (struct dep), 1), + sizeof (struct dep)); + + if (*p) + { + /* Files that follow '|' are "order-only" prerequisites that satisfy the + dependency by existing: their modification times are irrelevant. */ + struct dep *ood; + + ++p; + ood = (struct dep *) + multi_glob (parse_file_seq (&p, '\0', sizeof (struct dep), 1), + sizeof (struct dep)); + + if (! new) + new = ood; + else + { + struct dep *dp; + for (dp = new; dp->next != NULL; dp = dp->next) + ; + dp->next = ood; + } + + for (; ood != NULL; ood = ood->next) + ood->ignore_mtime = 1; + } + + return new; +} + + +/* Set the intermediate flag. */ + +static void +set_intermediate (const void *item) +{ + struct file *f = (struct file *) item; + f->intermediate = 1; +} + +/* Expand and parse each dependency line. */ +static void +expand_deps (struct file *f) +{ + struct dep *d; + struct dep *old = f->deps; + char *file_stem = f->stem; + unsigned int last_dep_has_cmds = f->updating; + int initialized = 0; + + f->updating = 0; + f->deps = 0; + + for (d = old; d != 0; d = d->next) + { + struct dep *new, *d1; + char *p; + + if (! d->name) + continue; + + /* Create the dependency list. + If we're not doing 2nd expansion, then it's just the name. */ + if (! d->need_2nd_expansion) + p = d->name; + else + { + /* If it's from a static pattern rule, convert the patterns into + "$*" so they'll expand properly. */ + if (d->staticpattern) + { + char *o; + char *buffer = variable_expand (""); + + o = subst_expand (buffer, d->name, "%", "$*", 1, 2, 0); + + free (d->name); + d->name = savestring (buffer, o - buffer); + d->staticpattern = 0; /* Clear staticpattern so that we don't + re-expand %s below. */ + } + + /* We are going to do second expansion so initialize file variables + for the file. Since the stem for static pattern rules comes from + individual dep lines, we will temporarily set f->stem to d->stem. + */ + if (!initialized) + { + initialize_file_variables (f, 0); + initialized = 1; + } + + if (d->stem != 0) + f->stem = d->stem; + + set_file_variables (f); + + p = variable_expand_for_file (d->name, f); + + if (d->stem != 0) + f->stem = file_stem; + } + + /* Parse the prerequisites. */ + new = parse_prereqs (p); + + /* If this dep list was from a static pattern rule, expand the %s. We + use patsubst_expand to translate the prerequisites' patterns into + plain prerequisite names. */ + if (new && d->staticpattern) + { + char *pattern = "%"; + char *buffer = variable_expand (""); + struct dep *dp = new, *dl = 0; + + while (dp != 0) + { + char *percent = find_percent (dp->name); + if (percent) + { + /* We have to handle empty stems specially, because that + would be equivalent to $(patsubst %,dp->name,) which + will always be empty. */ + if (d->stem[0] == '\0') + /* This needs memmove() in ISO C. */ + bcopy (percent+1, percent, strlen (percent)); + else + { + char *o = patsubst_expand (buffer, d->stem, pattern, + dp->name, pattern+1, + percent+1); + if (o == buffer) + dp->name[0] = '\0'; + else + { + free (dp->name); + dp->name = savestring (buffer, o - buffer); + } + } + + /* If the name expanded to the empty string, ignore it. */ + if (dp->name[0] == '\0') + { + struct dep *df = dp; + if (dp == new) + dp = new = new->next; + else + dp = dl->next = dp->next; + /* @@ Are we leaking df->name here? */ + df->name = 0; + free_dep (df); + continue; + } + } + dl = dp; + dp = dp->next; + } + } + + /* Enter them as files. */ + for (d1 = new; d1 != 0; d1 = d1->next) + { + d1->file = lookup_file (d1->name); + if (d1->file == 0) + d1->file = enter_file (d1->name); + else + free (d1->name); + d1->name = 0; + d1->staticpattern = 0; + d1->need_2nd_expansion = 0; + } + + /* Add newly parsed deps to f->deps. If this is the last dependency + line and this target has commands then put it in front so the + last dependency line (the one with commands) ends up being the + first. This is important because people expect $< to hold first + prerequisite from the rule with commands. If it is not the last + dependency line or the rule does not have commands then link it + at the end so it appears in makefile order. */ + + if (new != 0) + { + if (d->next == 0 && last_dep_has_cmds) + { + struct dep **d_ptr; + for (d_ptr = &new; *d_ptr; d_ptr = &(*d_ptr)->next) + ; + + *d_ptr = f->deps; + f->deps = new; + } + else + { + struct dep **d_ptr; + for (d_ptr = &f->deps; *d_ptr; d_ptr = &(*d_ptr)->next) + ; + + *d_ptr = new; + } + } + } + + free_dep_chain (old); +} + /* For each dependency of each file, make the `struct dep' point at the appropriate `struct file' (which may have to be created). @@ -410,33 +626,34 @@ remove_intermediates (sig) and various other special targets. */ void -snap_deps () +snap_deps (void) { - register struct file *f; - register struct file *f2; - register struct dep *d; - register struct file **file_slot_0; - register struct file **file_slot; - register struct file **file_end; + struct file *f; + struct file *f2; + struct dep *d; + struct file **file_slot_0; + struct file **file_slot; + struct file **file_end; + + /* Perform second expansion and enter each dependency + name as a file. */ + + /* Expand .SUFFIXES first; it's dependencies are used for + $$* calculation. */ + for (f = lookup_file (".SUFFIXES"); f != 0; f = f->prev) + expand_deps (f); - /* Enter each dependency name as a file. */ /* We must use hash_dump (), because within this loop we might add new files to the table, possibly causing an in-situ table expansion. */ file_slot_0 = (struct file **) hash_dump (&files, 0, 0); file_end = file_slot_0 + files.ht_fill; for (file_slot = file_slot_0; file_slot < file_end; file_slot++) - for (f2 = *file_slot; f2 != 0; f2 = f2->prev) - for (d = f2->deps; d != 0; d = d->next) - if (d->name != 0) - { - d->file = lookup_file (d->name); - if (d->file == 0) - d->file = enter_file (d->name); - else - free (d->name); - d->name = 0; - } + for (f = *file_slot; f != 0; f = f->prev) + { + if (strcmp (f->name, ".SUFFIXES") != 0) + expand_deps (f); + } free (file_slot_0); for (f = lookup_file (".PRECIOUS"); f != 0; f = f->prev) @@ -453,8 +670,9 @@ snap_deps () for (d = f->deps; d != 0; d = d->next) for (f2 = d->file; f2 != 0; f2 = f2->prev) { - /* Mark this file as phony and nonexistent. */ + /* Mark this file as phony nonexistent target. */ f2->phony = 1; + f2->is_target = 1; f2->last_mtime = NONEXISTENT_MTIME; f2->mtime_before_update = NONEXISTENT_MTIME; } @@ -484,7 +702,10 @@ snap_deps () f2->intermediate = f2->secondary = 1; /* .SECONDARY with no deps listed marks *all* files that way. */ else - all_secondary = 1; + { + all_secondary = 1; + hash_map (&files, set_intermediate); + } } f = lookup_file (".EXPORT_ALL_VARIABLES"); @@ -513,21 +734,26 @@ snap_deps () f2->command_flags |= COMMANDS_SILENT; } - f = lookup_file (".POSIX"); - if (f != 0 && f->is_target) - posix_pedantic = 1; - f = lookup_file (".NOTPARALLEL"); if (f != 0 && f->is_target) not_parallel = 1; + +#ifndef NO_MINUS_C_MINUS_O + /* If .POSIX was defined, remove OUTPUT_OPTION to comply. */ + /* This needs more work: what if the user sets this in the makefile? + if (posix_pedantic) + define_variable (STRING_SIZE_TUPLE("OUTPUT_OPTION"), "", o_default, 1); + */ +#endif + + /* Remember that we've done this. */ + snapped_deps = 1; } /* Set the `command_state' member of FILE and all its `also_make's. */ void -set_command_state (file, state) - struct file *file; - int state; +set_command_state (struct file *file, enum cmd_state state) { struct dep *d; @@ -540,10 +766,7 @@ set_command_state (file, state) /* Convert an external file timestamp to internal form. */ FILE_TIMESTAMP -file_timestamp_cons (fname, s, ns) - char const *fname; - time_t s; - int ns; +file_timestamp_cons (const char *fname, time_t s, int ns) { int offset = ORDINARY_MTIME_MIN + (FILE_TIMESTAMP_HI_RES ? ns : 0); FILE_TIMESTAMP product = (FILE_TIMESTAMP) s << FILE_TIMESTAMP_LO_BITS; @@ -565,8 +788,7 @@ file_timestamp_cons (fname, s, ns) /* Return the current time as a file timestamp, setting *RESOLUTION to its resolution. */ FILE_TIMESTAMP -file_timestamp_now (resolution) - int *resolution; +file_timestamp_now (int *resolution) { int r; time_t s; @@ -606,7 +828,9 @@ file_timestamp_now (resolution) s = time ((time_t *) 0); ns = 0; +#if FILE_TIMESTAMP_HI_RES got_time: +#endif *resolution = r; return file_timestamp_cons (0, s, ns); } @@ -614,9 +838,7 @@ file_timestamp_now (resolution) /* Place into the buffer P a printable representation of the file timestamp TS. */ void -file_timestamp_sprintf (p, ts) - char *p; - FILE_TIMESTAMP ts; +file_timestamp_sprintf (char *p, FILE_TIMESTAMP ts) { time_t t = FILE_TIMESTAMP_S (ts); struct tm *tm = localtime (&t); @@ -648,9 +870,9 @@ file_timestamp_sprintf (p, ts) /* Print the data base of files. */ static void -print_file (f) - struct file *f; +print_file (const void *item) { + struct file *f = (struct file *) item; struct dep *d; struct dep *ood = 0; @@ -684,7 +906,7 @@ print_file (f) if (f->cmd_target) puts (_("# Command-line target.")); if (f->dontcare) - puts (_("# A default or MAKEFILES makefile.")); + puts (_("# A default, MAKEFILES, or -include/sinclude makefile.")); puts (f->tried_implicit ? _("# Implicit rule search has been done.") : _("# Implicit rule search has not been done.")); @@ -756,10 +978,13 @@ print_file (f) if (f->cmds != 0) print_commands (f->cmds); + + if (f->prev) + print_file ((const void *) f->prev); } void -print_file_data_base () +print_file_data_base (void) { puts (_("\n# Files")); @@ -772,8 +997,7 @@ print_file_data_base () #define EXPANSION_INCREMENT(_l) ((((_l) / 500) + 1) * 500) char * -build_target_list (value) - char *value; +build_target_list (char *value) { static unsigned long last_targ_count = 0; @@ -819,7 +1043,7 @@ build_target_list (value) } void -init_hash_files () +init_hash_files (void) { hash_init (&files, 1000, file_hash_1, file_hash_2, file_hash_cmp); } diff --git a/src/bin/make/filedef.h b/src/bin/make/filedef.h index b7d6e6769d..e4fe7c970f 100644 --- a/src/bin/make/filedef.h +++ b/src/bin/make/filedef.h @@ -1,22 +1,20 @@ /* Definition of target file data structures for GNU Make. -Copyright (C) 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1997, -2002 Free Software Foundation, Inc. +Copyright (C) 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, +1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006 Free Software +Foundation, Inc. This file is part of GNU Make. -GNU Make is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 2, or (at your option) -any later version. +GNU Make is free software; you can redistribute it and/or modify it under the +terms of the GNU General Public License as published by the Free Software +Foundation; either version 2, or (at your option) any later version. -GNU Make is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. +GNU Make is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR +A PARTICULAR PURPOSE. See the GNU General Public License for more details. -You should have received a copy of the GNU General Public License -along with GNU Make; see the file COPYING. If not, write to -the Free Software Foundation, Inc., 59 Temple Place - Suite 330, -Boston, MA 02111-1307, USA. */ +You should have received a copy of the GNU General Public License along with +GNU Make; see the file COPYING. If not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. */ /* Structure that represents the info on one file @@ -42,6 +40,7 @@ struct file struct file *prev; /* Previous entry for same file name; used when there are multiple double-colon entries for the same file. */ + struct file *last; /* Last entry for the same file name. */ /* File that this file was renamed to. After any time that a file could be renamed, call `check_renamed' (below). */ @@ -65,7 +64,7 @@ struct file short int update_status; /* Status of the last attempt to update, or -1 if none has been made. */ - enum /* State of the commands. */ + enum cmd_state /* State of the commands. */ { /* Note: It is important that cs_not_started be zero. */ cs_not_started, /* Not yet started. */ cs_deps_running, /* Dep commands running. */ @@ -84,31 +83,32 @@ struct file unsigned int is_target:1; /* Nonzero if file is described as target. */ unsigned int cmd_target:1; /* Nonzero if file was given on cmd line. */ unsigned int phony:1; /* Nonzero if this is a phony file - i.e., a dependency of .PHONY. */ + i.e., a prerequisite of .PHONY. */ unsigned int intermediate:1;/* Nonzero if this is an intermediate file. */ - /* Nonzero, for an intermediate file, - means remove_intermediates should not delete it. */ - unsigned int secondary:1; + unsigned int secondary:1; /* Nonzero means remove_intermediates should + not delete it. */ unsigned int dontcare:1; /* Nonzero if no complaint is to be made if this target cannot be remade. */ unsigned int ignore_vpath:1;/* Nonzero if we threw out VPATH name. */ unsigned int pat_searched:1;/* Nonzero if we already searched for pattern-specific variables. */ - unsigned int considered:1; /* equal to `considered' if file has been + unsigned int considered:1; /* equal to 'considered' if file has been considered on current scan of goal chain */ }; extern struct file *default_goal_file, *suffix_file, *default_file; +extern char **default_goal_name; extern struct file *lookup_file PARAMS ((char *name)); extern struct file *enter_file PARAMS ((char *name)); +extern struct dep *parse_prereqs PARAMS ((char *prereqs)); extern void remove_intermediates PARAMS ((int sig)); extern void snap_deps PARAMS ((void)); extern void rename_file PARAMS ((struct file *file, char *name)); extern void rehash_file PARAMS ((struct file *file, char *name)); -extern void set_command_state PARAMS ((struct file *file, int state)); +extern void set_command_state PARAMS ((struct file *file, enum cmd_state state)); extern void notice_finished_file PARAMS ((struct file *file)); extern void init_hash_files PARAMS ((void)); extern char *build_target_list PARAMS ((char *old_list)); @@ -197,3 +197,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/src/bin/make/function.c b/src/bin/make/function.c index cf646d6fba..c62f7abc92 100644 --- a/src/bin/make/function.c +++ b/src/bin/make/function.c @@ -1,21 +1,20 @@ /* Builtin function expansion for GNU Make. -Copyright (C) 1988, 1989, 1991-1997, 1999, 2002 Free Software Foundation, Inc. +Copyright (C) 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, +1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006 Free Software +Foundation, Inc. This file is part of GNU Make. -GNU Make is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 2, or (at your option) -any later version. +GNU Make is free software; you can redistribute it and/or modify it under the +terms of the GNU General Public License as published by the Free Software +Foundation; either version 2, or (at your option) any later version. -GNU Make is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. +GNU Make is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR +A PARTICULAR PURPOSE. See the GNU General Public License for more details. -You should have received a copy of the GNU General Public License -along with GNU Make; see the file COPYING. If not, write to -the Free Software Foundation, Inc., 59 Temple Place - Suite 330, -Boston, MA 02111-1307, USA. */ +You should have received a copy of the GNU General Public License along with +GNU Make; see the file COPYING. If not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. */ #include "make.h" #include "filedef.h" @@ -41,25 +40,21 @@ struct function_table_entry }; static unsigned long -function_table_entry_hash_1 (keyv) - const void *keyv; +function_table_entry_hash_1 (const void *keyv) { struct function_table_entry const *key = (struct function_table_entry const *) keyv; return_STRING_N_HASH_1 (key->name, key->len); } static unsigned long -function_table_entry_hash_2 (keyv) - const void *keyv; +function_table_entry_hash_2 (const void *keyv) { struct function_table_entry const *key = (struct function_table_entry const *) keyv; return_STRING_N_HASH_2 (key->name, key->len); } static int -function_table_entry_hash_cmp (xv, yv) - const void *xv; - const void *yv; +function_table_entry_hash_cmp (const void *xv, const void *yv) { struct function_table_entry const *x = (struct function_table_entry const *) xv; struct function_table_entry const *y = (struct function_table_entry const *) yv; @@ -76,21 +71,16 @@ static struct hash_table function_table; each occurrence of SUBST with REPLACE. TEXT is null-terminated. SLEN is the length of SUBST and RLEN is the length of REPLACE. If BY_WORD is nonzero, substitutions are done only on matches which are complete - whitespace-delimited words. If SUFFIX_ONLY is nonzero, substitutions are - done only at the ends of whitespace-delimited words. */ + whitespace-delimited words. */ char * -subst_expand (o, text, subst, replace, slen, rlen, by_word, suffix_only) - char *o; - char *text; - char *subst, *replace; - unsigned int slen, rlen; - int by_word, suffix_only; +subst_expand (char *o, char *text, char *subst, char *replace, + unsigned int slen, unsigned int rlen, int by_word) { - register char *t = text; - register char *p; + char *t = text; + char *p; - if (slen == 0 && !by_word && !suffix_only) + if (slen == 0 && !by_word) { /* The first occurrence of "" in any string is its end. */ o = variable_buffer_output (o, t, strlen (t)); @@ -101,13 +91,13 @@ subst_expand (o, text, subst, replace, slen, rlen, by_word, suffix_only) do { - if ((by_word | suffix_only) && slen == 0) + if (by_word && slen == 0) /* When matching by words, the empty string should match the end of each word, rather than the end of the whole text. */ p = end_of_token (next_token (t)); else { - p = sindex (t, 0, subst, slen); + p = strstr (t, subst); if (p == 0) { /* No more matches. Output everything left on the end. */ @@ -122,11 +112,9 @@ subst_expand (o, text, subst, replace, slen, rlen, by_word, suffix_only) /* If we're substituting only by fully matched words, or only at the ends of words, check that this case qualifies. */ - if ((by_word - && ((p > t && !isblank ((unsigned char)p[-1])) - || (p[slen] != '\0' && !isblank ((unsigned char)p[slen])))) - || (suffix_only - && (p[slen] != '\0' && !isblank ((unsigned char)p[slen])))) + if (by_word + && ((p > text && !isblank ((unsigned char)p[-1])) + || (p[slen] != '\0' && !isblank ((unsigned char)p[slen])))) /* Struck out. Output the rest of the string that is no longer to be replaced. */ o = variable_buffer_output (o, subst, slen); @@ -135,60 +123,73 @@ subst_expand (o, text, subst, replace, slen, rlen, by_word, suffix_only) o = variable_buffer_output (o, replace, rlen); /* Advance T past the string to be replaced. */ - t = p + slen; + { + char *nt = p + slen; + t = nt; + } } while (*t != '\0'); return o; } - + /* Store into VARIABLE_BUFFER at O the result of scanning TEXT and replacing strings matching PATTERN with REPLACE. If PATTERN_PERCENT is not nil, PATTERN has already been run through find_percent, and PATTERN_PERCENT is the result. If REPLACE_PERCENT is not nil, REPLACE has already been - run through find_percent, and REPLACE_PERCENT is the result. */ + run through find_percent, and REPLACE_PERCENT is the result. + Note that we expect PATTERN_PERCENT and REPLACE_PERCENT to point to the + character _AFTER_ the %, not to the % itself. +*/ char * -patsubst_expand (o, text, pattern, replace, pattern_percent, replace_percent) - char *o; - char *text; - register char *pattern, *replace; - register char *pattern_percent, *replace_percent; +patsubst_expand (char *o, char *text, char *pattern, char *replace, + char *pattern_percent, char *replace_percent) { unsigned int pattern_prepercent_len, pattern_postpercent_len; - unsigned int replace_prepercent_len, replace_postpercent_len = 0; + unsigned int replace_prepercent_len, replace_postpercent_len; char *t; unsigned int len; int doneany = 0; /* We call find_percent on REPLACE before checking PATTERN so that REPLACE will be collapsed before we call subst_expand if PATTERN has no %. */ - if (replace_percent == 0) - replace_percent = find_percent (replace); - if (replace_percent != 0) + if (!replace_percent) { - /* Record the length of REPLACE before and after the % so - we don't have to compute these lengths more than once. */ - replace_prepercent_len = replace_percent - replace; - replace_postpercent_len = strlen (replace_percent + 1); + replace_percent = find_percent (replace); + if (replace_percent) + ++replace_percent; + } + + /* Record the length of REPLACE before and after the % so we don't have to + compute these lengths more than once. */ + if (replace_percent) + { + replace_prepercent_len = replace_percent - replace - 1; + replace_postpercent_len = strlen (replace_percent); } else - /* We store the length of the replacement - so we only need to compute it once. */ - replace_prepercent_len = strlen (replace); + { + replace_prepercent_len = strlen (replace); + replace_postpercent_len = 0; + } - if (pattern_percent == 0) - pattern_percent = find_percent (pattern); - if (pattern_percent == 0) + if (!pattern_percent) + { + pattern_percent = find_percent (pattern); + if (pattern_percent) + ++pattern_percent; + } + if (!pattern_percent) /* With no % in the pattern, this is just a simple substitution. */ return subst_expand (o, text, pattern, replace, - strlen (pattern), strlen (replace), 1, 0); + strlen (pattern), strlen (replace), 1); /* Record the length of PATTERN before and after the % so we don't have to compute it more than once. */ - pattern_prepercent_len = pattern_percent - pattern; - pattern_postpercent_len = strlen (pattern_percent + 1); + pattern_prepercent_len = pattern_percent - pattern - 1; + pattern_postpercent_len = strlen (pattern_percent); while ((t = find_next_token (&text, &len)) != 0) { @@ -201,16 +202,16 @@ patsubst_expand (o, text, pattern, replace, pattern_percent, replace_percent) /* Does the prefix match? */ if (!fail && pattern_prepercent_len > 0 && (*t != *pattern - || t[pattern_prepercent_len - 1] != pattern_percent[-1] + || t[pattern_prepercent_len - 1] != pattern_percent[-2] || !strneq (t + 1, pattern + 1, pattern_prepercent_len - 1))) fail = 1; /* Does the suffix match? */ if (!fail && pattern_postpercent_len > 0 - && (t[len - 1] != pattern_percent[pattern_postpercent_len] - || t[len - pattern_postpercent_len] != pattern_percent[1] + && (t[len - 1] != pattern_percent[pattern_postpercent_len - 1] + || t[len - pattern_postpercent_len] != *pattern_percent || !strneq (&t[len - pattern_postpercent_len], - &pattern_percent[1], pattern_postpercent_len - 1))) + pattern_percent, pattern_postpercent_len - 1))) fail = 1; if (fail) @@ -231,7 +232,7 @@ patsubst_expand (o, text, pattern, replace, pattern_percent, replace_percent) len - (pattern_prepercent_len + pattern_postpercent_len)); /* Output the part of the replacement after the %. */ - o = variable_buffer_output (o, replace_percent + 1, + o = variable_buffer_output (o, replace_percent, replace_postpercent_len); } } @@ -255,8 +256,7 @@ patsubst_expand (o, text, pattern, replace, pattern_percent, replace_percent) /* Look up a function by name. */ static const struct function_table_entry * -lookup_function (s) - const char *s; +lookup_function (const char *s) { const char *e = s; @@ -277,8 +277,7 @@ lookup_function (s) /* Return 1 if PATTERN matches STR, 0 if not. */ int -pattern_matches (pattern, percent, str) - register char *pattern, *percent, *str; +pattern_matches (char *pattern, char *percent, char *str) { unsigned int sfxlen, strlength; @@ -312,11 +311,8 @@ pattern_matches (pattern, percent, str) */ static char * -find_next_argument (startparen, endparen, ptr, end) - char startparen; - char endparen; - const char *ptr; - const char *end; +find_next_argument (char startparen, char endparen, + const char *ptr, const char *end) { int count = 0; @@ -343,8 +339,7 @@ find_next_argument (startparen, endparen, ptr, end) only good until the next call to string_glob. */ static char * -string_glob (line) - char *line; +string_glob (char *line) { static char *result = 0; static unsigned int length; @@ -406,10 +401,7 @@ string_glob (line) */ static char * -func_patsubst (o, argv, funcname) - char *o; - char **argv; - const char *funcname; +func_patsubst (char *o, char **argv, const char *funcname UNUSED) { o = patsubst_expand (o, argv[2], argv[0], argv[1], (char *) 0, (char *) 0); return o; @@ -417,10 +409,7 @@ func_patsubst (o, argv, funcname) static char * -func_join (o, argv, funcname) - char *o; - char **argv; - const char *funcname; +func_join (char *o, char **argv, const char *funcname UNUSED) { int doneany = 0; @@ -460,10 +449,7 @@ func_join (o, argv, funcname) static char * -func_origin (o, argv, funcname) - char *o; - char **argv; - const char *funcname; +func_origin (char *o, char **argv, const char *funcname UNUSED) { /* Expand the argument. */ register struct variable *v = lookup_variable (argv[0], strlen (argv[0])); @@ -502,6 +488,22 @@ func_origin (o, argv, funcname) return o; } +static char * +func_flavor (char *o, char **argv, const char *funcname UNUSED) +{ + register struct variable *v = lookup_variable (argv[0], strlen (argv[0])); + + if (v == 0) + o = variable_buffer_output (o, "undefined", 9); + else + if (v->recursive) + o = variable_buffer_output (o, "recursive", 9); + else + o = variable_buffer_output (o, "simple", 6); + + return o; +} + #ifdef VMS # define IS_PATHSEP(c) ((c) == ']') #else @@ -514,10 +516,7 @@ func_origin (o, argv, funcname) static char * -func_notdir_suffix (o, argv, funcname) - char *o; - char **argv; - const char *funcname; +func_notdir_suffix (char *o, char **argv, const char *funcname) { /* Expand the argument. */ char *list_iterator = argv[0]; @@ -575,10 +574,7 @@ func_notdir_suffix (o, argv, funcname) static char * -func_basename_dir (o, argv, funcname) - char *o; - char **argv; - const char *funcname; +func_basename_dir (char *o, char **argv, const char *funcname) { /* Expand the argument. */ char *p3 = argv[0]; @@ -634,10 +630,7 @@ func_basename_dir (o, argv, funcname) } static char * -func_addsuffix_addprefix (o, argv, funcname) - char *o; - char **argv; - const char *funcname; +func_addsuffix_addprefix (char *o, char **argv, const char *funcname) { int fixlen = strlen (argv[0]); char *list_iterator = argv[1]; @@ -667,23 +660,17 @@ func_addsuffix_addprefix (o, argv, funcname) } static char * -func_subst (o, argv, funcname) - char *o; - char **argv; - const char *funcname; +func_subst (char *o, char **argv, const char *funcname UNUSED) { o = subst_expand (o, argv[2], argv[0], argv[1], strlen (argv[0]), - strlen (argv[1]), 0, 0); + strlen (argv[1]), 0); return o; } static char * -func_firstword (o, argv, funcname) - char *o; - char **argv; - const char *funcname; +func_firstword (char *o, char **argv, const char *funcname UNUSED) { unsigned int i; char *words = argv[0]; /* Use a temp variable for find_next_token */ @@ -695,12 +682,25 @@ func_firstword (o, argv, funcname) return o; } +static char * +func_lastword (char *o, char **argv, const char *funcname UNUSED) +{ + unsigned int i; + char *words = argv[0]; /* Use a temp variable for find_next_token */ + char *p = 0; + char *t; + + while ((t = find_next_token (&words, &i))) + p = t; + + if (p != 0) + o = variable_buffer_output (o, p, i); + + return o; +} static char * -func_words (o, argv, funcname) - char *o; - char **argv; - const char *funcname; +func_words (char *o, char **argv, const char *funcname UNUSED) { int i = 0; char *word_iterator = argv[0]; @@ -716,49 +716,40 @@ func_words (o, argv, funcname) return o; } +/* Set begpp to point to the first non-whitespace character of the string, + * and endpp to point to the last non-whitespace character of the string. + * If the string is empty or contains nothing but whitespace, endpp will be + * begpp-1. + */ char * -strip_whitespace (begpp, endpp) - char **begpp; - char **endpp; +strip_whitespace (const char **begpp, const char **endpp) { - while (isspace ((unsigned char)**begpp) && *begpp <= *endpp) + while (*begpp <= *endpp && isspace ((unsigned char)**begpp)) (*begpp) ++; - while (isspace ((unsigned char)**endpp) && *endpp >= *begpp) + while (*endpp >= *begpp && isspace ((unsigned char)**endpp)) (*endpp) --; - return *begpp; + return (char *)*begpp; } -int -is_numeric (p) - char *p; +static void +check_numeric (const char *s, const char *message) { - char *end = p + strlen (p) - 1; - char *beg = p; - strip_whitespace (&p, &end); + const char *end = s + strlen (s) - 1; + const char *beg = s; + strip_whitespace (&s, &end); - while (p <= end) - if (!ISDIGIT (*(p++))) /* ISDIGIT only evals its arg once: see make.h. */ - return 0; + for (; s <= end; ++s) + if (!ISDIGIT (*s)) /* ISDIGIT only evals its arg once: see make.h. */ + break; - return (end - beg >= 0); -} - -void -check_numeric (s, message) - char *s; - char *message; -{ - if (!is_numeric (s)) - fatal (reading_file, message); + if (s <= end || end - beg < 0) + fatal (*expanding_var, "%s: '%s'", message, beg); } static char * -func_word (o, argv, funcname) - char *o; - char **argv; - const char *funcname; +func_word (char *o, char **argv, const char *funcname UNUSED) { char *end_p=0; int i=0; @@ -769,7 +760,8 @@ func_word (o, argv, funcname) i = atoi (argv[0]); if (i == 0) - fatal (reading_file, _("first argument to `word' function must be greater than 0")); + fatal (*expanding_var, + _("first argument to `word' function must be greater than 0")); end_p = argv[1]; @@ -784,10 +776,7 @@ func_word (o, argv, funcname) } static char * -func_wordlist (o, argv, funcname) - char *o; - char **argv; - const char *funcname; +func_wordlist (char *o, char **argv, const char *funcname UNUSED) { int start, count; @@ -798,6 +787,10 @@ func_wordlist (o, argv, funcname) _("non-numeric second argument to `wordlist' function")); start = atoi (argv[0]); + if (start < 1) + fatal (*expanding_var, + "invalid first argument to `wordlist' function: `%d'", start); + count = atoi (argv[1]) - start + 1; if (count > 0) @@ -824,24 +817,17 @@ func_wordlist (o, argv, funcname) } static char* -func_findstring (o, argv, funcname) - char *o; - char **argv; - const char *funcname; +func_findstring (char *o, char **argv, const char *funcname UNUSED) { /* Find the first occurrence of the first string in the second. */ - int i = strlen (argv[0]); - if (sindex (argv[1], 0, argv[0], i) != 0) - o = variable_buffer_output (o, argv[0], i); + if (strstr (argv[1], argv[0]) != 0) + o = variable_buffer_output (o, argv[0], strlen (argv[0])); return o; } static char * -func_foreach (o, argv, funcname) - char *o; - char **argv; - const char *funcname; +func_foreach (char *o, char **argv, const char *funcname UNUSED) { /* expand only the first two. */ char *varname = expand_argument (argv[0], NULL); @@ -900,23 +886,19 @@ struct a_word }; static unsigned long -a_word_hash_1 (key) - const void *key; +a_word_hash_1 (const void *key) { return_STRING_HASH_1 (((struct a_word const *) key)->str); } static unsigned long -a_word_hash_2 (key) - const void *key; +a_word_hash_2 (const void *key) { return_STRING_HASH_2 (((struct a_word const *) key)->str); } static int -a_word_hash_cmp (x, y) - const void *x; - const void *y; +a_word_hash_cmp (const void *x, const void *y) { int result = ((struct a_word const *) x)->length - ((struct a_word const *) y)->length; if (result) @@ -935,10 +917,7 @@ struct a_pattern }; static char * -func_filter_filterout (o, argv, funcname) - char *o; - char **argv; - const char *funcname; +func_filter_filterout (char *o, char **argv, const char *funcname) { struct a_word *wordhead; struct a_word **wordtail; @@ -1068,10 +1047,7 @@ func_filter_filterout (o, argv, funcname) static char * -func_strip (o, argv, funcname) - char *o; - char **argv; - const char *funcname; +func_strip (char *o, char **argv, const char *funcname UNUSED) { char *p = argv[0]; int doneany =0; @@ -1103,10 +1079,7 @@ func_strip (o, argv, funcname) Print a warning or fatal message. */ static char * -func_error (o, argv, funcname) - char *o; - char **argv; - const char *funcname; +func_error (char *o, char **argv, const char *funcname) { char **argvp; char *msg, *p; @@ -1129,12 +1102,24 @@ func_error (o, argv, funcname) } strcpy (p, *argvp); - if (*funcname == 'e') - fatal (reading_file, "%s", msg); + switch (*funcname) { + case 'e': + fatal (reading_file, "%s", msg); + + case 'w': + error (reading_file, "%s", msg); + break; + + case 'i': + printf ("%s\n", msg); + fflush(stdout); + break; + + default: + fatal (*expanding_var, "Internal error: func_error: '%s'", funcname); + } /* The warning function expands to the empty string. */ - error (reading_file, "%s", msg); - return o; } @@ -1143,10 +1128,7 @@ func_error (o, argv, funcname) chop argv[0] into words, and sort them. */ static char * -func_sort (o, argv, funcname) - char *o; - char **argv; - const char *funcname; +func_sort (char *o, char **argv, const char *funcname UNUSED) { char **words = 0; int nwords = 0; @@ -1208,13 +1190,10 @@ func_sort (o, argv, funcname) */ static char * -func_if (o, argv, funcname) - char *o; - char **argv; - const char *funcname; +func_if (char *o, char **argv, const char *funcname UNUSED) { - char *begp = argv[0]; - char *endp = begp + strlen (argv[0]); + const char *begp = argv[0]; + const char *endp = begp + strlen (argv[0]) - 1; int result = 0; /* Find the result of the condition: if we have a value, and it's not @@ -1223,9 +1202,9 @@ func_if (o, argv, funcname) strip_whitespace (&begp, &endp); - if (begp < endp) + if (begp <= endp) { - char *expansion = expand_argument (begp, NULL); + char *expansion = expand_argument (begp, endp+1); result = strlen (expansion); free (expansion); @@ -1251,11 +1230,112 @@ func_if (o, argv, funcname) return o; } +/* + $(or condition1[,condition2[,condition3[...]]]) + + A CONDITION is false iff it evaluates to an empty string. White + space before and after CONDITION are stripped before evaluation. + + CONDITION1 is evaluated. If it's true, then this is the result of + expansion. If it's false, CONDITION2 is evaluated, and so on. If none of + the conditions are true, the expansion is the empty string. + + Once a CONDITION is true no further conditions are evaluated + (short-circuiting). +*/ + static char * -func_wildcard (o, argv, funcname) - char *o; - char **argv; - const char *funcname; +func_or (char *o, char **argv, const char *funcname UNUSED) +{ + for ( ; *argv ; ++argv) + { + const char *begp = *argv; + const char *endp = begp + strlen (*argv) - 1; + char *expansion; + int result = 0; + + /* Find the result of the condition: if it's false keep going. */ + + strip_whitespace (&begp, &endp); + + if (begp > endp) + continue; + + expansion = expand_argument (begp, endp+1); + result = strlen (expansion); + + /* If the result is false keep going. */ + if (!result) + { + free (expansion); + continue; + } + + /* It's true! Keep this result and return. */ + o = variable_buffer_output (o, expansion, result); + free (expansion); + break; + } + + return o; +} + +/* + $(and condition1[,condition2[,condition3[...]]]) + + A CONDITION is false iff it evaluates to an empty string. White + space before and after CONDITION are stripped before evaluation. + + CONDITION1 is evaluated. If it's false, then this is the result of + expansion. If it's true, CONDITION2 is evaluated, and so on. If all of + the conditions are true, the expansion is the result of the last condition. + + Once a CONDITION is false no further conditions are evaluated + (short-circuiting). +*/ + +static char * +func_and (char *o, char **argv, const char *funcname UNUSED) +{ + char *expansion; + int result; + + while (1) + { + const char *begp = *argv; + const char *endp = begp + strlen (*argv) - 1; + + /* An empty condition is always false. */ + strip_whitespace (&begp, &endp); + if (begp > endp) + return o; + + expansion = expand_argument (begp, endp+1); + result = strlen (expansion); + + /* If the result is false, stop here: we're done. */ + if (!result) + break; + + /* Otherwise the result is true. If this is the last one, keep this + result and quit. Otherwise go on to the next one! */ + + if (*(++argv)) + free (expansion); + else + { + o = variable_buffer_output (o, expansion, result); + break; + } + } + + free (expansion); + + return o; +} + +static char * +func_wildcard (char *o, char **argv, const char *funcname UNUSED) { #ifdef _AMIGA @@ -1276,22 +1356,26 @@ func_wildcard (o, argv, funcname) */ static char * -func_eval (o, argv, funcname) - char *o; - char **argv; - const char *funcname; +func_eval (char *o, char **argv, const char *funcname UNUSED) { + char *buf; + unsigned int len; + + /* Eval the buffer. Pop the current variable buffer setting so that the + eval'd code can use its own without conflicting. */ + + install_variable_buffer (&buf, &len); + eval_buffer (argv[0]); + restore_variable_buffer (buf, len); + return o; } static char * -func_value (o, argv, funcname) - char *o; - char **argv; - const char *funcname; +func_value (char *o, char **argv, const char *funcname UNUSED) { /* Look up the variable. */ struct variable *v = lookup_variable (argv[0], strlen (argv[0])); @@ -1306,10 +1390,8 @@ func_value (o, argv, funcname) /* \r is replaced on UNIX as well. Is this desirable? */ -void -fold_newlines (buffer, length) - char *buffer; - int *length; +static void +fold_newlines (char *buffer, unsigned int *length) { char *dst = buffer; char *src = buffer; @@ -1368,7 +1450,7 @@ windows32_openpipe (int *pipedes, int *pid_p, char **command_argv, char **envp) 0, TRUE, DUPLICATE_SAME_ACCESS) == FALSE) { - fatal (NILF, _("create_child_process: DuplicateHandle(In) failed (e=%d)\n"), + fatal (NILF, _("create_child_process: DuplicateHandle(In) failed (e=%ld)\n"), GetLastError()); } @@ -1379,12 +1461,12 @@ windows32_openpipe (int *pipedes, int *pid_p, char **command_argv, char **envp) 0, TRUE, DUPLICATE_SAME_ACCESS) == FALSE) { - fatal (NILF, _("create_child_process: DuplicateHandle(Err) failed (e=%d)\n"), + fatal (NILF, _("create_child_process: DuplicateHandle(Err) failed (e=%ld)\n"), GetLastError()); } if (!CreatePipe(&hChildOutRd, &hChildOutWr, &saAttr, 0)) - fatal (NILF, _("CreatePipe() failed (e=%d)\n"), GetLastError()); + fatal (NILF, _("CreatePipe() failed (e=%ld)\n"), GetLastError()); hProcess = process_init_fd(hIn, hChildOutWr, hErr); @@ -1493,13 +1575,9 @@ msdos_openpipe (int* pipedes, int *pidp, char *text) #else #ifndef _AMIGA static char * -func_shell (o, argv, funcname) - char *o; - char **argv; - const char *funcname; +func_shell (char *o, char **argv, const char *funcname UNUSED) { char* batch_filename = NULL; - int i; #ifdef __MSDOS__ FILE *fpipe; @@ -1524,12 +1602,15 @@ func_shell (o, argv, funcname) because target_environment hits a loop trying to expand $(var) to put it in the environment. This is even more confusing when var was not explicitly exported, but just appeared in the - calling environment. */ + calling environment. + + envp = target_environment (NILF); + */ 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, @@ -1539,6 +1620,7 @@ func_shell (o, argv, funcname) error_prefix = ""; #ifdef WINDOWS32 + windows32_openpipe (pipedes, &pid, command_argv, envp); if (pipedes[0] < 0) { @@ -1547,36 +1629,50 @@ func_shell (o, argv, funcname) return o; } else -#else /* WINDOWS32 */ -# ifdef __MSDOS__ +#elif defined(__MSDOS__) + fpipe = msdos_openpipe (pipedes, &pid, argv[0]); if (pipedes[0] < 0) { perror_with_name (error_prefix, "pipe"); return o; } -# else + +#else + if (pipe (pipedes) < 0) { perror_with_name (error_prefix, "pipe"); return o; } +# ifdef __EMX__ + + /* close some handles that are unnecessary for the child process */ + CLOSE_ON_EXEC(pipedes[1]); + CLOSE_ON_EXEC(pipedes[0]); + /* Never use fork()/exec() here! Use spawn() instead in exec_command() */ + pid = child_execute_job (0, pipedes[1], command_argv, envp); + if (pid < 0) + perror_with_name (error_prefix, "spawn"); + +# else /* ! __EMX__ */ + pid = vfork (); if (pid < 0) perror_with_name (error_prefix, "fork"); else if (pid == 0) child_execute_job (0, pipedes[1], command_argv, envp); else -# endif /* ! __MSDOS__ */ -#endif /* WINDOWS32 */ +# endif + +#endif { /* We are the parent. */ - char *buffer; - unsigned int maxlen; + unsigned int maxlen, i; int cc; /* Record the PID for reap_children. */ @@ -1606,7 +1702,7 @@ func_shell (o, argv, funcname) buffer = (char *) xrealloc (buffer, maxlen + 1); } - cc = read (pipedes[0], &buffer[i], maxlen - i); + EINTRLOOP (cc, read (pipedes[0], &buffer[i], maxlen - i)); if (cc <= 0) break; } @@ -1620,8 +1716,8 @@ func_shell (o, argv, funcname) (void) close (pipedes[0]); #endif - /* Loop until child_handler sets shell_function_completed - to the status of our child shell. */ + /* Loop until child_handler or reap_children() sets + shell_function_completed to the status of our child shell. */ while (shell_function_completed == 0) reap_children (1, 0); @@ -1639,17 +1735,15 @@ func_shell (o, argv, funcname) if (shell_function_completed == -1) { - /* This most likely means that the execvp failed, - so we should just write out the error message - that came in over the pipe from the child. */ + /* This likely means that the execvp failed, so we should just + write the error message in the pipe from the child. */ fputs (buffer, stderr); fflush (stderr); } else { - /* The child finished normally. Replace all - newlines in its output with spaces, and put - that in the variable output buffer. */ + /* The child finished normally. Replace all newlines in its output + with spaces, and put that in the variable output buffer. */ fold_newlines (buffer, &i); o = variable_buffer_output (o, buffer, i); } @@ -1681,8 +1775,8 @@ func_shell (char *o, char **argv, const char *funcname) BPTR child_stdout; char tmp_output[FILENAME_MAX]; - unsigned int maxlen = 200; - int cc, i; + unsigned int maxlen = 200, i; + int cc; char * buffer, * ptr; char ** aptr; int len = 0; @@ -1756,7 +1850,7 @@ func_shell (char *o, char **argv, const char *funcname) equality. Return is string-boolean, ie, the empty string is false. */ static char * -func_eq (char* o, char **argv, char *funcname) +func_eq (char *o, char **argv, char *funcname) { int result = ! strcmp (argv[0], argv[1]); o = variable_buffer_output (o, result ? "1" : "", result); @@ -1768,9 +1862,9 @@ func_eq (char* o, char **argv, char *funcname) string-boolean not operator. */ static char * -func_not (char* o, char **argv, char *funcname) +func_not (char *o, char **argv, char *funcname) { - char * s = argv[0]; + char *s = argv[0]; int result = 0; while (isspace ((unsigned char)*s)) s++; @@ -1781,6 +1875,159 @@ func_not (char* o, char **argv, char *funcname) #endif +/* Return the absolute name of file NAME which does not contain any `.', + `..' components nor any repeated path separators ('/'). */ + +static char * +abspath (const char *name, char *apath) +{ + char *dest; + const char *start, *end, *apath_limit; + + if (name[0] == '\0' || apath == NULL) + return NULL; + + apath_limit = apath + GET_PATH_MAX; + + if (name[0] != '/') + { + /* It is unlikely we would make it until here but just to make sure. */ + if (!starting_directory) + return NULL; + + strcpy (apath, starting_directory); + + dest = strchr (apath, '\0'); + } + else + { + apath[0] = '/'; + dest = apath + 1; + } + + for (start = end = name; *start != '\0'; start = end) + { + unsigned long len; + + /* Skip sequence of multiple path-separators. */ + while (*start == '/') + ++start; + + /* Find end of path component. */ + for (end = start; *end != '\0' && *end != '/'; ++end) + ; + + len = end - start; + + if (len == 0) + break; + else if (len == 1 && start[0] == '.') + /* nothing */; + else if (len == 2 && start[0] == '.' && start[1] == '.') + { + /* Back up to previous component, ignore if at root already. */ + if (dest > apath + 1) + while ((--dest)[-1] != '/'); + } + else + { + if (dest[-1] != '/') + *dest++ = '/'; + + if (dest + len >= apath_limit) + return NULL; + + dest = memcpy (dest, start, len); + dest += len; + *dest = '\0'; + } + } + + /* Unless it is root strip trailing separator. */ + if (dest > apath + 1 && dest[-1] == '/') + --dest; + + *dest = '\0'; + + return apath; +} + + +static char * +func_realpath (char *o, char **argv, const char *funcname UNUSED) +{ + /* Expand the argument. */ + char *p = argv[0]; + char *path = 0; + int doneany = 0; + unsigned int len = 0; + PATH_VAR (in); + PATH_VAR (out); + + while ((path = find_next_token (&p, &len)) != 0) + { + if (len < GET_PATH_MAX) + { + strncpy (in, path, len); + in[len] = '\0'; + + if + ( +#ifdef HAVE_REALPATH + realpath (in, out) +#else + abspath (in, out) +#endif + ) + { + o = variable_buffer_output (o, out, strlen (out)); + o = variable_buffer_output (o, " ", 1); + doneany = 1; + } + } + } + + /* Kill last space. */ + if (doneany) + --o; + + return o; +} + +static char * +func_abspath (char *o, char **argv, const char *funcname UNUSED) +{ + /* Expand the argument. */ + char *p = argv[0]; + char *path = 0; + int doneany = 0; + unsigned int len = 0; + PATH_VAR (in); + PATH_VAR (out); + + while ((path = find_next_token (&p, &len)) != 0) + { + if (len < GET_PATH_MAX) + { + strncpy (in, path, len); + in[len] = '\0'; + + if (abspath (in, out)) + { + o = variable_buffer_output (o, out, strlen (out)); + o = variable_buffer_output (o, " ", 1); + doneany = 1; + } + } + } + + /* Kill last space. */ + if (doneany) + --o; + + return o; +} + /* Lookup table for builtin functions. This doesn't have to be sorted; we use a straight lookup. We might gain @@ -1799,6 +2046,7 @@ static char *func_call PARAMS ((char *o, char **argv, const char *funcname)); static struct function_table_entry function_table_init[] = { /* Name/size */ /* MIN MAX EXP? Function */ + { STRING_SIZE_TUPLE("abspath"), 0, 1, 1, func_abspath}, { STRING_SIZE_TUPLE("addprefix"), 2, 2, 1, func_addsuffix_addprefix}, { STRING_SIZE_TUPLE("addsuffix"), 2, 2, 1, func_addsuffix_addprefix}, { STRING_SIZE_TUPLE("basename"), 0, 1, 1, func_basename_dir}, @@ -1810,8 +2058,11 @@ static struct function_table_entry function_table_init[] = { STRING_SIZE_TUPLE("filter-out"), 2, 2, 1, func_filter_filterout}, { STRING_SIZE_TUPLE("findstring"), 2, 2, 1, func_findstring}, { STRING_SIZE_TUPLE("firstword"), 0, 1, 1, func_firstword}, + { STRING_SIZE_TUPLE("flavor"), 0, 1, 1, func_flavor}, { STRING_SIZE_TUPLE("join"), 2, 2, 1, func_join}, + { STRING_SIZE_TUPLE("lastword"), 0, 1, 1, func_lastword}, { STRING_SIZE_TUPLE("patsubst"), 3, 3, 1, func_patsubst}, + { STRING_SIZE_TUPLE("realpath"), 0, 1, 1, func_realpath}, { STRING_SIZE_TUPLE("shell"), 0, 1, 1, func_shell}, { STRING_SIZE_TUPLE("sort"), 0, 1, 1, func_sort}, { STRING_SIZE_TUPLE("strip"), 0, 1, 1, func_strip}, @@ -1822,9 +2073,12 @@ 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}, + { STRING_SIZE_TUPLE("or"), 1, 0, 0, func_or}, + { STRING_SIZE_TUPLE("and"), 1, 0, 0, func_and}, { STRING_SIZE_TUPLE("value"), 0, 1, 1, func_value}, { STRING_SIZE_TUPLE("eval"), 0, 1, 1, func_eval}, #ifdef EXPERIMENTAL @@ -1839,15 +2093,12 @@ static struct function_table_entry function_table_init[] = /* These must come after the definition of function_table. */ static char * -expand_builtin_function (o, argc, argv, entry_p) - char *o; - int argc; - char **argv; - struct function_table_entry *entry_p; +expand_builtin_function (char *o, int argc, char **argv, + const struct function_table_entry *entry_p) { if (argc < (int)entry_p->minimum_args) - fatal (reading_file, - _("Insufficient number of arguments (%d) to function `%s'"), + fatal (*expanding_var, + _("insufficient number of arguments (%d) to function `%s'"), argc, entry_p->name); /* I suppose technically some function could do something with no @@ -1858,8 +2109,8 @@ expand_builtin_function (o, argc, argv, entry_p) return o; if (!entry_p->func_ptr) - fatal (reading_file, _("Unimplemented on this platform: function `%s'"), - entry_p->name); + fatal (*expanding_var, + _("unimplemented on this platform: function `%s'"), entry_p->name); return entry_p->func_ptr (o, argv, entry_p->name); } @@ -1870,9 +2121,7 @@ expand_builtin_function (o, argc, argv, entry_p) *STRINGP past the reference and returning nonzero. If not, return zero. */ int -handle_function (op, stringp) - char **op; - char **stringp; +handle_function (char **op, char **stringp) { const struct function_table_entry *entry_p; char openparen = (*stringp)[0]; @@ -1910,7 +2159,7 @@ handle_function (op, stringp) break; if (count >= 0) - fatal (reading_file, + fatal (*expanding_var, _("unterminated call to function `%s': missing `%c'"), entry_p->name, closeparen); @@ -1979,16 +2228,15 @@ handle_function (op, stringp) assigned to $1, $2, ... $N. $0 is the name of the function. */ static char * -func_call (o, argv, funcname) - char *o; - char **argv; - const char *funcname; +func_call (char *o, char **argv, const char *funcname UNUSED) { + static int max_args = 0; char *fname; char *cp; char *body; int flen; int i; + int saved_args; const struct function_table_entry *entry_p; struct variable *v; @@ -2051,12 +2299,28 @@ func_call (o, argv, funcname) define_variable (num, strlen (num), *argv, o_automatic, 0); } + /* If the number of arguments we have is < max_args, it means we're inside + a recursive invocation of $(call ...). Fill in the remaining arguments + in the new scope with the empty value, to hide them from this + invocation. */ + + for (; i < max_args; ++i) + { + char num[11]; + + sprintf (num, "%d", i); + define_variable (num, strlen (num), "", o_automatic, 0); + } + /* Expand the body in the context of the arguments, adding the result to the variable buffer. */ v->exp_count = EXP_COUNT_MAX; + saved_args = max_args; + max_args = i; o = variable_expand_string (o, body, flen+3); + max_args = saved_args; v->exp_count = 0; @@ -2066,7 +2330,7 @@ func_call (o, argv, funcname) } void -hash_init_function_table () +hash_init_function_table (void) { hash_init (&function_table, FUNCTION_TABLE_ENTRIES * 2, function_table_entry_hash_1, function_table_entry_hash_2, diff --git a/src/bin/make/getloadavg.c b/src/bin/make/getloadavg.c index 7d575cd6a1..9367e473a5 100644 --- a/src/bin/make/getloadavg.c +++ b/src/bin/make/getloadavg.c @@ -1,21 +1,21 @@ /* Get the system load averages. - Copyright (C) 1985, 86, 87, 88, 89, 91, 92, 93, 1994, 1995, 1997 - Free Software Foundation, Inc. +Copyright (C) 1985, 1986, 1987, 1988, 1989, 1990, 1991, 1992, 1993, 1994, +1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006 Free +Software Foundation, Inc. - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2, or (at your option) - any later version. +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, - USA. */ +You should have received a copy of the GNU General Public License along with +this program; see the file COPYING. If not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. */ /* Compile-time symbols that this file uses: @@ -355,7 +355,7 @@ extern int errno; /* LOAD_AVE_TYPE should only get defined if we're going to use the nlist method. */ -# if !defined(LOAD_AVE_TYPE) && (defined(BSD) || defined(LDAV_CVT) || defined(KERNEL_FILE) || defined(LDAV_SYMBOL)) +# if !defined(LOAD_AVE_TYPE) && (defined(BSD) || defined(LDAV_CVT) || defined(KERNEL_FILE) || defined(LDAV_SYMBOL)) && !defined(__riscos__) # define LOAD_AVE_TYPE double # endif @@ -498,9 +498,7 @@ static kvm_t *kd; or -1 if an error occurred. */ int -getloadavg (loadavg, nelem) - double loadavg[]; - int nelem; +getloadavg (double loadavg[], int nelem) { int elem = 0; /* Return value. */ @@ -994,9 +992,7 @@ getloadavg (loadavg, nelem) #include "make.h" int -main (argc, argv) - int argc; - char **argv; +main (int argc, char **argv) { int naptime = 0; diff --git a/src/bin/make/getopt.c b/src/bin/make/getopt.c index cd774190fc..f0fac4fe5e 100644 --- a/src/bin/make/getopt.c +++ b/src/bin/make/getopt.c @@ -1,29 +1,29 @@ /* Getopt for GNU. - NOTE: getopt is now part of the C library, so if you don't know what - "Keep this file name-space clean" means, talk to drepper@gnu.org - before changing it! +NOTE: getopt is now part of the C library, so if you don't know what +"Keep this file name-space clean" means, talk to drepper@gnu.org +before changing it! - Copyright (C) 1987, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98 - Free Software Foundation, Inc. +Copyright (C) 1987, 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996, +1997, 1998, 2000, 2001, 2002, 2003, 2004, 2005, 2006 Free Software +Foundation, Inc. - NOTE: The canonical source of this file is maintained with the GNU C Library. - Bugs can be reported to bug-glibc@gnu.org. +NOTE: The canonical source of this file is maintained with the GNU C Library. +Bugs can be reported to bug-glibc@gnu.org. - This program is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by the - Free Software Foundation; either version 2, or (at your option) any - later version. +This program is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License as published by the +Free Software Foundation; either version 2, or (at your option) any +later version. - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License along with +this program; see the file COPYING. If not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. */ - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, - USA. */ - /* This tells Alpha OSF/1 not to define a getopt prototype in . Ditto for AIX 3.2 and . */ #ifndef _NO_PROTO @@ -210,9 +210,7 @@ extern char *getenv (); #endif static char * -my_index (str, chr) - const char *str; - int chr; +my_index (const char *str, int chr) { while (*str) { @@ -262,8 +260,7 @@ static char *const *original_argv; /* Make sure the environment variable bash 2.0 puts in the environment is valid for the getopt call we must make sure that the ARGV passed to getopt is that one passed to the process. */ -static void -__attribute__ ((unused)) +static void __attribute__ ((unused)) store_args_and_env (int argc, char *const *argv) { /* XXX This is no good solution. We should rather copy the args so @@ -300,8 +297,7 @@ static void exchange (char **); #endif static void -exchange (argv) - char **argv; +exchange (char **argv) { int bottom = first_nonopt; int middle = last_nonopt; @@ -385,10 +381,7 @@ exchange (argv) static const char *_getopt_initialize (int, char *const *, const char *); #endif static const char * -_getopt_initialize (argc, argv, optstring) - int argc; - char *const *argv; - const char *optstring; +_getopt_initialize (int argc, char *const *argv, const char *optstring) { /* Start processing options with ARGV-element 1 (since ARGV-element 0 is the program name); the sequence of previously skipped @@ -507,13 +500,8 @@ _getopt_initialize (argc, argv, optstring) long-named options. */ int -_getopt_internal (argc, argv, optstring, longopts, longind, long_only) - int argc; - char *const *argv; - const char *optstring; - const struct option *longopts; - int *longind; - int long_only; +_getopt_internal (int argc, char *const *argv, const char *optstring, + const struct option *longopts, int *longind, int long_only) { optarg = NULL; @@ -961,10 +949,7 @@ _getopt_internal (argc, argv, optstring, longopts, longind, long_only) } int -getopt (argc, argv, optstring) - int argc; - char *const *argv; - const char *optstring; +getopt (int argc, char *const *argv, const char *optstring) { return _getopt_internal (argc, argv, optstring, (const struct option *) 0, @@ -980,9 +965,7 @@ getopt (argc, argv, optstring) the above definition of `getopt'. */ int -main (argc, argv) - int argc; - char **argv; +main (int argc, char **argv) { int c; int digit_optind = 0; diff --git a/src/bin/make/getopt.h b/src/bin/make/getopt.h index fb30719a86..80efe9652f 100644 --- a/src/bin/make/getopt.h +++ b/src/bin/make/getopt.h @@ -1,23 +1,23 @@ /* Declarations for getopt. - Copyright (C) 1989,90,91,92,93,94,96,97 Free Software Foundation, Inc. +Copyright (C) 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, +1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006 Free Software Foundation, Inc. - NOTE: The canonical source of this file is maintained with the GNU C Library. - Bugs can be reported to bug-glibc@gnu.org. +NOTE: The canonical source of this file is maintained with the GNU C Library. +Bugs can be reported to bug-glibc@gnu.org. - This program is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by the - Free Software Foundation; either version 2, or (at your option) any - later version. +This program is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License as published by the +Free Software Foundation; either version 2, or (at your option) any +later version. - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, - USA. */ +You should have received a copy of the GNU General Public License along with +this program; see the file COPYING. If not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. */ #ifndef _GETOPT_H #define _GETOPT_H 1 diff --git a/src/bin/make/getopt1.c b/src/bin/make/getopt1.c index ff257374c3..9ad51274b5 100644 --- a/src/bin/make/getopt1.c +++ b/src/bin/make/getopt1.c @@ -1,24 +1,24 @@ /* getopt_long and getopt_long_only entry points for GNU getopt. - Copyright (C) 1987,88,89,90,91,92,93,94,96,97,98 - Free Software Foundation, Inc. +Copyright (C) 1987, 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1996, 1997, +1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006 Free Software +Foundation, Inc. - NOTE: The canonical source of this file is maintained with the GNU C Library. - Bugs can be reported to bug-glibc@gnu.org. +NOTE: The canonical source of this file is maintained with the GNU C Library. +Bugs can be reported to bug-glibc@gnu.org. - This program is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by the - Free Software Foundation; either version 2, or (at your option) any - later version. +This program is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License as published by the +Free Software Foundation; either version 2, or (at your option) any +later version. - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, - USA. */ +You should have received a copy of the GNU General Public License along with +this program; see the file COPYING. If not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. */ #ifdef HAVE_CONFIG_H #include @@ -66,12 +66,8 @@ #endif int -getopt_long (argc, argv, options, long_options, opt_index) - int argc; - char *const *argv; - const char *options; - const struct option *long_options; - int *opt_index; +getopt_long (int argc, char *const *argv, const char *options, + const struct option *long_options, int *opt_index) { return _getopt_internal (argc, argv, options, long_options, opt_index, 0); } @@ -82,12 +78,8 @@ getopt_long (argc, argv, options, long_options, opt_index) instead. */ int -getopt_long_only (argc, argv, options, long_options, opt_index) - int argc; - char *const *argv; - const char *options; - const struct option *long_options; - int *opt_index; +getopt_long_only (int argc, char *const *argv, const char *options, + const struct option *long_options, int *opt_index) { return _getopt_internal (argc, argv, options, long_options, opt_index, 1); } @@ -100,9 +92,7 @@ getopt_long_only (argc, argv, options, long_options, opt_index) #include int -main (argc, argv) - int argc; - char **argv; +main (int argc, char **argv) { int c; int digit_optind = 0; diff --git a/src/bin/make/gettext.h b/src/bin/make/gettext.h index ea67f30815..17e999147c 100644 --- a/src/bin/make/gettext.h +++ b/src/bin/make/gettext.h @@ -1,20 +1,19 @@ /* Convenience header for conditional use of GNU . - Copyright (C) 1995-1998, 2000-2002 Free Software Foundation, Inc. +Copyright (C) 1995, 1996, 1997, 1998, 2000, 2001, 2002, 2003, 2004, 2005, +2006 Free Software Foundation, Inc. +This file is part of GNU Make. - This program is free software; you can redistribute it and/or modify it - under the terms of the GNU Library General Public License as published - by the Free Software Foundation; either version 2, or (at your option) - any later version. +GNU Make is free software; you can redistribute it and/or modify it under the +terms of the GNU General Public License as published by the Free Software +Foundation; either version 2, or (at your option) any later version. - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Library General Public License for more details. +GNU Make is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR +A PARTICULAR PURPOSE. See the GNU General Public License for more details. - You should have received a copy of the GNU Library General Public - License along with this program; if not, write to the Free Software - Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, - USA. */ +You should have received a copy of the GNU General Public License along with +GNU Make; see the file COPYING. If not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. */ #ifndef _LIBGETTEXT_H #define _LIBGETTEXT_H 1 diff --git a/src/bin/make/glob/fnmatch.c b/src/bin/make/glob/fnmatch.c index 1f4ead5f98..49dd2f5900 100644 --- a/src/bin/make/glob/fnmatch.c +++ b/src/bin/make/glob/fnmatch.c @@ -1,20 +1,20 @@ /* Copyright (C) 1991, 92, 93, 96, 97, 98, 99 Free Software Foundation, Inc. - This file is part of the GNU C Library. +This file is part of the GNU C Library. - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Library General Public License as - published by the Free Software Foundation; either version 2 of the - License, or (at your option) any later version. +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Library General Public License as +published by the Free Software Foundation; either version 2 of the +License, or (at your option) any later version. - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Library General Public License for more details. +This library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Library General Public License for more details. - You should have received a copy of the GNU Library General Public - License along with this library; see the file COPYING.LIB. If not, - write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, - Boston, MA 02111-1307, USA. */ +You should have received a copy of the GNU Library General Public License +along with this library; see the file COPYING.LIB. If not, write to the Free +Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA. */ #if HAVE_CONFIG_H # include diff --git a/src/bin/make/glob/fnmatch.h b/src/bin/make/glob/fnmatch.h index cc3ec37940..07a258f61c 100644 --- a/src/bin/make/glob/fnmatch.h +++ b/src/bin/make/glob/fnmatch.h @@ -1,20 +1,20 @@ /* Copyright (C) 1991, 92, 93, 96, 97, 98, 99 Free Software Foundation, Inc. - This file is part of the GNU C Library. +This file is part of the GNU C Library. - The GNU C Library is free software; you can redistribute it and/or - modify it under the terms of the GNU Library General Public License as - published by the Free Software Foundation; either version 2 of the - License, or (at your option) any later version. +The GNU C Library is free software; you can redistribute it and/or +modify it under the terms of the GNU Library General Public License as +published by the Free Software Foundation; either version 2 of the +License, or (at your option) any later version. - The GNU C Library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Library General Public License for more details. +The GNU C Library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Library General Public License for more details. - You should have received a copy of the GNU Library General Public - License along with the GNU C Library; see the file COPYING.LIB. If not, - write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, - Boston, MA 02111-1307, USA. */ +You should have received a copy of the GNU Library General Public License +along with this library; see the file COPYING.LIB. If not, write to the Free +Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA. */ #ifndef _FNMATCH_H #define _FNMATCH_H 1 @@ -37,7 +37,7 @@ extern "C" { #endif /* C++ or ANSI C. */ #ifndef const -# if (defined __STDC__ && __STDC__) || defined __cplusplus +# if (defined __STDC__ && __STDC__) || defined __cplusplus || defined WINDOWS32 # define __const const # else # define __const diff --git a/src/bin/make/glob/glob.c b/src/bin/make/glob/glob.c index 9d09c1656f..1395e4630b 100644 --- a/src/bin/make/glob/glob.c +++ b/src/bin/make/glob/glob.c @@ -1,19 +1,19 @@ /* Copyright (C) 1991,92,93,94,95,96,97,98,99 Free Software Foundation, Inc. - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Library General Public License as - published by the Free Software Foundation; either version 2 of the - License, or (at your option) any later version. +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Library General Public License as +published by the Free Software Foundation; either version 2 of the +License, or (at your option) any later version. - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Library General Public License for more details. +This library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Library General Public License for more details. - You should have received a copy of the GNU Library General Public - License along with this library; see the file COPYING.LIB. If not, - write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, - Boston, MA 02111-1307, USA. */ +You should have received a copy of the GNU Library General Public License +along with this library; see the file COPYING.LIB. If not, write to the Free +Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA. */ /* AIX requires this to be the first thing in the file. */ #if defined _AIX && !defined __GNUC__ @@ -188,12 +188,13 @@ __inline # ifndef __SASC # ifdef WINDOWS32 static void * +my_realloc (void *p, unsigned int n) # else static char * -# endif my_realloc (p, n) char *p; unsigned int n; +# endif { /* These casts are the for sake of the broken Ultrix compiler, which warns of illegal pointer combinations otherwise. */ @@ -299,11 +300,8 @@ static int glob_in_dir __P ((const char *pattern, const char *directory, static int prefix_array __P ((const char *prefix, char **array, size_t n)); static int collated_compare __P ((const __ptr_t, const __ptr_t)); -#ifdef VMS -/* these compilers like prototypes */ #if !defined _LIBC || !defined NO_GLOB_PATTERN_P -int __glob_pattern_p (const char *pattern, int quote); -#endif +int __glob_pattern_p __P ((const char *pattern, int quote)); #endif /* Find the end of the sub-pattern in a brace expression. We define @@ -1303,7 +1301,7 @@ glob_in_dir (pattern, directory, flags, errfunc, pglob) { int fnm_flags = ((!(flags & GLOB_PERIOD) ? FNM_PERIOD : 0) | ((flags & GLOB_NOESCAPE) ? FNM_NOESCAPE : 0) -#if defined _AMIGA || defined VMS +#if defined HAVE_CASE_INSENSITIVE_FS | FNM_CASEFOLD #endif ); diff --git a/src/bin/make/glob/glob.h b/src/bin/make/glob/glob.h index db4b919d03..c3ab64ad6c 100644 --- a/src/bin/make/glob/glob.h +++ b/src/bin/make/glob/glob.h @@ -1,19 +1,19 @@ /* Copyright (C) 1991, 92, 95, 96, 97, 98 Free Software Foundation, Inc. - The GNU C Library is free software; you can redistribute it and/or - modify it under the terms of the GNU Library General Public License as - published by the Free Software Foundation; either version 2 of the - License, or (at your option) any later version. +The GNU C Library is free software; you can redistribute it and/or +modify it under the terms of the GNU Library General Public License as +published by the Free Software Foundation; either version 2 of the +License, or (at your option) any later version. - The GNU C Library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Library General Public License for more details. +The GNU C Library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Library General Public License for more details. - You should have received a copy of the GNU Library General Public - License along with the GNU C Library; see the file COPYING.LIB. If not, - write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, - Boston, MA 02111-1307, USA. */ +You should have received a copy of the GNU Library General Public License +along with this library; see the file COPYING.LIB. If not, write to the Free +Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA. */ #ifndef _GLOB_H #define _GLOB_H 1 @@ -24,7 +24,7 @@ extern "C" { #undef __ptr_t #if defined __cplusplus || (defined __STDC__ && __STDC__) || defined WINDOWS32 -# if !defined __GLIBC__ || !defined __P || !defined __PMT +# if !defined __GLIBC__ # undef __P # undef __PMT # define __P(protos) protos @@ -47,9 +47,12 @@ extern "C" { /* We need `size_t' for the following definitions. */ #ifndef __size_t -# if defined __GNUC__ && __GNUC__ >= 2 -typedef __SIZE_TYPE__ __size_t; +# if defined __FreeBSD__ +# define __size_t size_t # else +# if defined __GNUC__ && __GNUC__ >= 2 +typedef __SIZE_TYPE__ __size_t; +# else /* This is a guess. */ /*hb * Conflicts with DECCs aready defined type __size_t. @@ -57,9 +60,10 @@ typedef __SIZE_TYPE__ __size_t; * Anyway if DECC is used and __SIZE_T is defined then __size_t is * already defined (and I hope it's exactly the one we need here). */ -#if !(defined __DECC && defined __SIZE_T) +# if !(defined __DECC && defined __SIZE_T) typedef unsigned long int __size_t; -#endif +# endif +# endif # endif #else /* The GNU CC stddef.h version defines __size_t as empty. We need a real diff --git a/src/bin/make/hash.c b/src/bin/make/hash.c index 9083b60a98..f11a74fc66 100644 --- a/src/bin/make/hash.c +++ b/src/bin/make/hash.c @@ -2,20 +2,19 @@ Copyright (C) 1995, 1999, 2002 Free Software Foundation, Inc. Written by Greg McGary - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2, or (at your option) - any later version. +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -*/ +You should have received a copy of the GNU General Public License along with +this program; see the file COPYING. If not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. */ #include "make.h" #include "hash.h" @@ -41,12 +40,8 @@ void *hash_deleted_item = &hash_deleted_item; given size. */ void -hash_init (ht, size, hash_1, hash_2, hash_cmp) - struct hash_table* ht; - unsigned long size; - hash_func_t hash_1; - hash_func_t hash_2; - hash_cmp_func_t hash_cmp; +hash_init (struct hash_table *ht, unsigned long size, + hash_func_t hash_1, hash_func_t hash_2, hash_cmp_func_t hash_cmp) { ht->ht_size = round_up_2 (size); ht->ht_empty_slots = ht->ht_size; @@ -71,11 +66,8 @@ hash_init (ht, size, hash_1, hash_2, hash_cmp) /* Load an array of items into `ht'. */ void -hash_load (ht, item_table, cardinality, size) - struct hash_table* ht; - void *item_table; - unsigned long cardinality; - unsigned long size; +hash_load (struct hash_table *ht, void *item_table, + unsigned long cardinality, unsigned long size) { char *items = (char *) item_table; while (cardinality--) @@ -91,9 +83,7 @@ hash_load (ht, item_table, cardinality, size) ht_fill on insertion. */ void ** -hash_find_slot (ht, key) - struct hash_table* ht; - void const *key; +hash_find_slot (struct hash_table *ht, const void *key) { void **slot; void **deleted_slot = 0; @@ -128,32 +118,25 @@ hash_find_slot (ht, key) } void * -hash_find_item (ht, key) - struct hash_table* ht; - void const *key; +hash_find_item (struct hash_table *ht, const void *key) { void **slot = hash_find_slot (ht, key); return ((HASH_VACANT (*slot)) ? 0 : *slot); } void * -hash_insert (ht, item) - struct hash_table* ht; - void *item; +hash_insert (struct hash_table *ht, const void *item) { void **slot = hash_find_slot (ht, item); - void *old_item = slot ? *slot : 0; + const void *old_item = slot ? *slot : 0; hash_insert_at (ht, item, slot); - return ((HASH_VACANT (old_item)) ? 0 : old_item); + return (void *)((HASH_VACANT (old_item)) ? 0 : old_item); } void * -hash_insert_at (ht, item, slot) - struct hash_table* ht; - void *item; - void const *slot; +hash_insert_at (struct hash_table *ht, const void *item, const void *slot) { - void *old_item = *(void **) slot; + const void *old_item = *(void **) slot; if (HASH_VACANT (old_item)) { ht->ht_fill++; @@ -172,18 +155,14 @@ hash_insert_at (ht, item, slot) } void * -hash_delete (ht, item) - struct hash_table* ht; - void const *item; +hash_delete (struct hash_table *ht, const void *item) { void **slot = hash_find_slot (ht, item); return hash_delete_at (ht, slot); } void * -hash_delete_at (ht, slot) - struct hash_table* ht; - void const *slot; +hash_delete_at (struct hash_table *ht, const void *slot) { void *item = *(void **) slot; if (!HASH_VACANT (item)) @@ -197,8 +176,7 @@ hash_delete_at (ht, slot) } void -hash_free_items (ht) - struct hash_table* ht; +hash_free_items (struct hash_table *ht) { void **vec = ht->ht_vec; void **end = &vec[ht->ht_size]; @@ -214,8 +192,7 @@ hash_free_items (ht) } void -hash_delete_items (ht) - struct hash_table* ht; +hash_delete_items (struct hash_table *ht) { void **vec = ht->ht_vec; void **end = &vec[ht->ht_size]; @@ -229,9 +206,7 @@ hash_delete_items (ht) } void -hash_free (ht, free_items) - struct hash_table* ht; - int free_items; +hash_free (struct hash_table *ht, int free_items) { if (free_items) hash_free_items (ht); @@ -246,9 +221,7 @@ hash_free (ht, free_items) } void -hash_map (ht, map) - struct hash_table *ht; - hash_map_func_t map; +hash_map (struct hash_table *ht, hash_map_func_t map) { void **slot; void **end = &ht->ht_vec[ht->ht_size]; @@ -261,10 +234,7 @@ hash_map (ht, map) } void -hash_map_arg (ht, map, arg) - struct hash_table *ht; - hash_map_arg_func_t map; - void *arg; +hash_map_arg (struct hash_table *ht, hash_map_arg_func_t map, void *arg) { void **slot; void **end = &ht->ht_vec[ht->ht_size]; @@ -279,8 +249,7 @@ hash_map_arg (ht, map, arg) /* Double the size of the hash table in the event of overflow... */ static void -hash_rehash (ht) - struct hash_table* ht; +hash_rehash (struct hash_table *ht) { unsigned long old_ht_size = ht->ht_size; void **old_vec = ht->ht_vec; @@ -307,9 +276,7 @@ hash_rehash (ht) } void -hash_print_stats (ht, out_FILE) - struct hash_table *ht; - FILE *out_FILE; +hash_print_stats (struct hash_table *ht, FILE *out_FILE) { /* GKM FIXME: honor NO_FLOAT */ fprintf (out_FILE, _("Load=%ld/%ld=%.0f%%, "), ht->ht_fill, ht->ht_size, @@ -325,10 +292,7 @@ hash_print_stats (ht, out_FILE) user-supplied vector, or malloc one. */ void ** -hash_dump (ht, vector_0, compare) - struct hash_table *ht; - void **vector_0; - qsort_cmp_t compare; +hash_dump (struct hash_table *ht, void **vector_0, qsort_cmp_t compare) { void **vector; void **slot; @@ -351,8 +315,7 @@ hash_dump (ht, vector_0, compare) /* Round a given number up to the nearest power of 2. */ static unsigned long -round_up_2 (n) - unsigned long n; +round_up_2 (unsigned long n) { n |= (n >> 1); n |= (n >> 2); diff --git a/src/bin/make/hash.h b/src/bin/make/hash.h index 405f1dab7f..d0ba835625 100644 --- a/src/bin/make/hash.h +++ b/src/bin/make/hash.h @@ -1,20 +1,20 @@ /* hash.h -- decls for hash table - Copyright (C) 1995, 1999, 2002 Free Software Foundation, Inc. - Written by Greg McGary +Copyright (C) 1995, 1999, 2002 Free Software Foundation, Inc. +Written by Greg McGary - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2, or (at your option) - any later version. +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ +You should have received a copy of the GNU General Public License along with +this program; see the file COPYING. If not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. */ #ifndef _hash_h_ #define _hash_h_ @@ -63,8 +63,8 @@ void hash_load __P((struct hash_table *ht, void *item_table, unsigned long cardinality, unsigned long size)); void **hash_find_slot __P((struct hash_table *ht, void const *key)); void *hash_find_item __P((struct hash_table *ht, void const *key)); -void *hash_insert __P((struct hash_table *ht, void *item)); -void *hash_insert_at __P((struct hash_table *ht, void *item, void const *slot)); +void *hash_insert __P((struct hash_table *ht, const void *item)); +void *hash_insert_at __P((struct hash_table *ht, const void *item, void const *slot)); void *hash_delete __P((struct hash_table *ht, void const *item)); void *hash_delete_at __P((struct hash_table *ht, void const *slot)); void hash_delete_items __P((struct hash_table *ht)); diff --git a/src/bin/make/implicit.c b/src/bin/make/implicit.c index 857895d7d0..014828fead 100644 --- a/src/bin/make/implicit.c +++ b/src/bin/make/implicit.c @@ -1,30 +1,33 @@ /* 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, 1995, 1996, 1997, +1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006 Free Software +Foundation, Inc. This file is part of GNU Make. -GNU Make is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 2, or (at your option) -any later version. +GNU Make is free software; you can redistribute it and/or modify it under the +terms of the GNU General Public License as published by the Free Software +Foundation; either version 2, or (at your option) any later version. -GNU Make is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. +GNU Make is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR +A PARTICULAR PURPOSE. See the GNU General Public License for more details. -You should have received a copy of the GNU General Public License -along with GNU Make; see the file COPYING. If not, write to -the Free Software Foundation, Inc., 59 Temple Place - Suite 330, -Boston, MA 02111-1307, USA. */ +You should have received a copy of the GNU General Public License along with +GNU Make; see the file COPYING. If not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. */ #include "make.h" +#include "filedef.h" #include "rule.h" #include "dep.h" -#include "filedef.h" #include "debug.h" +#include "variable.h" +#include "job.h" /* struct child, used inside commands.h */ +#include "commands.h" /* set_file_variables */ -static int pattern_search PARAMS ((struct file *file, int archive, unsigned int depth, - unsigned int recursions)); +static int +pattern_search PARAMS ((struct file *file, int archive, + unsigned int depth, unsigned int recursions)); /* For a FILE which has no commands specified, try to figure out some from the implicit pattern rules. @@ -33,9 +36,7 @@ static int pattern_search PARAMS ((struct file *file, int archive, unsigned int or returns 0 if no implicit rule was found. */ int -try_implicit_rule (file, depth) - struct file *file; - unsigned int depth; +try_implicit_rule (struct file *file, unsigned int depth) { DBF (DB_IMPLICIT, _("Looking for an implicit rule for `%s'.\n")); @@ -63,6 +64,124 @@ try_implicit_rule (file, depth) } +/* Struct idep captures information about implicit prerequisites + that come from implicit rules. */ +struct idep +{ + struct idep *next; /* struct dep -compatible interface */ + char *name; /* name of the prerequisite */ + struct file *intermediate_file; /* intermediate file, 0 otherwise */ + char *intermediate_pattern; /* pattern for intermediate file */ + unsigned char had_stem; /* had % substituted with stem */ + unsigned char ignore_mtime; /* ignore_mtime flag */ +}; + +static void +free_idep_chain (struct idep *p) +{ + struct idep *n; + + for (; p != 0; p = n) + { + n = p->next; + + if (p->name) + { + struct file *f = p->intermediate_file; + + if (f != 0 + && (f->stem < f->name || f->stem > f->name + strlen (f->name))) + free (f->stem); + + free (p->name); + } + + free (p); + } +} + + +/* Scans the BUFFER for the next word with whitespace as a separator. + Returns the pointer to the beginning of the word. LENGTH hold the + length of the word. */ + +static char * +get_next_word (char *buffer, unsigned int *length) +{ + char *p = buffer, *beg; + char c; + + /* Skip any leading whitespace. */ + while (isblank ((unsigned char)*p)) + ++p; + + beg = p; + c = *(p++); + + if (c == '\0') + return 0; + + + /* We already found the first value of "c", above. */ + while (1) + { + char closeparen; + int count; + + switch (c) + { + case '\0': + case ' ': + case '\t': + goto done_word; + + case '$': + c = *(p++); + if (c == '$') + break; + + /* This is a variable reference, so read it to the matching + close paren. */ + + if (c == '(') + closeparen = ')'; + else if (c == '{') + closeparen = '}'; + else + /* This is a single-letter variable reference. */ + break; + + for (count = 0; *p != '\0'; ++p) + { + if (*p == c) + ++count; + else if (*p == closeparen && --count < 0) + { + ++p; + break; + } + } + break; + + case '|': + goto done; + + default: + break; + } + + c = *(p++); + } + done_word: + --p; + + done: + if (length) + *length = p - beg; + + return beg; +} + /* Search the pattern rules for a rule with an existing dependency to make FILE. If a rule is found, the appropriate commands and deps are put in FILE and 1 is returned. If not, 0 is returned. @@ -78,11 +197,8 @@ try_implicit_rule (file, depth) DEPTH is used for debugging messages. */ static int -pattern_search (file, archive, depth, recursions) - struct file *file; - int archive; - unsigned int depth; - unsigned int recursions; +pattern_search (struct file *file, int archive, + unsigned int depth, unsigned int recursions) { /* Filename we are searching for a rule for. */ char *filename = archive ? strchr (file->name, '(') : file->name; @@ -98,18 +214,13 @@ pattern_search (file, archive, depth, recursions) except during a recursive call. */ struct file *intermediate_file = 0; - /* List of dependencies found recursively. */ - struct file **intermediate_files - = (struct file **) xmalloc (max_pattern_deps * sizeof (struct file *)); + /* This linked list records all the prerequisites actually + found for a rule along with some other useful information + (see struct idep for details). */ + struct idep* deps = 0; - /* List of the patterns used to find intermediate files. */ - char **intermediate_patterns - = (char **) alloca (max_pattern_deps * sizeof (char *)); - - /* This buffer records all the dependencies actually found for a rule. */ - char **found_files = (char **) alloca (max_pattern_deps * sizeof (char *)); - /* Number of dep names now in FOUND_FILES. */ - unsigned int deps_found = 0; + /* 1 if we need to remove explicit prerequisites, 0 otherwise. */ + unsigned int remove_explicit_deps = 0; /* Names of possible dependencies are constructed in this buffer. */ register char *depname = (char *) alloca (namelen + max_pattern_dep_length); @@ -147,11 +258,17 @@ pattern_search (file, archive, depth, recursions) that is not just `%'. */ int specific_rule_matched = 0; - register unsigned int i = 0; /* uninit checks OK */ - register struct rule *rule; - register struct dep *dep; + unsigned int i = 0; /* uninit checks OK */ + struct rule *rule; + struct dep *dep, *expl_d; - char *p, *vp; + char *p, *vname; + + struct idep *d; + struct idep **id_ptr; + struct dep **d_ptr; + + PATH_VAR (stem_str); /* @@ Need to get rid of stem, stemlen, etc. */ #ifndef NO_ARCHIVES if (archive || ar_name (filename)) @@ -227,17 +344,27 @@ pattern_search (file, archive, depth, recursions) /* Set CHECK_LASTSLASH if FILENAME contains a directory prefix and the target pattern does not contain a slash. */ + check_lastslash = 0; + if (lastslash) + { #ifdef VMS - check_lastslash = lastslash != 0 - && ((strchr (target, ']') == 0) - && (strchr (target, ':') == 0)); + check_lastslash = (strchr (target, ']') == 0 + && strchr (target, ':') == 0); #else - check_lastslash = lastslash != 0 && strchr (target, '/') == 0; + check_lastslash = strchr (target, '/') == 0; +#ifdef HAVE_DOS_PATHS + /* Didn't find it yet: check for DOS-type directories. */ + if (check_lastslash) + { + char *b = strchr (target, '\\'); + check_lastslash = !(b || (target[0] && target[1] == ':')); + } #endif +#endif + } if (check_lastslash) { - /* In that case, don't include the - directory prefix in STEM here. */ + /* If so, don't include the directory prefix in STEM here. */ unsigned int difference = lastslash - filename + 1; if (difference > stemlen) continue; @@ -298,19 +425,28 @@ pattern_search (file, archive, depth, recursions) tryrules[i] = 0; } + /* We are going to do second expansion so initialize file variables + for the rule. */ + initialize_file_variables (file, 0); + /* Try each rule once without intermediate files, then once with them. */ for (intermed_ok = 0; intermed_ok == !!intermed_ok; ++intermed_ok) { /* Try each pattern rule till we find one that applies. - If it does, copy the names of its dependencies (as substituted) - and store them in FOUND_FILES. DEPS_FOUND is the number of them. */ + If it does, expand its dependencies (as substituted) + and chain them in DEPS. */ for (i = 0; i < nrules; i++) { + struct file *f; + unsigned int failed = 0; int check_lastslash; + int file_variables_set = 0; rule = tryrules[i]; + remove_explicit_deps = 0; + /* RULE is nil when we discover that a rule, already placed in TRYRULES, should not be applied. */ if (rule == 0) @@ -340,145 +476,301 @@ pattern_search (file, archive, depth, recursions) DBS (DB_IMPLICIT, (_("Trying pattern rule with stem `%.*s'.\n"), (int) stemlen, stem)); + strncpy (stem_str, stem, stemlen); + stem_str[stemlen] = '\0'; + + /* Temporary assign STEM to file->stem (needed to set file + variables below). */ + file->stem = stem_str; + /* Try each dependency; see if it "exists". */ - deps_found = 0; for (dep = rule->deps; dep != 0; dep = dep->next) { - /* If the dependency name has a %, substitute the stem. */ - p = strchr (dep_name (dep), '%'); - if (p != 0) - { - register unsigned int i; - if (check_lastslash) - { - /* Copy directory name from the original FILENAME. */ - i = lastslash - filename + 1; - bcopy (filename, depname, i); - } - else - i = 0; - bcopy (dep_name (dep), depname + i, p - dep_name (dep)); - i += p - dep_name (dep); - bcopy (stem, depname + i, stemlen); - i += stemlen; - strcpy (depname + i, p + 1); - p = depname; - } - else - p = dep_name (dep); + unsigned int len; + char *p2; + unsigned int order_only = 0; /* Set if '|' was seen. */ - /* P is now the actual dependency name as substituted. */ + /* In an ideal world we would take the dependency line, + substitute the stem, re-expand the whole line and chop it + into individual prerequisites. Unfortunately this won't work + because of the "check_lastslash" twist. Instead, we will + have to go word by word, taking $()'s into account, for each + word we will substitute the stem, re-expand, chop it up, and, + if check_lastslash != 0, add the directory part to each + resulting prerequisite. */ - if (file_impossible_p (p)) - { - /* If this dependency has already been ruled - "impossible", then the rule fails and don't - bother trying it on the second pass either - since we know that will fail too. */ - DBS (DB_IMPLICIT, - (p == depname + p = get_next_word (dep->name, &len); + + while (1) + { + int add_dir = 0; + int had_stem = 0; + + if (p == 0) + break; /* No more words */ + + /* Is there a pattern in this prerequisite? */ + + for (p2 = p; p2 < p + len && *p2 != '%'; ++p2) + ; + + if (dep->need_2nd_expansion) + { + /* If the dependency name has %, substitute the stem. + + Watch out, we are going to do something tricky + here. If we just replace % with the stem value, + later, when we do the second expansion, we will + re-expand this stem value once again. This is not + good especially if you have certain characters in + your stem (like $). + + Instead, we will replace % with $* and allow the + second expansion to take care of it for us. This way + (since $* is a simple variable) there won't be + additional re-expansion of the stem. */ + + if (p2 < p + len) + { + register unsigned int i = p2 - p; + bcopy (p, depname, i); + bcopy ("$*", depname + i, 2); + bcopy (p2 + 1, depname + i + 2, len - i - 1); + depname[len + 2 - 1] = '\0'; + + if (check_lastslash) + add_dir = 1; + + had_stem = 1; + } + else + { + bcopy (p, depname, len); + depname[len] = '\0'; + } + + /* Set file variables. Note that we cannot do it once + at the beginning of the function because of the stem + value. */ + if (!file_variables_set) + { + set_file_variables (file); + file_variables_set = 1; + } + + p2 = variable_expand_for_file (depname, file); + } + else + { + if (p2 < p + len) + { + register unsigned int i = p2 - p; + bcopy (p, depname, i); + bcopy (stem_str, depname + i, stemlen); + bcopy (p2 + 1, depname + i + stemlen, len - i - 1); + depname[len + stemlen - 1] = '\0'; + + if (check_lastslash) + add_dir = 1; + + had_stem = 1; + } + else + { + bcopy (p, depname, len); + depname[len] = '\0'; + } + + p2 = depname; + } + + /* Parse the dependencies. */ + + while (1) + { + id_ptr = &deps; + + for (; *id_ptr; id_ptr = &(*id_ptr)->next) + ; + + *id_ptr = (struct idep *) + multi_glob ( + parse_file_seq (&p2, + order_only ? '\0' : '|', + sizeof (struct idep), + 1), sizeof (struct idep)); + + /* @@ It would be nice to teach parse_file_seq or + multi_glob to add prefix. This would save us some + reallocations. */ + + if (order_only || add_dir || had_stem) + { + unsigned long l = lastslash - filename + 1; + + for (d = *id_ptr; d != 0; d = d->next) + { + if (order_only) + d->ignore_mtime = 1; + + if (add_dir) + { + char *p = d->name; + + d->name = xmalloc (strlen (p) + l + 1); + + bcopy (filename, d->name, l); + bcopy (p, d->name + l, strlen (p) + 1); + + free (p); + } + + if (had_stem) + d->had_stem = 1; + } + } + + if (!order_only && *p2) + { + ++p2; + order_only = 1; + continue; + } + + break; + } + + p += len; + p = get_next_word (p, &len); + } + } + + /* Reset the stem in FILE. */ + + file->stem = 0; + + /* @@ This loop can be combined with the previous one. I do + it separately for now for transparency.*/ + + for (d = deps; d != 0; d = d->next) + { + char *name = d->name; + + if (file_impossible_p (name)) + { + /* If this dependency has already been ruled "impossible", + then the rule fails and don't bother trying it on the + second pass either since we know that will fail too. */ + DBS (DB_IMPLICIT, + (d->had_stem ? _("Rejecting impossible implicit prerequisite `%s'.\n") : _("Rejecting impossible rule prerequisite `%s'.\n"), - p)); - tryrules[i] = 0; - break; - } + name)); + tryrules[i] = 0; - intermediate_files[deps_found] = 0; + failed = 1; + break; + } - DBS (DB_IMPLICIT, - (p == depname + DBS (DB_IMPLICIT, + (d->had_stem ? _("Trying implicit prerequisite `%s'.\n") - : _("Trying rule prerequisite `%s'.\n"), p)); + : _("Trying rule prerequisite `%s'.\n"), name)); - /* The DEP->changed flag says that this dependency resides in a - nonexistent directory. So we normally can skip looking for - the file. However, if CHECK_LASTSLASH is set, then the - dependency file we are actually looking for is in a different - directory (the one gotten by prepending FILENAME's directory), - so it might actually exist. */ + /* If this prerequisite also happened to be explicitly mentioned + for FILE skip all the test below since it it has to be built + anyway, no matter which implicit rule we choose. */ - if (lookup_file (p) != 0 - || ((!dep->changed || check_lastslash) && file_exists_p (p))) - { - found_files[deps_found++] = xstrdup (p); - continue; - } - /* This code, given FILENAME = "lib/foo.o", dependency name - "lib/foo.c", and VPATH=src, searches for "src/lib/foo.c". */ - vp = p; - if (vpath_search (&vp, (FILE_TIMESTAMP *) 0)) - { - DBS (DB_IMPLICIT, - (_("Found prerequisite `%s' as VPATH `%s'\n"), p, vp)); - strcpy (vp, p); - found_files[deps_found++] = vp; - continue; - } + for (expl_d = file->deps; expl_d != 0; expl_d = expl_d->next) + if (streq (dep_name (expl_d), name)) + break; + if (expl_d != 0) + continue; - /* We could not find the file in any place we should look. - Try to make this dependency as an intermediate file, - but only on the second pass. */ + /* The DEP->changed flag says that this dependency resides in a + nonexistent directory. So we normally can skip looking for + the file. However, if CHECK_LASTSLASH is set, then the + dependency file we are actually looking for is in a different + directory (the one gotten by prepending FILENAME's directory), + so it might actually exist. */ - if (intermed_ok) - { - if (intermediate_file == 0) - intermediate_file - = (struct file *) alloca (sizeof (struct file)); + /* @@ dep->changed check is disabled. */ + if (((f = lookup_file (name)) != 0 && f->is_target) + /*|| ((!dep->changed || check_lastslash) && */ + || file_exists_p (name)) + continue; - DBS (DB_IMPLICIT, + /* This code, given FILENAME = "lib/foo.o", dependency name + "lib/foo.c", and VPATH=src, searches for "src/lib/foo.c". */ + vname = name; + if (vpath_search (&vname, (FILE_TIMESTAMP *) 0)) + { + DBS (DB_IMPLICIT, + (_("Found prerequisite `%s' as VPATH `%s'\n"), + name, + vname)); + + free (vname); + continue; + } + + + /* We could not find the file in any place we should look. Try + to make this dependency as an intermediate file, but only on + the second pass. */ + + if (intermed_ok) + { + if (intermediate_file == 0) + intermediate_file + = (struct file *) alloca (sizeof (struct file)); + + DBS (DB_IMPLICIT, (_("Looking for a rule with intermediate file `%s'.\n"), - p)); + name)); - bzero ((char *) intermediate_file, sizeof (struct file)); - intermediate_file->name = p; - if (pattern_search (intermediate_file, 0, depth + 1, - recursions + 1)) - { - p = xstrdup (p); - intermediate_patterns[deps_found] - = intermediate_file->name; - intermediate_file->name = p; - intermediate_files[deps_found] = intermediate_file; - intermediate_file = 0; - /* Allocate an extra copy to go in FOUND_FILES, - because every elt of FOUND_FILES is consumed - or freed later. */ - found_files[deps_found] = xstrdup (p); - ++deps_found; - continue; - } + bzero ((char *) intermediate_file, sizeof (struct file)); + intermediate_file->name = name; + if (pattern_search (intermediate_file, + 0, + depth + 1, + recursions + 1)) + { + d->intermediate_file = intermediate_file; + d->intermediate_pattern = intermediate_file->name; - /* If we have tried to find P as an intermediate - file and failed, mark that name as impossible - so we won't go through the search again later. */ - file_impossible (p); - } + intermediate_file->name = xstrdup (name); + intermediate_file = 0; - /* A dependency of this rule does not exist. - Therefore, this rule fails. */ - break; - } + continue; + } - /* This rule is no longer `in use' for recursive searches. */ + /* If we have tried to find P as an intermediate + file and failed, mark that name as impossible + so we won't go through the search again later. */ + if (intermediate_file->variables) + free_variable_set (intermediate_file->variables); + file_impossible (name); + } + + /* A dependency of this rule does not exist. Therefore, + this rule fails. */ + failed = 1; + break; + } + + /* This rule is no longer `in use' for recursive searches. */ rule->in_use = 0; - if (dep != 0) - { - /* This pattern rule does not apply. - If some of its dependencies succeeded, - free the data structure describing them. */ - while (deps_found-- > 0) - { - register struct file *f = intermediate_files[deps_found]; - free (found_files[deps_found]); - if (f != 0 - && (f->stem < f->name - || f->stem > f->name + strlen (f->name))) - free (f->stem); - } - } + if (failed) + { + /* This pattern rule does not apply. If some of its + dependencies succeeded, free the data structure + describing them. */ + free_idep_chain (deps); + deps = 0; + } else /* This pattern rule does apply. Stop looking for one. */ break; @@ -510,11 +802,29 @@ pattern_search (file, archive, depth, recursions) This includes the intermediate files, if any. Convert them into entries on the deps-chain of FILE. */ - while (deps_found-- > 0) + if (remove_explicit_deps) + { + /* Remove all the dependencies that didn't come from + this implicit rule. */ + + dep = file->deps; + while (dep != 0) + { + struct dep *next = dep->next; + free_dep (dep); + dep = next; + } + file->deps = 0; + } + + expl_d = file->deps; /* We will add them at the end. */ + d_ptr = &file->deps; + + for (d = deps; d != 0; d = d->next) { register char *s; - if (intermediate_files[deps_found] != 0) + if (d->intermediate_file != 0) { /* If we need to use an intermediate file, make sure it is entered as a target, with the info that was @@ -523,15 +833,30 @@ pattern_search (file, archive, depth, recursions) a target; therefore we can assume that the deps and cmds of F below are null before we change them. */ - struct file *imf = intermediate_files[deps_found]; - register struct file *f = enter_file (imf->name); + struct file *imf = d->intermediate_file; + register struct file *f = lookup_file (imf->name); + + /* We don't want to delete an intermediate file that happened + to be a prerequisite of some (other) target. Mark it as + precious. */ + if (f != 0) + f->precious = 1; + else + f = enter_file (imf->name); + f->deps = imf->deps; f->cmds = imf->cmds; f->stem = imf->stem; f->also_make = imf->also_make; - imf = lookup_file (intermediate_patterns[deps_found]); - if (imf != 0 && imf->precious) - f->precious = 1; + f->is_target = 1; + + if (!f->precious) + { + imf = lookup_file (d->intermediate_pattern); + if (imf != 0 && imf->precious) + f->precious = 1; + } + f->intermediate = 1; f->tried_implicit = 1; for (dep = f->deps; dep != 0; dep = dep->next) @@ -545,12 +870,12 @@ pattern_search (file, archive, depth, recursions) } } - dep = (struct dep *) xmalloc (sizeof (struct dep)); - dep->ignore_mtime = 0; - s = found_files[deps_found]; + dep = alloc_dep (); + dep->ignore_mtime = d->ignore_mtime; + s = d->name; /* Hijacking the name. */ + d->name = 0; if (recursions == 0) { - dep->name = 0; dep->file = lookup_file (s); if (dep->file == 0) /* enter_file consumes S's storage. */ @@ -563,10 +888,9 @@ pattern_search (file, archive, depth, recursions) else { dep->name = s; - dep->file = 0; - dep->changed = 0; } - if (intermediate_files[deps_found] == 0 && tryrules[foundrule]->terminal) + + if (d->intermediate_file == 0 && tryrules[foundrule]->terminal) { /* If the file actually existed (was not an intermediate file), and the rule that found it was a terminal one, then we want @@ -578,10 +902,13 @@ pattern_search (file, archive, depth, recursions) else dep->file->tried_implicit = 1; } - dep->next = file->deps; - file->deps = dep; + + *d_ptr = dep; + d_ptr = &dep->next; } + *d_ptr = expl_d; + if (!checked_lastslash[foundrule]) { /* Always allocate new storage, since STEM might be @@ -603,6 +930,14 @@ pattern_search (file, archive, depth, recursions) } file->cmds = rule->cmds; + file->is_target = 1; + + /* Set precious flag. */ + { + struct file *f = lookup_file (rule->targets[matches[foundrule]]); + if (f && f->precious) + file->precious = 1; + } /* If this rule builds other targets, too, put the others into FILE's `also_make' member. */ @@ -611,9 +946,10 @@ pattern_search (file, archive, depth, recursions) for (i = 0; rule->targets[i] != 0; ++i) if (i != matches[foundrule]) { - struct dep *new = (struct dep *) xmalloc (sizeof (struct dep)); + struct file *f; + struct dep *new = alloc_dep (); + /* GKM FIMXE: handle '|' here too */ - new->ignore_mtime = 0; new->name = p = (char *) xmalloc (rule->lens[i] + fullstemlen + 1); bcopy (rule->targets[i], p, rule->suffixes[i] - rule->targets[i] - 1); @@ -624,11 +960,22 @@ pattern_search (file, archive, depth, recursions) rule->lens[i] - (rule->suffixes[i] - rule->targets[i]) + 1); new->file = enter_file (new->name); new->next = file->also_make; + + /* Set precious flag. */ + f = lookup_file (rule->targets[i]); + if (f && f->precious) + new->file->precious = 1; + + /* Set the is_target flag so that this file is not treated + as intermediate by the pattern rule search algorithm and + file_exists_p cannot pick it up yet. */ + new->file->is_target = 1; + file->also_make = new; } done: - free (intermediate_files); + free_idep_chain (deps); free (tryrules); return rule != 0; diff --git a/src/bin/make/job.c b/src/bin/make/job.c index 63456a7a81..a81cd81cea 100644 --- a/src/bin/make/job.c +++ b/src/bin/make/job.c @@ -1,21 +1,20 @@ /* Job execution and handling for GNU Make. -Copyright (C) 1988,89,90,91,92,93,94,95,96,97,99 Free Software Foundation, Inc. +Copyright (C) 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, +1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006 Free Software +Foundation, Inc. This file is part of GNU Make. -GNU Make is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 2, or (at your option) -any later version. +GNU Make is free software; you can redistribute it and/or modify it under the +terms of the GNU General Public License as published by the Free Software +Foundation; either version 2, or (at your option) any later version. -GNU Make is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. +GNU Make is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR +A PARTICULAR PURPOSE. See the GNU General Public License for more details. -You should have received a copy of the GNU General Public License -along with GNU Make; see the file COPYING. If not, write to -the Free Software Foundation, Inc., 59 Temple Place - Suite 330, -Boston, MA 02111-1307, USA. */ +You should have received a copy of the GNU General Public License along with +GNU Make; see the file COPYING. If not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. */ #include "make.h" @@ -32,31 +31,50 @@ Boston, MA 02111-1307, USA. */ /* Default shell to use. */ #ifdef WINDOWS32 +#include + char *default_shell = "sh.exe"; int no_default_sh_exe = 1; int batch_mode_shell = 1; -#else /* WINDOWS32 */ -# ifdef _AMIGA +HANDLE main_thread; + +#elif defined (_AMIGA) + char default_shell[] = ""; extern int MyExecute (char **); -# else /* _AMIGA */ -# ifdef __MSDOS__ +int batch_mode_shell = 0; + +#elif defined (__MSDOS__) + /* The default shell is a pointer so we can change it if Makefile says so. It is without an explicit path so we get a chance to search the $PATH for it (since MSDOS doesn't have standard directories we could trust). */ char *default_shell = "command.com"; -# else /* __MSDOS__ */ -# ifdef VMS -# include -char default_shell[] = ""; -# else -char default_shell[] = "/bin/sh"; -# endif /* VMS */ -# endif /* __MSDOS__ */ int batch_mode_shell = 0; -# endif /* _AMIGA */ -#endif /* WINDOWS32 */ + +#elif defined (__EMX__) + +char *default_shell = "/bin/sh"; +int batch_mode_shell = 0; + +#elif defined (VMS) + +# include +char default_shell[] = ""; +int batch_mode_shell = 0; + +#elif defined (__riscos__) + +char default_shell[] = ""; +int batch_mode_shell = 0; + +#else + +char default_shell[] = "/bin/sh"; +int batch_mode_shell = 0; + +#endif #ifdef __MSDOS__ # include @@ -80,6 +98,7 @@ static int amiga_batch_file; # endif # include # include +static void vmsWaitForChildren PARAMS ((int *)); #endif #ifdef WINDOWS32 @@ -91,10 +110,8 @@ static int amiga_batch_file; # include "pathstuff.h" #endif /* WINDOWS32 */ -#ifdef HAVE_FCNTL_H -# include -#else -# include +#ifdef __EMX__ +# include #endif #if defined (HAVE_SYS_WAIT_H) || defined (HAVE_UNION_WAIT) @@ -157,21 +174,6 @@ extern int wait (); #endif /* Don't have `union wait'. */ -/* How to set close-on-exec for a file descriptor. */ - -#if !defined F_SETFD -# define CLOSE_ON_EXEC(_d) -#else -# ifndef FD_CLOEXEC -# define FD_CLOEXEC 1 -# endif -# define CLOSE_ON_EXEC(_d) (void) fcntl ((_d), F_SETFD, FD_CLOEXEC) -#endif - -#ifdef VMS -static int vms_jobsefnmask = 0; -#endif /* !VMS */ - #ifndef HAVE_UNISTD_H extern int dup2 (); extern int execve (); @@ -199,9 +201,6 @@ static void start_job_command PARAMS ((struct child *child)); static int load_too_high PARAMS ((void)); static int job_next_command PARAMS ((struct child *)); static int start_waiting_job PARAMS ((struct child *)); -#ifdef VMS -static void vmsWaitForChildren PARAMS ((int *)); -#endif /* Chain of all live (or recently deceased) children. */ @@ -223,26 +222,162 @@ static struct child *waiting_jobs = 0; int unixy_shell = 1; +/* Number of jobs started in the current second. */ + +unsigned long job_counter = 0; + +/* Number of jobserver tokens this instance is currently using. */ + +unsigned int jobserver_tokens = 0; #ifdef WINDOWS32 /* * The macro which references this function is defined in make.h. */ -int w32_kill(int pid, int sig) +int +w32_kill(int pid, int sig) { - return ((process_kill(pid, sig) == TRUE) ? 0 : -1); + return ((process_kill((HANDLE)pid, sig) == TRUE) ? 0 : -1); +} + +/* This function creates a temporary file name with an extension specified + * by the unixy arg. + * Return an xmalloc'ed string of a newly created temp file and its + * file descriptor, or die. */ +static char * +create_batch_file (char const *base, int unixy, int *fd) +{ + const char *const ext = unixy ? "sh" : "bat"; + const char *error = NULL; + char temp_path[MAXPATHLEN]; /* need to know its length */ + unsigned path_size = GetTempPath(sizeof temp_path, temp_path); + int path_is_dot = 0; + unsigned uniq = 1; + const unsigned sizemax = strlen (base) + strlen (ext) + 10; + + if (path_size == 0) + { + path_size = GetCurrentDirectory (sizeof temp_path, temp_path); + path_is_dot = 1; + } + + while (path_size > 0 && + path_size + sizemax < sizeof temp_path && + uniq < 0x10000) + { + unsigned size = sprintf (temp_path + path_size, + "%s%s-%x.%s", + temp_path[path_size - 1] == '\\' ? "" : "\\", + base, uniq, ext); + HANDLE h = CreateFile (temp_path, /* file name */ + GENERIC_READ | GENERIC_WRITE, /* desired access */ + 0, /* no share mode */ + NULL, /* default security attributes */ + CREATE_NEW, /* creation disposition */ + FILE_ATTRIBUTE_NORMAL | /* flags and attributes */ + FILE_ATTRIBUTE_TEMPORARY, /* we'll delete it */ + NULL); /* no template file */ + + if (h == INVALID_HANDLE_VALUE) + { + const DWORD er = GetLastError(); + + if (er == ERROR_FILE_EXISTS || er == ERROR_ALREADY_EXISTS) + ++uniq; + + /* the temporary path is not guaranteed to exist */ + else if (path_is_dot == 0) + { + path_size = GetCurrentDirectory (sizeof temp_path, temp_path); + path_is_dot = 1; + } + + else + { + error = map_windows32_error_to_string (er); + break; + } + } + else + { + const unsigned final_size = path_size + size + 1; + char *const path = (char *) xmalloc (final_size); + memcpy (path, temp_path, final_size); + *fd = _open_osfhandle ((long)h, 0); + if (unixy) + { + char *p; + int ch; + for (p = path; (ch = *p) != 0; ++p) + if (ch == '\\') + *p = '/'; + } + return path; /* good return */ + } + } + + *fd = -1; + if (error == NULL) + error = _("Cannot create a temporary file\n"); + fatal (NILF, error); + + /* not reached */ + return NULL; } #endif /* WINDOWS32 */ + +#ifdef __EMX__ +/* returns whether path is assumed to be a unix like shell. */ +int +_is_unixy_shell (const char *path) +{ + /* list of non unix shells */ + const char *known_os2shells[] = { + "cmd.exe", + "cmd", + "4os2.exe", + "4os2", + "4dos.exe", + "4dos", + "command.com", + "command", + NULL + }; + + /* find the rightmost '/' or '\\' */ + const char *name = strrchr (path, '/'); + const char *p = strrchr (path, '\\'); + unsigned i; + + if (name && p) /* take the max */ + name = (name > p) ? name : p; + else if (p) /* name must be 0 */ + name = p; + else if (!name) /* name and p must be 0 */ + name = path; + + if (*name == '/' || *name == '\\') name++; + + i = 0; + while (known_os2shells[i] != NULL) { + if (stricmp (name, known_os2shells[i]) == 0) /* strcasecmp() */ + return 0; /* not a unix shell */ + i++; + } + + /* in doubt assume a unix like shell */ + return 1; +} +#endif /* __EMX__ */ + /* Write an error message describing the exit status given in EXIT_CODE, EXIT_SIG, and COREDUMP, for the target TARGET_NAME. Append "(ignored)" if IGNORED is nonzero. */ static void -child_error (target_name, exit_code, exit_sig, coredump, ignored) - char *target_name; - int exit_code, exit_sig, coredump; - int ignored; +child_error (char *target_name, int exit_code, int exit_sig, int coredump, + int ignored) { if (ignored && silent_flag) return; @@ -265,117 +400,6 @@ child_error (target_name, exit_code, exit_sig, coredump, ignored) #endif /* VMS */ } -#ifdef VMS -/* Wait for nchildren children to terminate */ -static void -vmsWaitForChildren(int *status) -{ - while (1) - { - if (!vms_jobsefnmask) - { - *status = 0; - return; - } - - *status = sys$wflor (32, vms_jobsefnmask); - } - return; -} - -/* Set up IO redirection. */ - -char * -vms_redirect (desc, fname, ibuf) - struct dsc$descriptor_s *desc; - char *fname; - char *ibuf; -{ - char *fptr; - extern char *vmsify (); - - ibuf++; - while (isspace ((unsigned char)*ibuf)) - ibuf++; - fptr = ibuf; - while (*ibuf && !isspace ((unsigned char)*ibuf)) - ibuf++; - *ibuf = 0; - if (strcmp (fptr, "/dev/null") != 0) - { - strcpy (fname, vmsify (fptr, 0)); - if (strchr (fname, '.') == 0) - strcat (fname, "."); - } - desc->dsc$w_length = strlen(fname); - desc->dsc$a_pointer = fname; - desc->dsc$b_dtype = DSC$K_DTYPE_T; - desc->dsc$b_class = DSC$K_CLASS_S; - - if (*fname == 0) - printf (_("Warning: Empty redirection\n")); - return ibuf; -} - - -/* - found apostrophe at (p-1) - - inc p until after closing apostrophe. */ - -static char * -handle_apos (char *p) -{ - int alast; - int inside; - -#define SEPCHARS ",/()= " - - inside = 0; - - while (*p != 0) - { - if (*p == '"') - { - if (inside) - { - while ((alast > 0) - && (*p == '"')) - { - p++; - alast--; - } - if (alast == 0) - inside = 0; - else - { - fprintf (stderr, _("Syntax error, still inside '\"'\n")); - exit (3); - } - } - else - { - p++; - if (strchr (SEPCHARS, *p)) - break; - inside = 1; - alast = 1; - while (*p == '"') - { - alast++; - p++; - } - } - } - else - p++; - } - - return p; -} - -#endif - /* Handle a dead child. This handler may or may not ever be installed. @@ -390,8 +414,7 @@ handle_apos (char *p) static unsigned int dead_children = 0; RETSIGTYPE -child_handler (sig) - int sig; +child_handler (int sig UNUSED) { ++dead_children; @@ -401,9 +424,15 @@ child_handler (sig) job_rfd = -1; } - DB (DB_JOBS, (_("Got a SIGCHLD; %u unreaped children.\n"), dead_children)); -} +#ifdef __EMX__ + /* The signal handler must called only once! */ + signal (SIGCHLD, SIG_DFL); +#endif + /* This causes problems if the SIGCHLD interrupts a printf(). + DB (DB_JOBS, (_("Got a SIGCHLD; %u unreaped children.\n"), dead_children)); + */ +} extern int shell_function_pid, shell_function_completed; @@ -415,12 +444,13 @@ extern int shell_function_pid, shell_function_completed; print an error message first. */ void -reap_children (block, err) - int block, err; +reap_children (int block, int err) { +#ifndef WINDOWS32 WAIT_T status; /* Initially, assume we have some. */ int reap_more = 1; +#endif #ifdef WAIT_NOHANG # define REAP_MORE reap_more @@ -440,17 +470,23 @@ reap_children (block, err) && (block || REAP_MORE)) { int remote = 0; - register int pid; + pid_t pid; int exit_code, exit_sig, coredump; register struct child *lastc, *c; int child_failed; int any_remote, any_local; + int dontcare; if (err && block) { - /* We might block for a while, so let the user know why. */ + static int printed = 0; + + /* We might block for a while, so let the user know why. + Only print this message once no matter how many jobs are left. */ fflush (stdout); - error (NILF, _("*** Waiting for unfinished jobs....")); + if (!printed) + error (NILF, _("*** Waiting for unfinished jobs....")); + printed = 1; } /* We have one less dead child to reap. As noted in @@ -534,6 +570,10 @@ reap_children (block, err) exit_code = WEXITSTATUS (status); exit_sig = WIFSIGNALED (status) ? WTERMSIG (status) : 0; coredump = WCOREDUMP (status); + + /* If we have started jobs in this second, remove one. */ + if (job_counter) + --job_counter; } else { @@ -577,30 +617,55 @@ reap_children (block, err) #ifdef WINDOWS32 { HANDLE hPID; - int err; + int werr; + HANDLE hcTID, hcPID; + exit_code = 0; + exit_sig = 0; + coredump = 0; + + /* Record the thread ID of the main process, so that we + could suspend it in the signal handler. */ + if (!main_thread) + { + hcTID = GetCurrentThread (); + hcPID = GetCurrentProcess (); + if (!DuplicateHandle (hcPID, hcTID, hcPID, &main_thread, 0, + FALSE, DUPLICATE_SAME_ACCESS)) + { + DWORD e = GetLastError (); + fprintf (stderr, + "Determine main thread ID (Error %ld: %s)\n", + e, map_windows32_error_to_string(e)); + } + else + DB (DB_VERBOSE, ("Main thread handle = 0x%08lx\n", + (unsigned long)main_thread)); + } /* wait for anything to finish */ - if (hPID = process_wait_for_any()) { + hPID = process_wait_for_any(); + if (hPID) + { - /* was an error found on this process? */ - err = process_last_err(hPID); + /* was an error found on this process? */ + werr = process_last_err(hPID); - /* get exit data */ - exit_code = process_exit_code(hPID); + /* get exit data */ + exit_code = process_exit_code(hPID); - if (err) - fprintf(stderr, "make (e=%d): %s", - exit_code, map_windows32_error_to_string(exit_code)); + if (werr) + fprintf(stderr, "make (e=%d): %s", + exit_code, map_windows32_error_to_string(exit_code)); - /* signal */ - exit_sig = process_signal(hPID); + /* signal */ + exit_sig = process_signal(hPID); - /* cleanup process */ - process_cleanup(hPID); + /* cleanup process */ + process_cleanup(hPID); - coredump = 0; - } - pid = (int) hPID; + coredump = 0; + } + pid = (pid_t) hPID; } #endif /* WINDOWS32 */ } @@ -651,12 +716,17 @@ reap_children (block, err) if (c->good_stdin) good_stdin_used = 0; + dontcare = c->dontcare; + if (child_failed && !c->noerror && !ignore_errors_flag) { /* The commands failed. Write an error message, delete non-precious targets, and abort. */ static int delete_on_error = -1; - child_error (c->file->name, exit_code, exit_sig, coredump, 0); + + if (!dontcare) + child_error (c->file->name, exit_code, exit_sig, coredump, 0); + c->file->update_status = 2; if (delete_on_error == -1) { @@ -756,7 +826,7 @@ reap_children (block, err) /* If the job failed, and the -k flag was not given, die, unless we are already in the process of dying. */ - if (!err && child_failed && !keep_going_flag && + if (!err && child_failed && !dontcare && !keep_going_flag && /* fatal_error_signal will die with the right signal. */ !handling_fatal_signal) die (2); @@ -771,26 +841,32 @@ reap_children (block, err) /* Free the storage allocated for CHILD. */ static void -free_child (child) - register struct child *child; +free_child (struct child *child) { - /* If this child is the only one it was our "free" job, so don't put a - token back for it. This child has already been removed from the list, - so if there any left this wasn't the last one. */ + if (!jobserver_tokens) + fatal (NILF, "INTERNAL: Freeing child 0x%08lx (%s) but no tokens left!\n", + (unsigned long int) child, child->file->name); - if (job_fds[1] >= 0 && children) + /* If we're using the jobserver and this child is not the only outstanding + job, put a token back into the pipe for it. */ + + if (job_fds[1] >= 0 && jobserver_tokens > 1) { char token = '+'; + int r; /* Write a job token back to the pipe. */ - if (write (job_fds[1], &token, 1) != 1) + EINTRLOOP (r, write (job_fds[1], &token, 1)); + if (r != 1) pfatal_with_name (_("write jobserver")); DB (DB_JOBS, (_("Released token for child 0x%08lx (%s).\n"), (unsigned long int) child, child->file->name)); } + --jobserver_tokens; + if (handling_fatal_signal) /* Don't bother free'ing if about to die. */ return; @@ -818,7 +894,7 @@ extern sigset_t fatal_signal_set; #endif void -block_sigs () +block_sigs (void) { #ifdef POSIX (void) sigprocmask (SIG_BLOCK, &fatal_signal_set, (sigset_t *) 0); @@ -829,9 +905,9 @@ block_sigs () #endif } -#ifdef POSIX +#ifdef POSIX void -unblock_sigs () +unblock_sigs (void) { sigset_t empty; sigemptyset (&empty); @@ -840,21 +916,42 @@ unblock_sigs () #endif #ifdef MAKE_JOBSERVER +RETSIGTYPE +job_noop (int sig UNUSED) +{ +} /* Set the child handler action flags to FLAGS. */ static void -set_child_handler_action_flags (flags) - int flags; +set_child_handler_action_flags (int set_handler, int set_alarm) { struct sigaction sa; + +#ifdef __EMX__ + /* The child handler must be turned off here. */ + signal (SIGCHLD, SIG_DFL); +#endif + bzero ((char *) &sa, sizeof sa); sa.sa_handler = child_handler; - sa.sa_flags = flags; + sa.sa_flags = set_handler ? 0 : SA_RESTART; #if defined SIGCHLD sigaction (SIGCHLD, &sa, NULL); #endif #if defined SIGCLD && SIGCLD != SIGCHLD sigaction (SIGCLD, &sa, NULL); #endif +#if defined SIGALRM + if (set_alarm) + { + /* If we're about to enter the read(), set an alarm to wake up in a + second so we can check if the load has dropped and we can start more + work. On the way out, turn off the alarm and set SIG_DFL. */ + alarm (set_handler ? 1 : 0); + sa.sa_handler = set_handler ? job_noop : SIG_DFL; + sa.sa_flags = 0; + sigaction (SIGALRM, &sa, NULL); + } +#endif } #endif @@ -867,10 +964,9 @@ set_child_handler_action_flags (flags) it can be cleaned up in the event of a fatal signal. */ static void -start_job_command (child) - register struct child *child; +start_job_command (struct child *child) { -#ifndef _AMIGA +#if !defined(_AMIGA) && !defined(WINDOWS32) static int bad_stdin = -1; #endif register char *p; @@ -891,7 +987,7 @@ start_job_command (child) | child->file->cmds->lines_flags[child->command_line - 1]); p = child->command_ptr; - child->noerror = flags & COMMANDS_NOERROR; + child->noerror = ((flags & COMMANDS_NOERROR) != 0); while (*p != '\0') { @@ -1006,7 +1102,7 @@ start_job_command (child) #if !defined(VMS) && !defined(_AMIGA) if ( -#ifdef __MSDOS__ +#if defined __MSDOS__ || defined (__EMX__) unixy_shell /* the test is complicated and we already did it */ #else (argv[0] && !strcmp (argv[0], "/bin/sh")) @@ -1119,7 +1215,6 @@ start_job_command (child) child->remote = 0; #ifdef VMS - if (!child_execute_job (argv, child)) { /* Fork failed! */ perror_with_name ("vfork", ""); @@ -1129,6 +1224,40 @@ start_job_command (child) #else parent_environ = environ; + +# ifdef __EMX__ + /* If we aren't running a recursive command and we have a jobserver + pipe, close it before exec'ing. */ + if (!(flags & COMMANDS_RECURSE) && job_fds[0] >= 0) + { + CLOSE_ON_EXEC (job_fds[0]); + CLOSE_ON_EXEC (job_fds[1]); + } + if (job_rfd >= 0) + CLOSE_ON_EXEC (job_rfd); + + /* Never use fork()/exec() here! Use spawn() instead in exec_command() */ + child->pid = child_execute_job (child->good_stdin ? 0 : bad_stdin, 1, + argv, child->environment); + if (child->pid < 0) + { + /* spawn failed! */ + unblock_sigs (); + perror_with_name ("spawn", ""); + goto error; + } + + /* undo CLOSE_ON_EXEC() after the child process has been started */ + if (!(flags & COMMANDS_RECURSE) && job_fds[0] >= 0) + { + fcntl (job_fds[0], F_SETFD, 0); + fcntl (job_fds[1], F_SETFD, 0); + } + if (job_rfd >= 0) + fcntl (job_rfd, F_SETFD, 0); + +#else /* !__EMX__ */ + child->pid = vfork (); environ = parent_environ; /* Restore value child may have clobbered. */ if (child->pid == 0) @@ -1156,6 +1285,7 @@ start_job_command (child) perror_with_name ("vfork", ""); goto error; } +# endif /* !__EMX__ */ #endif /* !VMS */ } @@ -1250,16 +1380,20 @@ start_job_command (child) int i; unblock_sigs(); fprintf(stderr, - _("process_easy() failed failed to launch process (e=%d)\n"), - process_last_err(hPID)); - for (i = 0; argv[i]; i++) - fprintf(stderr, "%s ", argv[i]); - fprintf(stderr, _("\nCounted %d args in failed launch\n"), i); + _("process_easy() failed to launch process (e=%ld)\n"), + process_last_err(hPID)); + for (i = 0; argv[i]; i++) + fprintf(stderr, "%s ", argv[i]); + fprintf(stderr, _("\nCounted %d args in failed launch\n"), i); + goto error; } } #endif /* WINDOWS32 */ #endif /* __MSDOS__ or Amiga or WINDOWS32 */ + /* Bump the number of jobs started in this second. */ + ++job_counter; + /* We are the parent side. Set the state to say the commands are running and return. */ @@ -1284,8 +1418,7 @@ start_job_command (child) the load was too high and the child was put on the `waiting_jobs' chain. */ static int -start_waiting_job (c) - struct child *c; +start_waiting_job (struct child *c) { struct file *f = c->file; @@ -1297,7 +1430,12 @@ start_waiting_job (c) /* If we are running at least one job already and the load average is too high, make this one wait. */ - if (!c->remote && job_slots_used > 0 && load_too_high ()) + if (!c->remote + && ((job_slots_used > 0 && load_too_high ()) +#ifdef WINDOWS32 + || (process_used_slots () >= MAXIMUM_WAIT_OBJECTS) +#endif + )) { /* Put this child on the chain of children waiting for the load average to go down. */ @@ -1344,8 +1482,7 @@ start_waiting_job (c) /* Create a `struct child' for FILE and start its commands running. */ void -new_job (file) - register struct file *file; +new_job (struct file *file) { register struct commands *cmds = file->cmds; register struct child *c; @@ -1473,6 +1610,10 @@ new_job (file) c->command_lines = lines; c->sh_batch_file = NULL; + /* Cache dontcare flag because file->dontcare can be changed once we + return. Check dontcare inheritance mechanism for details. */ + c->dontcare = file->dontcare; + /* Fetch the first command line to be run. */ job_next_command (c); @@ -1507,7 +1648,7 @@ new_job (file) children ? "" : "don't ")); /* If we don't already have a job started, use our "free" token. */ - if (!children) + if (!jobserver_tokens) break; /* Read a token. As long as there's no token available we'll block. @@ -1542,15 +1683,25 @@ new_job (file) /* Reap anything that's currently waiting. */ reap_children (0, 0); - /* If our "free" token has become available, use it. */ - if (!children) + /* Kick off any jobs we have waiting for an opportunity that + can run now (ie waiting for load). */ + start_waiting_jobs (); + + /* If our "free" slot has become available, use it; we don't need an + actual token. */ + if (!jobserver_tokens) break; + /* There must be at least one child already, or we have no business + waiting for a token. */ + if (!children) + fatal (NILF, "INTERNAL: no children as we go to sleep on read\n"); + /* Set interruptible system calls, and read() for a job token. */ - set_child_handler_action_flags (0); + set_child_handler_action_flags (1, waiting_jobs != NULL); got_token = read (job_rfd, &token, 1); saved_errno = errno; - set_child_handler_action_flags (SA_RESTART); + set_child_handler_action_flags (0, waiting_jobs != NULL); /* If we got one, we're done here. */ if (got_token == 1) @@ -1570,6 +1721,8 @@ new_job (file) } #endif + ++jobserver_tokens; + /* The job is now primed. Start it running. (This will notice if there are in fact no commands.) */ (void) start_waiting_job (c); @@ -1587,8 +1740,7 @@ new_job (file) Returns nonzero if there is another command. */ static int -job_next_command (child) - struct child *child; +job_next_command (struct child *child) { while (child->command_ptr == 0 || *child->command_ptr == '\0') { @@ -1606,17 +1758,67 @@ job_next_command (child) return 1; } +/* Determine if the load average on the system is too high to start a new job. + The real system load average is only recomputed once a second. However, a + very parallel make can easily start tens or even hundreds of jobs in a + second, which brings the system to its knees for a while until that first + batch of jobs clears out. + + To avoid this we use a weighted algorithm to try to account for jobs which + have been started since the last second, and guess what the load average + would be now if it were computed. + + This algorithm was provided by Thomas Riedl , + who writes: + +! calculate something load-oid and add to the observed sys.load, +! so that latter can catch up: +! - every job started increases jobctr; +! - every dying job decreases a positive jobctr; +! - the jobctr value gets zeroed every change of seconds, +! after its value*weight_b is stored into the 'backlog' value last_sec +! - weight_a times the sum of jobctr and last_sec gets +! added to the observed sys.load. +! +! The two weights have been tried out on 24 and 48 proc. Sun Solaris-9 +! machines, using a several-thousand-jobs-mix of cpp, cc, cxx and smallish +! sub-shelled commands (rm, echo, sed...) for tests. +! lowering the 'direct influence' factor weight_a (e.g. to 0.1) +! resulted in significant excession of the load limit, raising it +! (e.g. to 0.5) took bad to small, fast-executing jobs and didn't +! reach the limit in most test cases. +! +! lowering the 'history influence' weight_b (e.g. to 0.1) resulted in +! exceeding the limit for longer-running stuff (compile jobs in +! the .5 to 1.5 sec. range),raising it (e.g. to 0.5) overrepresented +! small jobs' effects. + + */ + +#define LOAD_WEIGHT_A 0.25 +#define LOAD_WEIGHT_B 0.25 + static int -load_too_high () +load_too_high (void) { -#if defined(__MSDOS__) || defined(VMS) || defined(_AMIGA) +#if defined(__MSDOS__) || defined(VMS) || defined(_AMIGA) || defined(__riscos__) return 1; #else - double load; + static double last_sec; + static time_t last_now; + double load, guess; + time_t now; + +#ifdef WINDOWS32 + /* sub_proc.c cannot wait for more than MAXIMUM_WAIT_OBJECTS children */ + if (process_used_slots () >= MAXIMUM_WAIT_OBJECTS) + return 1; +#endif if (max_load_average < 0) return 0; + /* Find the real system load average. */ make_access (); if (getloadavg (&load, 1) != 1) { @@ -1636,16 +1838,34 @@ load_too_high () } user_access (); - DB (DB_JOBS, ("Current system load = %f (max requested = %f)\n", - load, max_load_average)); - return load >= max_load_average; + /* If we're in a new second zero the counter and correct the backlog + value. Only keep the backlog for one extra second; after that it's 0. */ + now = time (NULL); + if (last_now < now) + { + if (last_now == now - 1) + last_sec = LOAD_WEIGHT_B * job_counter; + else + last_sec = 0.0; + + job_counter = 0; + last_now = now; + } + + /* Try to guess what the load would be right now. */ + guess = load + (LOAD_WEIGHT_A * (job_counter + last_sec)); + + DB (DB_JOBS, ("Estimated system load = %f (actual = %f) (max requested = %f)\n", + guess, load, max_load_average)); + + return guess >= max_load_average; #endif } /* Start jobs that are waiting for the load to be lower. */ void -start_waiting_jobs () +start_waiting_jobs (void) { struct child *job; @@ -1670,565 +1890,74 @@ start_waiting_jobs () } #ifndef WINDOWS32 -#ifdef VMS -#include -#include -/* This is called as an AST when a child process dies (it won't get - interrupted by anything except a higher level AST). -*/ -int vmsHandleChildTerm(struct child *child) -{ - int status; - register struct child *lastc, *c; - int child_failed; - - vms_jobsefnmask &= ~(1 << (child->efn - 32)); - - lib$free_ef(&child->efn); - - (void) sigblock (fatal_signal_mask); - - child_failed = !(child->cstatus & 1 || ((child->cstatus & 7) == 0)); - - /* Search for a child matching the deceased one. */ - lastc = 0; -#if defined(RECURSIVEJOBS) /* I've had problems with recursive stuff and process handling */ - for (c = children; c != 0 && c != child; lastc = c, c = c->next); -#else - c = child; -#endif - - if (child_failed && !c->noerror && !ignore_errors_flag) - { - /* The commands failed. Write an error message, - delete non-precious targets, and abort. */ - child_error (c->file->name, c->cstatus, 0, 0, 0); - c->file->update_status = 1; - delete_child_targets (c); - } - else - { - if (child_failed) - { - /* The commands failed, but we don't care. */ - child_error (c->file->name, c->cstatus, 0, 0, 1); - child_failed = 0; - } - -#if defined(RECURSIVEJOBS) /* I've had problems with recursive stuff and process handling */ - /* If there are more commands to run, try to start them. */ - start_job (c); - - switch (c->file->command_state) - { - case cs_running: - /* Successfully started. */ - break; - - case cs_finished: - if (c->file->update_status != 0) { - /* We failed to start the commands. */ - delete_child_targets (c); - } - break; - - default: - error (NILF, _("internal error: `%s' command_state"), - c->file->name); - abort (); - break; - } -#endif /* RECURSIVEJOBS */ - } - - /* Set the state flag to say the commands have finished. */ - c->file->command_state = cs_finished; - notice_finished_file (c->file); - -#if defined(RECURSIVEJOBS) /* I've had problems with recursive stuff and process handling */ - /* Remove the child from the chain and free it. */ - if (lastc == 0) - children = c->next; - else - lastc->next = c->next; - free_child (c); -#endif /* RECURSIVEJOBS */ - - /* There is now another slot open. */ - if (job_slots_used > 0) - --job_slots_used; - - /* If the job failed, and the -k flag was not given, die. */ - if (child_failed && !keep_going_flag) - die (EXIT_FAILURE); - - (void) sigsetmask (sigblock (0) & ~(fatal_signal_mask)); - - return 1; -} - -/* VMS: - Spawn a process executing the command in ARGV and return its pid. */ - -#define MAXCMDLEN 200 - -/* local helpers to make ctrl+c and ctrl+y working, see below */ -#include -#include -#include - -static int ctrlMask= LIB$M_CLI_CTRLY; -static int oldCtrlMask; -static int setupYAstTried= 0; -static int pidToAbort= 0; -static int chan= 0; - -static void reEnableAst(void) { - lib$enable_ctrl (&oldCtrlMask,0); -} - -static astHandler (void) { - if (pidToAbort) { - sys$forcex (&pidToAbort, 0, SS$_ABORT); - pidToAbort= 0; - } - kill (getpid(),SIGQUIT); -} - -static void tryToSetupYAst(void) { - $DESCRIPTOR(inputDsc,"SYS$COMMAND"); - int status; - struct { - short int status, count; - int dvi; - } iosb; - - setupYAstTried++; - - if (!chan) { - status= sys$assign(&inputDsc,&chan,0,0); - if (!(status&SS$_NORMAL)) { - lib$signal(status); - return; - } - } - status= sys$qiow (0, chan, IO$_SETMODE|IO$M_CTRLYAST,&iosb,0,0, - astHandler,0,0,0,0,0); - if (status==SS$_ILLIOFUNC) { - sys$dassgn(chan); -#ifdef CTRLY_ENABLED_ANYWAY - fprintf (stderr, - _("-warning, CTRL-Y will leave sub-process(es) around.\n")); -#else - return; -#endif - } - if (status==SS$_NORMAL) - status= iosb.status; - if (!(status&SS$_NORMAL)) { - lib$signal(status); - return; - } - - /* called from AST handler ? */ - if (setupYAstTried>1) - return; - if (atexit(reEnableAst)) - fprintf (stderr, - _("-warning, you may have to re-enable CTRL-Y handling from DCL.\n")); - status= lib$disable_ctrl (&ctrlMask, &oldCtrlMask); - if (!(status&SS$_NORMAL)) { - lib$signal(status); - return; - } -} +/* EMX: Start a child process. This function returns the new pid. */ +# if defined __MSDOS__ || defined __EMX__ int -child_execute_job (argv, child) - char *argv; - struct child *child; +child_execute_job (int stdin_fd, int stdout_fd, char **argv, char **envp) { - int i; - static struct dsc$descriptor_s cmddsc; - static struct dsc$descriptor_s pnamedsc; - static struct dsc$descriptor_s ifiledsc; - static struct dsc$descriptor_s ofiledsc; - static struct dsc$descriptor_s efiledsc; - int have_redirection = 0; - int have_newline = 0; + int pid; + /* stdin_fd == 0 means: nothing to do for stdin; + stdout_fd == 1 means: nothing to do for stdout */ + int save_stdin = (stdin_fd != 0) ? dup (0) : 0; + int save_stdout = (stdout_fd != 1) ? dup (1): 1; - int spflags = CLI$M_NOWAIT; - int status; - char *cmd = alloca (strlen (argv) + 512), *p, *q; - char ifile[256], ofile[256], efile[256]; - char *comname = 0; - char procname[100]; + /* < 0 only if dup() failed */ + if (save_stdin < 0) + fatal (NILF, _("no more file handles: could not duplicate stdin\n")); + if (save_stdout < 0) + fatal (NILF, _("no more file handles: could not duplicate stdout\n")); - /* Parse IO redirection. */ + /* Close unnecessary file handles for the child. */ + if (save_stdin != 0) + CLOSE_ON_EXEC (save_stdin); + if (save_stdout != 1) + CLOSE_ON_EXEC (save_stdout); - ifile[0] = 0; - ofile[0] = 0; - efile[0] = 0; + /* Connect the pipes to the child process. */ + if (stdin_fd != 0) + (void) dup2 (stdin_fd, 0); + if (stdout_fd != 1) + (void) dup2 (stdout_fd, 1); - DB (DB_JOBS, ("child_execute_job (%s)\n", argv)); + /* stdin_fd and stdout_fd must be closed on exit because we are + still in the parent process */ + if (stdin_fd != 0) + CLOSE_ON_EXEC (stdin_fd); + if (stdout_fd != 1) + CLOSE_ON_EXEC (stdout_fd); - while (isspace ((unsigned char)*argv)) - argv++; + /* Run the command. */ + pid = exec_command (argv, envp); - if (*argv == 0) - return 0; - - sprintf (procname, "GMAKE_%05x", getpid () & 0xfffff); - pnamedsc.dsc$w_length = strlen(procname); - pnamedsc.dsc$a_pointer = procname; - pnamedsc.dsc$b_dtype = DSC$K_DTYPE_T; - pnamedsc.dsc$b_class = DSC$K_CLASS_S; - - /* Handle comments and redirection. */ - for (p = argv, q = cmd; *p; p++, q++) + /* Restore stdout/stdin of the parent and close temporary FDs. */ + if (stdin_fd != 0) { - switch (*p) - { - case '#': - *p-- = 0; - *q-- = 0; - break; - case '\\': - p++; - if (*p == '\n') - p++; - if (isspace ((unsigned char)*p)) - { - do { p++; } while (isspace ((unsigned char)*p)); - p--; - } - *q = *p; - break; - case '<': - p = vms_redirect (&ifiledsc, ifile, p); - *q = ' '; - have_redirection = 1; - break; - case '>': - have_redirection = 1; - if (*(p-1) == '2') - { - q--; - if (strncmp (p, ">&1", 3) == 0) - { - p += 3; - strcpy (efile, "sys$output"); - efiledsc.dsc$w_length = strlen(efile); - efiledsc.dsc$a_pointer = efile; - efiledsc.dsc$b_dtype = DSC$K_DTYPE_T; - efiledsc.dsc$b_class = DSC$K_CLASS_S; - } - else - { - p = vms_redirect (&efiledsc, efile, p); - } - } - else - { - p = vms_redirect (&ofiledsc, ofile, p); - } - *q = ' '; - break; - case '\n': - have_newline = 1; - default: - *q = *p; - break; - } - } - *q = *p; - - if (strncmp (cmd, "builtin_", 8) == 0) - { - child->pid = 270163; - child->efn = 0; - child->cstatus = 1; - - DB (DB_JOBS, (_("BUILTIN [%s][%s]\n"), cmd, cmd+8)); - - p = cmd + 8; - - if ((*(p) == 'c') - && (*(p+1) == 'd') - && ((*(p+2) == ' ') || (*(p+2) == '\t'))) - { - p += 3; - while ((*p == ' ') || (*p == '\t')) - p++; - DB (DB_JOBS, (_("BUILTIN CD %s\n"), p)); - if (chdir (p)) - return 0; - else - return 1; - } - else if ((*(p) == 'r') - && (*(p+1) == 'm') - && ((*(p+2) == ' ') || (*(p+2) == '\t'))) - { - int in_arg; - - /* rm */ - p += 3; - while ((*p == ' ') || (*p == '\t')) - p++; - in_arg = 1; - - DB (DB_JOBS, (_("BUILTIN RM %s\n"), p)); - while (*p) - { - switch (*p) - { - case ' ': - case '\t': - if (in_arg) - { - *p++ = ';'; - in_arg = 0; - } - break; - default: - break; - } - p++; - } - } + if (dup2 (save_stdin, 0) != 0) + fatal (NILF, _("Could not restore stdin\n")); else - { - printf(_("Unknown builtin command '%s'\n"), cmd); - fflush(stdout); - return 0; - } + close (save_stdin); } - /* Create a *.com file if either the command is too long for - lib$spawn, or the command contains a newline, or if redirection - is desired. Forcing commands with newlines into DCLs allows to - store search lists on user mode logicals. */ - - if (strlen (cmd) > MAXCMDLEN - || (have_redirection != 0) - || (have_newline != 0)) + if (stdout_fd != 1) { - FILE *outfile; - char c; - char *sep; - int alevel = 0; /* apostrophe level */ - - if (strlen (cmd) == 0) - { - printf (_("Error, empty command\n")); - fflush (stdout); - return 0; - } - - outfile = open_tmpfile (&comname, "sys$scratch:CMDXXXXXX.COM"); - if (outfile == 0) - pfatal_with_name (_("fopen (temporary file)")); - - if (ifile[0]) - { - fprintf (outfile, "$ assign/user %s sys$input\n", ifile); - DB (DB_JOBS, (_("Redirected input from %s\n"), ifile)); - ifiledsc.dsc$w_length = 0; - } - - if (efile[0]) - { - fprintf (outfile, "$ define sys$error %s\n", efile); - DB (DB_JOBS, (_("Redirected error to %s\n"), efile)); - efiledsc.dsc$w_length = 0; - } - - if (ofile[0]) - { - fprintf (outfile, "$ define sys$output %s\n", ofile); - DB (DB_JOBS, (_("Redirected output to %s\n"), ofile)); - ofiledsc.dsc$w_length = 0; - } - - p = sep = q = cmd; - for (c = '\n'; c; c = *q++) - { - switch (c) - { - case '\n': - /* At a newline, skip any whitespace around a leading $ - from the command and issue exactly one $ into the DCL. */ - while (isspace ((unsigned char)*p)) - p++; - if (*p == '$') - p++; - while (isspace ((unsigned char)*p)) - p++; - fwrite (p, 1, q - p, outfile); - fputc ('$', outfile); - fputc (' ', outfile); - /* Reset variables. */ - p = sep = q; - break; - - /* Nice places for line breaks are after strings, after - comma or space and before slash. */ - case '"': - q = handle_apos (q + 1); - sep = q; - break; - case ',': - case ' ': - sep = q; - break; - case '/': - case '\0': - sep = q - 1; - break; - default: - break; - } - if (sep - p > 78) - { - /* Enough stuff for a line. */ - fwrite (p, 1, sep - p, outfile); - p = sep; - if (*sep) - { - /* The command continues. */ - fputc ('-', outfile); - } - fputc ('\n', outfile); - } - } - - fwrite (p, 1, q - p, outfile); - fputc ('\n', outfile); - - fclose (outfile); - - sprintf (cmd, "$ @%s", comname); - - DB (DB_JOBS, (_("Executing %s instead\n"), cmd)); + if (dup2 (save_stdout, 1) != 1) + fatal (NILF, _("Could not restore stdout\n")); + else + close (save_stdout); } - cmddsc.dsc$w_length = strlen(cmd); - cmddsc.dsc$a_pointer = cmd; - cmddsc.dsc$b_dtype = DSC$K_DTYPE_T; - cmddsc.dsc$b_class = DSC$K_CLASS_S; - - child->efn = 0; - while (child->efn < 32 || child->efn > 63) - { - status = lib$get_ef ((unsigned long *)&child->efn); - if (!(status & 1)) - return 0; - } - - sys$clref (child->efn); - - vms_jobsefnmask |= (1 << (child->efn - 32)); - -/* - LIB$SPAWN [command-string] - [,input-file] - [,output-file] - [,flags] - [,process-name] - [,process-id] [,completion-status-address] [,byte-integer-event-flag-num] - [,AST-address] [,varying-AST-argument] - [,prompt-string] [,cli] [,table] -*/ - -#ifndef DONTWAITFORCHILD -/* - * Code to make ctrl+c and ctrl+y working. - * The problem starts with the synchronous case where after lib$spawn is - * called any input will go to the child. But with input re-directed, - * both control characters won't make it to any of the programs, neither - * the spawning nor to the spawned one. Hence the caller needs to spawn - * with CLI$M_NOWAIT to NOT give up the input focus. A sys$waitfr - * has to follow to simulate the wanted synchronous behaviour. - * The next problem is ctrl+y which isn't caught by the crtl and - * therefore isn't converted to SIGQUIT (for a signal handler which is - * already established). The only way to catch ctrl+y, is an AST - * assigned to the input channel. But ctrl+y handling of DCL needs to be - * disabled, otherwise it will handle it. Not to mention the previous - * ctrl+y handling of DCL needs to be re-established before make exits. - * One more: At the time of LIB$SPAWN signals are blocked. SIGQUIT will - * make it to the signal handler after the child "normally" terminates. - * This isn't enough. It seems reasonable for simple command lines like - * a 'cc foobar.c' spawned in a subprocess but it is unacceptable for - * spawning make. Therefore we need to abort the process in the AST. - * - * Prior to the spawn it is checked if an AST is already set up for - * ctrl+y, if not one is set up for a channel to SYS$COMMAND. In general - * this will work except if make is run in a batch environment, but there - * nobody can press ctrl+y. During the setup the DCL handling of ctrl+y - * is disabled and an exit handler is established to re-enable it. - * If the user interrupts with ctrl+y, the assigned AST will fire, force - * an abort to the subprocess and signal SIGQUIT, which will be caught by - * the already established handler and will bring us back to common code. - * After the spawn (now /nowait) a sys$waitfr simulates the /wait and - * enables the ctrl+y be delivered to this code. And the ctrl+c too, - * which the crtl converts to SIGINT and which is caught by the common - * signal handler. Because signals were blocked before entering this code - * sys$waitfr will always complete and the SIGQUIT will be processed after - * it (after termination of the current block, somewhere in common code). - * And SIGINT too will be delayed. That is ctrl+c can only abort when the - * current command completes. Anyway it's better than nothing :-) - */ - - if (!setupYAstTried) - tryToSetupYAst(); - status = lib$spawn (&cmddsc, /* cmd-string */ - (ifiledsc.dsc$w_length == 0)?0:&ifiledsc, /* input-file */ - (ofiledsc.dsc$w_length == 0)?0:&ofiledsc, /* output-file */ - &spflags, /* flags */ - &pnamedsc, /* proc name */ - &child->pid, &child->cstatus, &child->efn, - 0, 0, - 0, 0, 0); - pidToAbort= child->pid; - status= sys$waitfr (child->efn); - pidToAbort= 0; - vmsHandleChildTerm(child); -#else - status = lib$spawn (&cmddsc, - (ifiledsc.dsc$w_length == 0)?0:&ifiledsc, - (ofiledsc.dsc$w_length == 0)?0:&ofiledsc, - &spflags, - &pnamedsc, - &child->pid, &child->cstatus, &child->efn, - vmsHandleChildTerm, child, - 0, 0, 0); -#endif - - if (!(status & 1)) - { - printf (_("Error spawning, %d\n") ,status); - fflush (stdout); - } - - if (comname && !ISDB (DB_JOBS)) - unlink (comname); - - return (status & 1); + return pid; } -#else /* !VMS */ +#elif !defined (_AMIGA) && !defined (__MSDOS__) && !defined (VMS) -#if !defined (_AMIGA) && !defined (__MSDOS__) /* UNIX: Replace the current process with one executing the command in ARGV. STDIN_FD and STDOUT_FD are used as the process's stdin and stdout; ENVP is the environment of the new program. This function does not return. */ - void -child_execute_job (stdin_fd, stdout_fd, argv, envp) - int stdin_fd, stdout_fd; - char **argv, **envp; +child_execute_job (int stdin_fd, int stdout_fd, char **argv, char **envp) { if (stdin_fd != 0) (void) dup2 (stdin_fd, 0); @@ -2242,17 +1971,20 @@ child_execute_job (stdin_fd, stdout_fd, argv, envp) /* Run the command. */ exec_command (argv, envp); } -#endif /* !AMIGA && !__MSDOS__ */ -#endif /* !VMS */ +#endif /* !AMIGA && !__MSDOS__ && !VMS */ #endif /* !WINDOWS32 */ #ifndef _AMIGA /* Replace the current process with one running the command in ARGV, with environment ENVP. This function does not return. */ +/* EMX: This function returns the pid of the child process. */ +# ifdef __EMX__ +int +# else void -exec_command (argv, envp) - char **argv, **envp; +# endif +exec_command (char **argv, char **envp) { #ifdef VMS /* to work around a problem with signals and execve: ignore them */ @@ -2281,7 +2013,7 @@ exec_command (argv, envp) { int i; fprintf(stderr, - _("process_easy() failed failed to launch process (e=%d)\n"), + _("process_easy() failed failed to launch process (e=%ld)\n"), process_last_err(hPID)); for (i = 0; argv[i]; i++) fprintf(stderr, "%s ", argv[i]); @@ -2290,7 +2022,8 @@ exec_command (argv, envp) } /* wait and reap last child */ - while (hWaitPID = process_wait_for_any()) + hWaitPID = process_wait_for_any(); + while (hWaitPID) { /* was an error found on this process? */ err = process_last_err(hWaitPID); @@ -2310,8 +2043,8 @@ exec_command (argv, envp) break; else fprintf(stderr, - _("make reaped child pid %d, still waiting for pid %d\n"), - hWaitPID, hPID); + _("make reaped child pid %ld, still waiting for pid %ld\n"), + (DWORD)hWaitPID, (DWORD)hPID); } /* return child's exit code as our exit code */ @@ -2319,13 +2052,33 @@ exec_command (argv, envp) #else /* !WINDOWS32 */ +# ifdef __EMX__ + int pid; +# endif + /* Be the user, permanently. */ child_access (); +# ifdef __EMX__ + + /* Run the program. */ + pid = spawnvpe (P_NOWAIT, argv[0], argv, envp); + + if (pid >= 0) + return pid; + + /* the file might have a strange shell extension */ + if (errno == ENOENT) + errno = ENOEXEC; + +# else + /* Run the program. */ environ = envp; execvp (argv[0], argv); +# endif /* !__EMX__ */ + switch (errno) { case ENOENT: @@ -2338,8 +2091,18 @@ exec_command (argv, envp) char *shell; char **new_argv; int argc; + int i=1; +# ifdef __EMX__ + /* Do not use $SHELL from the environment */ + struct variable *p = lookup_variable ("SHELL", 5); + if (p) + shell = p->value; + else + shell = 0; +# else shell = getenv ("SHELL"); +# endif if (shell == 0) shell = default_shell; @@ -2347,16 +2110,37 @@ exec_command (argv, envp) while (argv[argc] != 0) ++argc; +# ifdef __EMX__ + if (!unixy_shell) + ++argc; +# endif + new_argv = (char **) alloca ((1 + argc + 1) * sizeof (char *)); new_argv[0] = shell; - new_argv[1] = argv[0]; + +# ifdef __EMX__ + if (!unixy_shell) + { + new_argv[1] = "/c"; + ++i; + --argc; + } +# endif + + new_argv[i] = argv[0]; while (argc > 0) { - new_argv[1 + argc] = argv[argc]; + new_argv[i + argc] = argv[argc]; --argc; } +# ifdef __EMX__ + pid = spawnvpe (P_NOWAIT, shell, new_argv, envp); + if (pid >= 0) + break; +# else execvp (shell, new_argv); +# endif if (errno == ENOENT) error (NILF, _("%s: Shell program not found"), shell); else @@ -2364,18 +2148,28 @@ exec_command (argv, envp) break; } +# ifdef __EMX__ + case EINVAL: + /* this nasty error was driving me nuts :-( */ + error (NILF, _("spawnvpe: environment space might be exhausted")); + /* FALLTHROUGH */ +# endif + default: perror_with_name ("execvp: ", argv[0]); break; } +# ifdef __EMX__ + return pid; +# else _exit (127); +# endif #endif /* !WINDOWS32 */ #endif /* !VMS */ } #else /* On Amiga */ -void exec_command (argv) - char **argv; +void exec_command (char **argv) { MyExecute (argv); } @@ -2402,10 +2196,8 @@ void clean_tmp (void) IFS is the value of $IFS, or nil (meaning the default). */ static char ** -construct_command_argv_internal (line, restp, shell, ifs, batch_filename_ptr) - char *line, **restp; - char *shell, *ifs; - char **batch_filename_ptr; +construct_command_argv_internal (char *line, char **restp, char *shell, + char *ifs, char **batch_filename_ptr) { #ifdef __MSDOS__ /* MSDOS supports both the stock DOS shell and ports of Unixy shells. @@ -2449,16 +2241,43 @@ construct_command_argv_internal (line, restp, shell, ifs, batch_filename_ptr) char *sh_chars; char **sh_cmds; -#else -#ifdef _AMIGA +#elif defined (__EMX__) + static char sh_chars_dos[] = "*?[];|<>%^&()"; + static char *sh_cmds_dos[] = { "break", "call", "cd", "chcp", "chdir", "cls", + "copy", "ctty", "date", "del", "dir", "echo", + "erase", "exit", "for", "goto", "if", "md", + "mkdir", "path", "pause", "prompt", "rd", + "rmdir", "rem", "ren", "rename", "set", + "shift", "time", "type", "ver", "verify", + "vol", ":", 0 }; + + static char sh_chars_os2[] = "*?[];|<>%^()\"'&"; + static char *sh_cmds_os2[] = { "call", "cd", "chcp", "chdir", "cls", "copy", + "date", "del", "detach", "dir", "echo", + "endlocal", "erase", "exit", "for", "goto", "if", + "keys", "md", "mkdir", "move", "path", "pause", + "prompt", "rd", "rem", "ren", "rename", "rmdir", + "set", "setlocal", "shift", "start", "time", + "type", "ver", "verify", "vol", ":", 0 }; + + static char sh_chars_sh[] = "#;\"*?[]&|<>(){}$`^~'"; + static char *sh_cmds_sh[] = { "echo", "cd", "eval", "exec", "exit", "login", + "logout", "set", "umask", "wait", "while", + "for", "case", "if", ":", ".", "break", + "continue", "export", "read", "readonly", + "shift", "times", "trap", "switch", "unset", + 0 }; + char *sh_chars; + char **sh_cmds; + +#elif defined (_AMIGA) static char sh_chars[] = "#;\"|<>()?*$`"; static char *sh_cmds[] = { "cd", "eval", "if", "delete", "echo", "copy", "rename", "set", "setenv", "date", "makedir", "skip", "else", "endif", "path", "prompt", "unset", "unsetenv", "version", 0 }; -#else -#ifdef WINDOWS32 +#elif defined (WINDOWS32) static char sh_chars_dos[] = "\"|&<>"; static char *sh_cmds_dos[] = { "break", "call", "cd", "chcp", "chdir", "cls", "copy", "ctty", "date", "del", "dir", "echo", @@ -2478,26 +2297,28 @@ construct_command_argv_internal (line, restp, shell, ifs, batch_filename_ptr) 0 }; char* sh_chars; char** sh_cmds; +#elif defined(__riscos__) + static char sh_chars[] = ""; + static char *sh_cmds[] = { 0 }; #else /* must be UNIX-ish */ - static char sh_chars[] = "#;\"*?[]&|<>(){}$`^~"; - static char *sh_cmds[] = { "cd", "eval", "exec", "exit", "login", - "logout", "set", "umask", "wait", "while", "for", - "case", "if", ":", ".", "break", "continue", - "export", "read", "readonly", "shift", "times", - "trap", "switch", 0 }; -#endif /* WINDOWS32 */ -#endif /* Amiga */ -#endif /* __MSDOS__ */ + static char sh_chars[] = "#;\"*?[]&|<>(){}$`^~!"; + static char *sh_cmds[] = { ".", ":", "break", "case", "cd", "continue", + "eval", "exec", "exit", "export", "for", "if", + "login", "logout", "read", "readonly", "set", + "shift", "switch", "test", "times", "trap", + "umask", "wait", "while", 0 }; +#endif register int i; register char *p; register char *ap; char *end; int instring, word_has_equals, seen_nonequals, last_argument_was_empty; char **new_argv = 0; + char *argstr = 0; #ifdef WINDOWS32 int slow_flag = 0; - if (no_default_sh_exe) { + if (!unixy_shell) { sh_cmds = sh_cmds_dos; sh_chars = sh_chars_dos; } else { @@ -2534,14 +2355,17 @@ construct_command_argv_internal (line, restp, shell, ifs, batch_filename_ptr) if (slow_flag) goto slow; #else /* not WINDOWS32 */ -#ifdef __MSDOS__ +#if defined (__MSDOS__) || defined (__EMX__) else if (stricmp (shell, default_shell)) { extern int _is_unixy_shell (const char *_path); - message (1, _("$SHELL changed (was `%s', now `%s')"), default_shell, shell); + DB (DB_BASIC, (_("$SHELL changed (was `%s', now `%s')\n"), + default_shell, shell)); unixy_shell = _is_unixy_shell (shell); - default_shell = shell; + /* we must allocate a copy of shell: construct_command_argv() will free + * shell after this function returns. */ + default_shell = xstrdup (shell); } if (unixy_shell) { @@ -2552,11 +2376,18 @@ construct_command_argv_internal (line, restp, shell, ifs, batch_filename_ptr) { sh_chars = sh_chars_dos; sh_cmds = sh_cmds_dos; +# ifdef __EMX__ + if (_osmode == OS2_MODE) + { + sh_chars = sh_chars_os2; + sh_cmds = sh_cmds_os2; + } +# endif } -#else /* not __MSDOS__ */ +#else /* !__MSDOS__ */ else if (strcmp (shell, default_shell)) goto slow; -#endif /* not __MSDOS__ */ +#endif /* !__MSDOS__ && !__EMX__ */ #endif /* not WINDOWS32 */ if (ifs != 0) @@ -2570,7 +2401,7 @@ construct_command_argv_internal (line, restp, shell, ifs, batch_filename_ptr) new_argv = (char **) xmalloc (i * sizeof (char *)); /* All the args can fit in a buffer as big as LINE is. */ - ap = new_argv[0] = (char *) xmalloc (i); + ap = new_argv[0] = argstr = (char *) xmalloc (i); end = ap + i; /* I is how many complete arguments have been found. */ @@ -2578,12 +2409,10 @@ construct_command_argv_internal (line, restp, shell, ifs, batch_filename_ptr) instring = word_has_equals = seen_nonequals = last_argument_was_empty = 0; for (p = line; *p != '\0'; ++p) { - if (ap > end) - abort (); + assert (ap <= end); if (instring) { - string_char: /* Inside a string, just copy any char except a closing quote or a backslash-newline combination. */ if (*p == instring) @@ -2593,7 +2422,28 @@ construct_command_argv_internal (line, restp, shell, ifs, batch_filename_ptr) last_argument_was_empty = 1; } else if (*p == '\\' && p[1] == '\n') - goto swallow_escaped_newline; + { + /* Backslash-newline is handled differently depending on what + kind of string we're in: inside single-quoted strings you + keep them; in double-quoted strings they disappear. + For DOS/Windows/OS2, if we don't have a POSIX shell, + we keep the pre-POSIX behavior of removing the + backslash-newline. */ + if (instring == '"' +#if defined (__MSDOS__) || defined (__EMX__) || defined (WINDOWS32) + || !unixy_shell +#endif + ) + ++p; + else + { + *(ap++) = *(p++); + *(ap++) = *p; + } + /* If there's a TAB here, skip it. */ + if (p[1] == '\t') + ++p; + } else if (*p == '\n' && restp != NULL) { /* End of the command line. */ @@ -2633,47 +2483,30 @@ construct_command_argv_internal (line, restp, shell, ifs, batch_filename_ptr) break; case '\\': - /* Backslash-newline combinations are eaten. */ + /* Backslash-newline has special case handling, ref POSIX. + We're in the fastpath, so emulate what the shell would do. */ if (p[1] == '\n') { - swallow_escaped_newline: + /* Throw out the backslash and newline. */ + ++p; - /* Eat the backslash, the newline, and following whitespace, - replacing it all with a single space. */ - p += 2; + /* If there is a tab after a backslash-newline, remove it. */ + if (p[1] == '\t') + ++p; - /* If there is a tab after a backslash-newline, - remove it from the source line which will be echoed, - since it was most likely used to line - up the continued line with the previous one. */ - if (*p == '\t') - /* Note these overlap and strcpy() is undefined for - overlapping objects in ANSI C. The strlen() _IS_ right, - since we need to copy the nul byte too. */ - bcopy (p + 1, p, strlen (p)); - - if (instring) - goto string_char; - else - { - if (ap != new_argv[i]) - /* Treat this as a space, ending the arg. - But if it's at the beginning of the arg, it should - just get eaten, rather than becoming an empty arg. */ - goto end_of_arg; - else - p = next_token (p) - 1; - } + /* If there's nothing in this argument yet, skip any + whitespace before the start of the next word. */ + if (ap == new_argv[i]) + p = next_token (p + 1) - 1; } else if (p[1] != '\0') { #ifdef HAVE_DOS_PATHS - /* Only remove backslashes before characters special - to Unixy shells. All other backslashes are copied - verbatim, since they are probably DOS-style - directory separators. This still leaves a small - window for problems, but at least it should work - for the vast majority of naive users. */ + /* Only remove backslashes before characters special to Unixy + shells. All other backslashes are copied verbatim, since + they are probably DOS-style directory separators. This + still leaves a small window for problems, but at least it + should work for the vast majority of naive users. */ #ifdef __MSDOS__ /* A dot is only special as part of the "..." @@ -2688,7 +2521,7 @@ construct_command_argv_internal (line, restp, shell, ifs, batch_filename_ptr) #endif if (p[1] != '\\' && p[1] != '\'' && !isspace ((unsigned char)p[1]) - && (strchr (sh_chars_sh, p[1]) == 0)) + && strchr (sh_chars_sh, p[1]) == 0) /* back up one notch, to copy the backslash */ --p; #endif /* HAVE_DOS_PATHS */ @@ -2717,7 +2550,6 @@ construct_command_argv_internal (line, restp, shell, ifs, batch_filename_ptr) case ' ': case '\t': - end_of_arg: /* We have the end of an argument. Terminate the text of the argument. */ *ap++ = '\0'; @@ -2740,14 +2572,20 @@ construct_command_argv_internal (line, restp, shell, ifs, batch_filename_ptr) { register int j; for (j = 0; sh_cmds[j] != 0; ++j) - if (streq (sh_cmds[j], new_argv[0])) - goto slow; + { + if (streq (sh_cmds[j], new_argv[0])) + goto slow; +# ifdef __EMX__ + /* Non-Unix shells are case insensitive. */ + if (!unixy_shell + && strcasecmp (sh_cmds[j], new_argv[0]) == 0) + goto slow; +# endif + } } /* Ignore multiple whitespace chars. */ - p = next_token (p); - /* Next iteration should examine the first nonwhite char. */ - --p; + p = next_token (p) - 1; break; default: @@ -2777,10 +2615,14 @@ construct_command_argv_internal (line, restp, shell, ifs, batch_filename_ptr) } if (new_argv[0] == 0) - /* Line was empty. */ - return 0; - else - return new_argv; + { + /* Line was empty. */ + free (argstr); + free ((char *)new_argv); + return 0; + } + + return new_argv; slow:; /* We must use the shell. */ @@ -2788,8 +2630,8 @@ construct_command_argv_internal (line, restp, shell, ifs, batch_filename_ptr) if (new_argv != 0) { /* Free the old argument list we were working on. */ - free (new_argv[0]); - free ((void *)new_argv); + free (argstr); + free ((char *)new_argv); } #ifdef __MSDOS__ @@ -2859,6 +2701,11 @@ construct_command_argv_internal (line, restp, shell, ifs, batch_filename_ptr) + (line_len * 2) + 1); char *command_ptr = NULL; /* used for batch_mode_shell mode */ +# ifdef __EMX__ /* is this necessary? */ + if (!unixy_shell) + minus_c[1] = '/'; /* " /c " */ +# endif + ap = new_line; bcopy (shell, ap, shell_len); ap += shell_len; @@ -2874,23 +2721,26 @@ construct_command_argv_internal (line, restp, shell, ifs, batch_filename_ptr) } else if (*p == '\\' && p[1] == '\n') { - /* Eat the backslash, the newline, and following whitespace, - replacing it all with a single space (which is escaped - from the shell). */ - p += 2; + /* POSIX says we keep the backslash-newline, but throw out + the next char if it's a TAB. If we don't have a POSIX + shell on DOS/Windows/OS2, mimic the pre-POSIX behavior + and remove the backslash/newline. */ +#if defined (__MSDOS__) || defined (__EMX__) || defined (WINDOWS32) +# define PRESERVE_BSNL unixy_shell +#else +# define PRESERVE_BSNL 1 +#endif + if (PRESERVE_BSNL) + { + *(ap++) = '\\'; + *(ap++) = '\\'; + *(ap++) = '\n'; + } - /* If there is a tab after a backslash-newline, - remove it from the source line which will be echoed, - since it was most likely used to line - up the continued line with the previous one. */ - if (*p == '\t') - bcopy (p + 1, p, strlen (p)); + ++p; + if (p[1] == '\t') + ++p; - p = next_token (p); - --p; - if (unixy_shell && !batch_mode_shell) - *ap++ = '\\'; - *ap++ = ' '; continue; } @@ -2920,36 +2770,29 @@ construct_command_argv_internal (line, restp, shell, ifs, batch_filename_ptr) /* Some shells do not work well when invoked as 'sh -c xxx' to run a command line (e.g. Cygnus GNUWIN32 sh.exe on WIN32 systems). In these cases, run commands via a script file. */ - if ((no_default_sh_exe || batch_mode_shell) && batch_filename_ptr) { + if (just_print_flag) { + /* Need to allocate new_argv, although it's unused, because + start_job_command will want to free it and its 0'th element. */ + new_argv = (char **) xmalloc(2 * sizeof (char *)); + new_argv[0] = xstrdup (""); + new_argv[1] = NULL; + } else if ((no_default_sh_exe || batch_mode_shell) && batch_filename_ptr) { + int temp_fd; FILE* batch = NULL; int id = GetCurrentProcessId(); PATH_VAR(fbuf); - char* fname = NULL; /* create a file name */ sprintf(fbuf, "make%d", id); - fname = tempnam(".", fbuf); - - /* create batch file name */ - *batch_filename_ptr = xmalloc(strlen(fname) + 5); - strcpy(*batch_filename_ptr, fname); - - /* make sure path name is in DOS backslash format */ - if (!unixy_shell) { - fname = *batch_filename_ptr; - for (i = 0; fname[i] != '\0'; ++i) - if (fname[i] == '/') - fname[i] = '\\'; - strcat(*batch_filename_ptr, ".bat"); - } else { - strcat(*batch_filename_ptr, ".sh"); - } + *batch_filename_ptr = create_batch_file (fbuf, unixy_shell, &temp_fd); DB (DB_JOBS, (_("Creating temporary batch file %s\n"), *batch_filename_ptr)); - /* create batch file to execute command */ - batch = fopen (*batch_filename_ptr, "w"); + /* Create a FILE object for the batch file, and write to it the + commands to be executed. Put the batch file in TEXT mode. */ + _setmode (temp_fd, _O_TEXT); + batch = _fdopen (temp_fd, "wt"); if (!unixy_shell) fputs ("@echo off\n", batch); fputs (command_ptr, batch); @@ -2972,18 +2815,87 @@ construct_command_argv_internal (line, restp, shell, ifs, batch_filename_ptr) new_argv = construct_command_argv_internal (new_line, (char **) NULL, (char *) 0, (char *) 0, (char **) 0); -#ifdef __MSDOS__ +#ifdef __EMX__ + else if (!unixy_shell) + { + /* new_line is local, must not be freed therefore + We use line here instead of new_line because we run the shell + manually. */ + size_t line_len = strlen (line); + char *p = new_line; + char *q = new_line; + memcpy (new_line, line, line_len + 1); + /* replace all backslash-newline combination and also following tabs */ + while (*q != '\0') + { + if (q[0] == '\\' && q[1] == '\n') + { + q += 2; /* remove '\\' and '\n' */ + if (q[0] == '\t') + q++; /* remove 1st tab in the next line */ + } + else + *p++ = *q++; + } + *p = '\0'; + +# ifndef NO_CMD_DEFAULT + if (strnicmp (new_line, "echo", 4) == 0 + && (new_line[4] == ' ' || new_line[4] == '\t')) + { + /* the builtin echo command: handle it separately */ + size_t echo_len = line_len - 5; + char *echo_line = new_line + 5; + + /* special case: echo 'x="y"' + cmd works this way: a string is printed as is, i.e., no quotes + are removed. But autoconf uses a command like echo 'x="y"' to + determine whether make works. autoconf expects the output x="y" + so we will do exactly that. + Note: if we do not allow cmd to be the default shell + we do not need this kind of voodoo */ + if (echo_line[0] == '\'' + && echo_line[echo_len - 1] == '\'' + && strncmp (echo_line + 1, "ac_maketemp=", + strlen ("ac_maketemp=")) == 0) + { + /* remove the enclosing quotes */ + memmove (echo_line, echo_line + 1, echo_len - 2); + echo_line[echo_len - 2] = '\0'; + } + } +# endif + + { + /* Let the shell decide what to do. Put the command line into the + 2nd command line argument and hope for the best ;-) */ + size_t sh_len = strlen (shell); + + /* exactly 3 arguments + NULL */ + new_argv = (char **) xmalloc (4 * sizeof (char *)); + /* Exactly strlen(shell) + strlen("/c") + strlen(line) + 3 times + the trailing '\0' */ + new_argv[0] = (char *) malloc (sh_len + line_len + 5); + memcpy (new_argv[0], shell, sh_len + 1); + new_argv[1] = new_argv[0] + sh_len + 1; + memcpy (new_argv[1], "/c", 3); + new_argv[2] = new_argv[1] + 3; + memcpy (new_argv[2], new_line, line_len + 1); + new_argv[3] = NULL; + } + } +#elif defined(__MSDOS__) else { - /* With MSDOS shells, we must construct the command line here - instead of recursively calling ourselves, because we - cannot backslash-escape the special characters (see above). */ - new_argv = (char **) xmalloc (sizeof (char *)); - line_len = strlen (new_line) - shell_len - sizeof (minus_c) + 1; - new_argv[0] = xmalloc (line_len + 1); - strncpy (new_argv[0], - new_line + shell_len + sizeof (minus_c) - 1, line_len); - new_argv[0][line_len] = '\0'; + /* With MSDOS shells, we must construct the command line here + instead of recursively calling ourselves, because we + cannot backslash-escape the special characters (see above). */ + new_argv = (char **) xmalloc (sizeof (char *)); + line_len = strlen (new_line) - shell_len - sizeof (minus_c) + 1; + new_argv[0] = xmalloc (line_len + 1); + strncpy (new_argv[0], + new_line + shell_len + sizeof (minus_c) - 1, line_len); + new_argv[0][line_len] = '\0'; } #else else @@ -3011,10 +2923,8 @@ construct_command_argv_internal (line, restp, shell, ifs, batch_filename_ptr) variable expansion for $(SHELL) and $(IFS). */ char ** -construct_command_argv (line, restp, file, batch_filename_ptr) - char *line, **restp; - struct file *file; - char** batch_filename_ptr; +construct_command_argv (char *line, char **restp, struct file *file, + char **batch_filename_ptr) { char *shell, *ifs; char **argv; @@ -3072,10 +2982,55 @@ construct_command_argv (line, restp, file, batch_filename_ptr) * is not confused. */ if (shell) { - char *p = w32ify(shell, 0); - strcpy(shell, p); + char *p = w32ify (shell, 0); + strcpy (shell, p); } #endif +#ifdef __EMX__ + { + static const char *unixroot = NULL; + static const char *last_shell = ""; + static int init = 0; + if (init == 0) + { + unixroot = getenv ("UNIXROOT"); + /* unixroot must be NULL or not empty */ + if (unixroot && unixroot[0] == '\0') unixroot = NULL; + init = 1; + } + + /* if we have an unixroot drive and if shell is not default_shell + (which means it's either cmd.exe or the test has already been + performed) and if shell is an absolute path without drive letter, + try whether it exists e.g.: if "/bin/sh" does not exist use + "$UNIXROOT/bin/sh" instead. */ + if (unixroot && shell && strcmp (shell, last_shell) != 0 + && (shell[0] == '/' || shell[0] == '\\')) + { + /* trying a new shell, check whether it exists */ + size_t size = strlen (shell); + char *buf = xmalloc (size + 7); + memcpy (buf, shell, size); + memcpy (buf + size, ".exe", 5); /* including the trailing '\0' */ + if (access (shell, F_OK) != 0 && access (buf, F_OK) != 0) + { + /* try the same for the unixroot drive */ + memmove (buf + 2, buf, size + 5); + buf[0] = unixroot[0]; + buf[1] = unixroot[1]; + if (access (buf, F_OK) == 0) + /* we have found a shell! */ + /* free(shell); */ + shell = buf; + else + free (buf); + } + else + free (buf); + } + } +#endif /* __EMX__ */ + ifs = allocated_variable_expand_for_file ("$(IFS)", file); warn_undefined_variables_flag = save; @@ -3091,8 +3046,7 @@ construct_command_argv (line, restp, file, batch_filename_ptr) #if !defined(HAVE_DUP2) && !defined(_AMIGA) int -dup2 (old, new) - int old, new; +dup2 (int old, int new) { int fd; @@ -3108,3 +3062,9 @@ dup2 (old, new) return fd; } #endif /* !HAPE_DUP2 && !_AMIGA */ + +/* On VMS systems, include special VMS functions. */ + +#ifdef VMS +#include "vmsjobs.c" +#endif diff --git a/src/bin/make/job.h b/src/bin/make/job.h index 00e9599cf3..436b979d73 100644 --- a/src/bin/make/job.h +++ b/src/bin/make/job.h @@ -1,25 +1,40 @@ /* Definitions for managing subprocesses in GNU Make. -Copyright (C) 1992, 1993, 1996, 1999 Free Software Foundation, Inc. +Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, +2002, 2003, 2004, 2005, 2006 Free Software Foundation, Inc. This file is part of GNU Make. -GNU Make is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 2, or (at your option) -any later version. +GNU Make is free software; you can redistribute it and/or modify it under the +terms of the GNU General Public License as published by the Free Software +Foundation; either version 2, or (at your option) any later version. -GNU Make is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. +GNU Make is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR +A PARTICULAR PURPOSE. See the GNU General Public License for more details. -You should have received a copy of the GNU General Public License -along with GNU Make; see the file COPYING. If not, write to -the Free Software Foundation, Inc., 59 Temple Place - Suite 330, -Boston, MA 02111-1307, USA. */ +You should have received a copy of the GNU General Public License along with +GNU Make; see the file COPYING. If not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. */ #ifndef SEEN_JOB_H #define SEEN_JOB_H +#ifdef HAVE_FCNTL_H +# include +#else +# include +#endif + +/* How to set close-on-exec for a file descriptor. */ + +#if !defined F_SETFD +# define CLOSE_ON_EXEC(_d) +#else +# ifndef FD_CLOEXEC +# define FD_CLOEXEC 1 +# endif +# define CLOSE_ON_EXEC(_d) (void) fcntl ((_d), F_SETFD, FD_CLOEXEC) +#endif + /* Structure describing a running or dead child process. */ struct child @@ -46,6 +61,7 @@ struct child unsigned int good_stdin:1; /* Nonzero if this child has a good stdin. */ unsigned int deleted:1; /* Nonzero if targets have been deleted. */ + unsigned int dontcare:1; /* Saved dontcare flag. */ }; extern struct child *children; @@ -57,11 +73,15 @@ extern void start_waiting_jobs PARAMS ((void)); extern char **construct_command_argv PARAMS ((char *line, char **restp, struct file *file, char** batch_file)); #ifdef VMS extern int child_execute_job PARAMS ((char *argv, struct child *child)); +#elif defined(__EMX__) +extern int child_execute_job PARAMS ((int stdin_fd, int stdout_fd, char **argv, char **envp)); #else extern void child_execute_job PARAMS ((int stdin_fd, int stdout_fd, char **argv, char **envp)); #endif #ifdef _AMIGA extern void exec_command PARAMS ((char **argv)); +#elif defined(__EMX__) +extern int exec_command PARAMS ((char **argv, char **envp)); #else extern void exec_command PARAMS ((char **argv, char **envp)); #endif @@ -80,4 +100,6 @@ extern int fatal_signal_mask; #endif #endif +extern unsigned int jobserver_tokens; + #endif /* SEEN_JOB_H */ diff --git a/src/bin/make/main.c b/src/bin/make/main.c index a04671db19..483babfcc2 100644 --- a/src/bin/make/main.c +++ b/src/bin/make/main.c @@ -1,22 +1,20 @@ /* Argument parsing and main program of GNU Make. -Copyright (C) 1988, 1989, 1990, 1991, 1994, 1995, 1996, 1997, 1998, 1999, -2002 Free Software Foundation, Inc. +Copyright (C) 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, +1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006 Free Software +Foundation, Inc. This file is part of GNU Make. -GNU Make is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 2, or (at your option) -any later version. +GNU Make is free software; you can redistribute it and/or modify it under the +terms of the GNU General Public License as published by the Free Software +Foundation; either version 2, or (at your option) any later version. -GNU Make is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. +GNU Make is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR +A PARTICULAR PURPOSE. See the GNU General Public License for more details. -You should have received a copy of the GNU General Public License -along with GNU Make; see the file COPYING. If not, write to -the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, -MA 02111-1307, USA. */ +You should have received a copy of the GNU General Public License along with +GNU Make; see the file COPYING. If not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. */ #include "make.h" #include "dep.h" @@ -35,12 +33,25 @@ MA 02111-1307, USA. */ #endif #ifdef WINDOWS32 #include +#include #include "pathstuff.h" #endif -#if defined(MAKE_JOBSERVER) && defined(HAVE_FCNTL_H) +#ifdef __EMX__ +# include +# include +#endif +#ifdef HAVE_FCNTL_H # include #endif +#if defined(HAVE_SYS_RESOURCE_H) && defined(HAVE_GETRLIMIT) && defined(HAVE_SETRLIMIT) +# define SET_STACK_SIZE +#endif + +#ifdef SET_STACK_SIZE +# include +#endif + #ifdef _AMIGA int __stack = 20000; /* Make sure we have 20K of stack space */ #endif @@ -70,6 +81,7 @@ extern void exit PARAMS ((int)) __attribute__ ((noreturn)); extern double atof (); #endif +static void clean_jobserver PARAMS ((int status)); static void print_data_base PARAMS ((void)); static void print_version PARAMS ((void)); static void decode_switches PARAMS ((int argc, char **argv, int env)); @@ -180,6 +192,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; @@ -201,6 +217,7 @@ static struct stringlist *makefiles = 0; unsigned int job_slots = 1; unsigned int default_job_slots = 1; +static unsigned int master_job_slots = 0; /* Value of job_slots that means no limit. */ @@ -253,7 +270,17 @@ int warn_undefined_variables_flag; /* If nonzero, always build all targets, regardless of whether they appear out of date or not. */ +static int always_make_set = 0; int always_make_flag = 0; + +/* If nonzero, we're in the "try to rebuild makefiles" phase. */ + +int rebuilding_makefiles = 0; + +/* Remember the original value of the SHELL variable, from the environment. */ + +struct variable shell_var; + /* The usage output. We write it this way to make life easier for the translators, especially those trying to translate to right-to-left @@ -294,6 +321,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_("\ @@ -333,7 +362,7 @@ static const char *const usage[] = static const struct command_switch switches[] = { { 'b', ignore, 0, 0, 0, 0, 0, 0, 0 }, - { 'B', flag, (char *) &always_make_flag, 1, 1, 0, 0, 0, "always-make" }, + { 'B', flag, (char *) &always_make_set, 1, 1, 0, 0, 0, "always-make" }, { 'C', string, (char *) &directories, 0, 0, 0, 0, 0, "directory" }, { 'd', flag, (char *) &debug_flag, 1, 1, 0, 0, 0, 0 }, { CHAR_MAX+1, string, (char *) &db_flags, 1, 1, 0, "basic", 0, "debug" }, @@ -341,51 +370,53 @@ 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" }, - { '\0', } + "warn-undefined-variables" }, + { 0, 0, 0, 0, 0, 0, 0, 0, 0 } }; /* Secondary long names for options. */ @@ -439,6 +470,10 @@ unsigned int makelevel; struct file *default_goal_file; +/* Pointer to the value of the .DEFAULT_GOAL special + variable. */ +char ** default_goal_name; + /* Pointer to structure for the file .DEFAULT whose commands are used for any file that has none of its own. This is zero if the makefiles do not define .DEFAULT. */ @@ -450,6 +485,11 @@ struct file *default_file; int posix_pedantic; +/* Nonzero if we have seen the '.SECONDEXPANSION' target. + This turns on secondary expansion of prerequisites. */ + +int second_expansion; + /* Nonzero if we have seen the `.NOTPARALLEL' target. This turns off parallel builds for this invocation of make. */ @@ -478,9 +518,7 @@ int fatal_signal_mask; typedef RETSIGTYPE (*bsd_signal_ret_t) (); static bsd_signal_ret_t -bsd_signal (sig, func) - int sig; - bsd_signal_ret_t func; +bsd_signal (int sig, bsd_signal_ret_t func) { struct sigaction act, oact; act.sa_handler = func; @@ -495,17 +533,17 @@ bsd_signal (sig, func) #endif static void -initialize_global_hash_tables () +initialize_global_hash_tables (void) { init_hash_global_variable_set (); + strcache_init (); init_hash_files (); hash_init_directories (); hash_init_function_table (); } static struct file * -enter_command_line_file (name) - char *name; +enter_command_line_file (char *name) { if (name[0] == '\0') fatal (NILF, _("empty string invalid as file name")); @@ -543,15 +581,16 @@ enter_command_line_file (name) /* Toggle -d on receipt of SIGUSR1. */ +#ifdef SIGUSR1 static RETSIGTYPE -debug_signal_handler (sig) - int sig; +debug_signal_handler (int sig UNUSED) { db_level = db_level ? DB_NONE : DB_BASIC; } +#endif static void -decode_debug_flags () +decode_debug_flags (void) { char **pp; @@ -628,23 +667,23 @@ handle_runtime_exceptions( struct _EXCEPTION_POINTERS *exinfo ) if (! ISDB (DB_VERBOSE)) { sprintf(errmsg, - _("%s: Interrupt/Exception caught (code = 0x%x, addr = 0x%x)\n"), - prg, exrec->ExceptionCode, exrec->ExceptionAddress); + _("%s: Interrupt/Exception caught (code = 0x%lx, addr = 0x%lx)\n"), + prg, exrec->ExceptionCode, (DWORD)exrec->ExceptionAddress); fprintf(stderr, errmsg); exit(255); } sprintf(errmsg, - _("\nUnhandled exception filter called from program %s\nExceptionCode = %x\nExceptionFlags = %x\nExceptionAddress = %x\n"), + _("\nUnhandled exception filter called from program %s\nExceptionCode = %lx\nExceptionFlags = %lx\nExceptionAddress = %lx\n"), prg, exrec->ExceptionCode, exrec->ExceptionFlags, - exrec->ExceptionAddress); + (DWORD)exrec->ExceptionAddress); if (exrec->ExceptionCode == EXCEPTION_ACCESS_VIOLATION && exrec->NumberParameters >= 2) sprintf(&errmsg[strlen(errmsg)], (exrec->ExceptionInformation[0] - ? _("Access violation: write operation at address %x\n") - : _("Access violation: read operation at address %x\n")), + ? _("Access violation: write operation at address %lx\n") + : _("Access violation: read operation at address %lx\n")), exrec->ExceptionInformation[1]); /* turn this on if we want to put stuff in the event log too */ @@ -688,10 +727,11 @@ handle_runtime_exceptions( struct _EXCEPTION_POINTERS *exinfo ) */ int -find_and_set_default_shell(char *token) +find_and_set_default_shell (char *token) { int sh_found = 0; - char* search_token; + char *search_token; + char *tokend; PATH_VAR(sh_path); extern char *default_shell; @@ -700,8 +740,29 @@ find_and_set_default_shell(char *token) else search_token = token; - if (!no_default_sh_exe && - (token == NULL || !strcmp(search_token, default_shell))) { + + /* If the user explicitly requests the DOS cmd shell, obey that request. + However, make sure that's what they really want by requiring the value + of SHELL either equal, or have a final path element of, "cmd" or + "cmd.exe" case-insensitive. */ + tokend = search_token + strlen (search_token) - 3; + if (((tokend == search_token + || (tokend > search_token + && (tokend[-1] == '/' || tokend[-1] == '\\'))) + && !strcmpi (tokend, "cmd")) + || ((tokend - 4 == search_token + || (tokend - 4 > search_token + && (tokend[-5] == '/' || tokend[-5] == '\\'))) + && !strcmpi (tokend - 4, "cmd.exe"))) { + batch_mode_shell = 1; + unixy_shell = 0; + sprintf (sh_path, "%s", search_token); + default_shell = xstrdup (w32ify (sh_path, 0)); + DB (DB_VERBOSE, + (_("find_and_set_shell setting default_shell = %s\n"), default_shell)); + sh_found = 1; + } else if (!no_default_sh_exe && + (token == NULL || !strcmp (search_token, default_shell))) { /* no new information, path already set or known */ sh_found = 1; } else if (file_exists_p(search_token)) { @@ -713,11 +774,9 @@ find_and_set_default_shell(char *token) sh_found = 1; } else { char *p; - struct variable *v = lookup_variable ("Path", 4); + struct variable *v = lookup_variable (STRING_SIZE_TUPLE ("PATH")); - /* - * Search Path for shell - */ + /* Search Path for shell */ if (v && v->value) { char *ep; @@ -775,22 +834,22 @@ find_and_set_default_shell(char *token) #ifdef __MSDOS__ static void -msdos_return_to_initial_directory () +msdos_return_to_initial_directory (void) { if (directory_before_chdir) chdir (directory_before_chdir); } #endif -extern char *mktemp (); -extern int mkstemp (); +extern char *mktemp PARAMS ((char *template)); +extern int mkstemp PARAMS ((char *template)); FILE * -open_tmpfile(name, template) - char **name; - const char *template; +open_tmpfile(char **name, const char *template) { +#ifdef HAVE_FDOPEN int fd; +#endif #if defined HAVE_MKSTEMP || defined HAVE_MKTEMP # define TEMPLATE_LEN strlen (template) @@ -827,22 +886,22 @@ open_tmpfile(name, template) } -#ifndef _AMIGA +#ifdef _AMIGA int -main (argc, argv, envp) - int argc; - char **argv; - char **envp; +main (int argc, char **argv) #else -int main (int argc, char ** argv) +int +main (int argc, char **argv, char **envp) #endif { static char *stdin_nm = 0; - register struct file *f; - register unsigned int i; + struct file *f; + int i; + int makefile_status = MAKE_SUCCESS; char **p; struct dep *read_makefiles; PATH_VAR (current_directory); + unsigned int restarts = 0; #ifdef WINDOWS32 char *unix_path = NULL; char *windows32_path = NULL; @@ -854,6 +913,27 @@ int main (int argc, char ** argv) no_default_sh_exe = 1; #endif +#ifdef SET_STACK_SIZE + /* Get rid of any avoidable limit on stack size. */ + { + struct rlimit rlim; + + /* Set the stack limit huge so that alloca does not fail. */ + if (getrlimit (RLIMIT_STACK, &rlim) == 0) + { + rlim.rlim_cur = rlim.rlim_max; + setrlimit (RLIMIT_STACK, &rlim); + } + } +#endif + +#ifdef HAVE_ATEXIT + atexit (close_stdout); +#endif + + /* Needed for OS/2 */ + initialize_main(&argc, &argv); + default_goal_file = 0; reading_file = 0; @@ -960,7 +1040,7 @@ int main (int argc, char ** argv) #else program = strrchr (argv[0], '/'); #endif -#ifdef __MSDOS__ +#if defined(__MSDOS__) || defined(__EMX__) if (program == 0) program = strrchr (argv[0], '\\'); else @@ -973,6 +1053,21 @@ int main (int argc, char ** argv) } if (program == 0 && argv[0][1] == ':') program = argv[0] + 1; +#endif +#ifdef WINDOWS32 + if (program == 0) + { + /* Extract program from full path */ + int argv0_len; + program = strrchr (argv[0], '\\'); + if (program) + { + argv0_len = strlen(program); + if (argv0_len > 4 && streq (&program[argv0_len - 4], ".exe")) + /* Remove .exe extension */ + program[argv0_len - 4] = '\0'; + } + } #endif if (program == 0) program = argv[0]; @@ -994,7 +1089,7 @@ int main (int argc, char ** argv) #endif { #ifdef HAVE_GETCWD - perror_with_name ("getcwd: ", ""); + perror_with_name ("getcwd", ""); #else error (NILF, "getwd: %s", current_directory); #endif @@ -1010,7 +1105,24 @@ int main (int argc, char ** argv) /* Initialize the special variables. */ define_variable (".VARIABLES", 10, "", o_default, 0)->special = 1; - /* define_variable (".TARGETS", 8, "", o_default, 0); */ + /* define_variable (".TARGETS", 8, "", o_default, 0)->special = 1; */ + + /* Set up .FEATURES */ + define_variable (".FEATURES", 9, + "target-specific order-only second-expansion else-if", + o_default, 0); +#ifndef NO_ARCHIVES + do_variable_definition (NILF, ".FEATURES", "archives", + o_default, f_append, 0); +#endif +#ifdef MAKE_JOBSERVER + do_variable_definition (NILF, ".FEATURES", "jobserver", + o_default, f_append, 0); +#endif +#ifdef MAKE_SYMLINKS + do_variable_definition (NILF, ".FEATURES", "check-symlink", + o_default, f_append, 0); +#endif /* Read in variables from the environment. It is important that this be done before $(MAKE) is figured out so its definitions will not be @@ -1019,51 +1131,63 @@ int main (int argc, char ** argv) #ifndef _AMIGA for (i = 0; envp[i] != 0; ++i) { - int do_not_define; - register char *ep = envp[i]; + int do_not_define = 0; + char *ep = envp[i]; - /* by default, everything gets defined and exported */ - do_not_define = 0; - - while (*ep != '=') + while (*ep != '\0' && *ep != '=') ++ep; #ifdef WINDOWS32 if (!unix_path && strneq(envp[i], "PATH=", 5)) unix_path = ep+1; - else if (!windows32_path && !strnicmp(envp[i], "Path=", 5)) { + else if (!strnicmp(envp[i], "Path=", 5)) { do_not_define = 1; /* it gets defined after loop exits */ - windows32_path = ep+1; + if (!windows32_path) + windows32_path = ep+1; } #endif /* The result of pointer arithmetic is cast to unsigned int for machines where ptrdiff_t is a different size that doesn't widen the same. */ if (!do_not_define) - define_variable (envp[i], (unsigned int) (ep - envp[i]), - ep + 1, o_env, 1) - /* Force exportation of every variable culled from the environment. - We used to rely on target_environment's v_default code to do this. - But that does not work for the case where an environment variable - is redefined in a makefile with `override'; it should then still - be exported, because it was originally in the environment. */ - ->export = v_export; + { + struct variable *v; + + v = define_variable (envp[i], (unsigned int) (ep - envp[i]), + ep + 1, o_env, 1); + /* Force exportation of every variable culled from the environment. + We used to rely on target_environment's v_default code to do this. + But that does not work for the case where an environment variable + is redefined in a makefile with `override'; it should then still + be exported, because it was originally in the environment. */ + v->export = v_export; + + /* Another wrinkle is that POSIX says the value of SHELL set in the + makefile won't change the value of SHELL given to subprocesses */ + if (streq (v->name, "SHELL")) + { +#ifndef __MSDOS__ + v->export = v_noexport; +#endif + shell_var.name = "SHELL"; + shell_var.value = xstrdup (ep + 1); + } + + /* If MAKE_RESTARTS is set, remember it but don't export it. */ + if (streq (v->name, "MAKE_RESTARTS")) + { + v->export = v_noexport; + restarts = (unsigned int) atoi (ep + 1); + } + } } #ifdef WINDOWS32 - /* - * Make sure that this particular spelling of 'Path' is available + /* If we didn't find a correctly spelled PATH we define PATH as + * either the first mispelled value or an empty string */ - if (windows32_path) - define_variable("Path", 4, windows32_path, o_env, 1)->export = v_export; - else if (unix_path) - define_variable("Path", 4, unix_path, o_env, 1)->export = v_export; - else - define_variable("Path", 4, "", o_env, 1)->export = v_export; - - /* - * PATH defaults to Path iff PATH not found and Path is found. - */ - if (!unix_path && windows32_path) - define_variable("PATH", 4, windows32_path, o_env, 1)->export = v_export; + if (!unix_path) + define_variable("PATH", 4, + windows32_path ? windows32_path : "", + o_env, 1)->export = v_export; #endif #else /* For Amiga, read the ENV: device, ignoring all dirs */ { @@ -1098,17 +1222,17 @@ int main (int argc, char ** argv) /* Decode the switches. */ - decode_env_switches ("MAKEFLAGS", 9); + decode_env_switches (STRING_SIZE_TUPLE ("MAKEFLAGS")); #if 0 /* People write things like: MFLAGS="CC=gcc -pipe" "CFLAGS=-g" and we set the -p, -i and -e switches. Doesn't seem quite right. */ - decode_env_switches ("MFLAGS", 6); + decode_env_switches (STRING_SIZE_TUPLE ("MFLAGS")); #endif decode_switches (argc, argv, 0); #ifdef WINDOWS32 if (suspend_flag) { - fprintf(stderr, "%s (pid = %d)\n", argv[0], GetCurrentProcessId()); + fprintf(stderr, "%s (pid = %ld)\n", argv[0], GetCurrentProcessId()); fprintf(stderr, _("%s is suspending for 30 seconds..."), argv[0]); Sleep(30 * 1000); fprintf(stderr, _("done sleep(30). Continuing.\n")); @@ -1117,14 +1241,18 @@ int main (int argc, char ** argv) decode_debug_flags (); + /* Set always_make_flag if -B was given and we've not restarted already. */ + always_make_flag = always_make_set && (restarts == 0); + /* Print version information. */ - if (print_version_flag || print_data_base_flag || db_level) - print_version (); + { + print_version (); - /* `make --version' is supposed to just print the version and exit. */ - if (print_version_flag) - die (0); + /* `make --version' is supposed to just print the version and exit. */ + if (print_version_flag) + die (0); + } #ifndef VMS /* Set the "MAKE_COMMAND" variable to the name we were invoked with. @@ -1144,7 +1272,7 @@ int main (int argc, char ** argv) strneq(argv[0], "//", 2)) argv[0] = xstrdup(w32ify(argv[0],1)); #else /* WINDOWS32 */ -#ifdef __MSDOS__ +#if defined (__MSDOS__) || defined (__EMX__) if (strchr (argv[0], '\\')) { char *p; @@ -1159,7 +1287,12 @@ int main (int argc, char ** argv) program that uses a non-absolute name. */ if (current_directory[0] != '\0' && argv[0] != 0 - && (argv[0][0] != '/' && (argv[0][0] == '\0' || argv[0][1] != ':'))) + && (argv[0][0] != '/' && (argv[0][0] == '\0' || argv[0][1] != ':')) +#ifdef __EMX__ + /* do not prepend cwd if argv[0] contains no '/', e.g. "make" */ + && (strchr (argv[0], '/') != 0 || strchr (argv[0], '\\') != 0) +# endif + ) argv[0] = concat (current_directory, "/", argv[0]); #else /* !__MSDOS__ */ if (current_directory[0] != '\0' @@ -1228,16 +1361,27 @@ int main (int argc, char ** argv) for (i = 0; directories->list[i] != 0; ++i) { char *dir = directories->list[i]; + char *expanded = 0; if (dir[0] == '~') { - char *expanded = tilde_expand (dir); + expanded = tilde_expand (dir); if (expanded != 0) dir = expanded; } +#ifdef WINDOWS32 + /* WINDOWS32 chdir() doesn't work if the directory has a trailing '/' + But allow -C/ just in case someone wants that. */ + { + char *p = dir + strlen (dir) - 1; + while (p > dir && (p[0] == '/' || p[0] == '\\')) + --p; + p[1] = '\0'; + } +#endif if (chdir (dir) < 0) pfatal_with_name (dir); - if (dir != directories->list[i]) - free (dir); + if (expanded) + free (expanded); } #ifdef WINDOWS32 @@ -1255,7 +1399,7 @@ int main (int argc, char ** argv) #endif /* WINDOWS32 */ /* Figure out the level of recursion. */ { - struct variable *v = lookup_variable (MAKELEVEL_NAME, MAKELEVEL_LENGTH); + struct variable *v = lookup_variable (STRING_SIZE_TUPLE (MAKELEVEL_NAME)); if (v != 0 && v->value[0] != '\0' && v->value[0] != '-') makelevel = (unsigned int) atoi (v->value); else @@ -1292,7 +1436,7 @@ int main (int argc, char ** argv) #endif { #ifdef HAVE_GETCWD - perror_with_name ("getcwd: ", ""); + perror_with_name ("getcwd", ""); #else error (NILF, "getwd: %s", current_directory); #endif @@ -1302,7 +1446,7 @@ int main (int argc, char ** argv) starting_directory = current_directory; } - (void) define_variable ("CURDIR", 6, current_directory, o_default, 0); + (void) define_variable ("CURDIR", 6, current_directory, o_file, 0); /* Read any stdin makefiles into temporary files. */ @@ -1333,7 +1477,7 @@ int main (int argc, char ** argv) #define DEFAULT_TMPFILE "GmXXXXXX" if (((tmpdir = getenv ("TMPDIR")) == NULL || *tmpdir == '\0') -#if defined __MSDOS__ || defined(WINDOWS32) +#if defined (__MSDOS__) || defined (WINDOWS32) || defined (__EMX__) /* These are also used commonly on these platforms. */ && ((tmpdir = getenv ("TEMP")) == NULL || *tmpdir == '\0') && ((tmpdir = getenv ("TMP")) == NULL || *tmpdir == '\0') @@ -1359,7 +1503,7 @@ int main (int argc, char ** argv) 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); @@ -1384,6 +1528,7 @@ int main (int argc, char ** argv) } } +#ifndef __EMX__ /* Don't use a SIGCHLD handler for OS/2 */ #if defined(MAKE_JOBSERVER) || !defined(HAVE_WAIT_NOHANG) /* Set up to handle children dying. This must be done before reading in the makefiles so that `shell' function calls will work. @@ -1406,6 +1551,7 @@ int main (int argc, char ** argv) bsd_signal (SIGCLD, child_handler); # endif } +#endif #endif /* Let the user send us SIGUSR1 to toggle the -d flag during the run. */ @@ -1437,10 +1583,15 @@ int main (int argc, char ** argv) /* Define the default variables. */ define_default_variables (); - /* Read all the makefiles. */ - default_file = enter_file (".DEFAULT"); + { + struct variable *v = define_variable (".DEFAULT_GOAL", 13, "", o_file, 0); + default_goal_name = &v->value; + } + + /* Read all the makefiles. */ + read_makefiles = read_all_makefiles (makefiles == 0 ? (char **) 0 : makefiles->list); @@ -1448,19 +1599,13 @@ int main (int argc, char ** argv) /* look one last time after reading all Makefiles */ if (no_default_sh_exe) no_default_sh_exe = !find_and_set_default_shell(NULL); - - if (no_default_sh_exe && job_slots != 1) { - error (NILF, _("Do not specify -j or --jobs if sh.exe is not available.")); - error (NILF, _("Resetting make for single job mode.")); - job_slots = 1; - } #endif /* WINDOWS32 */ -#ifdef __MSDOS__ +#if defined (__MSDOS__) || defined (__EMX__) /* We need to know what kind of shell we will be using. */ { extern int _is_unixy_shell (const char *_path); - struct variable *shv = lookup_variable ("SHELL", 5); + struct variable *shv = lookup_variable (STRING_SIZE_TUPLE ("SHELL")); extern int unixy_shell; extern char *default_shell; @@ -1476,16 +1621,20 @@ int main (int argc, char ** argv) default_shell = shell_path; } } -#endif /* __MSDOS__ */ +#endif /* __MSDOS__ || __EMX__ */ /* Decode switches again, in case the variables were set by the makefile. */ - decode_env_switches ("MAKEFLAGS", 9); + decode_env_switches (STRING_SIZE_TUPLE ("MAKEFLAGS")); #if 0 - decode_env_switches ("MFLAGS", 6); + decode_env_switches (STRING_SIZE_TUPLE ("MFLAGS")); #endif -#ifdef __MSDOS__ - if (job_slots != 1) +#if defined (__MSDOS__) || defined (__EMX__) + if (job_slots != 1 +# ifdef __EMX__ + && _osmode != OS2_MODE /* turn off -j if we are in DOS mode */ +# endif + ) { error (NILF, _("Parallel jobs (-j) are not supported on this platform.")); @@ -1500,9 +1649,10 @@ int main (int argc, char ** argv) if (jobserver_fds) { char *cp; + unsigned int ui; - for (i=1; i < jobserver_fds->idx; ++i) - if (!streq (jobserver_fds->list[0], jobserver_fds->list[i])) + for (ui=1; ui < jobserver_fds->idx; ++ui) + if (!streq (jobserver_fds->list[0], jobserver_fds->list[ui])) fatal (NILF, _("internal error: multiple --jobserver-fds options")); /* Now parse the fds string and make sure it has the proper format. */ @@ -1564,9 +1714,16 @@ int main (int argc, char ** argv) top make, we just subtract one from the number the user wants. We want job_slots to be 0 to indicate we're using the jobserver. */ + master_job_slots = job_slots; + while (--job_slots) - if (write (job_fds[1], &c, 1) != 1) - pfatal_with_name (_("init jobserver pipe")); + { + int r; + + EINTRLOOP (r, write (job_fds[1], &c, 1)); + if (r != 1) + pfatal_with_name (_("init jobserver pipe")); + } /* Fill in the jobserver_fds struct for our children. */ @@ -1581,6 +1738,14 @@ int main (int argc, char ** argv) } #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); @@ -1612,9 +1777,9 @@ int main (int argc, char ** argv) build_vpath_lists (); - /* Mark files given with -o flags as very old - and as having been updated already, and files given with -W flags as - brand new (time-stamp as far as possible into the future). */ + /* Mark files given with -o flags as very old and as having been updated + already, and files given with -W flags as brand new (time-stamp as far + as possible into the future). If restarts is set we'll do -W later. */ if (old_files != 0) for (p = old_files->list; *p != 0; ++p) @@ -1626,7 +1791,7 @@ int main (int argc, char ** argv) f->command_state = cs_finished; } - if (new_files != 0) + if (!restarts && new_files != 0) { for (p = new_files->list; *p != 0; ++p) { @@ -1647,6 +1812,7 @@ int main (int argc, char ** argv) char **nargv = argv; int nargc = argc; int orig_db_level = db_level; + int status; if (! ISDB (DB_MAKEFILES)) db_level = DB_NONE; @@ -1685,7 +1851,7 @@ int main (int argc, char ** argv) last->next = d->next; /* Free the storage. */ - free ((char *) d); + free_dep (d); d = last == 0 ? read_makefiles : last->next; @@ -1707,7 +1873,11 @@ int main (int argc, char ** argv) /* Set up `MAKEFLAGS' specially while remaking makefiles. */ define_makeflags (1, 1); - switch (update_goal_chain (read_makefiles, 1)) + rebuilding_makefiles = 1; + status = update_goal_chain (read_makefiles); + rebuilding_makefiles = 0; + + switch (status) { case 1: /* The only way this can happen is if the user specified -q and asked @@ -1728,7 +1898,7 @@ int main (int argc, char ** argv) /* Nonzero if any makefile we care about failed in updating or could not be found at all. */ int any_failed = 0; - register unsigned int i; + unsigned int i; struct dep *d; for (i = 0, d = read_makefiles; d != 0; ++i, d = d->next) @@ -1756,6 +1926,7 @@ int main (int argc, char ** argv) mtime = file_mtime_no_search (d->file); any_remade |= (mtime != NONEXISTENT_MTIME && mtime != makefile_mtimes[i]); + makefile_status = MAKE_FAILURE; } } else @@ -1799,10 +1970,12 @@ int main (int argc, char ** argv) log_working_directory (0); + clean_jobserver (0); + if (makefiles != 0) { /* These names might have changed. */ - register unsigned int i, j = 0; + int i, j = 0; for (i = 1; i < argc; ++i) if (strneq (argv[i], "-f", 2)) /* XXX */ { @@ -1843,44 +2016,61 @@ int main (int argc, char ** argv) fatal (NILF, _("Couldn't change back to original directory.")); } -#ifndef _AMIGA - for (p = environ; *p != 0; ++p) - if ((*p)[MAKELEVEL_LENGTH] == '=' - && strneq (*p, MAKELEVEL_NAME, MAKELEVEL_LENGTH)) - { - /* The SGI compiler apparently can't understand - the concept of storing the result of a function - in something other than a local variable. */ - char *sgi_loses; - sgi_loses = (char *) alloca (40); - *p = sgi_loses; - sprintf (*p, "%s=%u", MAKELEVEL_NAME, makelevel); - break; - } -#else /* AMIGA */ - { - char buffer[256]; - int len; - - len = GetVar (MAKELEVEL_NAME, buffer, sizeof (buffer), GVF_GLOBAL_ONLY); - - if (len != -1) - { - sprintf (buffer, "%u", makelevel); - SetVar (MAKELEVEL_NAME, buffer, -1, GVF_GLOBAL_ONLY); - } - } -#endif + ++restarts; if (ISDB (DB_BASIC)) { char **p; - fputs (_("Re-executing:"), stdout); + printf (_("Re-executing[%u]:"), restarts); for (p = nargv; *p != 0; ++p) printf (" %s", *p); putchar ('\n'); } +#ifndef _AMIGA + for (p = environ; *p != 0; ++p) + { + if (strneq (*p, MAKELEVEL_NAME, MAKELEVEL_LENGTH) + && (*p)[MAKELEVEL_LENGTH] == '=') + { + /* The SGI compiler apparently can't understand + the concept of storing the result of a function + in something other than a local variable. */ + char *sgi_loses; + sgi_loses = (char *) alloca (40); + *p = sgi_loses; + sprintf (*p, "%s=%u", MAKELEVEL_NAME, makelevel); + } + if (strneq (*p, "MAKE_RESTARTS=", 14)) + { + char *sgi_loses; + sgi_loses = (char *) alloca (40); + *p = sgi_loses; + sprintf (*p, "MAKE_RESTARTS=%u", restarts); + restarts = 0; + } + } +#else /* AMIGA */ + { + char buffer[256]; + + sprintf (buffer, "%u", makelevel); + SetVar (MAKELEVEL_NAME, buffer, -1, GVF_GLOBAL_ONLY); + + sprintf (buffer, "%u", restarts); + SetVar ("MAKE_RESTARTS", buffer, -1, GVF_GLOBAL_ONLY); + restarts = 0; + } +#endif + + /* If we didn't set the restarts variable yet, add it. */ + if (restarts) + { + char *b = alloca (40); + sprintf (b, "MAKE_RESTARTS=%u", restarts); + putenv (b); + } + fflush (stdout); fflush (stderr); @@ -1888,11 +2078,30 @@ int main (int argc, char ** argv) if (job_rfd >= 0) close (job_rfd); -#ifndef _AMIGA - exec_command (nargv, environ); -#else +#ifdef _AMIGA exec_command (nargv); exit (0); +#elif defined (__EMX__) + { + /* It is not possible to use execve() here because this + would cause the parent process to be terminated with + exit code 0 before the child process has been terminated. + Therefore it may be the best solution simply to spawn the + child process including all file handles and to wait for its + termination. */ + int pid; + int status; + pid = child_execute_job (0, 1, nargv, environ); + + /* is this loop really necessary? */ + do { + pid = wait (&status); + } while (pid <= 0); + /* use the exit code of the child process */ + exit (WIFEXITED(status) ? WEXITSTATUS(status) : EXIT_FAILURE); + } +#else + exec_command (nargv, environ); #endif /* NOTREACHED */ @@ -1903,11 +2112,28 @@ int main (int argc, char ** argv) } db_level = orig_db_level; + + /* Free the makefile mtimes (if we allocated any). */ + if (makefile_mtimes) + free ((char *) makefile_mtimes); } /* Set up `MAKEFLAGS' again for the normal targets. */ define_makeflags (1, 0); + /* Set always_make_flag if -B was given. */ + always_make_flag = always_make_set; + + /* If restarts is set we haven't set up -W files yet, so do that now. */ + if (restarts && new_files != 0) + { + for (p = new_files->list; *p != 0; ++p) + { + f = enter_command_line_file (*p); + f->last_mtime = f->mtime_before_update = NEW_MTIME; + } + } + /* If there is a temp file from reading a makefile from stdin, get rid of it now. */ if (stdin_nm && unlink (stdin_nm) < 0 && errno != ENOENT) @@ -1919,18 +2145,44 @@ int main (int argc, char ** argv) /* If there were no command-line goals, use the default. */ if (goals == 0) { - if (default_goal_file != 0) - { - goals = (struct dep *) xmalloc (sizeof (struct dep)); - goals->next = 0; - goals->name = 0; - goals->ignore_mtime = 0; - goals->file = default_goal_file; - } + if (**default_goal_name != '\0') + { + if (default_goal_file == 0 || + strcmp (*default_goal_name, default_goal_file->name) != 0) + { + default_goal_file = lookup_file (*default_goal_name); + + /* In case user set .DEFAULT_GOAL to a non-existent target + name let's just enter this name into the table and let + the standard logic sort it out. */ + if (default_goal_file == 0) + { + struct nameseq *ns; + char *p = *default_goal_name; + + ns = multi_glob ( + parse_file_seq (&p, '\0', sizeof (struct nameseq), 1), + sizeof (struct nameseq)); + + /* .DEFAULT_GOAL should contain one target. */ + if (ns->next != 0) + fatal (NILF, _(".DEFAULT_GOAL contains more than one target")); + + default_goal_file = enter_file (ns->name); + + ns->name = 0; /* It was reused by enter_file(). */ + free_ns_chain (ns); + } + } + + goals = alloc_dep (); + goals->file = default_goal_file; + } } else lastgoal->next = 0; + if (!goals) { if (read_makefiles == 0) @@ -1943,13 +2195,13 @@ int main (int argc, char ** argv) DB (DB_BASIC, (_("Updating goal targets....\n"))); - switch (update_goal_chain (goals, 0)) + switch (update_goal_chain (goals)) { case -1: /* Nothing happened. */ case 0: /* Updated successfully. */ - status = MAKE_SUCCESS; + status = makefile_status; break; case 1: /* We are under -q and would run some commands. */ @@ -1973,6 +2225,7 @@ int main (int argc, char ** argv) die (status); } + /* NOTREACHED */ return 0; } @@ -1985,11 +2238,11 @@ static struct option long_options[(sizeof (switches) / sizeof (switches[0])) + /* Fill in the string and vector for getopt. */ static void -init_switches () +init_switches (void) { - register char *p; - register int c; - register unsigned int i; + char *p; + unsigned int c; + unsigned int i; if (options[0] != '\0') /* Already done. */ @@ -2042,9 +2295,7 @@ init_switches () } static void -handle_non_switch_argument (arg, env) - char *arg; - int env; +handle_non_switch_argument (char *arg, int env) { /* Non-option argument. It might be a variable definition. */ struct variable *v; @@ -2054,13 +2305,21 @@ handle_non_switch_argument (arg, env) v = try_variable_definition (0, arg, o_command, 0); if (v != 0) { - /* It is indeed a variable definition. Record a pointer to - the variable for later use in define_makeflags. */ - struct command_variable *cv - = (struct command_variable *) xmalloc (sizeof (*cv)); - cv->variable = v; - cv->next = command_variables; - command_variables = cv; + /* It is indeed a variable definition. If we don't already have this + one, record a pointer to the variable for later use in + define_makeflags. */ + struct command_variable *cv; + + for (cv = command_variables; cv != 0; cv = cv->next) + if (cv->variable == v) + break; + + if (! cv) { + cv = (struct command_variable *) xmalloc (sizeof (*cv)); + cv->variable = v; + cv->next = command_variables; + command_variables = cv; + } } else if (! env) { @@ -2072,24 +2331,23 @@ handle_non_switch_argument (arg, env) if (goals == 0) { - goals = (struct dep *) xmalloc (sizeof (struct dep)); + goals = alloc_dep (); lastgoal = goals; } else { - lastgoal->next = (struct dep *) xmalloc (sizeof (struct dep)); + lastgoal->next = alloc_dep (); lastgoal = lastgoal->next; } - lastgoal->name = 0; + lastgoal->file = f; - lastgoal->ignore_mtime = 0; { /* Add this target name to the MAKECMDGOALS variable. */ struct variable *v; char *value; - v = lookup_variable ("MAKECMDGOALS", 12); + v = lookup_variable (STRING_SIZE_TUPLE ("MAKECMDGOALS")); if (v == 0) value = f->name; else @@ -2112,10 +2370,8 @@ handle_non_switch_argument (arg, env) /* Print a nice usage method. */ static void -print_usage (bad) - int bad; +print_usage (int bad) { - extern char *make_host; const char *const *cpp; FILE *usageto; @@ -2142,10 +2398,7 @@ print_usage (bad) They came from the environment if ENV is nonzero. */ static void -decode_switches (argc, argv, env) - int argc; - char **argv; - int env; +decode_switches (int argc, char **argv, int env) { int bad = 0; register const struct command_switch *cs; @@ -2208,6 +2461,12 @@ decode_switches (argc, argv, env) if (optarg == 0) optarg = cs->noarg_value; + else if (*optarg == '\0') + { + error (NILF, _("the `-%c' option requires a non-empty string argument"), + cs->c); + bad = 1; + } sl = *(struct stringlist **) cs->value_ptr; if (sl == 0) @@ -2309,9 +2568,7 @@ decode_switches (argc, argv, env) decode_switches. */ static void -decode_env_switches (envar, len) - char *envar; - unsigned int len; +decode_env_switches (char *envar, unsigned int len) { char *varref = (char *) alloca (2 + len + 2); char *value, *p; @@ -2382,8 +2639,7 @@ decode_env_switches (envar, len) Allocating space for OUT twice the length of IN is always sufficient. */ static char * -quote_for_env (out, in) - char *out, *in; +quote_for_env (char *out, char *in) { while (*in != '\0') { @@ -2402,8 +2658,7 @@ quote_for_env (out, in) Don't include options with the `no_makefile' flag set if MAKEFILE. */ static void -define_makeflags (all, makefile) - int all, makefile; +define_makeflags (int all, int makefile) { static const char ref[] = "$(MAKEOVERRIDES)"; static const char posixref[] = "$(-*-command-variables-*-)"; @@ -2665,7 +2920,7 @@ define_makeflags (all, makefile) /* Print version information. */ static void -print_version () +print_version (void) { static int printed_version = 0; @@ -2681,7 +2936,7 @@ print_version () word "Copyright", so it hardly seems worth it. */ printf ("%sGNU Make %s\n\ -%sCopyright (C) 2002 Free Software Foundation, Inc.\n", +%sCopyright (C) 2006 Free Software Foundation, Inc.\n", precede, version_string, precede); printf (_("%sThis is free software; see the source for copying conditions.\n\ @@ -2689,6 +2944,12 @@ print_version () %sPARTICULAR PURPOSE.\n"), precede, precede, precede); + if (!remote_description || *remote_description == '\0') + printf (_("\n%sThis program built for %s\n"), precede, make_host); + else + printf (_("\n%sThis program built for %s (%s)\n"), + precede, make_host, remote_description); + printed_version = 1; /* Flush stdout so the user doesn't have to wait to see the @@ -2711,16 +2972,66 @@ print_data_base () print_rule_data_base (); print_file_data_base (); print_vpath_data_base (); + strcache_print_stats ("#"); when = time ((time_t *) 0); printf (_("\n# Finished Make data base on %s\n"), ctime (&when)); } + +static void +clean_jobserver (int status) +{ + char token = '+'; + + /* Sanity: have we written all our jobserver tokens back? If our + exit status is 2 that means some kind of syntax error; we might not + have written all our tokens so do that now. If tokens are left + after any other error code, that's bad. */ + + if (job_fds[0] != -1 && jobserver_tokens) + { + if (status != 2) + error (NILF, + "INTERNAL: Exiting with %u jobserver tokens (should be 0)!", + jobserver_tokens); + else + while (jobserver_tokens--) + { + int r; + + EINTRLOOP (r, write (job_fds[1], &token, 1)); + if (r != 1) + perror_with_name ("write", ""); + } + } + + + /* Sanity: If we're the master, were all the tokens written back? */ + + if (master_job_slots) + { + /* We didn't write one for ourself, so start at 1. */ + unsigned int tcnt = 1; + + /* Close the write side, so the read() won't hang. */ + close (job_fds[1]); + + while (read (job_fds[0], &token, 1) == 1) + ++tcnt; + + if (tcnt != master_job_slots) + error (NILF, + "INTERNAL: Exiting with %u jobserver tokens available; should be %u!", + tcnt, master_job_slots); + + close (job_fds[0]); + } +} /* Exit with STATUS, cleaning up as necessary. */ void -die (status) - int status; +die (int status) { static char dying = 0; @@ -2734,7 +3045,8 @@ die (status) print_version (); /* Wait for children to die. */ - for (err = (status != 0); job_slots_used > 0; err = 0) + err = (status != 0); + while (job_slots_used > 0) reap_children (1, err); /* Let the remote job module clean up its state. */ @@ -2746,6 +3058,8 @@ die (status) if (print_data_base_flag) print_data_base (); + clean_jobserver (status); + /* Try to move back to the original directory. This is essential on MS-DOS (where there is really only one process), and on Unix it puts core files in the original directory instead of the -C @@ -2764,8 +3078,7 @@ die (status) left (according to ENTERING) the current directory. */ void -log_working_directory (entering) - int entering; +log_working_directory (int entering) { static int entered = 0; @@ -2785,9 +3098,9 @@ log_working_directory (entering) if (makelevel == 0) if (starting_directory == 0) if (entering) - printf (_("%s: Entering an unknown directory"), program); + printf (_("%s: Entering an unknown directory\n"), program); else - printf (_("%s: Leaving an unknown directory"), program); + printf (_("%s: Leaving an unknown directory\n"), program); else if (entering) printf (_("%s: Entering directory `%s'\n"), @@ -2798,10 +3111,10 @@ log_working_directory (entering) else if (starting_directory == 0) if (entering) - printf (_("%s[%u]: Entering an unknown directory"), + printf (_("%s[%u]: Entering an unknown directory\n"), program, makelevel); else - printf (_("%s[%u]: Leaving an unknown directory"), + printf (_("%s[%u]: Leaving an unknown directory\n"), program, makelevel); else if (entering) @@ -2810,4 +3123,7 @@ log_working_directory (entering) else printf (_("%s[%u]: Leaving directory `%s'\n"), program, makelevel, starting_directory); + + /* Flush stdout to be sure this comes before any stderr output. */ + fflush (stdout); } diff --git a/src/bin/make/make.h b/src/bin/make/make.h index 6648ea0dba..994f4f225c 100644 --- a/src/bin/make/make.h +++ b/src/bin/make/make.h @@ -1,22 +1,20 @@ /* Miscellaneous global declarations and portability cruft for GNU Make. -Copyright (C) 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1999, -2002 Free Software Foundation, Inc. +Copyright (C) 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, +1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006 Free Software +Foundation, Inc. This file is part of GNU Make. -GNU Make is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 2, or (at your option) -any later version. +GNU Make is free software; you can redistribute it and/or modify it under the +terms of the GNU General Public License as published by the Free Software +Foundation; either version 2, or (at your option) any later version. -GNU Make is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. +GNU Make is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR +A PARTICULAR PURPOSE. See the GNU General Public License for more details. -You should have received a copy of the GNU General Public License -along with GNU Make; see the file COPYING. If not, write to -the Free Software Foundation, Inc., 59 Temple Place - Suite 330, -Boston, MA 02111-1307, USA. */ +You should have received a copy of the GNU General Public License along with +GNU Make; see the file COPYING. If not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. */ /* We use instead of "config.h" so that a compilation using -I. -I$srcdir will use ./config.h rather than $srcdir/config.h @@ -42,7 +40,7 @@ char *alloca (); /* Use prototypes if available. */ -#if defined (__cplusplus) || (defined (__STDC__) && __STDC__) +#if defined (__cplusplus) || defined (__STDC__) # undef PARAMS # define PARAMS(protos) protos #else /* Not C++ or ANSI C. */ @@ -210,6 +208,7 @@ extern unsigned int get_path_max PARAMS ((void)); # define __printf__ printf # endif #endif +#define UNUSED __attribute__ ((unused)) #if defined (STDC_HEADERS) || defined (__GNU_LIBRARY__) # include @@ -275,16 +274,15 @@ extern void bzero PARAMS ((char *, int)); extern void bcopy PARAMS ((const char *b1, char *b2, int)); # endif -#endif /* ANSI_STRING. */ -#undef ANSI_STRING - /* SCO Xenix has a buggy macro definition in . */ #undef strerror - -#if !defined(ANSI_STRING) && !defined(__DECC) +#if !defined(__DECC) extern char *strerror PARAMS ((int errnum)); #endif +#endif /* !ANSI_STRING. */ +#undef ANSI_STRING + #if HAVE_INTTYPES_H # include #endif @@ -349,15 +347,17 @@ extern int strcmpi (const char *,const char *); #define S_(msg1,msg2,num) ngettext (msg1,msg2,num) /* Handle other OSs. */ - -#if defined(__MSDOS__) || defined(WINDOWS32) +#if defined(HAVE_DOS_PATHS) # define PATH_SEPARATOR_CHAR ';' +#elif defined(VMS) +# define PATH_SEPARATOR_CHAR ',' #else -# if defined(VMS) -# define PATH_SEPARATOR_CHAR ',' -# else -# define PATH_SEPARATOR_CHAR ':' -# endif +# define PATH_SEPARATOR_CHAR ':' +#endif + +/* This is needed for getcwd() and chdir(). */ +#if defined(_MSC_VER) || defined(__BORLANDC__) +# include #endif #ifdef WINDOWS32 @@ -368,7 +368,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); @@ -381,7 +380,7 @@ extern int unixy_shell; struct floc { - char *filenm; + const char *filenm; unsigned long lineno; }; #define NILF ((struct floc *)0) @@ -389,9 +388,16 @@ struct floc #define STRING_SIZE_TUPLE(_s) (_s), (sizeof (_s)-1) -/* Fancy processing for variadic functions in both ANSI and pre-ANSI - compilers. */ -#if defined __STDC__ && __STDC__ +/* We have to have stdarg.h or varargs.h AND v*printf or doprnt to use + variadic versions of these functions. */ + +#if HAVE_STDARG_H || HAVE_VARARGS_H +# if HAVE_VPRINTF || HAVE_DOPRNT +# define USE_VARIADIC 1 +# endif +#endif + +#if HAVE_ANSI_COMPILER && USE_VARIADIC && HAVE_STDARG_H extern void message (int prefix, const char *fmt, ...) __attribute__ ((__format__ (__printf__, 2, 3))); extern void error (const struct floc *flocp, const char *fmt, ...) @@ -415,15 +421,11 @@ 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 *sindex PARAMS ((const char *, unsigned int, \ - const char *, unsigned int)); extern char *lindex PARAMS ((const char *, const char *, int)); extern int alpha_compare PARAMS ((const void *, const void *)); extern void print_spaces PARAMS ((unsigned int)); -extern char *find_char_unquote PARAMS ((char *, int, int, int)); extern char *find_percent PARAMS ((char *)); extern FILE *open_tmpfile PARAMS ((char **, const char *)); @@ -449,7 +451,7 @@ extern void install_default_implicit_rules PARAMS ((void)); extern void build_vpath_lists PARAMS ((void)); extern void construct_vpath_list PARAMS ((char *pattern, char *dirpath)); extern int vpath_search PARAMS ((char **file, FILE_TIMESTAMP *mtime_ptr)); -extern int gpath_search PARAMS ((char *file, int len)); +extern int gpath_search PARAMS ((char *file, unsigned int len)); extern void construct_include_path PARAMS ((char **arg_dirs)); @@ -457,6 +459,18 @@ extern void user_access PARAMS ((void)); extern void make_access PARAMS ((void)); extern void child_access PARAMS ((void)); +extern void close_stdout PARAMS ((void)); + +extern char *strip_whitespace PARAMS ((const char **begpp, const char **endpp)); + +/* String caching */ +extern void strcache_init PARAMS ((void)); +extern void strcache_print_stats PARAMS ((const char *prefix)); +extern int strcache_iscached PARAMS ((const char *str)); +extern const char *strcache_add PARAMS ((const char *str)); +extern const char *strcache_add_len PARAMS ((const char *str, int len)); +extern int strcache_setbufsize PARAMS ((int size)); + #ifdef HAVE_VFORK_H # include #endif @@ -476,22 +490,23 @@ extern long int lseek (); #ifdef HAVE_GETCWD # if !defined(VMS) && !defined(__DECC) extern char *getcwd (); -#endif +# endif #else extern char *getwd (); # define getcwd(buf, len) getwd (buf) #endif extern const struct floc *reading_file; +extern const struct floc **expanding_var; 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; +extern int second_expansion, clock_skew_detected, rebuilding_makefiles; /* can we run commands via 'sh -c xxx' or must we use batch files? */ extern int batch_mode_shell; @@ -508,7 +523,7 @@ extern int max_load_average; extern char *program; extern char *starting_directory; extern unsigned int makelevel; -extern char *version_string, *remote_description; +extern char *version_string, *remote_description, *make_host; extern unsigned int commands_started; @@ -538,25 +553,59 @@ extern int handling_fatal_signal; #include #endif - -/* If we have broken SA_RESTART support, then wrap stat() and readdir() with - versions that handle EINTR. Note that there are still plenty of system - calls that can fail with EINTR but this, reportedly, gets the vast - majority of failure cases. If you still experience failures you'll need - to either get a system where SA_RESTART works, or you need to avoid -j. */ - -#ifdef HAVE_BROKEN_RESTART - -/* Here we make an assumption that a system with a broken SA_RESTART has - dirent.h. Right now the only system I know of in this category is PTX, and - it does have dirent.h. -*/ -#include - -#define stat(_f,_b) atomic_stat ((_f), (_b)) -#define readdir(_d) atomic_readdir (_d) - -extern int atomic_stat PARAMS ((const char *file, struct stat *buf)); -extern struct dirent *atomic_readdir PARAMS ((DIR *dir)); - +#ifndef initialize_main +# ifdef __EMX__ +# define initialize_main(pargc, pargv) \ + { _wildcard(pargc, pargv); _response(pargc, pargv); } +# else +# define initialize_main(pargc, pargv) +# endif #endif + + +#ifdef __EMX__ +# if !HAVE_STRCASECMP +# define strcasecmp stricmp +# endif + +# if !defined chdir +# define chdir _chdir2 +# endif +# if !defined getcwd +# define getcwd _getcwd2 +# endif + +/* NO_CHDIR2 causes make not to use _chdir2() and _getcwd2() instead of + chdir() and getcwd(). This avoids some error messages for the + make testsuite but restricts the drive letter support. */ +# ifdef NO_CHDIR2 +# warning NO_CHDIR2: usage of drive letters restricted +# undef chdir +# undef getcwd +# endif +#endif + +#ifndef initialize_main +# define initialize_main(pargc, pargv) +#endif + + +/* Some systems (like Solaris, PTX, etc.) do not support the SA_RESTART flag + properly according to POSIX. So, we try to wrap common system calls with + checks for EINTR. Note that there are still plenty of system calls that + can fail with EINTR but this, reportedly, gets the vast majority of + failure cases. If you still experience failures you'll need to either get + a system where SA_RESTART works, or you need to avoid -j. */ + +#define EINTRLOOP(_v,_c) while (((_v)=_c)==-1 && errno==EINTR) + +/* While system calls that return integers are pretty consistent about + returning -1 on failure and setting errno in that case, functions that + return pointers are not always so well behaved. Sometimes they return + NULL for expected behavior: one good example is readdir() which returns + NULL at the end of the directory--and _doesn't_ reset errno. So, we have + to do it ourselves here. */ + +#define ENULLLOOP(_v,_c) do{ errno = 0; \ + while (((_v)=_c)==0 && errno==EINTR); }while(0) + diff --git a/src/bin/make/misc.c b/src/bin/make/misc.c index 7f0b1b30f4..07f3c016af 100644 --- a/src/bin/make/misc.c +++ b/src/bin/make/misc.c @@ -1,22 +1,20 @@ /* Miscellaneous generic support functions for GNU Make. -Copyright (C) 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1997, -2002 Free Software Foundation, Inc. +Copyright (C) 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, +1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006 Free Software +Foundation, Inc. This file is part of GNU Make. -GNU Make is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 2, or (at your option) -any later version. +GNU Make is free software; you can redistribute it and/or modify it under the +terms of the GNU General Public License as published by the Free Software +Foundation; either version 2, or (at your option) any later version. -GNU Make is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. +GNU Make is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR +A PARTICULAR PURPOSE. See the GNU General Public License for more details. -You should have received a copy of the GNU General Public License -along with GNU Make; see the file COPYING. If not, write to -the Free Software Foundation, Inc., 59 Temple Place - Suite 330, -Boston, MA 02111-1307, USA. */ +You should have received a copy of the GNU General Public License along with +GNU Make; see the file COPYING. If not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. */ #include "make.h" #include "dep.h" @@ -30,9 +28,8 @@ Boston, MA 02111-1307, USA. */ This fancy stuff all came from GNU fileutils, except for the VA_PRINTF and VA_END macros used here since we have multiple print functions. */ -#if HAVE_VPRINTF || HAVE_DOPRNT -# define HAVE_STDVARARGS 1 -# if __STDC__ +#if USE_VARIADIC +# if HAVE_STDARG_H # include # define VA_START(args, lastarg) va_start(args, lastarg) # else @@ -46,7 +43,7 @@ Boston, MA 02111-1307, USA. */ # endif # define VA_END(args) va_end(args) #else -/* # undef HAVE_STDVARARGS */ +/* We can't use any variadic interface! */ # define va_alist a1, a2, a3, a4, a5, a6, a7, a8 # define va_dcl char *a1, *a2, *a3, *a4, *a5, *a6, *a7, *a8; # define VA_START(args, lastarg) @@ -60,8 +57,7 @@ Boston, MA 02111-1307, USA. */ zero if they are equal. */ int -alpha_compare (v1, v2) - const void *v1, *v2; +alpha_compare (const void *v1, const void *v2) { const char *s1 = *((char **)v1); const char *s2 = *((char **)v2); @@ -76,8 +72,7 @@ alpha_compare (v1, v2) This is done by copying the text at LINE into itself. */ void -collapse_continuations (line) - char *line; +collapse_continuations (char *line) { register char *in, *out, *p; register int backslash; @@ -152,29 +147,11 @@ collapse_continuations (line) *out = '\0'; } - - -/* Remove comments from LINE. - This is done by copying the text at LINE onto itself. */ - -void -remove_comments (line) - char *line; -{ - char *comment; - - comment = find_char_unquote (line, '#', 0, 0); - - if (comment != 0) - /* Cut off the line at the #. */ - *comment = '\0'; -} /* Print N spaces (used in debug for target-depth). */ void -print_spaces (n) - unsigned int n; +print_spaces (unsigned int n) { while (n-- > 0) putchar (' '); @@ -185,8 +162,7 @@ print_spaces (n) concatenate those of s1, s2, s3. */ char * -concat (s1, s2, s3) - const char *s1, *s2, *s3; +concat (const char *s1, const char *s2, const char *s3) { unsigned int len1, len2, len3; char *result; @@ -211,7 +187,7 @@ concat (s1, s2, s3) /* Print a message on stdout. */ void -#if __STDC__ && HAVE_STDVARARGS +#if HAVE_ANSI_COMPILER && USE_VARIADIC && HAVE_STDARG_H message (int prefix, const char *fmt, ...) #else message (prefix, fmt, va_alist) @@ -220,7 +196,7 @@ message (prefix, fmt, va_alist) va_dcl #endif { -#if HAVE_STDVARARGS +#if USE_VARIADIC va_list args; #endif @@ -247,7 +223,7 @@ message (prefix, fmt, va_alist) /* Print an error message. */ void -#if __STDC__ && HAVE_STDVARARGS +#if HAVE_ANSI_COMPILER && USE_VARIADIC && HAVE_STDARG_H error (const struct floc *flocp, const char *fmt, ...) #else error (flocp, fmt, va_alist) @@ -256,7 +232,7 @@ error (flocp, fmt, va_alist) va_dcl #endif { -#if HAVE_STDVARARGS +#if USE_VARIADIC va_list args; #endif @@ -280,7 +256,7 @@ error (flocp, fmt, va_alist) /* Print an error message and exit. */ void -#if __STDC__ && HAVE_STDVARARGS +#if HAVE_ANSI_COMPILER && USE_VARIADIC && HAVE_STDARG_H fatal (const struct floc *flocp, const char *fmt, ...) #else fatal (flocp, fmt, va_alist) @@ -289,7 +265,7 @@ fatal (flocp, fmt, va_alist) va_dcl #endif { -#if HAVE_STDVARARGS +#if USE_VARIADIC va_list args; #endif @@ -316,8 +292,7 @@ fatal (flocp, fmt, va_alist) #undef strerror char * -strerror (errnum) - int errnum; +strerror (int errnum) { extern int errno, sys_nerr; #ifndef __DECC @@ -336,8 +311,7 @@ strerror (errnum) /* Print an error message from errno. */ void -perror_with_name (str, name) - const char *str, *name; +perror_with_name (const char *str, const char *name) { error (NILF, _("%s%s: %s"), str, name, strerror (errno)); } @@ -345,8 +319,7 @@ perror_with_name (str, name) /* Print an error message from errno and exit. */ void -pfatal_with_name (name) - const char *name; +pfatal_with_name (const char *name) { fatal (NILF, _("%s: %s"), name, strerror (errno)); @@ -363,10 +336,10 @@ pfatal_with_name (name) #undef xstrdup char * -xmalloc (size) - unsigned int size; +xmalloc (unsigned int size) { - char *result = (char *) malloc (size); + /* Make sure we don't allocate 0, for pre-ANSI libraries. */ + char *result = (char *) malloc (size ? size : 1); if (result == 0) fatal (NILF, _("virtual memory exhausted")); return result; @@ -374,13 +347,13 @@ xmalloc (size) char * -xrealloc (ptr, size) - char *ptr; - unsigned int size; +xrealloc (char *ptr, unsigned int size) { char *result; /* Some older implementations of realloc() don't conform to ANSI. */ + if (! size) + size = 1; result = ptr ? realloc (ptr, size) : malloc (size); if (result == 0) fatal (NILF, _("virtual memory exhausted")); @@ -389,8 +362,7 @@ xrealloc (ptr, size) char * -xstrdup (ptr) - const char *ptr; +xstrdup (const char *ptr) { char *result; @@ -413,9 +385,7 @@ xstrdup (ptr) #endif /* HAVE_DMALLOC_H */ char * -savestring (str, length) - const char *str; - unsigned int length; +savestring (const char *str, unsigned int length) { register char *out = (char *) xmalloc (length + 1); if (length > 0) @@ -424,37 +394,6 @@ savestring (str, length) return out; } -/* Search string BIG (length BLEN) for an occurrence of - string SMALL (length SLEN). Return a pointer to the - beginning of the first occurrence, or return nil if none found. */ - -char * -sindex (big, blen, small, slen) - const char *big; - unsigned int blen; - const char *small; - unsigned int slen; -{ - if (!blen) - blen = strlen (big); - if (!slen) - slen = strlen (small); - - if (slen && blen >= slen) - { - register unsigned int b; - - /* Quit when there's not enough room left for the small string. */ - --slen; - blen -= slen; - - for (b = 0; b < blen; ++b, ++big) - if (*big == *small && strneq (big + 1, small + 1, slen)) - return (char *)big; - } - - return 0; -} /* Limited INDEX: Search through the string STRING, which ends at LIMIT, for the character C. @@ -463,9 +402,7 @@ sindex (big, blen, small, slen) instead of at the first null. */ char * -lindex (s, limit, c) - register const char *s, *limit; - int c; +lindex (const char *s, const char *limit, int c) { while (s < limit) if (*s++ == c) @@ -477,12 +414,11 @@ lindex (s, limit, c) /* Return the address of the first whitespace or null in the string S. */ char * -end_of_token (s) - char *s; +end_of_token (const char *s) { while (*s != '\0' && !isblank ((unsigned char)*s)) ++s; - return s; + return (char *)s; } #ifdef WINDOWS32 @@ -490,9 +426,7 @@ end_of_token (s) * Same as end_of_token, but take into account a stop character */ char * -end_of_token_w32 (s, stopchar) - char *s; - char stopchar; +end_of_token_w32 (char *s, char stopchar) { register char *p = s; register int backslash = 0; @@ -520,8 +454,7 @@ end_of_token_w32 (s, stopchar) /* Return the address of the first nonwhitespace or null in the string S. */ char * -next_token (s) - const char *s; +next_token (const char *s) { while (isblank ((unsigned char)*s)) ++s; @@ -532,9 +465,7 @@ next_token (s) length of the token into *LENGTHPTR if LENGTHPTR is not nil. */ char * -find_next_token (ptr, lengthptr) - char **ptr; - unsigned int *lengthptr; +find_next_token (char **ptr, unsigned int *lengthptr) { char *p = next_token (*ptr); char *end; @@ -548,12 +479,37 @@ find_next_token (ptr, lengthptr) return p; } + +/* Allocate a new `struct dep' with all fields initialized to 0. */ + +struct dep * +alloc_dep () +{ + struct dep *d = (struct dep *) xmalloc (sizeof (struct dep)); + bzero ((char *) d, sizeof (struct dep)); + return d; +} + + +/* Free `struct dep' along with `name' and `stem'. */ + +void +free_dep (struct dep *d) +{ + if (d->name != 0) + free (d->name); + + if (d->stem != 0) + free (d->stem); + + free ((char *)d); +} + /* Copy a chain of `struct dep', making a new chain with the same contents as the old one. */ struct dep * -copy_dep_chain (d) - register struct dep *d; +copy_dep_chain (const struct dep *d) { register struct dep *c; struct dep *firstnew = 0; @@ -563,8 +519,12 @@ copy_dep_chain (d) { c = (struct dep *) xmalloc (sizeof (struct dep)); bcopy ((char *) d, (char *) c, sizeof (struct dep)); + if (c->name != 0) c->name = xstrdup (c->name); + if (c->stem != 0) + c->stem = xstrdup (c->stem); + c->next = 0; if (firstnew == 0) firstnew = lastnew = c; @@ -576,13 +536,46 @@ copy_dep_chain (d) return firstnew; } + +/* Free a chain of 'struct dep'. */ + +void +free_dep_chain (struct dep *d) +{ + while (d != 0) + { + struct dep *df = d; + d = d->next; + free_dep (df); + } +} +/* Free a chain of `struct nameseq'. Each nameseq->name is freed + as well. For `struct dep' chains use free_dep_chain. */ + +void +free_ns_chain (struct nameseq *n) +{ + register struct nameseq *tmp; + + while (n != 0) + { + if (n->name != 0) + free (n->name); + + tmp = n; + + n = n->next; + + free (tmp); + } + +} #ifdef iAPX286 /* The losing compiler on this machine can't handle this macro. */ char * -dep_name (dep) - struct dep *dep; +dep_name (struct dep *dep) { return dep->name == 0 ? dep->file->name : dep->name; } @@ -641,8 +634,7 @@ static enum { make, user } current_access; /* Under -d, write a message describing the current IDs. */ static void -log_access (flavor) - char *flavor; +log_access (const char *flavor) { if (! ISDB (DB_JOBS)) return; @@ -659,7 +651,7 @@ log_access (flavor) static void -init_access () +init_access (void) { #ifndef VMS user_uid = getuid (); @@ -683,7 +675,7 @@ init_access () /* Give the process appropriate permissions for access to user data (i.e., to stat files, or to spawn a child process). */ void -user_access () +user_access (void) { #ifdef GETLOADAVG_PRIVILEGED @@ -759,7 +751,7 @@ user_access () /* Give the process appropriate permissions for access to make data (i.e., the load average). */ void -make_access () +make_access (void) { #ifdef GETLOADAVG_PRIVILEGED @@ -807,7 +799,7 @@ make_access () /* Give the process appropriate permissions for a child process. This is like user_access, but you can't get back to make_access. */ void -child_access () +child_access (void) { #ifdef GETLOADAVG_PRIVILEGED @@ -840,7 +832,7 @@ child_access () #ifdef NEED_GET_PATH_MAX unsigned int -get_path_max () +get_path_max (void) { static unsigned int value; @@ -858,36 +850,48 @@ get_path_max () #endif -#ifdef HAVE_BROKEN_RESTART +/* This code is stolen from gnulib. + If/when we abandon the requirement to work with K&R compilers, we can + remove this (and perhaps other parts of GNU make!) and migrate to using + gnulib directly. -#undef stat -#undef readdir + This is called only through atexit(), which means die() has already been + invoked. So, call exit() here directly. Apparently that works...? +*/ -int -atomic_stat(file, buf) - const char *file; - struct stat *buf; +/* Close standard output, exiting with status 'exit_failure' on failure. + If a program writes *anything* to stdout, that program should close + stdout and make sure that it succeeds before exiting. Otherwise, + suppose that you go to the extreme of checking the return status + of every function that does an explicit write to stdout. The last + printf can succeed in writing to the internal stream buffer, and yet + the fclose(stdout) could still fail (due e.g., to a disk full error) + when it tries to write out that buffered data. Thus, you would be + left with an incomplete output file and the offending program would + exit successfully. Even calling fflush is not always sufficient, + since some file systems (NFS and CODA) buffer written/flushed data + until an actual close call. + + Besides, it's wasteful to check the return value from every call + that writes to stdout -- just let the internal stream state record + the failure. That's what the ferror test is checking below. + + It's important to detect such failures and exit nonzero because many + tools (most notably `make' and other build-management systems) depend + on being able to detect failure in other tools via their exit status. */ + +void +close_stdout (void) { - int r; + int prev_fail = ferror (stdout); + int fclose_fail = fclose (stdout); - while ((r = stat (file, buf)) < 0) - if (errno != EINTR) - break; - - return r; + if (prev_fail || fclose_fail) + { + if (fclose_fail) + error (NILF, _("write error: %s"), strerror (errno)); + else + error (NILF, _("write error")); + exit (EXIT_FAILURE); + } } - -struct dirent * -atomic_readdir(dir) - DIR *dir; -{ - struct dirent *r; - - while ((r = readdir (dir)) == NULL) - if (errno != EINTR) - break; - - return r; -} - -#endif /* HAVE_BROKEN_RESTART */ diff --git a/src/bin/make/read.c b/src/bin/make/read.c index 9a4c609dfc..f6e89861eb 100644 --- a/src/bin/make/read.c +++ b/src/bin/make/read.c @@ -1,22 +1,20 @@ /* Reading and parsing of makefiles for GNU Make. Copyright (C) 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, -2002 Free Software Foundation, Inc. +1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006 Free Software +Foundation, Inc. This file is part of GNU Make. -GNU Make is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 2, or (at your option) -any later version. +GNU Make is free software; you can redistribute it and/or modify it under the +terms of the GNU General Public License as published by the Free Software +Foundation; either version 2, or (at your option) any later version. -GNU Make is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. +GNU Make is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR +A PARTICULAR PURPOSE. See the GNU General Public License for more details. -You should have received a copy of the GNU General Public License -along with GNU Make; see the file COPYING. If not, write to -the Free Software Foundation, Inc., 59 Temple Place - Suite 330, -Boston, MA 02111-1307, USA. */ +You should have received a copy of the GNU General Public License along with +GNU Make; see the file COPYING. If not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. */ #include "make.h" @@ -78,7 +76,9 @@ struct conditionals { unsigned int if_cmds; /* Depth of conditional nesting. */ unsigned int allocated; /* Elts allocated in following arrays. */ - char *ignoring; /* Are we ignoring or interepreting? */ + char *ignoring; /* Are we ignoring or interpreting? + 0=interpreting, 1=not yet interpreted, + 2=already interpreted */ char *seen_else; /* Have we already seen an `else'? */ }; @@ -130,24 +130,25 @@ static long readline PARAMS ((struct ebuffer *ebuf)); static void do_define PARAMS ((char *name, unsigned int namelen, enum variable_origin origin, struct ebuffer *ebuf)); -static int conditional_line PARAMS ((char *line, const struct floc *flocp)); +static int conditional_line PARAMS ((char *line, int len, const struct floc *flocp)); static void record_files PARAMS ((struct nameseq *filenames, char *pattern, char *pattern_percent, struct dep *deps, unsigned int cmds_started, char *commands, unsigned int commands_idx, int two_colon, - int have_sysv_atvar, - const struct floc *flocp, int set_default)); + const struct floc *flocp)); static void record_target_var PARAMS ((struct nameseq *filenames, char *defn, - int two_colon, enum variable_origin origin, + int enabled, const struct floc *flocp)); static enum make_word_type get_next_mword PARAMS ((char *buffer, char *delim, char **startp, unsigned int *length)); +static void remove_comments PARAMS ((char *line)); +static char *find_char_unquote PARAMS ((char *string, int stop1, + int stop2, int blank, int ignorevars)); /* Read in all the makefiles and return the chain of their names. */ struct dep * -read_all_makefiles (makefiles) - char **makefiles; +read_all_makefiles (char **makefiles) { unsigned int num_makefiles = 0; @@ -185,10 +186,7 @@ read_all_makefiles (makefiles) { if (*p != '\0') *p++ = '\0'; - name = xstrdup (name); - if (eval_makefile (name, - RM_NO_DEFAULT_GOAL|RM_INCLUDED|RM_DONTCARE) < 2) - free (name); + eval_makefile (name, RM_NO_DEFAULT_GOAL|RM_INCLUDED|RM_DONTCARE); } free (value); @@ -250,11 +248,9 @@ read_all_makefiles (makefiles) tail = tail->next; for (p = default_makefiles; *p != 0; ++p) { - struct dep *d = (struct dep *) xmalloc (sizeof (struct dep)); - d->name = 0; + struct dep *d = alloc_dep (); d->file = enter_file (*p); d->file->dontcare = 1; - d->ignore_mtime = 0; /* Tell update_goal_chain to bail out as soon as this file is made, and main not to die if we can't make this file. */ d->changed = RM_DONTCARE; @@ -272,18 +268,46 @@ read_all_makefiles (makefiles) return read_makefiles; } +/* Install a new conditional and return the previous one. */ + +static struct conditionals * +install_conditionals (struct conditionals *new) +{ + struct conditionals *save = conditionals; + + bzero ((char *) new, sizeof (*new)); + conditionals = new; + + return save; +} + +/* Free the current conditionals and reinstate a saved one. */ + +static void +restore_conditionals (struct conditionals *saved) +{ + /* Free any space allocated by conditional_line. */ + if (conditionals->ignoring) + free (conditionals->ignoring); + if (conditionals->seen_else) + free (conditionals->seen_else); + + /* Restore state. */ + conditionals = saved; +} + static int -eval_makefile (filename, flags) - char *filename; - int flags; +eval_makefile (char *filename, int flags) { struct dep *deps; struct ebuffer ebuf; const struct floc *curfile; + char *expanded = 0; + char *included = 0; int makefile_errno; int r; - ebuf.floc.filenm = filename; + ebuf.floc.filenm = strcache_add (filename); ebuf.floc.lineno = 1; if (ISDB (DB_VERBOSE)) @@ -306,7 +330,7 @@ eval_makefile (filename, flags) in which case it was already done. */ if (!(flags & RM_NO_TILDE) && filename[0] == '~') { - char *expanded = tilde_expand (filename); + expanded = tilde_expand (filename); if (expanded != 0) filename = expanded; } @@ -323,35 +347,36 @@ eval_makefile (filename, flags) register unsigned int i; for (i = 0; include_directories[i] != 0; ++i) { - char *name = concat (include_directories[i], "/", filename); - ebuf.fp = fopen (name, "r"); - if (ebuf.fp == 0) - free (name); - else + included = concat (include_directories[i], "/", filename); + ebuf.fp = fopen (included, "r"); + if (ebuf.fp) { - filename = name; + filename = included; break; } + free (included); } + /* If we're not using it, we already freed it above. */ + if (filename != included) + included = 0; } /* Add FILENAME to the chain of read makefiles. */ - deps = (struct dep *) xmalloc (sizeof (struct dep)); + deps = alloc_dep (); deps->next = read_makefiles; read_makefiles = deps; - deps->name = 0; deps->file = lookup_file (filename); if (deps->file == 0) - { - deps->file = enter_file (xstrdup (filename)); - if (flags & RM_DONTCARE) - deps->file->dontcare = 1; - } - if (filename != ebuf.floc.filenm) - free (filename); + deps->file = enter_file (xstrdup (filename)); filename = deps->file->name; deps->changed = flags; - deps->ignore_mtime = 0; + if (flags & RM_DONTCARE) + deps->file->dontcare = 1; + + if (expanded) + free (expanded); + if (included) + free (included); /* If the makefile can't be found at all, give up entirely. */ @@ -383,14 +408,16 @@ eval_makefile (filename, flags) fclose (ebuf.fp); free (ebuf.bufstart); + alloca (0); return r; } int -eval_buffer (buffer) - char *buffer; +eval_buffer (char *buffer) { struct ebuffer ebuf; + struct conditionals *saved; + struct conditionals new; const struct floc *curfile; int r; @@ -405,38 +432,35 @@ eval_buffer (buffer) curfile = reading_file; reading_file = &ebuf.floc; + saved = install_conditionals (&new); + r = eval (&ebuf, 1); + restore_conditionals (saved); + reading_file = curfile; + alloca (0); return r; } /* Read file FILENAME as a makefile and add its contents to the data base. - SET_DEFAULT is true if we are allowed to set the default goal. + SET_DEFAULT is true if we are allowed to set the default goal. */ - FILENAME is added to the `read_makefiles' chain. - - Returns 0 if a file was not found or not read. - Returns 1 if FILENAME was found and read. - Returns 2 if FILENAME was read, and we kept a reference (don't free it). */ static int -eval (ebuf, set_default) - struct ebuffer *ebuf; - int set_default; +eval (struct ebuffer *ebuf, int set_default) { - static char *collapsed = 0; - static unsigned int collapsed_length = 0; + char *collapsed = 0; + unsigned int collapsed_length = 0; unsigned int commands_len = 200; char *commands; unsigned int commands_idx = 0; unsigned int cmds_started, tgts_started; int ignoring = 0, in_ignored_define = 0; int no_targets = 0; /* Set when reading a rule without targets. */ - int have_sysv_atvar = 0; struct nameseq *filenames = 0; struct dep *deps = 0; long nlines = 0; @@ -453,7 +477,7 @@ eval (ebuf, set_default) fi.lineno = tgts_started; \ record_files (filenames, pattern, pattern_percent, deps, \ cmds_started, commands, commands_idx, two_colon, \ - have_sysv_atvar, &fi, set_default); \ + &fi); \ } \ filenames = 0; \ commands_idx = 0; \ @@ -481,7 +505,7 @@ eval (ebuf, set_default) while (1) { - int linelen; + unsigned int linelen; char *line; int len; char *p; @@ -537,13 +561,15 @@ eval (ebuf, set_default) } } - /* This line is not a shell command line. Don't worry about tabs. */ + /* This line is not a shell command line. Don't worry about tabs. + Get more space if we need it; we don't need to preserve the current + contents of the buffer. */ if (collapsed_length < linelen+1) { collapsed_length = linelen+1; - if (collapsed != 0) - free (collapsed); + if (collapsed) + free ((char *)collapsed); collapsed = (char *) xmalloc (collapsed_length); } strcpy (collapsed, line); @@ -588,17 +614,17 @@ eval (ebuf, set_default) ignoring anything, since they control what we will do with following lines. */ - if (!in_ignored_define - && (word1eq ("ifdef") || word1eq ("ifndef") - || word1eq ("ifeq") || word1eq ("ifneq") - || word1eq ("else") || word1eq ("endif"))) + if (!in_ignored_define) { - int i = conditional_line (p, fstart); - if (i < 0) - fatal (fstart, _("invalid syntax in conditional")); + int i = conditional_line (p, len, fstart); + if (i != -2) + { + if (i == -1) + fatal (fstart, _("invalid syntax in conditional")); - ignoring = i; - continue; + ignoring = i; + continue; + } } if (word1eq ("endef")) @@ -770,12 +796,13 @@ eval (ebuf, set_default) int noerror = (p[0] != 'i'); p = allocated_variable_expand (p2); + + /* If no filenames, it's a no-op. */ if (*p == '\0') - { - error (fstart, - _("no file name for `%sinclude'"), noerror ? "-" : ""); - continue; - } + { + free (p); + continue; + } /* Parse the list of file names. */ p2 = p; @@ -787,9 +814,7 @@ eval (ebuf, set_default) /* Save the state of conditionals and start the included makefile with a clean slate. */ - save = conditionals; - bzero ((char *) &new_conditionals, sizeof new_conditionals); - conditionals = &new_conditionals; + save = install_conditionals (&new_conditionals); /* Record the rules that are waiting so they will determine the default goal before those in the included makefile. */ @@ -807,22 +832,13 @@ eval (ebuf, set_default) r = eval_makefile (name, (RM_INCLUDED | RM_NO_TILDE | (noerror ? RM_DONTCARE : 0))); - if (!r) - { - if (!noerror) - error (fstart, "%s: %s", name, strerror (errno)); - free (name); - } + if (!r && !noerror) + error (fstart, "%s: %s", name, strerror (errno)); + free (name); } - /* Free any space allocated by conditional_line. */ - if (conditionals->ignoring) - free (conditionals->ignoring); - if (conditionals->seen_else) - free (conditionals->seen_else); - - /* Restore state. */ - conditionals = save; + /* Restore conditional state. */ + restore_conditionals (save); goto rule_complete; } @@ -831,21 +847,11 @@ eval (ebuf, set_default) /* This line has been dealt with. */ goto rule_complete; + /* This line starts with a tab but was not caught above because there + was no preceding target, and the line might have been usable as a + variable definition. But now we know it is definitely lossage. */ if (line[0] == '\t') - { - p = collapsed; /* Ignore comments, etc. */ - while (isblank ((unsigned char)*p)) - ++p; - if (*p == '\0') - /* The line is completely blank; that is harmless. */ - continue; - - /* This line starts with a tab but was not caught above - because there was no preceding target, and the line - might have been usable as a variable definition. - But now we know it is definitely lossage. */ - fatal(fstart, _("commands commence before first target")); - } + fatal(fstart, _("commands commence before first target")); /* This line describes some target files. This is complicated by the existence of target-specific variables, because we can't @@ -860,9 +866,11 @@ eval (ebuf, set_default) { enum make_word_type wtype; enum variable_origin v_origin; + int exported; char *cmdleft, *semip, *lb_next; unsigned int len, plen = 0; char *colonp; + const char *end, *beg; /* Helpers for whitespace stripping. */ /* Record the previous rule. */ @@ -871,7 +879,7 @@ eval (ebuf, set_default) /* Search the line for an unquoted ; that is not after an unquoted #. */ - cmdleft = find_char_unquote (line, ';', '#', 0); + cmdleft = find_char_unquote (line, ';', '#', 0, 1); if (cmdleft != 0 && *cmdleft == '#') { /* We found a comment before a semicolon. */ @@ -911,13 +919,14 @@ eval (ebuf, set_default) } p2 = variable_expand_string(NULL, lb_next, len); + while (1) { lb_next += len; if (cmdleft == 0) { /* Look for a semicolon in the expanded line. */ - cmdleft = find_char_unquote (p2, ';', 0, 0); + cmdleft = find_char_unquote (p2, ';', 0, 0, 0); if (cmdleft != 0) { @@ -944,7 +953,7 @@ eval (ebuf, set_default) } } - colonp = find_char_unquote(p2, ':', 0, 0); + colonp = find_char_unquote(p2, ':', 0, 0, 0); #ifdef HAVE_DOS_PATHS /* The drive spec brain-damage strikes again... */ /* Note that the only separators of targets in this context @@ -953,7 +962,7 @@ eval (ebuf, set_default) while (colonp && (colonp[1] == '/' || colonp[1] == '\\') && colonp > p2 && isalpha ((unsigned char)colonp[-1]) && (colonp == p2 + 1 || strchr (" \t(", colonp[-2]) != 0)) - colonp = find_char_unquote(colonp + 1, ':', 0, 0); + colonp = find_char_unquote(colonp + 1, ':', 0, 0, 0); #endif if (colonp != 0) break; @@ -1024,16 +1033,25 @@ eval (ebuf, set_default) p2 = variable_buffer + l; } - /* See if it's an "override" keyword; if so see if what comes after - it looks like a variable definition. */ + /* See if it's an "override" or "export" keyword; if so see if what + comes after it looks like a variable definition. */ wtype = get_next_mword (p2, NULL, &p, &len); v_origin = o_file; - if (wtype == w_static && word1eq ("override")) + exported = 0; + if (wtype == w_static) { - v_origin = o_override; - wtype = get_next_mword (p+len, NULL, &p, &len); + if (word1eq ("override")) + { + v_origin = o_override; + wtype = get_next_mword (p+len, NULL, &p, &len); + } + else if (word1eq ("export")) + { + exported = 1; + wtype = get_next_mword (p+len, NULL, &p, &len); + } } if (wtype != w_eol) @@ -1045,18 +1063,20 @@ eval (ebuf, set_default) after it. */ if (semip) { + unsigned int l = p - variable_buffer; *(--semip) = ';'; variable_buffer_output (p2 + strlen (p2), semip, strlen (semip)+1); + p = variable_buffer + l; } - record_target_var (filenames, p, two_colon, v_origin, fstart); + record_target_var (filenames, p, v_origin, exported, fstart); filenames = 0; continue; } /* This is a normal target, _not_ a target-specific variable. Unquote any = in the dependency list. */ - find_char_unquote (lb_next, '=', 0, 0); + find_char_unquote (lb_next, '=', 0, 0, 0); /* We have some targets, so don't ignore the following commands. */ no_targets = 0; @@ -1071,22 +1091,12 @@ eval (ebuf, set_default) /* Look for a semicolon in the expanded line. */ if (cmdleft == 0) { - cmdleft = find_char_unquote (p2, ';', 0, 0); + cmdleft = find_char_unquote (p2, ';', 0, 0, 0); if (cmdleft != 0) *(cmdleft++) = '\0'; } } - /* Do any of the prerequisites appear to have $@ etc.? */ - have_sysv_atvar = 0; - if (!posix_pedantic) - for (p = strchr (p2, '$'); p != 0; p = strchr (p+1, '$')) - if (p[1] == '@' || (p[1] == '(' && p[2] == '@')) - { - have_sysv_atvar = 1; - break; - } - /* Is this a static pattern rule: `target: %targ: %dep; ...'? */ p = strchr (p2, ':'); while (p != 0 && p[-1] == '\\') @@ -1123,7 +1133,7 @@ eval (ebuf, set_default) do { check_again = 0; - /* For DOS paths, skip a "C:\..." or a "C:/..." */ + /* For DOS-style paths, skip a "C:\..." or a "C:/..." */ if (p != 0 && (p[1] == '\\' || p[1] == '/') && isalpha ((unsigned char)p[-1]) && (p == p2 + 1 || strchr (" \t:(", p[-2]) != 0)) { @@ -1146,31 +1156,24 @@ eval (ebuf, set_default) pattern_percent = find_percent (pattern); if (pattern_percent == 0) fatal (fstart, _("target pattern contains no `%%'")); - free((char *)target); + free ((char *)target); } else pattern = 0; - /* Parse the dependencies. */ - deps = (struct dep *) - multi_glob (parse_file_seq (&p2, '|', sizeof (struct dep), 1), - sizeof (struct dep)); - if (*p2) + /* Strip leading and trailing whitespaces. */ + beg = p2; + end = beg + strlen (beg) - 1; + strip_whitespace (&beg, &end); + + if (beg <= end && *beg != '\0') { - /* Files that follow '|' are special prerequisites that - need only exist in order to satisfy the dependency. - Their modification times are irrelevant. */ - struct dep **deps_ptr = &deps; - struct dep *d; - for (deps_ptr = &deps; *deps_ptr; deps_ptr = &(*deps_ptr)->next) - ; - ++p2; - *deps_ptr = (struct dep *) - multi_glob (parse_file_seq (&p2, '\0', sizeof (struct dep), 1), - sizeof (struct dep)); - for (d = *deps_ptr; d != 0; d = d->next) - d->ignore_mtime = 1; + /* Put all the prerequisites here; they'll be parsed later. */ + deps = alloc_dep (); + deps->name = savestring (beg, end - beg + 1); } + else + deps = 0; commands_idx = 0; if (cmdleft != 0) @@ -1191,6 +1194,82 @@ eval (ebuf, set_default) commands[commands_idx++] = '\n'; } + /* Determine if this target should be made default. We used to do + this in record_files() but because of the delayed target recording + and because preprocessor directives are legal in target's commands + it is too late. Consider this fragment for example: + + foo: + + ifeq ($(.DEFAULT_GOAL),foo) + ... + endif + + Because the target is not recorded until after ifeq directive is + evaluated the .DEFAULT_GOAL does not contain foo yet as one + would expect. Because of this we have to move some of the logic + here. */ + + if (**default_goal_name == '\0' && set_default) + { + char* name; + struct dep *d; + struct nameseq *t = filenames; + + for (; t != 0; t = t->next) + { + int reject = 0; + name = t->name; + + /* We have nothing to do if this is an implicit rule. */ + if (strchr (name, '%') != 0) + break; + + /* See if this target's name does not start with a `.', + unless it contains a slash. */ + if (*name == '.' && strchr (name, '/') == 0 +#ifdef HAVE_DOS_PATHS + && strchr (name, '\\') == 0 +#endif + ) + continue; + + + /* If this file is a suffix, don't let it be + the default goal file. */ + for (d = suffix_file->deps; d != 0; d = d->next) + { + register struct dep *d2; + if (*dep_name (d) != '.' && streq (name, dep_name (d))) + { + reject = 1; + break; + } + for (d2 = suffix_file->deps; d2 != 0; d2 = d2->next) + { + register unsigned int len = strlen (dep_name (d2)); + if (!strneq (name, dep_name (d2), len)) + continue; + if (streq (name + len, dep_name (d))) + { + reject = 1; + break; + } + } + + if (reject) + break; + } + + if (!reject) + { + define_variable_global (".DEFAULT_GOAL", 13, t->name, + o_file, 0, NILF); + break; + } + } + } + continue; } @@ -1209,22 +1288,36 @@ eval (ebuf, set_default) /* At eof, record the last rule. */ record_waiting_files (); + if (collapsed) + free ((char *) collapsed); free ((char *) commands); return 1; } - + +/* Remove comments from LINE. + This is done by copying the text at LINE onto itself. */ + +static void +remove_comments (char *line) +{ + char *comment; + + comment = find_char_unquote (line, '#', 0, 0, 0); + + if (comment != 0) + /* Cut off the line at the #. */ + *comment = '\0'; +} + /* Execute a `define' directive. The first line has already been read, and NAME is the name of the variable to be defined. The following lines remain to be read. */ static void -do_define (name, namelen, origin, ebuf) - char *name; - unsigned int namelen; - enum variable_origin origin; - struct ebuffer *ebuf; +do_define (char *name, unsigned int namelen, + enum variable_origin origin, struct ebuffer *ebuf) { struct floc defstart; long nlines = 0; @@ -1247,8 +1340,8 @@ do_define (name, namelen, origin, ebuf) unsigned int len; char *line; - ebuf->floc.lineno += nlines; nlines = readline (ebuf); + ebuf->floc.lineno += nlines; /* If there is nothing left to eval, we're done. */ if (nlines < 0) @@ -1328,69 +1421,108 @@ do_define (name, namelen, origin, ebuf) FILENAME and LINENO are the filename and line number in the current makefile. They are used for error messages. - Value is -1 if the line is invalid, + Value is -2 if the line is not a conditional at all, + -1 if the line is an invalid conditional, 0 if following text should be interpreted, 1 if following text should be ignored. */ static int -conditional_line (line, flocp) - char *line; - const struct floc *flocp; +conditional_line (char *line, int len, const struct floc *flocp) { - int notdef; char *cmdname; - register unsigned int i; + enum { c_ifdef, c_ifndef, c_ifeq, c_ifneq, c_else, c_endif } cmdtype; + unsigned int i; + unsigned int o; - if (*line == 'i') - { - /* It's an "if..." command. */ - notdef = line[2] == 'n'; - if (notdef) - { - cmdname = line[3] == 'd' ? "ifndef" : "ifneq"; - line += cmdname[3] == 'd' ? 7 : 6; - } - else - { - cmdname = line[2] == 'd' ? "ifdef" : "ifeq"; - line += cmdname[2] == 'd' ? 6 : 5; - } - } + /* Compare a word, both length and contents. */ +#define word1eq(s) (len == sizeof(s)-1 && strneq (s, line, sizeof(s)-1)) +#define chkword(s, t) if (word1eq (s)) { cmdtype = (t); cmdname = (s); } + + /* Make sure this line is a conditional. */ + chkword ("ifdef", c_ifdef) + else chkword ("ifndef", c_ifndef) + else chkword ("ifeq", c_ifeq) + else chkword ("ifneq", c_ifneq) + else chkword ("else", c_else) + else chkword ("endif", c_endif) else - { - /* It's an "else" or "endif" command. */ - notdef = line[1] == 'n'; - cmdname = notdef ? "endif" : "else"; - line += notdef ? 5 : 4; - } + return -2; - line = next_token (line); + /* Found one: skip past it and any whitespace after it. */ + line = next_token (line + len); - if (*cmdname == 'e') +#define EXTRANEOUS() error (flocp, _("Extraneous text after `%s' directive"), cmdname) + + /* An 'endif' cannot contain extra text, and reduces the if-depth by 1 */ + if (cmdtype == c_endif) { if (*line != '\0') - error (flocp, _("Extraneous text after `%s' directive"), cmdname); - /* "Else" or "endif". */ - if (conditionals->if_cmds == 0) + EXTRANEOUS (); + + if (!conditionals->if_cmds) fatal (flocp, _("extraneous `%s'"), cmdname); - /* NOTDEF indicates an `endif' command. */ - if (notdef) - --conditionals->if_cmds; - else if (conditionals->seen_else[conditionals->if_cmds - 1]) - fatal (flocp, _("only one `else' per conditional")); + + --conditionals->if_cmds; + + goto DONE; + } + + /* An 'else' statement can either be simple, or it can have another + conditional after it. */ + if (cmdtype == c_else) + { + const char *p; + + if (!conditionals->if_cmds) + fatal (flocp, _("extraneous `%s'"), cmdname); + + o = conditionals->if_cmds - 1; + + if (conditionals->seen_else[o]) + fatal (flocp, _("only one `else' per conditional")); + + /* Change the state of ignorance. */ + switch (conditionals->ignoring[o]) + { + case 0: + /* We've just been interpreting. Never do it again. */ + conditionals->ignoring[o] = 2; + break; + case 1: + /* We've never interpreted yet. Maybe this time! */ + conditionals->ignoring[o] = 0; + break; + } + + /* It's a simple 'else'. */ + if (*line == '\0') + { + conditionals->seen_else[o] = 1; + goto DONE; + } + + /* The 'else' has extra text. That text must be another conditional + and cannot be an 'else' or 'endif'. */ + + /* Find the length of the next word. */ + for (p = line+1; *p != '\0' && !isspace ((unsigned char)*p); ++p) + ; + len = p - line; + + /* If it's 'else' or 'endif' or an illegal conditional, fail. */ + if (word1eq("else") || word1eq("endif") + || conditional_line (line, len, flocp) < 0) + EXTRANEOUS (); else - { - /* Toggle the state of ignorance. */ - conditionals->ignoring[conditionals->if_cmds - 1] - = !conditionals->ignoring[conditionals->if_cmds - 1]; - /* Record that we have seen an `else' in this conditional. - A second `else' will be erroneous. */ - conditionals->seen_else[conditionals->if_cmds - 1] = 1; - } - for (i = 0; i < conditionals->if_cmds; ++i) - if (conditionals->ignoring[i]) - return 1; - return 0; + { + /* conditional_line() created a new level of conditional. + Raise it back to this level. */ + if (conditionals->ignoring[o] < 2) + conditionals->ignoring[o] = conditionals->ignoring[o+1]; + --conditionals->if_cmds; + } + + goto DONE; } if (conditionals->allocated == 0) @@ -1400,7 +1532,7 @@ conditional_line (line, flocp) conditionals->seen_else = (char *) xmalloc (conditionals->allocated); } - ++conditionals->if_cmds; + o = conditionals->if_cmds++; if (conditionals->if_cmds > conditionals->allocated) { conditionals->allocated += 5; @@ -1411,38 +1543,41 @@ conditional_line (line, flocp) } /* Record that we have seen an `if...' but no `else' so far. */ - conditionals->seen_else[conditionals->if_cmds - 1] = 0; + conditionals->seen_else[o] = 0; /* Search through the stack to see if we're already ignoring. */ - for (i = 0; i < conditionals->if_cmds - 1; ++i) + for (i = 0; i < o; ++i) if (conditionals->ignoring[i]) { - /* We are already ignoring, so just push a level - to match the next "else" or "endif", and keep ignoring. - We don't want to expand variables in the condition. */ - conditionals->ignoring[conditionals->if_cmds - 1] = 1; + /* We are already ignoring, so just push a level to match the next + "else" or "endif", and keep ignoring. We don't want to expand + variables in the condition. */ + conditionals->ignoring[o] = 1; return 1; } - if (cmdname[notdef ? 3 : 2] == 'd') + if (cmdtype == c_ifdef || cmdtype == c_ifndef) { - /* "Ifdef" or "ifndef". */ char *var; struct variable *v; - register char *p = end_of_token (line); - i = p - line; + char *p; + + /* Expand the thing we're looking up, so we can use indirect and + constructed variable names. */ + var = allocated_variable_expand (line); + + /* Make sure there's only one variable name to test. */ + p = end_of_token (var); + i = p - var; p = next_token (p); if (*p != '\0') return -1; - /* Expand the thing we're looking up, so we can use indirect and - constructed variable names. */ - line[i] = '\0'; - var = allocated_variable_expand (line); + var[i] = '\0'; + v = lookup_variable (var, i); - v = lookup_variable (var, strlen (var)); - conditionals->ignoring[conditionals->if_cmds - 1] - = (v != 0 && *v->value != '\0') == notdef; + conditionals->ignoring[o] = + ((v != 0 && *v->value != '\0') == (cmdtype == c_ifndef)); free (var); } @@ -1460,7 +1595,7 @@ conditional_line (line, flocp) /* Find the end of the first string. */ if (termin == ',') { - register int count = 0; + int count = 0; for (; *line != '\0'; ++line) if (*line == '(') ++count; @@ -1534,13 +1669,13 @@ conditional_line (line, flocp) *line = '\0'; line = next_token (++line); if (*line != '\0') - error (flocp, _("Extraneous text after `%s' directive"), cmdname); + EXTRANEOUS (); s2 = variable_expand (s2); - conditionals->ignoring[conditionals->if_cmds - 1] - = streq (s1, s2) == notdef; + conditionals->ignoring[o] = (streq (s1, s2) == (cmdtype == c_ifneq)); } + DONE: /* Search through the stack to see if we're ignoring. */ for (i = 0; i < conditionals->if_cmds; ++i) if (conditionals->ignoring[i]) @@ -1551,23 +1686,19 @@ conditional_line (line, flocp) /* Remove duplicate dependencies in CHAIN. */ static unsigned long -dep_hash_1 (key) - const void *key; +dep_hash_1 (const void *key) { return_STRING_HASH_1 (dep_name ((struct dep const *) key)); } static unsigned long -dep_hash_2 (key) - const void *key; +dep_hash_2 (const void *key) { return_STRING_HASH_2 (dep_name ((struct dep const *) key)); } static int -dep_hash_cmp (x, y) - const void *x; - const void *y; +dep_hash_cmp (const void *x, const void *y) { struct dep *dx = (struct dep *) x; struct dep *dy = (struct dep *) y; @@ -1585,8 +1716,7 @@ dep_hash_cmp (x, y) void -uniquize_deps (chain) - struct dep *chain; +uniquize_deps (struct dep *chain) { struct hash_table deps; register struct dep **depp; @@ -1628,12 +1758,9 @@ uniquize_deps (chain) variable value list. */ static void -record_target_var (filenames, defn, two_colon, origin, flocp) - struct nameseq *filenames; - char *defn; - int two_colon; - enum variable_origin origin; - const struct floc *flocp; +record_target_var (struct nameseq *filenames, char *defn, + enum variable_origin origin, int exported, + const struct floc *flocp) { struct nameseq *nextf; struct variable_set_list *global; @@ -1647,9 +1774,9 @@ record_target_var (filenames, defn, two_colon, origin, flocp) { struct variable *v; register char *name = filenames->name; - struct variable_set_list *vlist; char *fname; char *percent; + struct pattern_var *p; nextf = filenames->next; free ((char *) filenames); @@ -1659,11 +1786,19 @@ record_target_var (filenames, defn, two_colon, origin, flocp) percent = find_percent (name); if (percent) { - struct pattern_var *p; - /* Get a reference for this pattern-specific variable struct. */ - p = create_pattern_var(name, percent); - vlist = p->vars; + p = create_pattern_var (name, percent); + p->variable.fileinfo = *flocp; + /* I don't think this can fail since we already determined it was a + variable definition. */ + v = parse_variable_definition (&p->variable, defn); + assert (v != 0); + + if (v->flavor == f_simple) + v->value = allocated_variable_expand (v->value); + else + v->value = xstrdup (v->value); + fname = p->target; } else @@ -1681,16 +1816,19 @@ record_target_var (filenames, defn, two_colon, origin, flocp) f = f->double_colon; initialize_file_variables (f, 1); - vlist = f->variables; fname = f->name; + + current_variable_set_list = f->variables; + v = try_variable_definition (flocp, defn, origin, 1); + if (!v) + error (flocp, _("Malformed target-specific variable definition")); + current_variable_set_list = global; } - /* Make the new variable context current and define the variable. */ - current_variable_set_list = vlist; - v = try_variable_definition (flocp, defn, origin, 1); - if (!v) - error (flocp, _("Malformed per-target variable definition")); + /* Set up the variable to be *-specific. */ + v->origin = origin; v->per_target = 1; + v->export = exported ? v_export : v_default; /* If it's not an override, check to see if there was a command-line setting. If so, reset the value. */ @@ -1699,12 +1837,14 @@ record_target_var (filenames, defn, two_colon, origin, flocp) struct variable *gv; int len = strlen(v->name); - current_variable_set_list = global; gv = lookup_variable (v->name, len); if (gv && (gv->origin == o_env_override || gv->origin == o_command)) { - v = define_variable_in_set (v->name, len, gv->value, gv->origin, - gv->recursive, vlist->set, flocp); + if (v->value != 0) + free (v->value); + v->value = xstrdup (gv->value); + v->origin = gv->origin; + v->recursive = gv->recursive; v->append = 0; } } @@ -1713,8 +1853,6 @@ record_target_var (filenames, defn, two_colon, origin, flocp) if (name != fname && (name < fname || name > fname + strlen (fname))) free (name); } - - current_variable_set_list = global; } /* Record a description line for files FILENAMES, @@ -1729,19 +1867,10 @@ record_target_var (filenames, defn, two_colon, origin, flocp) that are not incorporated into other data structures. */ static void -record_files (filenames, pattern, pattern_percent, deps, cmds_started, - commands, commands_idx, two_colon, have_sysv_atvar, - flocp, set_default) - struct nameseq *filenames; - char *pattern, *pattern_percent; - struct dep *deps; - unsigned int cmds_started; - char *commands; - unsigned int commands_idx; - int two_colon; - int have_sysv_atvar; - const struct floc *flocp; - int set_default; +record_files (struct nameseq *filenames, char *pattern, char *pattern_percent, + struct dep *deps, unsigned int cmds_started, char *commands, + unsigned int commands_idx, int two_colon, + const struct floc *flocp) { struct nameseq *nextf; int implicit = 0; @@ -1749,6 +1878,13 @@ record_files (filenames, pattern, pattern_percent, deps, cmds_started, 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)); @@ -1764,19 +1900,19 @@ record_files (filenames, pattern, pattern_percent, deps, cmds_started, { char *name = filenames->name; struct file *f; - struct dep *d; - struct dep *this; + struct dep *this = 0; char *implicit_percent; nextf = filenames->next; free (filenames); - /* Check for .POSIX. We used to do this in snap_deps() but that's not - good enough: it doesn't happen until after the makefile is read, - which means we cannot use its value during parsing. */ + /* Check for special targets. Do it here instead of, say, snap_deps() + so that we can immediately use the value. */ if (streq (name, ".POSIX")) posix_pedantic = 1; + else if (streq (name, ".SECONDEXPANSION")) + second_expansion = 1; implicit_percent = find_percent (name); implicit |= implicit_percent != 0; @@ -1811,144 +1947,19 @@ record_files (filenames, pattern, pattern_percent, deps, cmds_started, continue; } - /* If there are multiple filenames, copy the chain DEPS - for all but the last one. It is not safe for the same deps - to go in more than one place in the data base. */ - this = nextf != 0 ? copy_dep_chain (deps) : deps; - - if (pattern != 0) - { - /* If this is an extended static rule: - `targets: target%pattern: dep%pattern; cmds', - translate each dependency pattern into a plain filename - using the target pattern and this target's name. */ - if (!pattern_matches (pattern, pattern_percent, name)) - { - /* Give a warning if the rule is meaningless. */ - error (flocp, - _("target `%s' doesn't match the target pattern"), name); - this = 0; - } - else - { - /* We use patsubst_expand to do the work of translating - the target pattern, the target's name and the dependencies' - patterns into plain dependency names. */ - char *buffer = variable_expand (""); - - for (d = this; d != 0; d = d->next) - { - char *o; - char *percent = find_percent (d->name); - if (percent == 0) - continue; - o = patsubst_expand (buffer, name, pattern, d->name, - pattern_percent, percent); - /* If the name expanded to the empty string, that's - illegal. */ - if (o == buffer) - fatal (flocp, - _("target `%s' leaves prerequisite pattern empty"), - name); - free (d->name); - d->name = savestring (buffer, o - buffer); - } - } - } - - /* If at least one of the dependencies uses $$@ etc. deal with that. - It would be very nice and very simple to just expand everything, but - it would break a lot of backward compatibility. Maybe that's OK - since we're just emulating a SysV function, and if we do that then - why not emulate it completely (that's what SysV make does: it - re-expands the entire prerequisite list, all the time, with $@ - etc. in scope. But, it would be a pain indeed to document this - ("iff you use $$@, your prerequisite lists is expanded twice...") - Ouch. Maybe better to make the code more complex. */ - - if (have_sysv_atvar) + /* If this is a static pattern rule: + `targets: target%pattern: dep%pattern; cmds', + make sure the pattern matches this target name. */ + if (pattern && !pattern_matches (pattern, pattern_percent, name)) + error (flocp, _("target `%s' doesn't match the target pattern"), name); + else if (deps) { - char *p; - int tlen = strlen (name); - char *fnp = strrchr (name, '/'); - int dlen; - int flen; - - if (fnp) - { - dlen = fnp - name; - ++fnp; - flen = strlen (fnp); - } - else - { - dlen = 0; - fnp = name; - flen = tlen; - } - - - for (d = this; d != 0; d = d->next) - for (p = strchr (d->name, '$'); p != 0; p = strchr (p+1, '$')) - { - char *s = p; - char *at; - int atlen; - - /* If it's a '$@' or '$(@', it's escaped */ - if ((++p)[0] == '$' - && (p[1] == '@' || (p[1] == '(' && p[2] == '@'))) - { - bcopy (p, s, strlen (p)+1); - continue; - } - - /* Maybe found one. Check. p will point to '@' [for $@] or - ')' [for $(@)] or 'D' [for $(@D)] or 'F' [for $(@F)]. */ - if (p[0] != '@' - && (p[0] != '(' || (++p)[0] != '@' - || ((++p)[0] != ')' - && (p[1] != ')' || (p[0] != 'D' && p[0] != 'F'))))) - continue; - - /* Found one. Compute the length and string ptr. Move p - past the variable reference. */ - switch (p[0]) - { - case 'D': - atlen = dlen; - at = name; - p += 2; - break; - - case 'F': - atlen = flen; - at = fnp; - p += 2; - break; - - default: - atlen = tlen; - at = name; - ++p; - break; - } - - /* Get more space. */ - { - int soff = s - d->name; - int poff = p - d->name; - d->name = (char *) xrealloc (d->name, - strlen (d->name) + atlen + 1); - s = d->name + soff; - p = d->name + poff; - } - - /* Copy the string over. */ - bcopy(p, s+atlen, strlen (p)+1); - bcopy(at, s, atlen); - p = s + atlen - 1; - } + /* If there are multiple filenames, copy the chain DEPS for all but + the last one. It is not safe for the same deps to go in more + than one place in the database. */ + this = nextf != 0 ? copy_dep_chain (deps) : deps; + this->need_2nd_expansion = (second_expansion + && strchr (this->name, '$')); } if (!two_colon) @@ -1988,92 +1999,110 @@ record_files (filenames, pattern, pattern_percent, deps, cmds_started, f->cmds = 0; if (cmds != 0) f->cmds = cmds; - /* Defining .SUFFIXES with no dependencies - clears out the list of suffixes. */ + + /* Defining .SUFFIXES with no dependencies clears out the list of + suffixes. */ if (f == suffix_file && this == 0) { - d = f->deps; - while (d != 0) - { - struct dep *nextd = d->next; - free (d->name); - free ((char *)d); - d = nextd; - } + free_dep_chain (f->deps); f->deps = 0; } - else if (f->deps != 0) + else if (this != 0) { /* Add the file's old deps and the new ones in THIS together. */ - struct dep *firstdeps, *moredeps; - if (cmds != 0) - { - /* This is the rule with commands, so put its deps first. - The rationale behind this is that $< expands to the - first dep in the chain, and commands use $< expecting - to get the dep that rule specifies. */ - firstdeps = this; - moredeps = f->deps; - } - else - { - /* Append the new deps to the old ones. */ - firstdeps = f->deps; - moredeps = this; - } + if (f->deps != 0) + { + struct dep **d_ptr = &f->deps; - if (firstdeps == 0) - firstdeps = moredeps; - else - { - d = firstdeps; - while (d->next != 0) - d = d->next; - d->next = moredeps; - } + while ((*d_ptr)->next != 0) + d_ptr = &(*d_ptr)->next; - f->deps = firstdeps; - } - else - f->deps = this; + if (cmds != 0) + /* This is the rule with commands, so put its deps + last. The rationale behind this is that $< expands to + the first dep in the chain, and commands use $< + expecting to get the dep that rule specifies. However + the second expansion algorithm reverses the order thus + we need to make it last here. */ + (*d_ptr)->next = this; + else + { + /* This is the rule without commands. Put its + dependencies at the end but before dependencies from + the rule with commands (if any). This way everything + appears in makefile order. */ - /* If this is a static pattern rule, set the file's stem to - the part of its name that matched the `%' in the pattern, - so you can use $* in the commands. */ - if (pattern != 0) - { - static char *percent = "%"; - char *buffer = variable_expand (""); - char *o = patsubst_expand (buffer, name, pattern, percent, - pattern_percent, percent); - f->stem = savestring (buffer, o - buffer); + if (f->cmds != 0) + { + this->next = *d_ptr; + *d_ptr = this; + } + else + (*d_ptr)->next = this; + } + } + else + f->deps = this; + + /* This is a hack. I need a way to communicate to snap_deps() + that the last dependency line in this file came with commands + (so that logic in snap_deps() can put it in front and all + this $< -logic works). I cannot simply rely on file->cmds + being not 0 because of the cases like the following: + + foo: bar + foo: + ... + + I am going to temporarily "borrow" UPDATING member in + `struct file' for this. */ + + if (cmds != 0) + f->updating = 1; } } else { - /* Double-colon. Make a new record - even if the file already has one. */ + /* Double-colon. Make a new record even if there already is one. */ f = lookup_file (name); + /* Check for both : and :: rules. Check is_target so we don't lose on default suffix rules or makefiles. */ if (f != 0 && f->is_target && !f->double_colon) fatal (flocp, _("target file `%s' has both : and :: entries"), f->name); f = enter_file (name); - /* If there was an existing entry and it was a double-colon - entry, enter_file will have returned a new one, making it the - prev pointer of the old one, and setting its double_colon - pointer to the first one. */ + /* If there was an existing entry and it was a double-colon entry, + enter_file will have returned a new one, making it the prev + pointer of the old one, and setting its double_colon pointer to + the first one. */ if (f->double_colon == 0) - /* This is the first entry for this name, so we must - set its double_colon pointer to itself. */ + /* This is the first entry for this name, so we must set its + double_colon pointer to itself. */ f->double_colon = f; f->is_target = 1; f->deps = this; f->cmds = cmds; } + /* If this is a static pattern rule, set the stem to the part of its + name that matched the `%' in the pattern, so you can use $* in the + commands. */ + if (pattern) + { + static char *percent = "%"; + char *buffer = variable_expand (""); + char *o = patsubst_expand (buffer, name, pattern, percent, + pattern_percent+1, percent+1); + f->stem = savestring (buffer, o - buffer); + if (this) + { + this->staticpattern = 1; + this->stem = xstrdup (f->stem); + } + } + /* Free name if not needed further. */ if (f != 0 && name != f->name && (name < f->name || name > f->name + strlen (f->name))) @@ -2082,52 +2111,19 @@ record_files (filenames, pattern, pattern_percent, deps, cmds_started, name = f->name; } - /* See if this is first target seen whose name does - not start with a `.', unless it contains a slash. */ - if (default_goal_file == 0 && set_default - && (*name != '.' || strchr (name, '/') != 0 -#ifdef HAVE_DOS_PATHS - || strchr (name, '\\') != 0 -#endif - )) - { - int reject = 0; - - /* If this file is a suffix, don't - let it be the default goal file. */ - - for (d = suffix_file->deps; d != 0; d = d->next) - { - register struct dep *d2; - if (*dep_name (d) != '.' && streq (name, dep_name (d))) - { - reject = 1; - break; - } - for (d2 = suffix_file->deps; d2 != 0; d2 = d2->next) - { - register unsigned int len = strlen (dep_name (d2)); - if (!strneq (name, dep_name (d2), len)) - continue; - if (streq (name + len, dep_name (d))) - { - reject = 1; - break; - } - } - if (reject) - break; - } - - if (!reject) - default_goal_file = f; - } + /* If this target is a default target, update DEFAULT_GOAL_FILE. */ + if (streq (*default_goal_name, name) + && (default_goal_file == 0 + || ! streq (default_goal_file->name, name))) + default_goal_file = f; } if (implicit) { targets[target_idx] = 0; target_percents[target_idx] = 0; + if (deps) + deps->need_2nd_expansion = second_expansion; create_pattern_rule (targets, target_percents, two_colon, deps, cmds, 1); free ((char *) target_percents); } @@ -2137,38 +2133,72 @@ record_files (filenames, pattern, pattern_percent, deps, cmds_started, Backslashes quote STOPCHAR, blanks if BLANK is nonzero, and backslash. Quoting backslashes are removed from STRING by compacting it into itself. Returns a pointer to the first unquoted STOPCHAR if there is - one, or nil if there are none. */ + one, or nil if there are none. STOPCHARs inside variable references are + ignored if IGNOREVARS is true. -char * -find_char_unquote (string, stop1, stop2, blank) - char *string; - int stop1; - int stop2; - int blank; + STOPCHAR _cannot_ be '$' if IGNOREVARS is true. */ + +static char * +find_char_unquote (char *string, int stop1, int stop2, int blank, + int ignorevars) { unsigned int string_len = 0; register char *p = string; + if (ignorevars) + ignorevars = '$'; + while (1) { if (stop2 && blank) - while (*p != '\0' && *p != stop1 && *p != stop2 + while (*p != '\0' && *p != ignorevars && *p != stop1 && *p != stop2 && ! isblank ((unsigned char) *p)) ++p; else if (stop2) - while (*p != '\0' && *p != stop1 && *p != stop2) + while (*p != '\0' && *p != ignorevars && *p != stop1 && *p != stop2) ++p; else if (blank) - while (*p != '\0' && *p != stop1 + while (*p != '\0' && *p != ignorevars && *p != stop1 && ! isblank ((unsigned char) *p)) ++p; else - while (*p != '\0' && *p != stop1) + while (*p != '\0' && *p != ignorevars && *p != stop1) ++p; if (*p == '\0') break; + /* If we stopped due to a variable reference, skip over its contents. */ + if (*p == ignorevars) + { + char openparen = p[1]; + + p += 2; + + /* Skip the contents of a non-quoted, multi-char variable ref. */ + if (openparen == '(' || openparen == '{') + { + unsigned int pcount = 1; + char closeparen = (openparen == '(' ? ')' : '}'); + + while (*p) + { + if (*p == openparen) + ++pcount; + else if (*p == closeparen) + if (--pcount == 0) + { + ++p; + break; + } + ++p; + } + } + + /* Skipped the variable reference: look for STOPCHARS again. */ + continue; + } + if (p > string && p[-1] == '\\') { /* Search for more backslashes. */ @@ -2202,10 +2232,9 @@ find_char_unquote (string, stop1, stop2, blank) /* Search PATTERN for an unquoted %. */ char * -find_percent (pattern) - char *pattern; +find_percent (char *pattern) { - return find_char_unquote (pattern, '%', 0, 0); + return find_char_unquote (pattern, '%', 0, 0, 0); } /* Parse a string into a sequence of filenames represented as a @@ -2222,15 +2251,11 @@ find_percent (pattern) If STRIP is nonzero, strip `./'s off the beginning. */ struct nameseq * -parse_file_seq (stringp, stopchar, size, strip) - char **stringp; - int stopchar; - unsigned int size; - int strip; +parse_file_seq (char **stringp, int stopchar, unsigned int size, int strip) { - register struct nameseq *new = 0; - register struct nameseq *new1, *lastnew1; - register char *p = *stringp; + struct nameseq *new = 0; + struct nameseq *new1, *lastnew1; + char *p = *stringp; char *q; char *name; @@ -2251,7 +2276,7 @@ parse_file_seq (stringp, stopchar, size, strip) /* Yes, find end of next name. */ q = p; - p = find_char_unquote (q, stopchar, VMS_COMMA, 1); + p = find_char_unquote (q, stopchar, VMS_COMMA, 1, 0); #ifdef VMS /* convert comma separated list to space separated */ if (p && *p == ',') @@ -2262,7 +2287,7 @@ parse_file_seq (stringp, stopchar, size, strip) && !(isspace ((unsigned char)p[1]) || !p[1] || isspace ((unsigned char)p[-1]))) { - p = find_char_unquote (p+1, stopchar, VMS_COMMA, 1); + p = find_char_unquote (p+1, stopchar, VMS_COMMA, 1, 0); } #endif #ifdef HAVE_DOS_PATHS @@ -2273,7 +2298,7 @@ parse_file_seq (stringp, stopchar, size, strip) if (stopchar == ':') while (p != 0 && !isspace ((unsigned char)*p) && (p[1] == '\\' || p[1] == '/') && isalpha ((unsigned char)p[-1])) - p = find_char_unquote (p + 1, stopchar, VMS_COMMA, 1); + p = find_char_unquote (p + 1, stopchar, VMS_COMMA, 1, 0); #endif if (p == 0) p = q + strlen (q); @@ -2469,45 +2494,50 @@ parse_file_seq (stringp, stopchar, size, strip) */ static unsigned long -readstring (ebuf) - struct ebuffer *ebuf; +readstring (struct ebuffer *ebuf) { - char *p; + char *eol; /* If there is nothing left in this buffer, return 0. */ - if (ebuf->bufnext > ebuf->bufstart + ebuf->size) + if (ebuf->bufnext >= ebuf->bufstart + ebuf->size) return -1; /* Set up a new starting point for the buffer, and find the end of the next logical line (taking into account backslash/newline pairs). */ - p = ebuf->buffer = ebuf->bufnext; + eol = ebuf->buffer = ebuf->bufnext; while (1) { int backslash = 0; + char *bol = eol; + char *p; - /* Find the next newline. Keep track of backslashes as we look. */ - for (; *p != '\n' && *p != '\0'; ++p) - if (*p == '\\') - backslash = !backslash; + /* Find the next newline. At EOS, stop. */ + eol = p = strchr (eol , '\n'); + if (!eol) + { + ebuf->bufnext = ebuf->bufstart + ebuf->size + 1; + return 0; + } - /* If we got to the end of the string or a newline with no backslash, - we're done. */ - if (*p == '\0' || !backslash) + /* Found a newline; if it's escaped continue; else we're done. */ + while (p > bol && *(--p) == '\\') + backslash = !backslash; + if (!backslash) break; + ++eol; } /* Overwrite the newline char. */ - *p = '\0'; - ebuf->bufnext = p+1; + *eol = '\0'; + ebuf->bufnext = eol+1; return 0; } static long -readline (ebuf) - struct ebuffer *ebuf; +readline (struct ebuffer *ebuf) { char *p; char *end; @@ -2558,7 +2588,7 @@ readline (ebuf) /* We got a newline, so add one to the count of lines. */ ++nlines; -#if !defined(WINDOWS32) && !defined(__MSDOS__) +#if !defined(WINDOWS32) && !defined(__MSDOS__) && !defined(__EMX__) /* Check to see if the line was really ended with CRLF; if so ignore the CR. */ if ((p - start) > 1 && p[-2] == '\r') @@ -2631,11 +2661,7 @@ readline (ebuf) in a command list, etc.) */ static enum make_word_type -get_next_mword (buffer, delim, startp, length) - char *buffer; - char *delim; - char **startp; - unsigned int *length; +get_next_mword (char *buffer, char *delim, char **startp, unsigned int *length) { enum make_word_type wtype = w_bogus; char *p = buffer, *beg; @@ -2799,8 +2825,7 @@ get_next_mword (buffer, delim, startp, length) from the arguments and the default list. */ void -construct_include_path (arg_dirs) - char **arg_dirs; +construct_include_path (char **arg_dirs) { register unsigned int i; #ifdef VAXC /* just don't ask ... */ @@ -2827,6 +2852,7 @@ construct_include_path (arg_dirs) while (*arg_dirs != 0) { char *dir = *arg_dirs++; + int e; if (dir[0] == '~') { @@ -2835,7 +2861,8 @@ construct_include_path (arg_dirs) dir = expanded; } - if (stat (dir, &stbuf) == 0 && S_ISDIR (stbuf.st_mode)) + EINTRLOOP (e, stat (dir, &stbuf)); + if (e == 0 && S_ISDIR (stbuf.st_mode)) { if (idx == max - 1) { @@ -2868,13 +2895,18 @@ construct_include_path (arg_dirs) #endif for (i = 0; default_include_directories[i] != 0; ++i) - if (stat (default_include_directories[i], &stbuf) == 0 - && S_ISDIR (stbuf.st_mode)) - dirs[idx++] = default_include_directories[i]; + { + int e; + + EINTRLOOP (e, stat (default_include_directories[i], &stbuf)); + if (e == 0 && S_ISDIR (stbuf.st_mode)) + dirs[idx++] = default_include_directories[i]; + } dirs[idx] = 0; - /* Now compute the maximum length of any name in it. */ + /* Now compute the maximum length of any name in it. Also add each + dir to the .INCLUDE_DIRS variable. */ max_incl_len = 0; for (i = 0; i < idx; ++i) @@ -2887,6 +2919,10 @@ construct_include_path (arg_dirs) dirs[i] = savestring (dirs[i], len - 1); if (len > max_incl_len) max_incl_len = len; + + /* Append to .INCLUDE_DIRS. */ + do_variable_definition (NILF, ".INCLUDE_DIRS", dirs[i], + o_default, f_append, 0); } include_directories = dirs; @@ -2896,8 +2932,7 @@ construct_include_path (arg_dirs) Return a newly malloc'd string or 0. */ char * -tilde_expand (name) - char *name; +tilde_expand (char *name) { #ifndef VMS if (name[1] == '/' || name[1] == '\0') @@ -2978,9 +3013,7 @@ tilde_expand (name) that have room for additional info. */ struct nameseq * -multi_glob (chain, size) - struct nameseq *chain; - unsigned int size; +multi_glob (struct nameseq *chain, unsigned int size) { extern void dir_setup_glob (); register struct nameseq *new = 0; diff --git a/src/bin/make/remake.c b/src/bin/make/remake.c index 72c4d78a44..a7527347af 100644 --- a/src/bin/make/remake.c +++ b/src/bin/make/remake.c @@ -1,22 +1,20 @@ /* Basic dependency engine for GNU Make. -Copyright (C) 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1999, -2002 Free Software Foundation, Inc. +Copyright (C) 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, +1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006 Free Software +Foundation, Inc. This file is part of GNU Make. -GNU Make is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 2, or (at your option) -any later version. +GNU Make is free software; you can redistribute it and/or modify it under the +terms of the GNU General Public License as published by the Free Software +Foundation; either version 2, or (at your option) any later version. -GNU Make is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. +GNU Make is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR +A PARTICULAR PURPOSE. See the GNU General Public License for more details. -You should have received a copy of the GNU General Public License -along with GNU Make; see the file COPYING. If not, write to -the Free Software Foundation, Inc., 59 Temple Place - Suite 330, -Boston, MA 02111-1307, USA. */ +You should have received a copy of the GNU General Public License along with +GNU Make; see the file COPYING. If not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. */ #include "make.h" #include "filedef.h" @@ -73,21 +71,20 @@ static int library_search PARAMS ((char **lib, FILE_TIMESTAMP *mtime_ptr)); /* Remake all the goals in the `struct dep' chain GOALS. Return -1 if nothing was done, 0 if all goals were updated successfully, or 1 if a goal failed. - If MAKEFILES is nonzero, these goals are makefiles, so -t, -q, and -n should - be disabled for them unless they were also command-line targets, and we - should only make one goal at a time and return as soon as one goal whose - `changed' member is nonzero is successfully made. */ + + If rebuilding_makefiles is nonzero, these goals are makefiles, so -t, -q, + and -n should be disabled for them unless they were also command-line + targets, and we should only make one goal at a time and return as soon as + one goal whose `changed' member is nonzero is successfully made. */ int -update_goal_chain (goals, makefiles) - register struct dep *goals; - int makefiles; +update_goal_chain (struct dep *goals) { int t = touch_flag, q = question_flag, n = just_print_flag; unsigned int j = job_slots; int status = -1; -#define MTIME(file) (makefiles ? file_mtime_no_search (file) \ +#define MTIME(file) (rebuilding_makefiles ? file_mtime_no_search (file) \ : file_mtime (file)) /* Duplicate the chain so we can remove things from it. */ @@ -137,7 +134,7 @@ update_goal_chain (goals, makefiles) unsigned int ocommands_started; int x; check_renamed (file); - if (makefiles) + if (rebuilding_makefiles) { if (file->cmd_target) { @@ -154,13 +151,14 @@ update_goal_chain (goals, makefiles) actually run. */ ocommands_started = commands_started; - x = update_file (file, makefiles ? 1 : 0); + x = update_file (file, rebuilding_makefiles ? 1 : 0); check_renamed (file); /* Set the goal's `changed' flag if any commands were started by calling update_file above. We check this flag below to decide when to give an "up to date" diagnostic. */ - g->changed += commands_started - ocommands_started; + if (commands_started > ocommands_started) + g->changed = 1; /* If we updated a file and STATUS was not already 1, set it to 1 if updating failed, or to 0 if updating succeeded. Leave @@ -177,8 +175,8 @@ update_goal_chain (goals, makefiles) /* If -q just triggered, stop immediately. It doesn't matter how much more we run, since we already know the answer to return. */ - stop = (!keep_going_flag && !question_flag - && !makefiles); + stop = (question_flag && !keep_going_flag + && !rebuilding_makefiles); } else { @@ -194,10 +192,10 @@ update_goal_chain (goals, makefiles) as a command-line target), don't change STATUS. If STATUS is changed, we will get re-exec'd, and enter an infinite loop. */ - if (!makefiles + if (!rebuilding_makefiles || (!just_print_flag && !question_flag)) status = 0; - if (makefiles && file->dontcare) + if (rebuilding_makefiles && file->dontcare) /* This is a default makefile; stop remaking. */ stop = 1; } @@ -220,7 +218,7 @@ update_goal_chain (goals, makefiles) /* If we have found nothing whatever to do for the goal, print a message saying nothing needs doing. */ - if (!makefiles + if (!rebuilding_makefiles /* If the update_status is zero, we updated successfully or not at all. G->changed will have been set above if any commands were actually started for this goal. */ @@ -259,13 +257,14 @@ update_goal_chain (goals, makefiles) considered = !considered; } - if (makefiles) + if (rebuilding_makefiles) { touch_flag = t; question_flag = q; just_print_flag = n; job_slots = j; } + return status; } @@ -282,9 +281,7 @@ update_goal_chain (goals, makefiles) each is considered in turn. */ static int -update_file (file, depth) - struct file *file; - unsigned int depth; +update_file (struct file *file, unsigned int depth) { register int status = 0; register struct file *f; @@ -310,8 +307,12 @@ update_file (file, depth) status |= update_file_1 (f, depth); check_renamed (f); + /* Clean up any alloca() used during the update. */ + alloca (0); + + /* If we got an error, don't bother with double_colon etc. */ if (status != 0 && !keep_going_flag) - break; + return status; if (f->command_state == cs_running || f->command_state == cs_deps_running) @@ -325,25 +326,48 @@ update_file (file, depth) /* Process the remaining rules in the double colon chain so they're marked considered. Start their prerequisites, too. */ - for (; f != 0 ; f = f->prev) - { - struct dep *d; + if (file->double_colon) + for (; f != 0 ; f = f->prev) + { + struct dep *d; - f->considered = considered; + f->considered = considered; - for (d = f->deps; d != 0; d = d->next) - status |= update_file (d->file, depth + 1); - } + for (d = f->deps; d != 0; d = d->next) + status |= update_file (d->file, depth + 1); + } return status; } +/* Show a message stating the target failed to build. */ + +static void +complain (const struct file *file) +{ + const char *msg_noparent + = _("%sNo rule to make target `%s'%s"); + const char *msg_parent + = _("%sNo rule to make target `%s', needed by `%s'%s"); + + if (!keep_going_flag) + { + if (file->parent == 0) + fatal (NILF, msg_noparent, "", file->name, ""); + + fatal (NILF, msg_parent, "", file->name, file->parent->name, ""); + } + + if (file->parent == 0) + error (NILF, msg_noparent, "*** ", file->name, "."); + else + error (NILF, msg_parent, "*** ", file->name, file->parent->name, "."); +} + /* Consider a single `struct file' and update it as appropriate. */ static int -update_file_1 (file, depth) - struct file *file; - unsigned int depth; +update_file_1 (struct file *file, unsigned int depth) { register FILE_TIMESTAMP this_mtime; int noexist, must_make, deps_changed; @@ -359,6 +383,17 @@ update_file_1 (file, depth) { DBF (DB_VERBOSE, _("Recently tried and failed to update file `%s'.\n")); + + /* If the file we tried to make is marked dontcare then no message + was printed about it when it failed during the makefile rebuild. + If we're trying to build it again in the normal rebuild, print a + message now. */ + if (file->dontcare && !rebuilding_makefiles) + { + file->dontcare = 0; + complain (file); + } + return file->update_status; } @@ -437,6 +472,7 @@ update_file_1 (file, depth) { FILE_TIMESTAMP mtime; int maybe_make; + int dontcare = 0; check_renamed (d->file); @@ -460,7 +496,21 @@ update_file_1 (file, depth) d->file->parent = file; maybe_make = must_make; + + /* Inherit dontcare flag from our parent. */ + if (rebuilding_makefiles) + { + dontcare = d->file->dontcare; + d->file->dontcare = file->dontcare; + } + + dep_status |= check_dep (d->file, depth, this_mtime, &maybe_make); + + /* Restore original dontcare flag. */ + if (rebuilding_makefiles) + d->file->dontcare = dontcare; + if (! d->ignore_mtime) must_make = maybe_make; @@ -483,7 +533,12 @@ update_file_1 (file, depth) break; if (!running) - d->changed = file_mtime (d->file) != mtime; + /* The prereq is considered changed if the timestamp has changed while + it was built, OR it doesn't exist. + This causes the Linux kernel build to break. We'll defer this + fix until GNU make 3.82 to give them time to update. */ + d->changed = ((file_mtime (d->file) != mtime) + /* || (mtime == NONEXISTENT_MTIME) */); lastd = d; d = d->next; @@ -497,10 +552,26 @@ update_file_1 (file, depth) for (d = file->deps; d != 0; d = d->next) if (d->file->intermediate) { + int dontcare = 0; + FILE_TIMESTAMP mtime = file_mtime (d->file); check_renamed (d->file); d->file->parent = file; + + /* Inherit dontcare flag from our parent. */ + if (rebuilding_makefiles) + { + dontcare = d->file->dontcare; + d->file->dontcare = file->dontcare; + } + + dep_status |= update_file (d->file, depth); + + /* Restore original dontcare flag. */ + if (rebuilding_makefiles) + d->file->dontcare = dontcare; + check_renamed (d->file); { @@ -722,8 +793,7 @@ update_file_1 (file, depth) On return, FILE->update_status will no longer be -1 if it was. */ void -notice_finished_file (file) - register struct file *file; +notice_finished_file (struct file *file) { struct dep *d; int ran = file->command_state == cs_running; @@ -755,7 +825,8 @@ notice_finished_file (file) have_nonrecursing: if (file->phony) file->update_status = 0; - else + /* According to POSIX, -t doesn't affect targets with no cmds. */ + else if (file->cmds != 0) { /* Should set file's modification date and do nothing else. */ file->update_status = touch_file (file); @@ -778,7 +849,6 @@ notice_finished_file (file) if ((ran && !file->phony) || touched) { - struct file *f; int i = 0; /* If -n, -t, or -q and all the commands are recursive, we ran them so @@ -798,11 +868,34 @@ notice_finished_file (file) i = 1; file->last_mtime = i == 0 ? UNKNOWN_MTIME : NEW_MTIME; + } - /* Propagate the change of modification time to all the double-colon - entries for this file. */ - for (f = file->double_colon; f != 0; f = f->prev) - f->last_mtime = file->last_mtime; + if (file->double_colon) + { + /* If this is a double colon rule and it is the last one to be + updated, propagate the change of modification time to all the + double-colon entries for this file. + + We do it on the last update because it is important to handle + individual entries as separate rules with separate timestamps + while they are treated as targets and then as one rule with the + unified timestamp when they are considered as a prerequisite + of some target. */ + + struct file *f; + FILE_TIMESTAMP max_mtime = file->last_mtime; + + /* Check that all rules were updated and at the same time find + the max timestamp. We assume UNKNOWN_MTIME is newer then + any other value. */ + for (f = file->double_colon; f != 0 && f->updated; f = f->prev) + if (max_mtime != UNKNOWN_MTIME + && (f->last_mtime == UNKNOWN_MTIME || f->last_mtime > max_mtime)) + max_mtime = f->last_mtime; + + if (f == 0) + for (f = file->double_colon; f != 0; f = f->prev) + f->last_mtime = max_mtime; } if (ran && file->update_status != -1) @@ -837,11 +930,8 @@ notice_finished_file (file) Return nonzero if any updating failed. */ static int -check_dep (file, depth, this_mtime, must_make_ptr) - struct file *file; - unsigned int depth; - FILE_TIMESTAMP this_mtime; - int *must_make_ptr; +check_dep (struct file *file, unsigned int depth, + FILE_TIMESTAMP this_mtime, int *must_make_ptr) { struct dep *d; int dep_status = 0; @@ -849,10 +939,10 @@ check_dep (file, depth, this_mtime, must_make_ptr) ++depth; start_updating (file); - if (!file->intermediate) - /* If this is a non-intermediate file, update it and record - whether it is newer than THIS_MTIME. */ + if (file->phony || !file->intermediate) { + /* If this is a non-intermediate file, update it and record + whether it is newer than THIS_MTIME. */ FILE_TIMESTAMP mtime; dep_status = update_file (file, depth); check_renamed (file); @@ -908,13 +998,13 @@ check_dep (file, depth, this_mtime, must_make_ptr) if (lastd == 0) { file->deps = d->next; - free ((char *) d); + free_dep (d); d = file->deps; } else { lastd->next = d->next; - free ((char *) d); + free_dep (d); d = lastd->next; } continue; @@ -952,8 +1042,7 @@ check_dep (file, depth, this_mtime, must_make_ptr) #define TOUCH_ERROR(call) return (perror_with_name (call, file->name), 1) static int -touch_file (file) - register struct file *file; +touch_file (struct file *file) { if (!silent_flag) message (0, "touch %s", file->name); @@ -972,8 +1061,10 @@ touch_file (file) { struct stat statbuf; char buf; + int e; - if (fstat (fd, &statbuf) < 0) + EINTRLOOP (e, fstat (fd, &statbuf)); + if (e < 0) TOUCH_ERROR ("touch: fstat: "); /* Rewrite character 0 same as it already is. */ if (read (fd, &buf, 1) < 0) @@ -1003,8 +1094,7 @@ touch_file (file) Return the status from executing FILE's commands. */ static void -remake_file (file) - struct file *file; +remake_file (struct file *file) { if (file->cmds == 0) { @@ -1017,28 +1107,9 @@ remake_file (file) file->update_status = 0; else { - const char *msg_noparent - = _("%sNo rule to make target `%s'%s"); - const char *msg_parent - = _("%sNo rule to make target `%s', needed by `%s'%s"); - /* This is a dependency file we cannot remake. Fail. */ - if (!keep_going_flag && !file->dontcare) - { - if (file->parent == 0) - fatal (NILF, msg_noparent, "", file->name, ""); - - fatal (NILF, msg_parent, "", file->name, file->parent->name, ""); - } - - if (!file->dontcare) - { - if (file->parent == 0) - error (NILF, msg_noparent, "*** ", file->name, "."); - else - error (NILF, msg_parent, "*** ", - file->name, file->parent->name, "."); - } + if (!rebuilding_makefiles || !file->dontcare) + complain (file); file->update_status = 2; } } @@ -1070,9 +1141,7 @@ remake_file (file) FILE. */ FILE_TIMESTAMP -f_mtime (file, search) - register struct file *file; - int search; +f_mtime (struct file *file, int search) { FILE_TIMESTAMP mtime; @@ -1183,62 +1252,71 @@ f_mtime (file, search) rehash_file (file, name); check_renamed (file); - mtime = name_mtime (name); + /* If the result of a vpath search is -o or -W, preserve it. + Otherwise, find the mtime of the resulting file. */ + if (mtime != OLD_MTIME && mtime != NEW_MTIME) + mtime = name_mtime (name); } } } - { - /* Files can have bogus timestamps that nothing newly made will be - "newer" than. Updating their dependents could just result in loops. - So notify the user of the anomaly with a warning. + /* Files can have bogus timestamps that nothing newly made will be + "newer" than. Updating their dependents could just result in loops. + So notify the user of the anomaly with a warning. - We only need to do this once, for now. */ + We only need to do this once, for now. */ - if (!clock_skew_detected - && mtime != NONEXISTENT_MTIME - && !file->updated) - { - static FILE_TIMESTAMP adjusted_now; + if (!clock_skew_detected + && mtime != NONEXISTENT_MTIME && mtime != NEW_MTIME + && !file->updated) + { + static FILE_TIMESTAMP adjusted_now; - FILE_TIMESTAMP adjusted_mtime = mtime; + FILE_TIMESTAMP adjusted_mtime = mtime; #if defined(WINDOWS32) || defined(__MSDOS__) - /* Experimentation has shown that FAT filesystems can set file times - up to 3 seconds into the future! Play it safe. */ + /* Experimentation has shown that FAT filesystems can set file times + up to 3 seconds into the future! Play it safe. */ #define FAT_ADJ_OFFSET (FILE_TIMESTAMP) 3 - FILE_TIMESTAMP adjustment = FAT_ADJ_OFFSET << FILE_TIMESTAMP_LO_BITS; - if (ORDINARY_MTIME_MIN + adjustment <= adjusted_mtime) - adjusted_mtime -= adjustment; + FILE_TIMESTAMP adjustment = FAT_ADJ_OFFSET << FILE_TIMESTAMP_LO_BITS; + if (ORDINARY_MTIME_MIN + adjustment <= adjusted_mtime) + adjusted_mtime -= adjustment; +#elif defined(__EMX__) + /* FAT filesystems round time to the nearest even second! + Allow for any file (NTFS or FAT) to perhaps suffer from this + brain damage. */ + FILE_TIMESTAMP adjustment = (((FILE_TIMESTAMP_S (adjusted_mtime) & 1) == 0 + && FILE_TIMESTAMP_NS (adjusted_mtime) == 0) + ? (FILE_TIMESTAMP) 1 << FILE_TIMESTAMP_LO_BITS + : 0); #endif - /* If the file's time appears to be in the future, update our - concept of the present and try once more. */ - if (adjusted_now < adjusted_mtime) - { - int resolution; - FILE_TIMESTAMP now = file_timestamp_now (&resolution); - adjusted_now = now + (resolution - 1); - if (adjusted_now < adjusted_mtime) - { + /* If the file's time appears to be in the future, update our + concept of the present and try once more. */ + if (adjusted_now < adjusted_mtime) + { + int resolution; + FILE_TIMESTAMP now = file_timestamp_now (&resolution); + adjusted_now = now + (resolution - 1); + if (adjusted_now < adjusted_mtime) + { #ifdef NO_FLOAT - error (NILF, _("Warning: File `%s' has modification time in the future"), - file->name); + error (NILF, _("Warning: File `%s' has modification time in the future"), + file->name); #else - double from_now = - (FILE_TIMESTAMP_S (mtime) - FILE_TIMESTAMP_S (now) - + ((FILE_TIMESTAMP_NS (mtime) - FILE_TIMESTAMP_NS (now)) - / 1e9)); - error (NILF, _("Warning: File `%s' has modification time %.2g s in the future"), - file->name, from_now); + double from_now = + (FILE_TIMESTAMP_S (mtime) - FILE_TIMESTAMP_S (now) + + ((FILE_TIMESTAMP_NS (mtime) - FILE_TIMESTAMP_NS (now)) + / 1e9)); + error (NILF, _("Warning: File `%s' has modification time %.2g s in the future"), + file->name, from_now); #endif - clock_skew_detected = 1; - } - } - } - } + clock_skew_detected = 1; + } + } + } /* Store the mtime into all the entries for this file. */ if (file->double_colon) @@ -1267,20 +1345,100 @@ f_mtime (file, search) /* Return the mtime of the file or archive-member reference NAME. */ -static FILE_TIMESTAMP -name_mtime (name) - register char *name; -{ - struct stat st; +/* 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. */ - if (stat (name, &st) != 0) +static FILE_TIMESTAMP +name_mtime (char *name) +{ + FILE_TIMESTAMP mtime; + struct stat st; + int e; + + EINTRLOOP (e, stat (name, &st)); + if (e == 0) + mtime = FILE_TIMESTAMP_STAT_MODTIME (name, st); + else if (errno == ENOENT || errno == ENOTDIR) + mtime = NONEXISTENT_MTIME; + else { - if (errno != ENOENT && errno != ENOTDIR) - perror_with_name ("stat:", name); + perror_with_name ("stat: ", name); return NONEXISTENT_MTIME; } - return FILE_TIMESTAMP_STAT_MODTIME (name, st); + /* If we get here we either found it, or it doesn't exist. + If it doesn't exist see if we can use a symlink mtime instead. */ + +#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) + { + /* Just take what we have so far. */ + if (errno != ENOENT && errno != ENOTDIR) + 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; + + /* 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; } @@ -1289,9 +1447,7 @@ name_mtime (name) directories. */ static int -library_search (lib, mtime_ptr) - char **lib; - FILE_TIMESTAMP *mtime_ptr; +library_search (char **lib, FILE_TIMESTAMP *mtime_ptr) { static char *dirs[] = { @@ -1337,7 +1493,7 @@ library_search (lib, mtime_ptr) while ((p = find_next_token (&p2, &len)) != 0) { static char *buf = NULL; - static int buflen = 0; + static unsigned int buflen = 0; static int libdir_maxlen = -1; char *libbuf = variable_expand (""); diff --git a/src/bin/make/remote-stub.c b/src/bin/make/remote-stub.c index 69af39752a..0417c2b03c 100644 --- a/src/bin/make/remote-stub.c +++ b/src/bin/make/remote-stub.c @@ -1,21 +1,20 @@ /* Template for the remote job exportation interface to GNU Make. -Copyright (C) 1988, 1989, 1992, 1993, 1996 Free Software Foundation, Inc. +Copyright (C) 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, +1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006 Free Software +Foundation, Inc. This file is part of GNU Make. -GNU Make is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 2, or (at your option) -any later version. +GNU Make is free software; you can redistribute it and/or modify it under the +terms of the GNU General Public License as published by the Free Software +Foundation; either version 2, or (at your option) any later version. -GNU Make is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. +GNU Make is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR +A PARTICULAR PURPOSE. See the GNU General Public License for more details. -You should have received a copy of the GNU General Public License -along with GNU Make; see the file COPYING. If not, write to -the Free Software Foundation, Inc., 59 Temple Place - Suite 330, -Boston, MA 02111-1307, USA. */ +You should have received a copy of the GNU General Public License along with +GNU Make; see the file COPYING. If not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. */ #include "make.h" #include "filedef.h" @@ -28,22 +27,21 @@ char *remote_description = 0; /* Call once at startup even if no commands are run. */ void -remote_setup () +remote_setup (void) { } /* Called before exit. */ void -remote_cleanup () +remote_cleanup (void) { } /* Return nonzero if the next job should be done remotely. */ int -start_remote_job_p (first_p) - int first_p; +start_remote_job_p (int first_p UNUSED) { return 0; } @@ -56,12 +54,9 @@ start_remote_job_p (first_p) nonzero if it is remote (meaning *ID_PTR is a process ID). */ int -start_remote_job (argv, envp, stdin_fd, is_remote, id_ptr, used_stdin) - char **argv, **envp; - int stdin_fd; - int *is_remote; - int *id_ptr; - int *used_stdin; +start_remote_job (char **argv UNUSED, char **envp UNUSED, int stdin_fd UNUSED, + int *is_remote UNUSED, int *id_ptr UNUSED, + int *used_stdin UNUSED) { return -1; } @@ -73,9 +68,8 @@ start_remote_job (argv, envp, stdin_fd, is_remote, id_ptr, used_stdin) 0 if we would have to block and !BLOCK, or < 0 if there were none. */ int -remote_status (exit_code_ptr, signal_ptr, coredump_ptr, block) - int *exit_code_ptr, *signal_ptr, *coredump_ptr; - int block; +remote_status (int *exit_code_ptr UNUSED, int *signal_ptr UNUSED, + int *coredump_ptr UNUSED, int block UNUSED) { errno = ECHILD; return -1; @@ -85,7 +79,7 @@ remote_status (exit_code_ptr, signal_ptr, coredump_ptr, block) If this notification is done by raising the child termination signal, do not block that signal. */ void -block_remote_children () +block_remote_children (void) { return; } @@ -94,16 +88,14 @@ block_remote_children () If this is done by raising the child termination signal, do not unblock that signal. */ void -unblock_remote_children () +unblock_remote_children (void) { return; } /* Send signal SIG to child ID. Return 0 if successful, -1 if not. */ int -remote_kill (id, sig) - int id; - int sig; +remote_kill (int id UNUSED, int sig UNUSED) { return -1; } diff --git a/src/bin/make/rule.c b/src/bin/make/rule.c index e693c022fe..e988db5bbf 100644 --- a/src/bin/make/rule.c +++ b/src/bin/make/rule.c @@ -1,21 +1,20 @@ /* Pattern and suffix rule internals for GNU Make. -Copyright (C) 1988,89,90,91,92,93, 1998 Free Software Foundation, Inc. +Copyright (C) 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, +1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006 Free Software +Foundation, Inc. This file is part of GNU Make. -GNU Make is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 2, or (at your option) -any later version. +GNU Make is free software; you can redistribute it and/or modify it under the +terms of the GNU General Public License as published by the Free Software +Foundation; either version 2, or (at your option) any later version. -GNU Make is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. +GNU Make is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR +A PARTICULAR PURPOSE. See the GNU General Public License for more details. -You should have received a copy of the GNU General Public License -along with GNU Make; see the file COPYING. If not, write to -the Free Software Foundation, Inc., 59 Temple Place - Suite 330, -Boston, MA 02111-1307, USA. */ +You should have received a copy of the GNU General Public License along with +GNU Make; see the file COPYING. If not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. */ #include "make.h" #include "dep.h" @@ -51,14 +50,6 @@ unsigned int max_pattern_deps; unsigned int max_pattern_dep_length; -/* Chain of all pattern-specific variables. */ - -static struct pattern_var *pattern_vars; - -/* Pointer to last struct in the chain, so we can add onto the end. */ - -static struct pattern_var *last_pattern_var; - /* Pointer to structure for the file .SUFFIXES whose dependencies are the suffixes to be searched. */ @@ -74,10 +65,10 @@ unsigned int maxsuffix; completely when appropriate. */ void -count_implicit_rule_limits () +count_implicit_rule_limits (void) { char *name; - unsigned int namelen; + int namelen; register struct rule *rule, *lastrule; num_pattern_rules = max_pattern_targets = max_pattern_deps = 0; @@ -143,20 +134,6 @@ count_implicit_rule_limits () nonexistent subdirectory. */ dep->changed = !dir_file_exists_p (name, ""); -#ifdef VMS - if (dep->changed && strchr (name, ':') != 0) -#else - if (dep->changed && *name == '/') -#endif - { - /* The name is absolute and the directory does not exist. - This rule can never possibly match, since this dependency - can never possibly exist. So just remove the rule from - the list. */ - freerule (rule, lastrule); - --num_pattern_rules; - goto end_main_loop; - } } else /* This dependency does not reside in a subdirectory. */ @@ -167,7 +144,6 @@ count_implicit_rule_limits () max_pattern_deps = ndeps; lastrule = rule; - end_main_loop: rule = next; } @@ -182,9 +158,7 @@ count_implicit_rule_limits () If SOURCE is nil, it means there should be no deps. */ static void -convert_suffix_rule (target, source, cmds) - char *target, *source; - struct commands *cmds; +convert_suffix_rule (char *target, char *source, struct commands *cmds) { char *targname, *targpercent, *depname; char **names, **percents; @@ -227,10 +201,8 @@ convert_suffix_rule (target, source, cmds) depname = xmalloc (1 + len + 1); depname[0] = '%'; bcopy (source, depname + 1, len + 1); - deps = (struct dep *) xmalloc (sizeof (struct dep)); - deps->next = 0; + deps = alloc_dep (); deps->name = depname; - deps->ignore_mtime = 0; } create_pattern_rule (names, percents, 0, deps, cmds, 0); @@ -241,7 +213,7 @@ convert_suffix_rule (target, source, cmds) are converted and added to the chain of pattern rules. */ void -convert_to_pattern () +convert_to_pattern (void) { register struct dep *d, *d2; register struct file *f; @@ -310,9 +282,7 @@ convert_to_pattern () list. Return nonzero if RULE is used; zero if not. */ int -new_pattern_rule (rule, override) - register struct rule *rule; - int override; +new_pattern_rule (struct rule *rule, int override) { register struct rule *r, *lastrule; register unsigned int i, j; @@ -387,9 +357,7 @@ new_pattern_rule (rule, override) TERMINAL specifies what the `terminal' field of the rule should be. */ void -install_pattern_rule (p, terminal) - struct pspec *p; - int terminal; +install_pattern_rule (struct pspec *p, int terminal) { register struct rule *r; char *ptr; @@ -439,8 +407,7 @@ install_pattern_rule (p, terminal) points to RULE. */ static void -freerule (rule, lastrule) - register struct rule *rule, *lastrule; +freerule (struct rule *rule, struct rule *lastrule) { struct rule *next = rule->next; register unsigned int i; @@ -457,7 +424,8 @@ freerule (rule, lastrule) t = dep->next; /* We might leak dep->name here, but I'm not sure how to fix this: I think that pointer might be shared (e.g., in the file hash?) */ - free ((char *) dep); + dep->name = 0; /* Make sure free_dep does not free name. */ + free_dep (dep); dep = t; } @@ -501,16 +469,12 @@ freerule (rule, lastrule) it may be freed. */ void -create_pattern_rule (targets, target_percents, - terminal, deps, commands, override) - char **targets, **target_percents; - int terminal; - struct dep *deps; - struct commands *commands; - int override; +create_pattern_rule (char **targets, char **target_percents, + int terminal, struct dep *deps, + struct commands *commands, int override) { - register struct rule *r = (struct rule *) xmalloc (sizeof (struct rule)); - register unsigned int max_targets, i; + unsigned int max_targets, i; + struct rule *r = (struct rule *) xmalloc (sizeof (struct rule)); r->cmds = commands; r->deps = deps; @@ -548,83 +512,10 @@ create_pattern_rule (targets, target_percents, r->terminal = terminal; } -/* Create a new pattern-specific variable struct. */ - -struct pattern_var * -create_pattern_var (target, suffix) - char *target, *suffix; -{ - register struct pattern_var *p = 0; - unsigned int len = strlen(target); - - /* Look to see if this pattern already exists in the list. */ - for (p = pattern_vars; p != NULL; p = p->next) - if (p->len == len && !strcmp(p->target, target)) - break; - - if (p == 0) - { - p = (struct pattern_var *) xmalloc (sizeof (struct pattern_var)); - if (last_pattern_var != 0) - last_pattern_var->next = p; - else - pattern_vars = p; - last_pattern_var = p; - p->next = 0; - p->target = target; - p->len = len; - p->suffix = suffix + 1; - p->vars = create_new_variable_set(); - } - - return p; -} - -/* Look up a target in the pattern-specific variable list. */ - -struct pattern_var * -lookup_pattern_var (target) - char *target; -{ - struct pattern_var *p; - unsigned int targlen = strlen(target); - - for (p = pattern_vars; p != 0; p = p->next) - { - char *stem; - unsigned int stemlen; - - if (p->len > targlen) - /* It can't possibly match. */ - continue; - - /* From the lengths of the filename and the pattern parts, - find the stem: the part of the filename that matches the %. */ - stem = target + (p->suffix - p->target - 1); - stemlen = targlen - p->len + 1; - - /* Compare the text in the pattern before the stem, if any. */ - if (stem > target && !strneq (p->target, target, stem - target)) - continue; - - /* Compare the text in the pattern after the stem, if any. - We could test simply using streq, but this way we compare the - first two characters immediately. This saves time in the very - common case where the first character matches because it is a - period. */ - if (*p->suffix == stem[stemlen] - && (*p->suffix == '\0' || streq (&p->suffix[1], &stem[stemlen+1]))) - break; - } - - return p; -} - /* Print the data base of rules. */ static void /* Useful to call from gdb. */ -print_rule (r) - struct rule *r; +print_rule (struct rule *r) { register unsigned int i; register struct dep *d; @@ -649,7 +540,7 @@ print_rule (r) } void -print_rule_data_base () +print_rule_data_base (void) { register unsigned int rules, terminal; register struct rule *r; @@ -692,26 +583,4 @@ print_rule_data_base () fatal (NILF, _("BUG: num_pattern_rules wrong! %u != %u"), num_pattern_rules, rules); } - - puts (_("\n# Pattern-specific variable values")); - - { - struct pattern_var *p; - - rules = 0; - for (p = pattern_vars; p != 0; p = p->next) - { - ++rules; - - printf ("\n%s :\n", p->target); - print_variable_set (p->vars->set, "# "); - } - - if (rules == 0) - puts (_("\n# No pattern-specific variable values.")); - else - { - printf (_("\n# %u pattern-specific variable values"), rules); - } - } } diff --git a/src/bin/make/rule.h b/src/bin/make/rule.h index 30cc544924..99fb76e8ea 100644 --- a/src/bin/make/rule.h +++ b/src/bin/make/rule.h @@ -1,21 +1,20 @@ /* Definitions for using pattern rules in GNU Make. -Copyright (C) 1988, 1989, 1991, 1992, 1993 Free Software Foundation, Inc. +Copyright (C) 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, +1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006 Free Software +Foundation, Inc. This file is part of GNU Make. -GNU Make is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 2, or (at your option) -any later version. +GNU Make is free software; you can redistribute it and/or modify it under the +terms of the GNU General Public License as published by the Free Software +Foundation; either version 2, or (at your option) any later version. -GNU Make is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. +GNU Make is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR +A PARTICULAR PURPOSE. See the GNU General Public License for more details. -You should have received a copy of the GNU General Public License -along with GNU Make; see the file COPYING. If not, write to -the Free Software Foundation, Inc., 59 Temple Place - Suite 330, -Boston, MA 02111-1307, USA. */ +You should have received a copy of the GNU General Public License along with +GNU Make; see the file COPYING. If not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. */ /* Structure used for pattern rules. */ @@ -31,15 +30,6 @@ struct rule char in_use; /* If in use by a parent pattern_search. */ }; -struct pattern_var - { - struct pattern_var *next; - char *target; - unsigned int len; - char *suffix; - struct variable_set_list *vars; - }; - /* For calling install_pattern_rule. */ struct pspec { @@ -61,8 +51,6 @@ extern unsigned int maxsuffix; extern void install_pattern_rule PARAMS ((struct pspec *p, int terminal)); extern int new_pattern_rule PARAMS ((struct rule *rule, int override)); -extern struct pattern_var *create_pattern_var PARAMS ((char *target, char *suffix)); -extern struct pattern_var *lookup_pattern_var PARAMS ((char *target)); extern void count_implicit_rule_limits PARAMS ((void)); extern void convert_to_pattern PARAMS ((void)); extern void create_pattern_rule PARAMS ((char **targets, diff --git a/src/bin/make/signame.c b/src/bin/make/signame.c index 051d544967..fe7a45f937 100644 --- a/src/bin/make/signame.c +++ b/src/bin/make/signame.c @@ -1,33 +1,31 @@ /* Convert between signal names and numbers. -Copyright (C) 1990,92,93,95,96,99, 2002 Free Software Foundation, Inc. -This file was part of the GNU C Library, but is now part of GNU make. +Copyright (C) 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, +2000, 2001, 2002, 2003, 2004, 2005, 2006 Free Software Foundation, Inc. +This file is part of GNU Make. -GNU Make is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 2, or (at your option) -any later version. +GNU Make is free software; you can redistribute it and/or modify it under the +terms of the GNU General Public License as published by the Free Software +Foundation; either version 2, or (at your option) any later version. -GNU Make is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. +GNU Make is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR +A PARTICULAR PURPOSE. See the GNU General Public License for more details. -You should have received a copy of the GNU General Public License -along with GNU Make; see the file COPYING. If not, write to -the Free Software Foundation, Inc., 59 Temple Place - Suite 330, -Boston, MA 02111-1307, USA. */ +You should have received a copy of the GNU General Public License along with +GNU Make; see the file COPYING. If not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. */ #include "make.h" /* If the system provides strsignal, we don't need it. */ -#if !defined(HAVE_STRSIGNAL) +#if !HAVE_STRSIGNAL /* If the system provides sys_siglist, we'll use that. Otherwise create our own. */ -#if !defined(SYS_SIGLIST_DECLARED) +#if !HAVE_DECL_SYS_SIGLIST /* Some systems do not define NSIG in . */ #ifndef NSIG @@ -63,10 +61,7 @@ static int sig_table_nelts = 0; /* Enter signal number NUMBER into the tables with ABBREV and NAME. */ static void -init_sig (number, abbrev, name) - int number; - const char *abbrev; - const char *name; +init_sig (int number, const char *abbrev, const char *name) { /* If this value is ever greater than NSIG it seems like it'd be a bug in the system headers, but... better safe than sorry. We know, for @@ -83,7 +78,7 @@ init_sig (number, abbrev, name) } static int -signame_init () +signame_init (void) { int i; @@ -229,20 +224,25 @@ signame_init () return 1; } -#endif /* SYS_SIGLIST_DECLARED */ +#endif /* HAVE_DECL_SYS_SIGLIST */ char * -strsignal (signal) - int signal; +strsignal (int signal) { static char buf[] = "Signal 12345678901234567890"; -#if !defined(SYS_SIGLIST_DECLARED) +#if ! HAVE_DECL_SYS_SIGLIST +# if HAVE_DECL__SYS_SIGLIST +# define sys_siglist _sys_siglist +# elif HAVE_DECL___SYS_SIGLIST +# define sys_siglist __sys_siglist +# else static char sig_initted = 0; if (!sig_initted) sig_initted = signame_init (); +# endif #endif if (signal > 0 || signal < NSIG) diff --git a/src/bin/make/strcache.c b/src/bin/make/strcache.c new file mode 100644 index 0000000000..6cfae42461 --- /dev/null +++ b/src/bin/make/strcache.c @@ -0,0 +1,216 @@ +/* Constant string caching for GNU Make. +Copyright (C) 2006 Free Software Foundation, Inc. +This file is part of GNU Make. + +GNU Make is free software; you can redistribute it and/or modify it under the +terms of the GNU General Public License as published by the Free Software +Foundation; either version 2, or (at your option) any later version. + +GNU Make is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR +A PARTICULAR PURPOSE. See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License along with +GNU Make; see the file COPYING. If not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. */ + +#include "make.h" + +#include + +#include "hash.h" + +/* The size (in bytes) of each cache buffer. */ +#define CACHE_BUFFER_SIZE (4096) + + +/* A string cached here will never be freed, so we don't need to worry about + reference counting. We just store the string, and then remember it in a + hash so it can be looked up again. */ + +struct strcache { + struct strcache *next; /* The next block of strings. */ + char *end; /* Pointer to the beginning of the free space. */ + int count; /* # of strings in this buffer (for stats). */ + int bytesfree; /* The amount of the buffer that is free. */ + char buffer[1]; /* The buffer comes after this. */ +}; + +static int bufsize = CACHE_BUFFER_SIZE; +static struct strcache *strcache = NULL; + +static struct strcache * +new_cache() +{ + struct strcache *new; + new = (struct strcache *) xmalloc (sizeof (*new) + bufsize); + new->end = new->buffer; + new->count = 0; + new->bytesfree = bufsize; + + new->next = strcache; + strcache = new; + + return new; +} + +static const char * +add_string(const char *str, int len) +{ + struct strcache *best = NULL; + struct strcache *sp; + const char *res; + + /* If the string we want is too large to fit into a single buffer, then we're + screwed; nothing will ever fit! Change the maximum size of the cache to + be big enough. */ + if (len > bufsize) + bufsize = len * 2; + + /* First, find a cache with enough free space. We always look through all + the blocks and choose the one with the best fit (the one that leaves the + least amount of space free). */ + for (sp = strcache; sp != NULL; sp = sp->next) + if (sp->bytesfree > len && (!best || best->bytesfree > sp->bytesfree)) + best = sp; + + /* If nothing is big enough, make a new cache. */ + if (!best) + best = new_cache(); + + assert (best->bytesfree > len); + + /* Add the string to the best cache. */ + res = best->end; + memcpy (best->end, str, len); + best->end += len; + *(best->end++) = '\0'; + best->bytesfree -= len + 1; + ++best->count; + + return res; +} + + +/* Hash table of strings in the cache. */ + +static unsigned long +str_hash_1 (const void *key) +{ + return_ISTRING_HASH_1 ((const char *) key); +} + +static unsigned long +str_hash_2 (const void *key) +{ + return_ISTRING_HASH_2 ((const char *) key); +} + +static int +str_hash_cmp (const void *x, const void *y) +{ + return_ISTRING_COMPARE ((const char *) x, (const char *) y); +} + +static struct hash_table strings; + +static const char * +add_hash (const char *str, int len) +{ + /* Look up the string in the hash. If it's there, return it. */ + char **slot = (char **) hash_find_slot (&strings, str); + const char *key = *slot; + + if (!HASH_VACANT (key)) + return key; + + /* Not there yet so add it to a buffer, then into the hash table. */ + key = add_string (str, len); + hash_insert_at (&strings, key, slot); + return key; +} + +/* Returns true if the string is in the cache; false if not. */ +int +strcache_iscached (const char *str) +{ + struct strcache *sp; + + for (sp = strcache; sp != 0; sp = sp->next) + if (str >= sp->buffer && str < sp->end) + return 1; + + return 0; +} + +/* If the string is already in the cache, return a pointer to the cached + version. If not, add it then return a pointer to the cached version. + Note we do NOT take control of the string passed in. */ +const char * +strcache_add (const char *str) +{ + return add_hash (str, strlen (str)); +} + +const char * +strcache_add_len (const char *str, int len) +{ + char *key = alloca (len + 1); + memcpy (key, str, len); + key[len] = '\0'; + + return add_hash (key, len); +} + +int +strcache_setbufsize(int size) +{ + if (size > bufsize) + bufsize = size; + return bufsize; +} + +void +strcache_init (void) +{ + hash_init (&strings, 1000, str_hash_1, str_hash_2, str_hash_cmp); +} + + +/* Generate some stats output. */ + +void +strcache_print_stats (const char *prefix) +{ + int numbuffs = 0, numstrs = 0; + int totsize = 0, avgsize, maxsize = 0, minsize = bufsize; + int totfree = 0, avgfree, maxfree = 0, minfree = bufsize; + const struct strcache *sp; + + for (sp = strcache; sp != NULL; sp = sp->next) + { + int bf = sp->bytesfree; + int sz = (sp->end - sp->buffer) + bf; + + ++numbuffs; + numstrs += sp->count; + + totsize += sz; + maxsize = (sz > maxsize ? sz : maxsize); + minsize = (sz < minsize ? sz : minsize); + + totfree += bf; + maxfree = (bf > maxfree ? bf : maxfree); + minfree = (bf < minfree ? bf : minfree); + } + + avgsize = numbuffs ? (int)(totsize / numbuffs) : 0; + avgfree = numbuffs ? (int)(totfree / numbuffs) : 0; + + printf (_("\n%s # of strings in strcache: %d\n"), prefix, numstrs); + printf (_("%s # of strcache buffers: %d\n"), prefix, numbuffs); + printf (_("%s strcache size: total = %d / max = %d / min = %d / avg = %d\n"), + prefix, totsize, maxsize, minsize, avgsize); + printf (_("%s strcache free: total = %d / max = %d / min = %d / avg = %d\n"), + prefix, totfree, maxfree, minfree, avgfree); +} diff --git a/src/bin/make/variable.c b/src/bin/make/variable.c index bb8d8108a7..f23f7d12fe 100644 --- a/src/bin/make/variable.c +++ b/src/bin/make/variable.c @@ -1,24 +1,25 @@ /* Internals of variables for GNU Make. -Copyright (C) 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1996, 1997, -2002 Free Software Foundation, Inc. +Copyright (C) 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, +1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006 Free Software +Foundation, Inc. This file is part of GNU Make. -GNU Make is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 2, or (at your option) -any later version. +GNU Make is free software; you can redistribute it and/or modify it under the +terms of the GNU General Public License as published by the Free Software +Foundation; either version 2, or (at your option) any later version. -GNU Make is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. +GNU Make is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR +A PARTICULAR PURPOSE. See the GNU General Public License for more details. -You should have received a copy of the GNU General Public License -along with GNU Make; see the file COPYING. If not, write to -the Free Software Foundation, Inc., 59 Temple Place - Suite 330, -Boston, MA 02111-1307, USA. */ +You should have received a copy of the GNU General Public License along with +GNU Make; see the file COPYING. If not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. */ #include "make.h" + +#include + #include "dep.h" #include "filedef.h" #include "job.h" @@ -30,28 +31,93 @@ Boston, MA 02111-1307, USA. */ #endif #include "hash.h" +/* Chain of all pattern-specific variables. */ + +static struct pattern_var *pattern_vars; + +/* Pointer to last struct in the chain, so we can add onto the end. */ + +static struct pattern_var *last_pattern_var; + +/* Create a new pattern-specific variable struct. */ + +struct pattern_var * +create_pattern_var (char *target, char *suffix) +{ + register struct pattern_var *p + = (struct pattern_var *) xmalloc (sizeof (struct pattern_var)); + + if (last_pattern_var != 0) + last_pattern_var->next = p; + else + pattern_vars = p; + last_pattern_var = p; + p->next = 0; + + p->target = target; + p->len = strlen (target); + p->suffix = suffix + 1; + + return p; +} + +/* Look up a target in the pattern-specific variable list. */ + +static struct pattern_var * +lookup_pattern_var (struct pattern_var *start, char *target) +{ + struct pattern_var *p; + unsigned int targlen = strlen(target); + + for (p = start ? start->next : pattern_vars; p != 0; p = p->next) + { + char *stem; + unsigned int stemlen; + + if (p->len > targlen) + /* It can't possibly match. */ + continue; + + /* From the lengths of the filename and the pattern parts, + find the stem: the part of the filename that matches the %. */ + stem = target + (p->suffix - p->target - 1); + stemlen = targlen - p->len + 1; + + /* Compare the text in the pattern before the stem, if any. */ + if (stem > target && !strneq (p->target, target, stem - target)) + continue; + + /* Compare the text in the pattern after the stem, if any. + We could test simply using streq, but this way we compare the + first two characters immediately. This saves time in the very + common case where the first character matches because it is a + period. */ + if (*p->suffix == stem[stemlen] + && (*p->suffix == '\0' || streq (&p->suffix[1], &stem[stemlen+1]))) + break; + } + + return p; +} + /* Hash table of all global variable definitions. */ static unsigned long -variable_hash_1 (keyv) - const void *keyv; +variable_hash_1 (const void *keyv) { struct variable const *key = (struct variable const *) keyv; return_STRING_N_HASH_1 (key->name, key->length); } static unsigned long -variable_hash_2 (keyv) - const void *keyv; +variable_hash_2 (const void *keyv) { struct variable const *key = (struct variable const *) keyv; return_STRING_N_HASH_2 (key->name, key->length); } static int -variable_hash_cmp (xv, yv) - const void *xv; - const void *yv; +variable_hash_cmp (const void *xv, const void *yv) { struct variable const *x = (struct variable const *) xv; struct variable const *y = (struct variable const *) yv; @@ -79,7 +145,7 @@ struct variable_set_list *current_variable_set_list = &global_setlist; /* Implement variables. */ void -init_hash_global_variable_set () +init_hash_global_variable_set (void) { hash_init (&global_variable_set.table, VARIABLE_BUCKETS, variable_hash_1, variable_hash_2, variable_hash_cmp); @@ -93,14 +159,10 @@ init_hash_global_variable_set () that it should be recursively re-expanded. */ struct variable * -define_variable_in_set (name, length, value, origin, recursive, set, flocp) - const char *name; - unsigned int length; - char *value; - enum variable_origin origin; - int recursive; - struct variable_set *set; - const struct floc *flocp; +define_variable_in_set (const char *name, unsigned int length, + char *value, enum variable_origin origin, + int recursive, struct variable_set *set, + const struct floc *flocp) { struct variable *v; struct variable **var_slot; @@ -155,6 +217,7 @@ define_variable_in_set (name, length, value, origin, recursive, set, flocp) v->fileinfo.filenm = 0; v->origin = origin; v->recursive = recursive; + v->special = 0; v->expanding = 0; v->exp_count = 0; v->per_target = 0; @@ -190,8 +253,7 @@ define_variable_in_set (name, length, value, origin, recursive, set, flocp) #define EXPANSION_INCREMENT(_l) ((((_l) / 500) + 1) * 500) static struct variable * -handle_special_var (var) - struct variable *var; +handle_special_var (struct variable *var) { static unsigned long last_var_count = 0; @@ -275,9 +337,7 @@ handle_special_var (var) on the variable, or nil if no such variable is defined. */ struct variable * -lookup_variable (name, length) - const char *name; - unsigned int length; +lookup_variable (const char *name, unsigned int length) { const struct variable_set_list *setlist; struct variable var_key; @@ -361,10 +421,8 @@ lookup_variable (name, length) on the variable, or nil if no such variable is defined. */ struct variable * -lookup_variable_in_set (name, length, set) - const char *name; - unsigned int length; - const struct variable_set *set; +lookup_variable_in_set (const char *name, unsigned int length, + const struct variable_set *set) { struct variable var_key; @@ -384,11 +442,9 @@ lookup_variable_in_set (name, length, set) since the pattern variable might not have been defined yet. */ void -initialize_file_variables (file, reading) - struct file *file; - int reading; +initialize_file_variables (struct file *file, int reading) { - register struct variable_set_list *l = file->variables; + struct variable_set_list *l = file->variables; if (l == 0) { @@ -420,21 +476,55 @@ initialize_file_variables (file, reading) } /* If we're not reading makefiles and we haven't looked yet, see if - we can find a pattern variable. */ + we can find pattern variables for this target. */ if (!reading && !file->pat_searched) { - struct pattern_var *p = lookup_pattern_var (file->name); + struct pattern_var *p; - file->pat_searched = 1; + p = lookup_pattern_var (0, file->name); if (p != 0) { - /* If we found one, insert it between the current target's - variables and the next set, whatever it is. */ - file->pat_variables = (struct variable_set_list *) - xmalloc (sizeof (struct variable_set_list)); - file->pat_variables->set = p->vars->set; + struct variable_set_list *global = current_variable_set_list; + + /* We found at least one. Set up a new variable set to accumulate + all the pattern variables that match this target. */ + + file->pat_variables = create_new_variable_set (); + current_variable_set_list = file->pat_variables; + + do + { + /* We found one, so insert it into the set. */ + + struct variable *v; + + if (p->variable.flavor == f_simple) + { + v = define_variable_loc ( + p->variable.name, strlen (p->variable.name), + p->variable.value, p->variable.origin, + 0, &p->variable.fileinfo); + + v->flavor = f_simple; + } + else + { + v = do_variable_definition ( + &p->variable.fileinfo, p->variable.name, + p->variable.value, p->variable.origin, + p->variable.flavor, 1); + } + + /* Also mark it as a per-target and copy export status. */ + v->per_target = p->variable.per_target; + v->export = p->variable.export; + } + while ((p = lookup_pattern_var (p, file->name)) != 0); + + current_variable_set_list = global; } + file->pat_searched = 1; } /* If we have a pattern variable match, set it up. */ @@ -449,32 +539,8 @@ initialize_file_variables (file, reading) /* Pop the top set off the current variable set list, and free all its storage. */ -static void -free_variable_name_and_value (item) - void *item; -{ - struct variable *v = (struct variable *) item; - free (v->name); - free (v->value); -} - -void -pop_variable_scope () -{ - struct variable_set_list *setlist = current_variable_set_list; - struct variable_set *set = setlist->set; - - current_variable_set_list = setlist->next; - free ((char *) setlist); - - hash_map (&set->table, free_variable_name_and_value); - hash_free (&set->table, 1); - - free ((char *) set); -} - struct variable_set_list * -create_new_variable_set () +create_new_variable_set (void) { register struct variable_set_list *setlist; register struct variable_set *set; @@ -491,19 +557,87 @@ create_new_variable_set () return setlist; } -/* Create a new variable set and push it on the current setlist. */ +static void +free_variable_name_and_value (const void *item) +{ + struct variable *v = (struct variable *) item; + free (v->name); + free (v->value); +} + +void +free_variable_set (struct variable_set_list *list) +{ + hash_map (&list->set->table, free_variable_name_and_value); + hash_free (&list->set->table, 1); + free ((char *) list->set); + free ((char *) list); +} + +/* Create a new variable set and push it on the current setlist. + If we're pushing a global scope (that is, the current scope is the global + scope) then we need to "push" it the other way: file variable sets point + directly to the global_setlist so we need to replace that with the new one. + */ struct variable_set_list * -push_new_variable_scope () +push_new_variable_scope (void) { - return (current_variable_set_list = create_new_variable_set()); + current_variable_set_list = create_new_variable_set(); + if (current_variable_set_list->next == &global_setlist) + { + /* It was the global, so instead of new -> &global we want to replace + &global with the new one and have &global -> new, with current still + pointing to &global */ + struct variable_set *set = current_variable_set_list->set; + current_variable_set_list->set = global_setlist.set; + global_setlist.set = set; + current_variable_set_list->next = global_setlist.next; + global_setlist.next = current_variable_set_list; + current_variable_set_list = &global_setlist; + } + return (current_variable_set_list); +} + +void +pop_variable_scope (void) +{ + struct variable_set_list *setlist; + struct variable_set *set; + + /* Can't call this if there's no scope to pop! */ + assert(current_variable_set_list->next != NULL); + + if (current_variable_set_list != &global_setlist) + { + /* We're not pointing to the global setlist, so pop this one. */ + setlist = current_variable_set_list; + set = setlist->set; + current_variable_set_list = setlist->next; + } + else + { + /* This set is the one in the global_setlist, but there is another global + set beyond that. We want to copy that set to global_setlist, then + delete what used to be in global_setlist. */ + setlist = global_setlist.next; + set = global_setlist.set; + global_setlist.set = setlist->set; + global_setlist.next = setlist->next; + } + + /* Free the one we no longer need. */ + free ((char *) setlist); + hash_map (&set->table, free_variable_name_and_value); + hash_free (&set->table, 1); + free ((char *) set); } -/* Merge SET1 into SET0, freeing unused storage in SET1. */ +/* Merge FROM_SET into TO_SET, freeing unused storage in FROM_SET. */ static void -merge_variable_sets (to_set, from_set) - struct variable_set *to_set, *from_set; +merge_variable_sets (struct variable_set *to_set, + struct variable_set *from_set) { struct variable **from_var_slot = (struct variable **) from_set->table.ht_vec; struct variable **from_var_end = from_var_slot + from_set->table.ht_size; @@ -528,24 +662,31 @@ merge_variable_sets (to_set, from_set) /* Merge SETLIST1 into SETLIST0, freeing unused storage in SETLIST1. */ void -merge_variable_set_lists (setlist0, setlist1) - struct variable_set_list **setlist0, *setlist1; +merge_variable_set_lists (struct variable_set_list **setlist0, + struct variable_set_list *setlist1) { - register struct variable_set_list *list0 = *setlist0; + struct variable_set_list *to = *setlist0; struct variable_set_list *last0 = 0; - while (setlist1 != 0 && list0 != 0) - { - struct variable_set_list *next = setlist1; - setlist1 = setlist1->next; + /* If there's nothing to merge, stop now. */ + if (!setlist1) + return; - merge_variable_sets (list0->set, next->set); + /* This loop relies on the fact that all setlists terminate with the global + setlist (before NULL). If that's not true, arguably we SHOULD die. */ + if (to) + while (setlist1 != &global_setlist && to != &global_setlist) + { + struct variable_set_list *from = setlist1; + setlist1 = setlist1->next; - last0 = list0; - list0 = list0->next; - } + merge_variable_sets (to->set, from->set); - if (setlist1 != 0) + last0 = to; + to = to->next; + } + + if (setlist1 != &global_setlist) { if (last0 == 0) *setlist0 = setlist1; @@ -558,9 +699,9 @@ merge_variable_set_lists (setlist0, setlist1) of their structures so we can change their values quickly. */ void -define_automatic_variables () +define_automatic_variables (void) { -#ifdef WINDOWS32 +#if defined(WINDOWS32) || defined(__EMX__) extern char* default_shell; #else extern char default_shell[]; @@ -601,17 +742,65 @@ define_automatic_variables () (void) define_variable (shell_str, shlen, comp->value, o_env, 0); } } +#elif defined(__EMX__) + { + static char shell_str[] = "SHELL"; + const int shlen = sizeof (shell_str) - 1; + struct variable *shell = lookup_variable (shell_str, shlen); + struct variable *replace = lookup_variable ("MAKESHELL", 9); + + /* if $MAKESHELL is defined in the environment assume o_env_override */ + if (replace && *replace->value && replace->origin == o_env) + replace->origin = o_env_override; + + /* if $MAKESHELL is not defined use $SHELL but only if the variable + did not come from the environment */ + if (!replace || !*replace->value) + if (shell && *shell->value && (shell->origin == o_env + || shell->origin == o_env_override)) + { + /* overwrite whatever we got from the environment */ + free(shell->value); + shell->value = xstrdup (default_shell); + shell->origin = o_default; + } + + /* Some people do not like cmd to be used as the default + if $SHELL is not defined in the Makefile. + With -DNO_CMD_DEFAULT you can turn off this behaviour */ +# ifndef NO_CMD_DEFAULT + /* otherwise use $COMSPEC */ + if (!replace || !*replace->value) + replace = lookup_variable ("COMSPEC", 7); + + /* otherwise use $OS2_SHELL */ + if (!replace || !*replace->value) + replace = lookup_variable ("OS2_SHELL", 9); +# else +# warning NO_CMD_DEFAULT: GNU make will not use CMD.EXE as default shell +# endif + + if (replace && *replace->value) + /* overwrite $SHELL */ + (void) define_variable (shell_str, shlen, replace->value, + replace->origin, 0); + else + /* provide a definition if there is none */ + (void) define_variable (shell_str, shlen, default_shell, + o_default, 0); + } + #endif - /* This won't override any definition, but it - will provide one if there isn't one there. */ + /* This won't override any definition, but it will provide one if there + isn't one there. */ v = define_variable ("SHELL", 5, default_shell, o_default, 0); - v->export = v_export; /* Always export SHELL. */ - /* On MSDOS we do use SHELL from environment, since - it isn't a standard environment variable on MSDOS, - so whoever sets it, does that on purpose. */ -#ifndef __MSDOS__ + /* On MSDOS we do use SHELL from environment, since it isn't a standard + environment variable on MSDOS, so whoever sets it, does that on purpose. + On OS/2 we do not use SHELL from environment but we have already handled + that problem above. */ +#if !defined(__MSDOS__) && !defined(__EMX__) /* Don't let SHELL come from the environment. */ if (*v->value == '\0' || v->origin == o_env || v->origin == o_env_override) { @@ -661,8 +850,7 @@ int export_all_variables; The child's MAKELEVEL variable is incremented. */ char ** -target_environment (file) - struct file *file; +target_environment (struct file *file) { struct variable_set_list *set_list; register struct variable_set_list *s; @@ -728,7 +916,15 @@ target_environment (file) break; case v_noexport: - continue; + /* If this is the SHELL variable and it's not exported, then + add the value from our original environment. */ + if (streq (v->name, "SHELL")) + { + extern struct variable shell_var; + v = &shell_var; + break; + } + continue; case v_ifset: if (v->origin == o_default) @@ -794,17 +990,14 @@ target_environment (file) See the try_variable_definition() function for details on the parameters. */ struct variable * -do_variable_definition (flocp, varname, value, origin, flavor, target_var) - const struct floc *flocp; - const char *varname; - char *value; - enum variable_origin origin; - enum variable_flavor flavor; - int target_var; +do_variable_definition (const struct floc *flocp, const char *varname, + char *value, enum variable_origin origin, + enum variable_flavor flavor, int target_var) { char *p, *alloc_value = NULL; struct variable *v; int append = 0; + int conditional = 0; /* Calculate the variable's new value in VALUE. */ @@ -828,6 +1021,7 @@ do_variable_definition (flocp, varname, value, origin, flavor, target_var) if (v) return v; + conditional = 1; flavor = f_recursive; /* FALLTHROUGH */ case f_recursive: @@ -844,6 +1038,11 @@ do_variable_definition (flocp, varname, value, origin, flavor, target_var) append = 1; v = lookup_variable_in_set (varname, strlen (varname), current_variable_set_list->set); + + /* Don't append from the global set if a previous non-appending + target-specific variable definition exists. */ + if (v && !v->append) + append = 0; } else v = lookup_variable (varname, strlen (varname)); @@ -902,7 +1101,7 @@ do_variable_definition (flocp, varname, value, origin, flavor, target_var) 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. */ @@ -969,7 +1168,8 @@ do_variable_definition (flocp, varname, value, origin, flavor, target_var) else #endif /* __MSDOS__ */ #ifdef WINDOWS32 - if ((origin == o_file || origin == o_override) && streq (varname, "SHELL")) + if ((origin == o_file || origin == o_override || origin == o_command) + && streq (varname, "SHELL")) { extern char *default_shell; @@ -1005,6 +1205,7 @@ do_variable_definition (flocp, varname, value, origin, flavor, target_var) ? current_variable_set_list->set : NULL), flocp); v->append = append; + v->conditional = conditional; if (alloc_value) free (alloc_value); @@ -1026,19 +1227,14 @@ do_variable_definition (flocp, varname, value, origin, flavor, target_var) returned. */ struct variable * -try_variable_definition (flocp, line, origin, target_var) - const struct floc *flocp; - char *line; - enum variable_origin origin; - int target_var; +parse_variable_definition (struct variable *v, char *line) { register int c; register char *p = line; register char *beg; register char *end; enum variable_flavor flavor = f_bogus; - char *name, *expanded_name; - struct variable *v; + char *name; while (1) { @@ -1102,36 +1298,69 @@ try_variable_definition (flocp, line, origin, target_var) } } } + v->flavor = flavor; beg = next_token (line); while (end > beg && isblank ((unsigned char)end[-1])) --end; p = next_token (p); + v->value = p; /* Expand the name, so "$(foo)bar = baz" works. */ name = (char *) alloca (end - beg + 1); bcopy (beg, name, end - beg); name[end - beg] = '\0'; - expanded_name = allocated_variable_expand (name); + v->name = allocated_variable_expand (name); - if (expanded_name[0] == '\0') - fatal (flocp, _("empty variable name")); - - v = do_variable_definition (flocp, expanded_name, p, - origin, flavor, target_var); - - free (expanded_name); + if (v->name[0] == '\0') + fatal (&v->fileinfo, _("empty variable name")); return v; } +/* Try to interpret LINE (a null-terminated string) as a variable definition. + + ORIGIN may be o_file, o_override, o_env, o_env_override, + or o_command specifying that the variable definition comes + from a makefile, an override directive, the environment with + or without the -e switch, or the command line. + + See the comments for parse_variable_definition(). + + If LINE was recognized as a variable definition, a pointer to its `struct + variable' is returned. If LINE is not a variable definition, NULL is + returned. */ + +struct variable * +try_variable_definition (const struct floc *flocp, char *line, + enum variable_origin origin, int target_var) +{ + struct variable v; + struct variable *vp; + + if (flocp != 0) + v.fileinfo = *flocp; + else + v.fileinfo.filenm = 0; + + if (!parse_variable_definition (&v, line)) + return 0; + + vp = do_variable_definition (flocp, v.name, v.value, + origin, v.flavor, target_var); + + free (v.name); + + return vp; +} + /* Print information for variable V, prefixing it with PREFIX. */ static void -print_variable (v, prefix) - register struct variable *v; - char *prefix; +print_variable (const void *item, void *arg) { + const struct variable *v = (struct variable *) item; + const char *prefix = (char *) arg; const char *origin; switch (v->origin) @@ -1202,9 +1431,7 @@ print_variable (v, prefix) the actual variable definitions (everything else is comments). */ void -print_variable_set (set, prefix) - register struct variable_set *set; - char *prefix; +print_variable_set (struct variable_set *set, char *prefix) { hash_map_arg (&set->table, print_variable, prefix); @@ -1217,19 +1444,37 @@ print_variable_set (set, prefix) /* Print the data base of variables. */ void -print_variable_data_base () +print_variable_data_base (void) { puts (_("\n# Variables\n")); print_variable_set (&global_variable_set, ""); + + puts (_("\n# Pattern-specific Variable Values")); + + { + struct pattern_var *p; + int rules = 0; + + for (p = pattern_vars; p != 0; p = p->next) + { + ++rules; + printf ("\n%s :\n", p->target); + print_variable (&p->variable, "# "); + } + + if (rules == 0) + puts (_("\n# No pattern-specific variable values.")); + else + printf (_("\n# %u pattern-specific variable values"), rules); + } } /* Print all the local variables of FILE. */ void -print_file_variables (file) - struct file *file; +print_file_variables (struct file *file) { if (file->variables != 0) print_variable_set (file->variables->set, "# "); @@ -1237,27 +1482,27 @@ print_file_variables (file) #ifdef WINDOWS32 void -sync_Path_environment(void) +sync_Path_environment (void) { - char* path = allocated_variable_expand("$(Path)"); - static char* environ_path = NULL; + char *path = allocated_variable_expand ("$(PATH)"); + static char *environ_path = NULL; - if (!path) - return; + if (!path) + return; - /* - * If done this before, don't leak memory unnecessarily. - * Free the previous entry before allocating new one. - */ - if (environ_path) - free(environ_path); + /* + * If done this before, don't leak memory unnecessarily. + * Free the previous entry before allocating new one. + */ + if (environ_path) + free (environ_path); - /* - * Create something WINDOWS32 world can grok - */ - convert_Path_to_windows32(path, ';'); - environ_path = concat("Path", "=", path); - putenv(environ_path); - free(path); + /* + * Create something WINDOWS32 world can grok + */ + convert_Path_to_windows32 (path, ';'); + environ_path = concat ("PATH", "=", path); + putenv (environ_path); + free (path); } #endif diff --git a/src/bin/make/variable.h b/src/bin/make/variable.h index d9cd7f7c7d..46b18fad94 100644 --- a/src/bin/make/variable.h +++ b/src/bin/make/variable.h @@ -1,21 +1,20 @@ /* Definitions for using variables in GNU Make. -Copyright (C) 1988, 1989, 1990, 1991, 1992, 2002 Free Software Foundation, Inc. +Copyright (C) 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, +1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006 Free Software +Foundation, Inc. This file is part of GNU Make. -GNU Make is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 2, or (at your option) -any later version. +GNU Make is free software; you can redistribute it and/or modify it under the +terms of the GNU General Public License as published by the Free Software +Foundation; either version 2, or (at your option) any later version. -GNU Make is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. +GNU Make is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR +A PARTICULAR PURPOSE. See the GNU General Public License for more details. -You should have received a copy of the GNU General Public License -along with GNU Make; see the file COPYING. If not, write to -the Free Software Foundation, Inc., 59 Temple Place - Suite 330, -Boston, MA 02111-1307, USA. */ +You should have received a copy of the GNU General Public License along with +GNU Make; see the file COPYING. If not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. */ #include "hash.h" @@ -47,7 +46,6 @@ enum variable_flavor chained through `next'. */ #define EXP_COUNT_BITS 15 /* This gets all the bitfields into 32 bits */ - #define EXP_COUNT_MAX ((1<1, allow this many self-referential expansions. */ - + enum variable_flavor + flavor ENUM_BITFIELD (3); /* Variable flavor. */ enum variable_origin origin ENUM_BITFIELD (3); /* Variable origin. */ - - unsigned int exportable:1; /* Nonzero if the variable _could_ be - exported. */ enum variable_export { v_export, /* Export this variable. */ @@ -95,24 +94,38 @@ struct variable_set_list struct variable_set *set; /* Variable set. */ }; +/* Structure used for pattern-specific variables. */ + +struct pattern_var + { + struct pattern_var *next; + char *target; + unsigned int len; + char *suffix; + struct variable variable; + }; + extern char *variable_buffer; extern struct variable_set_list *current_variable_set_list; /* expand.c */ extern char *variable_buffer_output PARAMS ((char *ptr, char *string, unsigned int length)); extern char *variable_expand PARAMS ((char *line)); +extern char *variable_expand_for_file PARAMS ((char *line, struct file *file)); extern char *allocated_variable_expand_for_file PARAMS ((char *line, struct file *file)); #define allocated_variable_expand(line) \ allocated_variable_expand_for_file (line, (struct file *) 0) -extern char *expand_argument PARAMS ((char *str, char *end)); +extern char *expand_argument PARAMS ((const char *str, const char *end)); extern char *variable_expand_string PARAMS ((char *line, char *string, long length)); +extern void install_variable_buffer PARAMS ((char **bufp, unsigned int *lenp)); +extern void restore_variable_buffer PARAMS ((char *buf, unsigned int len)); /* function.c */ extern int handle_function PARAMS ((char **op, char **stringp)); extern int pattern_matches PARAMS ((char *pattern, char *percent, char *str)); extern char *subst_expand PARAMS ((char *o, char *text, char *subst, char *replace, - unsigned int slen, unsigned int rlen, int by_word, int suffix_only)); + unsigned int slen, unsigned int rlen, int by_word)); extern char *patsubst_expand PARAMS ((char *o, char *text, char *pattern, char *replace, char *pattern_percent, char *replace_percent)); @@ -123,14 +136,16 @@ extern char *recursively_expand_for_file PARAMS ((struct variable *v, /* variable.c */ extern struct variable_set_list *create_new_variable_set PARAMS ((void)); +extern void free_variable_set PARAMS ((struct variable_set_list *)); extern struct variable_set_list *push_new_variable_scope PARAMS ((void)); extern void pop_variable_scope PARAMS ((void)); extern void define_automatic_variables PARAMS ((void)); extern void initialize_file_variables PARAMS ((struct file *file, int read)); extern void print_file_variables PARAMS ((struct file *file)); extern void print_variable_set PARAMS ((struct variable_set *set, char *prefix)); -extern void merge_variable_set_lists PARAMS ((struct variable_set_list **setlist0, struct variable_set_list *setlist1)); +extern void merge_variable_set_lists PARAMS ((struct variable_set_list **to_list, struct variable_set_list *from_list)); extern struct variable *do_variable_definition PARAMS ((const struct floc *flocp, const char *name, char *value, enum variable_origin origin, enum variable_flavor flavor, int target_var)); +extern struct variable *parse_variable_definition PARAMS ((struct variable *v, char *line)); extern struct variable *try_variable_definition PARAMS ((const struct floc *flocp, char *line, enum variable_origin origin, int target_var)); extern void init_hash_global_variable_set PARAMS ((void)); extern void hash_init_function_table PARAMS ((void)); @@ -177,6 +192,8 @@ extern struct variable *define_variable_in_set extern char **target_environment PARAMS ((struct file *file)); +extern struct pattern_var *create_pattern_var PARAMS ((char *target, char *suffix)); + extern int export_all_variables; #define MAKELEVEL_NAME "MAKELEVEL" diff --git a/src/bin/make/version.c b/src/bin/make/version.c index 1918b6f7b8..7e718f8719 100644 --- a/src/bin/make/version.c +++ b/src/bin/make/version.c @@ -1,3 +1,21 @@ +/* Record version and build host architecture for GNU make. +Copyright (C) 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, +1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006 Free Software +Foundation, Inc. +This file is part of GNU Make. + +GNU Make is free software; you can redistribute it and/or modify it under the +terms of the GNU General Public License as published by the Free Software +Foundation; either version 2, or (at your option) any later version. + +GNU Make is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR +A PARTICULAR PURPOSE. See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License along with +GNU Make; see the file COPYING. If not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. */ + /* We use instead of "config.h" so that a compilation using -I. -I$srcdir will use ./config.h rather than $srcdir/config.h (which it would do because make.h was found in $srcdir). */ diff --git a/src/bin/make/vpath.c b/src/bin/make/vpath.c index 065779bea1..0945240383 100644 --- a/src/bin/make/vpath.c +++ b/src/bin/make/vpath.c @@ -1,21 +1,20 @@ /* Implementation of pattern-matching file search paths for GNU Make. -Copyright (C) 1988,89,91,92,93,94,95,96,97 Free Software Foundation, Inc. +Copyright (C) 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, +1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006 Free Software +Foundation, Inc. This file is part of GNU Make. -GNU Make is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 2, or (at your option) -any later version. +GNU Make is free software; you can redistribute it and/or modify it under the +terms of the GNU General Public License as published by the Free Software +Foundation; either version 2, or (at your option) any later version. -GNU Make is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. +GNU Make is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR +A PARTICULAR PURPOSE. See the GNU General Public License for more details. -You should have received a copy of the GNU General Public License -along with GNU Make; see the file COPYING. If not, write to -the Free Software Foundation, Inc., 59 Temple Place - Suite 330, -Boston, MA 02111-1307, USA. */ +You should have received a copy of the GNU General Public License along with +GNU Make; see the file COPYING. If not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. */ #include "make.h" #include "filedef.h" @@ -157,8 +156,7 @@ build_vpath_lists () VPATHS chain. */ void -construct_vpath_list (pattern, dirpath) - char *pattern, *dirpath; +construct_vpath_list (char *pattern, char *dirpath) { register unsigned int elem; register char *p; @@ -248,7 +246,7 @@ construct_vpath_list (pattern, dirpath) len = p - v; /* Make sure there's no trailing slash, but still allow "/" as a directory. */ -#ifdef __MSDOS__ +#if defined(__MSDOS__) || defined(__EMX__) /* We need also to leave alone a trailing slash in "d:/". */ if (len > 3 || (len > 1 && v[1] != ':')) #endif @@ -317,11 +315,9 @@ construct_vpath_list (pattern, dirpath) in. If it is found, return 1. Otherwise we return 0. */ int -gpath_search (file, len) - char *file; - int len; +gpath_search (char *file, unsigned int len) { - register char **gp; + char **gp; if (gpaths && (len <= gpaths->maxlen)) for (gp = gpaths->searchpath; *gp != NULL; ++gp) @@ -338,9 +334,7 @@ gpath_search (file, len) Otherwise we return 0. */ int -vpath_search (file, mtime_ptr) - char **file; - FILE_TIMESTAMP *mtime_ptr; +vpath_search (char **file, FILE_TIMESTAMP *mtime_ptr) { register struct vpath *v; @@ -375,10 +369,8 @@ vpath_search (file, mtime_ptr) Otherwise we return 0. */ static int -selective_vpath_search (path, file, mtime_ptr) - struct vpath *path; - char **file; - FILE_TIMESTAMP *mtime_ptr; +selective_vpath_search (struct vpath *path, char **file, + FILE_TIMESTAMP *mtime_ptr) { int not_target; char *name, *n; @@ -473,11 +465,27 @@ selective_vpath_search (path, file, mtime_ptr) In December 1993 I loosened this restriction to allow a file to be chosen if it is mentioned as a target in a makefile. This - seem logical. */ + seem logical. + + Special handling for -W / -o: make sure we preserve the special + values here. Actually this whole thing is a little bogus: I think + we should ditch the name/hname thing and look into the renamed + capability that already exists for files: that is, have a new struct + file* entry for the VPATH-found file, and set the renamed field if + we use it. + */ { struct file *f = lookup_file (name); if (f != 0) - exists = not_target || f->is_target; + { + exists = not_target || f->is_target; + if (exists && mtime_ptr + && (f->last_mtime == OLD_MTIME || f->last_mtime == NEW_MTIME)) + { + *mtime_ptr = f->last_mtime; + mtime_ptr = 0; + } + } } if (!exists) @@ -514,27 +522,37 @@ selective_vpath_search (path, file, mtime_ptr) *n = '/'; #endif - if (!exists_in_cache /* Makefile-mentioned file need not exist. */ - || stat (name, &st) == 0) /* Does it really exist? */ + if (exists_in_cache) /* Makefile-mentioned file need not exist. */ { - /* We have found a file. - Store the name we found into *FILE for the caller. */ + int e; - *file = savestring (name, (n + 1 - name) + flen); + EINTRLOOP (e, stat (name, &st)); /* Does it really exist? */ + if (e != 0) + { + exists = 0; + continue; + } - if (mtime_ptr != 0) - /* Store the modtime into *MTIME_PTR for the caller. - If we have had no need to stat the file here, - we record UNKNOWN_MTIME to indicate this. */ - *mtime_ptr = (exists_in_cache - ? FILE_TIMESTAMP_STAT_MODTIME (name, st) - : UNKNOWN_MTIME); + /* Store the modtime into *MTIME_PTR for the caller. */ + if (mtime_ptr != 0) + { + *mtime_ptr = FILE_TIMESTAMP_STAT_MODTIME (name, st); + mtime_ptr = 0; + } + } - free (name); - return 1; - } - else - exists = 0; + /* We have found a file. + Store the name we found into *FILE for the caller. */ + + *file = savestring (name, (n + 1 - name) + flen); + + /* If we get here and mtime_ptr hasn't been set, record + UNKNOWN_MTIME to indicate this. */ + if (mtime_ptr != 0) + *mtime_ptr = UNKNOWN_MTIME; + + free (name); + return 1; } } @@ -545,7 +563,7 @@ selective_vpath_search (path, file, mtime_ptr) /* Print the data base of VPATH search paths. */ void -print_vpath_data_base () +print_vpath_data_base (void) { register unsigned int nvpaths; register struct vpath *v;