OSDN Git Service

* combine.c (make_extraction, force_to_mode): Avoid warning on
[pf3gnuchains/gcc-fork.git] / gcc / gcc.c
index 89bae33..6ad53f0 100644 (file)
--- a/gcc/gcc.c
+++ b/gcc/gcc.c
@@ -1,5 +1,5 @@
 /* Compiler driver program that can handle many languages.
-   Copyright (C) 1987, 89, 92-98, 1999 Free Software Foundation, Inc.
+   Copyright (C) 1987, 89, 92-99, 2000 Free Software Foundation, Inc.
 
 This file is part of GNU CC.
 
@@ -48,7 +48,7 @@ compilation is specified by a string called a "spec".  */
 #include <sys/resource.h>
 #endif
 #ifdef NEED_DECLARATION_GETRUSAGE
-extern int getrusage(int, struct rusage *);
+extern int getrusage PARAMS ((int, struct rusage *));
 #endif
 
 /* By default there is no special suffix for executables.  */
@@ -65,22 +65,13 @@ extern int getrusage(int, struct rusage *);
 #define OBJECT_SUFFIX ".o"
 #endif
 
-/* By default, colon separates directories in a path.  */
-#ifndef PATH_SEPARATOR
-#define PATH_SEPARATOR ':'
-#endif
-
-#ifndef DIR_SEPARATOR
-#define DIR_SEPARATOR '/'
-#endif
-
-/* Define IS_DIR_SEPARATOR.  */
-#ifndef DIR_SEPARATOR_2
-# define IS_DIR_SEPARATOR(ch) ((ch) == DIR_SEPARATOR)
-#else /* DIR_SEPARATOR_2 */
-# define IS_DIR_SEPARATOR(ch) \
-       (((ch) == DIR_SEPARATOR) || ((ch) == DIR_SEPARATOR_2))
-#endif /* DIR_SEPARATOR_2 */
+#ifndef VMS
+/* FIXME: the location independence code for VMS is hairier than this,
+   and hasn't been written.  */
+#ifndef DIR_UP
+#define DIR_UP ".."
+#endif /* DIR_UP */
+#endif /* VMS */
 
 static char dir_separator_str[] = {DIR_SEPARATOR, 0};
 
@@ -91,6 +82,11 @@ static char dir_separator_str[] = {DIR_SEPARATOR, 0};
 #define GET_ENV_PATH_LIST(VAR,NAME)    do { (VAR) = getenv (NAME); } while (0)
 #endif
 
+/* Most every one is fine with LIBRARY_PATH.  For some, it conflicts.  */
+#ifndef LIBRARY_PATH_ENV
+#define LIBRARY_PATH_ENV "LIBRARY_PATH"
+#endif
+
 #ifndef HAVE_KILL
 #define kill(p,s) raise(s)
 #endif
@@ -100,6 +96,10 @@ static char dir_separator_str[] = {DIR_SEPARATOR, 0};
 
 #define MIN_FATAL_STATUS 1
 
+/* Flag saying to pass the greatest exit code returned by a sub-process
+   to the calling program.  */
+static int pass_exit_codes;
+
 /* Flag saying to print the directories gcc will search through looking for
    programs, libraries, etc.  */
 
@@ -168,6 +168,10 @@ static char *cross_compile = "0";
    run if this is non-zero.  */
 static int error_count = 0;
 
+/* Greatest exit code of sub-processes that has been encountered up to
+   now.  */
+static int greatest_status = 1;
+
 /* This is the obstack which we use to allocate many strings.  */
 
 static struct obstack obstack;
@@ -190,52 +194,58 @@ extern char *version_string;
 /* Forward declaration for prototypes.  */
 struct path_prefix;
 
-static void init_spec          PROTO((void));
-static void read_specs         PROTO((const char *, int));
-static void set_spec           PROTO((const char *, const char *));
-static struct compiler *lookup_compiler PROTO((const char *, size_t, const char *));
-static char *build_search_list PROTO((struct path_prefix *, const char *, int));
-static void putenv_from_prefixes PROTO((struct path_prefix *, const char *));
-static int access_check                PROTO((const char *, int));
-static char *find_a_file       PROTO((struct path_prefix *, const char *, int));
-static void add_prefix         PROTO((struct path_prefix *, const char *,
-                                      const char *, int, int, int *));
-static char *skip_whitespace   PROTO((char *));
-static void record_temp_file   PROTO((const char *, int, int));
-static void delete_if_ordinary PROTO((const char *));
-static void delete_temp_files  PROTO((void));
-static void delete_failure_queue PROTO((void));
-static void clear_failure_queue PROTO((void));
-static int check_live_switch   PROTO((int, int));
-static const char *handle_braces PROTO((const char *));
-static char *save_string       PROTO((const char *, int));
-static int do_spec_1           PROTO((const char *, int, const char *));
-static const char *find_file   PROTO((const char *));
-static int is_directory                PROTO((const char *, const char *, int));
-static void validate_switches  PROTO((const char *));
-static void validate_all_switches PROTO((void));
-static void give_switch                PROTO((int, int, int));
-static int used_arg            PROTO((const char *, int));
-static int default_arg         PROTO((const char *, int));
-static void set_multilib_dir   PROTO((void));
-static void print_multilib_info        PROTO((void));
-static void pfatal_with_name   PROTO((const char *)) ATTRIBUTE_NORETURN;
-static void perror_with_name   PROTO((const char *));
-static void pfatal_pexecute    PROTO((const char *, const char *))
+static void init_spec          PARAMS ((void));
+#ifndef VMS
+static char **split_directories        PARAMS ((const char *, int *));
+static void free_split_directories PARAMS ((char **));
+static char *make_relative_prefix PARAMS ((const char *, const char *, const char *));
+#endif /* VMS */
+static void read_specs         PARAMS ((const char *, int));
+static void set_spec           PARAMS ((const char *, const char *));
+static struct compiler *lookup_compiler PARAMS ((const char *, size_t, const char *));
+static char *build_search_list PARAMS ((struct path_prefix *, const char *, int));
+static void putenv_from_prefixes PARAMS ((struct path_prefix *, const char *));
+static int access_check                PARAMS ((const char *, int));
+static char *find_a_file       PARAMS ((struct path_prefix *, const char *, int));
+static void add_prefix         PARAMS ((struct path_prefix *, const char *,
+                                        const char *, int, int, int *));
+static char *skip_whitespace   PARAMS ((char *));
+static void record_temp_file   PARAMS ((const char *, int, int));
+static void delete_if_ordinary PARAMS ((const char *));
+static void delete_temp_files  PARAMS ((void));
+static void delete_failure_queue PARAMS ((void));
+static void clear_failure_queue PARAMS ((void));
+static int check_live_switch   PARAMS ((int, int));
+static const char *handle_braces PARAMS ((const char *));
+static char *save_string       PARAMS ((const char *, int));
+static int do_spec_1           PARAMS ((const char *, int, const char *));
+static const char *find_file   PARAMS ((const char *));
+static int is_directory                PARAMS ((const char *, const char *, int));
+static void validate_switches  PARAMS ((const char *));
+static void validate_all_switches PARAMS ((void));
+static void give_switch                PARAMS ((int, int, int));
+static int used_arg            PARAMS ((const char *, int));
+static int default_arg         PARAMS ((const char *, int));
+static void set_multilib_dir   PARAMS ((void));
+static void print_multilib_info        PARAMS ((void));
+static void pfatal_with_name   PARAMS ((const char *)) ATTRIBUTE_NORETURN;
+static void perror_with_name   PARAMS ((const char *));
+static void pfatal_pexecute    PARAMS ((const char *, const char *))
   ATTRIBUTE_NORETURN;
-static void error              PVPROTO((const char *, ...))
+static void error              PARAMS ((const char *, ...))
   ATTRIBUTE_PRINTF_1;
-static void notice             PVPROTO((const char *, ...))
+static void notice             PARAMS ((const char *, ...))
   ATTRIBUTE_PRINTF_1;
-static void display_help       PROTO((void));
-static void add_preprocessor_option    PROTO ((const char *, int));
-static void add_assembler_option       PROTO ((const char *, int));
-static void add_linker_option          PROTO ((const char *, int));
-static void process_command            PROTO ((int, char **));
-static int execute                     PROTO ((void));
-static void unused_prefix_warnings     PROTO ((struct path_prefix *));
-static void clear_args                 PROTO ((void));
-static void fatal_error                        PROTO ((int));
+static void display_help       PARAMS ((void));
+static void add_preprocessor_option    PARAMS ((const char *, int));
+static void add_assembler_option       PARAMS ((const char *, int));
+static void add_linker_option          PARAMS ((const char *, int));
+static void process_command            PARAMS ((int, char **));
+static int execute                     PARAMS ((void));
+static void unused_prefix_warnings     PARAMS ((struct path_prefix *));
+static void clear_args                 PARAMS ((void));
+static void fatal_error                        PARAMS ((int));
+static void set_input                  PARAMS ((const char *));
 \f
 /* Specs are strings containing lines, each of which (if not blank)
 is made up of a program name, and arguments separated by spaces.
@@ -262,11 +272,11 @@ or with constant text in a single argument.
        chosen in a way that is hard to predict even when previously
        chosen file names are known.  For example, `%g.s ... %g.o ... %g.s'
        might turn into `ccUVUUAU.s ccXYAXZ12.o ccUVUUAU.s'.  SUFFIX matches
-       the regexp "[.A-Za-z]*" or the special string "%O", which is
-       treated exactly as if %O had been pre-processed.  Previously, %g
-       was simply substituted with a file name chosen once per compilation,
-       without regard to any appended suffix (which was therefore treated
-       just like ordinary text), making such attacks more likely to succeed.
+       the regexp "[.A-Za-z]*%O"; "%O" is treated exactly as if it
+       had been pre-processed.  Previously, %g was simply substituted
+       with a file name chosen once per compilation, without regard
+       to any appended suffix (which was therefore treated just like
+       ordinary text), making such attacks more likely to succeed.
  %uSUFFIX
        like %g, but generates a new temporary file name even if %uSUFFIX
        was already seen.
@@ -296,12 +306,13 @@ or with constant text in a single argument.
        at all, but they are included among the output files, so they will
        be linked.
  %O    substitutes the suffix for object files.  Note that this is
-       handled specially when it immediately follows %g, %u, or %U,
-       because of the need for those to form complete file names.  The
-       handling is such that %O is treated exactly as if it had already
-       been substituted, except that %g, %u, and %U do not currently
-       support additional SUFFIX characters following %O as they would
-       following, for example, `.o'.
+        handled specially when it immediately follows %g, %u, or %U
+       (with or without a suffix argument) because of the need for
+       those to form complete file names.  The handling is such that
+       %O is treated exactly as if it had already been substituted,
+       except that %g, %u, and %U do not currently support additional
+       SUFFIX characters following %O as they would following, for
+       example, `.o'.
  %p    substitutes the standard macro predefinitions for the
        current target machine.  Use this when running cpp.
  %P    like %p, but puts `__' before and after the name of each macro.
@@ -606,10 +617,10 @@ static struct compiler default_compilers[] =
        %{C:%{!E:%eGNU C does not support -C without using -E}}\
        %{M} %{MM} %{MD:-MD %b.d} %{MMD:-MMD %b.d} %{MG}\
         %{!no-gcc:-D__GNUC__=%v1 -D__GNUC_MINOR__=%v2}\
-       %{ansi|std=*:%{!std=gnu*:-trigraphs -D__STRICT_ANSI__}}\
        %{!undef:%{!ansi:%{!std=*:%p}%{std=gnu*:%p}} %P} %{trigraphs}\
         %c %{Os:-D__OPTIMIZE_SIZE__} %{O*:%{!O0:-D__OPTIMIZE__}}\
        %{ffast-math:-D__FAST_MATH__}\
+       %{fshort-wchar:-D__WCHAR_TYPE__=short\\ unsigned\\ int}\
         %{traditional} %{ftraditional:-traditional}\
         %{traditional-cpp:-traditional}\
        %{fleading-underscore} %{fno-leading-underscore}\
@@ -620,10 +631,11 @@ static struct compiler default_compilers[] =
                   %{!Q:-quiet} -dumpbase %b.c %{d*} %{m*} %{a*}\
                   %{MD:-MD %b.d} %{MMD:-MMD %b.d} %{MG}\
                   %{!no-gcc:-D__GNUC__=%v1 -D__GNUC_MINOR__=%v2}\
-                 %{ansi|std=*:%{!std=gnu*:-trigraphs -D__STRICT_ANSI__}}\
                  %{!undef:%{!ansi:%{!std=*:%p}%{std=gnu*:%p}} %P} %{trigraphs}\
                   %c %{Os:-D__OPTIMIZE_SIZE__} %{O*:%{!O0:-D__OPTIMIZE__}}\
                  %{ffast-math:-D__FAST_MATH__}\
+                 %{fshort-wchar:-D__WCHAR_TYPE__=short\\ unsigned\\ int}\
+                 %{fshort-wchar:-D__WCHAR_TYPE__=short\\ unsigned\\ int}\
                   %{H} %C %{D*} %{U*} %{i*} %Z\
                   %{ftraditional:-traditional}\
                   %{traditional-cpp:-traditional}\
@@ -642,10 +654,10 @@ static struct compiler default_compilers[] =
        %{C:%{!E:%eGNU C does not support -C without using -E}}\
        %{M} %{MM} %{MD:-MD %b.d} %{MMD:-MMD %b.d} %{MG}\
         %{!no-gcc:-D__GNUC__=%v1 -D__GNUC_MINOR__=%v2}\
-       %{ansi|std=*:%{!std=gnu*:-trigraphs -D__STRICT_ANSI__}}\
        %{!undef:%{!ansi:%{!std=*:%p}%{std=gnu*:%p}} %P} %{trigraphs}\
         %c %{Os:-D__OPTIMIZE_SIZE__} %{O*:%{!O0:-D__OPTIMIZE__}}\
        %{ffast-math:-D__FAST_MATH__}\
+       %{fshort-wchar:-D__WCHAR_TYPE__=short\\ unsigned\\ int}\
         %{traditional} %{ftraditional:-traditional}\
         %{traditional-cpp:-traditional}\
        %{fleading-underscore} %{fno-leading-underscore}\
@@ -670,10 +682,10 @@ static struct compiler default_compilers[] =
        %{C:%{!E:%eGNU C does not support -C without using -E}}\
        %{M} %{MM} %{MD:-MD %b.d} %{MMD:-MMD %b.d} %{MG}\
         %{!no-gcc:-D__GNUC__=%v1 -D__GNUC_MINOR__=%v2}\
-       %{ansi|std=*:%{!std=gnu*:-trigraphs -D__STRICT_ANSI__}}\
        %{!undef:%{!ansi:%{!std=*:%p}%{std=gnu*:%p}} %P} %{trigraphs}\
         %c %{Os:-D__OPTIMIZE_SIZE__} %{O*:%{!O0:-D__OPTIMIZE__}}\
        %{ffast-math:-D__FAST_MATH__}\
+       %{fshort-wchar:-D__WCHAR_TYPE__=short\\ unsigned\\ int}\
         %{traditional} %{ftraditional:-traditional}\
         %{traditional-cpp:-traditional}\
        %{fleading-underscore} %{fno-leading-underscore}\
@@ -687,10 +699,11 @@ static struct compiler default_compilers[] =
        %{C:%{!E:%eGNU C does not support -C without using -E}}\
        %{M} %{MM} %{MD:-MD %b.d} %{MMD:-MMD %b.d} %{MG}\
         %{!no-gcc:-D__GNUC__=%v1 -D__GNUC_MINOR__=%v2}\
-       %{std=*:%{!std=gnu*:-trigraphs -D__STRICT_ANSI__}}\
        %{!undef:%{!std=*:%p}%{std=gnu*:%p} %P} %{trigraphs}\
         %c %{Os:-D__OPTIMIZE_SIZE__} %{O*:%{!O0:-D__OPTIMIZE__}}\
        %{ffast-math:-D__FAST_MATH__}\
+       %{fshort-wchar:-D__WCHAR_TYPE__=short\\ unsigned\\ int}\
+       %{fshort-wchar:-D__WCHAR_TYPE__=short\\ unsigned\\ int}\
         %{traditional} %{ftraditional:-traditional}\
         %{traditional-cpp:-traditional}\
        %{fleading-underscore} %{fno-leading-underscore}\
@@ -720,6 +733,7 @@ static struct compiler default_compilers[] =
         -$ %{!undef:%p %P} -D__ASSEMBLER__ \
         %c %{Os:-D__OPTIMIZE_SIZE__} %{O*:%{!O0:-D__OPTIMIZE__}}\
        %{ffast-math:-D__FAST_MATH__}\
+       %{fshort-wchar:-D__WCHAR_TYPE__=short\\ unsigned\\ int}\
         %{traditional} %{ftraditional:-traditional}\
         %{traditional-cpp:-traditional}\
        %{fleading-underscore} %{fno-leading-underscore}\
@@ -1274,8 +1288,6 @@ static int argbuf_index;
 
 #ifdef MKTEMP_EACH_FILE
 
-extern char *make_temp_file PROTO((const char *));
-
 /* This is the list of suffixes and codes (%g/%u/%U) and the associated
    temp file.  */
 
@@ -1384,6 +1396,11 @@ static const char *standard_startfile_prefix_2 = "/usr/lib/";
 static const char *tooldir_base_prefix = TOOLDIR_BASE_PREFIX;
 static const char *tooldir_prefix;
 
+#ifndef STANDARD_BINDIR_PREFIX
+#define STANDARD_BINDIR_PREFIX "/usr/local/bin"
+#endif
+static char *standard_bindir_prefix = STANDARD_BINDIR_PREFIX;
+
 /* Subdirectory to use for locating libraries.  Set by
    set_multilib_dir based on the compilation options.  */
 
@@ -1881,6 +1898,7 @@ build_search_list (paths, prefix, check_dir_p)
   struct prefix_list *pprefix;
 
   obstack_grow (&collect_obstack, prefix, strlen (prefix));
+  obstack_1grow (&collect_obstack, '=');
 
   for (pprefix = paths->plist; pprefix != 0; pprefix = pprefix->next)
     {
@@ -1937,6 +1955,242 @@ putenv_from_prefixes (paths, env_var)
   putenv (build_search_list (paths, env_var, 1));
 }
 \f
+#ifndef VMS
+
+/* FIXME: the location independence code for VMS is hairier than this,
+   and hasn't been written.  */
+
+/* Split a filename into component directories.  */
+
+static char **
+split_directories (name, ptr_num_dirs)
+     const char *name;
+     int *ptr_num_dirs;
+{
+  int num_dirs = 0;
+  char **dirs;
+  const char *p, *q;
+  int ch;
+
+  /* Count the number of directories.  Special case MSDOS disk names as part
+     of the initial directory.  */
+  p = name;
+#ifdef HAVE_DOS_BASED_FILE_SYSTEM
+  if (name[1] == ':' && IS_DIR_SEPARATOR (name[2]))
+    {
+      p += 3;
+      num_dirs++;
+    }
+#endif /* HAVE_DOS_BASED_FILE_SYSTEM */
+
+  while ((ch = *p++) != '\0')
+    {
+      if (IS_DIR_SEPARATOR (ch))
+       {
+         num_dirs++;
+         while (IS_DIR_SEPARATOR (*p))
+           p++;
+       }
+    }
+
+  dirs = (char **) xmalloc (sizeof (char *) * (num_dirs + 2));
+
+  /* Now copy the directory parts.  */
+  num_dirs = 0;
+  p = name;
+#ifdef HAVE_DOS_BASED_FILE_SYSTEM
+  if (name[1] == ':' && IS_DIR_SEPARATOR (name[2]))
+    {
+      dirs[num_dirs++] = save_string (p, 3);
+      p += 3;
+    }
+#endif /* HAVE_DOS_BASED_FILE_SYSTEM */
+
+  q = p;
+  while ((ch = *p++) != '\0')
+    {
+      if (IS_DIR_SEPARATOR (ch))
+       {
+         while (IS_DIR_SEPARATOR (*p))
+           p++;
+
+         dirs[num_dirs++] = save_string (q, p - q);
+         q = p;
+       }
+    }
+
+  if (p - 1 - q > 0)
+    dirs[num_dirs++] = save_string (q, p - 1 - q);
+
+  dirs[num_dirs] = NULL_PTR;
+  if (ptr_num_dirs)
+    *ptr_num_dirs = num_dirs;
+
+  return dirs;
+}
+
+/* Release storage held by split directories.  */
+
+static void
+free_split_directories (dirs)
+     char **dirs;
+{
+  int i = 0;
+
+  while (dirs[i] != NULL_PTR)
+    free (dirs[i++]);
+
+  free ((char *)dirs);
+}
+
+/* Given three strings PROGNAME, BIN_PREFIX, PREFIX, return a string that gets
+   to PREFIX starting with the directory portion of PROGNAME and a relative
+   pathname of the difference between BIN_PREFIX and PREFIX.
+
+   For example, if BIN_PREFIX is /alpha/beta/gamma/gcc/delta, PREFIX is
+   /alpha/beta/gamma/omega/, and PROGNAME is /red/green/blue/gcc, then this
+   function will return /reg/green/blue/../omega.
+
+   If no relative prefix can be found, return NULL.  */
+
+static char *
+make_relative_prefix (progname, bin_prefix, prefix)
+     const char *progname;
+     const char *bin_prefix;
+     const char *prefix;
+{
+  char **prog_dirs, **bin_dirs, **prefix_dirs;
+  int prog_num, bin_num, prefix_num, std_loc_p;
+  int i, n, common;
+
+  prog_dirs = split_directories (progname, &prog_num);
+  bin_dirs = split_directories (bin_prefix, &bin_num);
+
+  /* If there is no full pathname, try to find the program by checking in each
+     of the directories specified in the PATH environment variable.  */
+  if (prog_num == 1)
+    {
+      char *temp;
+
+      GET_ENV_PATH_LIST (temp, "PATH");
+      if (temp)
+       {
+         char *startp, *endp;
+         char *nstore = (char *) alloca (strlen (temp) + strlen (progname) + 1);
+
+         startp = endp = temp;
+         while (1)
+           {
+             if (*endp == PATH_SEPARATOR || *endp == 0)
+               {
+                 if (endp == startp)
+                   {
+                     nstore[0] = '.';
+                     nstore[1] = DIR_SEPARATOR;
+                     nstore[2] = '\0';
+                   }
+                 else
+                   {
+                     strncpy (nstore, startp, endp-startp);
+                     if (! IS_DIR_SEPARATOR (endp[-1]))
+                       {
+                         nstore[endp-startp] = DIR_SEPARATOR;
+                         nstore[endp-startp+1] = 0;
+                       }
+                     else
+                       nstore[endp-startp] = 0;
+                   }
+                 strcat (nstore, progname);
+                 if (! access (nstore, X_OK)
+#ifdef HAVE_EXECUTABLE_SUFFIX
+                      || ! access (strcat (nstore, EXECUTABLE_SUFFIX), X_OK)
+#endif
+                     )
+                   {
+                     free_split_directories (prog_dirs);
+                     progname = nstore;
+                     prog_dirs = split_directories (progname, &prog_num);
+                     break;
+                   }
+
+                 if (*endp == 0)
+                   break;
+                 endp = startp = endp + 1;
+               }
+             else
+               endp++;
+           }
+       }
+    }
+
+  /* Remove the program name from comparison of directory names.  */
+  prog_num--;
+
+  /* Determine if the compiler is installed in the standard location, and if
+     so, we don't need to specify relative directories.  Also, if argv[0]
+     doesn't contain any directory specifiers, there is not much we can do.  */
+  std_loc_p = 0;
+  if (prog_num == bin_num)
+    {
+      for (i = 0; i < bin_num; i++)
+       {
+         if (strcmp (prog_dirs[i], bin_dirs[i]) != 0)
+           break;
+       }
+
+      if (prog_num <= 0 || i == bin_num)
+       {
+         std_loc_p = 1;
+         free_split_directories (prog_dirs);
+         free_split_directories (bin_dirs);
+         prog_dirs = bin_dirs = (char **)0;
+         return NULL_PTR;
+       }
+    }
+
+  prefix_dirs = split_directories (prefix, &prefix_num);
+
+  /* Find how many directories are in common between bin_prefix & prefix */
+  n = (prefix_num < bin_num) ? prefix_num : bin_num;
+  for (common = 0; common < n; common++)
+    {
+      if (strcmp (bin_dirs[common], prefix_dirs[common]) != 0)
+       break;
+    }
+
+  /* If there are no common directories, there can be no relative prefix.  */
+  if (common == 0)
+    {
+      free_split_directories (prog_dirs);
+      free_split_directories (bin_dirs);
+      free_split_directories (prefix_dirs);
+      return NULL_PTR;
+    }
+
+  /* Build up the pathnames in argv[0].  */
+  for (i = 0; i < prog_num; i++)
+    obstack_grow (&obstack, prog_dirs[i], strlen (prog_dirs[i]));
+
+  /* Now build up the ..'s.  */
+  for (i = common; i < n; i++)
+    {
+      obstack_grow (&obstack, DIR_UP, sizeof (DIR_UP)-1);
+      obstack_1grow (&obstack, DIR_SEPARATOR);
+    }
+
+  /* Put in directories to move over to prefix.  */
+  for (i = common; i < prefix_num; i++)
+    obstack_grow (&obstack, prefix_dirs[i], strlen (prefix_dirs[i]));
+
+  free_split_directories (prog_dirs);
+  free_split_directories (bin_dirs);
+  free_split_directories (prefix_dirs);
+
+  obstack_1grow (&obstack, '\0');
+  return obstack_finish (&obstack);
+}
+#endif /* VMS */
+\f
 /* Check whether NAME can be accessed in MODE.  This is like access,
    except that it never considers directories to be executable.  */
 
@@ -1990,7 +2244,7 @@ find_a_file (pprefix, name, mode)
   /* Determine the filename to execute (special case for absolute paths).  */
 
   if (IS_DIR_SEPARATOR (*name)
-#ifdef HAVE_DOS_BASED_FILESYSTEM
+#ifdef HAVE_DOS_BASED_FILE_SYSTEM
       /* Check for disk name on MS-DOS-based systems.  */
       || (name[0] && name[1] == ':' && IS_DIR_SEPARATOR (name[2]))
 #endif
@@ -2310,7 +2564,7 @@ execute ()
     int ret_code = 0;
 #ifdef HAVE_GETRUSAGE
     struct timeval d;
-    double ut, st;
+    double ut = 0.0, st = 0.0;
 #endif
 
     for (i = 0; i < n_commands; )
@@ -2357,7 +2611,11 @@ execute ()
                    }
                  else if (WIFEXITED (status)
                           && WEXITSTATUS (status) >= MIN_FATAL_STATUS)
-                   ret_code = -1;
+                   {
+                     if (WEXITSTATUS (status) > greatest_status)
+                       greatest_status = WEXITSTATUS (status);
+                     ret_code = -1;
+                   }
                }
 #ifdef HAVE_GETRUSAGE
              if (report_times && ut + st != 0)
@@ -2484,6 +2742,7 @@ display_help ()
   printf ("Usage: %s [options] file...\n", programname);
   printf ("Options:\n");
 
+  printf ("  -pass-exit-codes         Exit with highest error code from a phase\n");
   printf ("  --help                   Display this information\n");
   if (! verbose_flag)
     printf ("  (Use '-v --help' to display command line options of sub-processes)\n");
@@ -2619,7 +2878,19 @@ process_command (argc, argv)
        }
     }
 
-  /* Set up the default search paths.  */
+  /* Set up the default search paths.  If there is no GCC_EXEC_PREFIX,
+     see if we can create it from the pathname specified in argv[0].  */
+
+#ifndef VMS
+  /* FIXME: make_relative_prefix doesn't yet work for VMS.  */
+  if (!gcc_exec_prefix)
+    {
+      gcc_exec_prefix = make_relative_prefix (argv[0], standard_bindir_prefix,
+                                             standard_exec_prefix);
+      if (gcc_exec_prefix)
+       putenv (concat ("GCC_EXEC_PREFIX=", gcc_exec_prefix, NULL_PTR));
+    }
+#endif
 
   if (gcc_exec_prefix)
     {
@@ -2677,7 +2948,7 @@ process_command (argc, argv)
        }
     }
 
-  GET_ENV_PATH_LIST (temp, "LIBRARY_PATH");
+  GET_ENV_PATH_LIST (temp, LIBRARY_PATH_ENV);
   if (temp && *cross_compile == '0')
     {
       const char *startp, *endp;
@@ -2787,6 +3058,11 @@ process_command (argc, argv)
          add_assembler_option ("--help", 6);
          add_linker_option ("--help", 6);
        }
+      else if (! strcmp (argv[i], "-pass-exit-codes"))
+       {
+         pass_exit_codes = 1;
+         n_switches++;
+       }
       else if (! strcmp (argv[i], "-print-search-dirs"))
        print_search_dirs = 1;
       else if (! strcmp (argv[i], "-print-libgcc-file-name"))
@@ -3080,6 +3356,8 @@ process_command (argc, argv)
   /* Use 2 as fourth arg meaning try just the machine as a suffix,
      as well as trying the machine and the version.  */
 #ifndef OS2
+  add_prefix (&exec_prefixes, standard_exec_prefix, "GCC",
+             0, 1, warn_std_ptr);
   add_prefix (&exec_prefixes, standard_exec_prefix, "BINUTILS",
              0, 2, warn_std_ptr);
   add_prefix (&exec_prefixes, standard_exec_prefix_1, "BINUTILS",
@@ -3155,6 +3433,8 @@ process_command (argc, argv)
        ;
       else if (! strncmp (argv[i], "-Wp,", 4))
        ;
+      else if (! strcmp (argv[i], "-pass-exit-codes"))
+       ;
       else if (! strcmp (argv[i], "-print-search-dirs"))
        ;
       else if (! strcmp (argv[i], "-print-libgcc-file-name"))
@@ -3662,7 +3942,7 @@ do_spec_1 (spec, inswitch, soft_matched_part)
              buf = (char *) alloca (p - q + 1);
              strncpy (buf, q, p - q);
              buf[p - q] = 0;
-             error (buf);
+             error ("%s", buf);
              return -1;
            }
            break;
@@ -3685,21 +3965,29 @@ do_spec_1 (spec, inswitch, soft_matched_part)
                struct temp_name *t;
                int suffix_length;
                const char *suffix = p;
+               char *saved_suffix = NULL;
 
+               while (*p == '.' || ISALPHA ((unsigned char)*p))
+                 p++;
+               suffix_length = p - suffix;
                if (p[0] == '%' && p[1] == 'O')
                  {
                    p += 2;
                    /* We don't support extra suffix characters after %O.  */
                    if (*p == '.' || ISALPHA ((unsigned char)*p))
                      abort ();
-                   suffix = OBJECT_SUFFIX;
-                   suffix_length = strlen (OBJECT_SUFFIX);
-                 }
-               else
-                 {
-                   while (*p == '.' || ISALPHA ((unsigned char)*p))
-                     p++;
-                   suffix_length = p - suffix;
+                   if (suffix_length == 0)
+                     suffix = OBJECT_SUFFIX;
+                   else
+                     {
+                       saved_suffix
+                         = (char *) xmalloc (suffix_length
+                                             + strlen (OBJECT_SUFFIX));
+                       strncpy (saved_suffix, suffix, suffix_length);
+                       strcpy (saved_suffix + suffix_length,
+                               OBJECT_SUFFIX);
+                     }
+                   suffix_length += strlen (OBJECT_SUFFIX);
                  }
 
                /* See if we already have an association of %g/%u/%U and
@@ -3728,6 +4016,9 @@ do_spec_1 (spec, inswitch, soft_matched_part)
                    t->filename_length = temp_filename_length;
                  }
 
+               if (saved_suffix)
+                 free (saved_suffix);
+
                obstack_grow (&obstack, t->filename, t->filename_length);
                delete_this_arg = 1;
 #else
@@ -3972,7 +4263,12 @@ do_spec_1 (spec, inswitch, soft_matched_part)
              char *y;
 
              /* Copy all of CPP_PREDEFINES into BUF,
-                but put __ after every -D and at the end of each arg.  */
+                but force them all into the reserved name space if they                         aren't already there.  The reserved name space is all
+                identifiers beginning with two underscores or with one
+                underscore and a capital letter.  We do the forcing by
+                adding up to two underscores to the beginning and end
+                of each symbol. e.g. mips, _mips, mips_, and _mips_ all
+                become __mips__.  */
              y = cpp_predefines;
              while (*y != 0)
                {
@@ -3988,7 +4284,8 @@ do_spec_1 (spec, inswitch, soft_matched_part)
                              && ! ISUPPER ((unsigned char)*(y+1))))
                        {
                          /* Stick __ at front of macro name.  */
-                         *x++ = '_';
+                         if (*y != '_')
+                           *x++ = '_';
                          *x++ = '_';
                          /* Arrange to stick __ at the end as well.  */
                          flag = 1;
@@ -4000,8 +4297,12 @@ do_spec_1 (spec, inswitch, soft_matched_part)
 
                      if (flag)
                        {
-                         *x++ = '_';
-                         *x++ = '_';
+                         if (x[-1] != '_')
+                           {
+                             if (x[-2] != '_')
+                               *x++ = '_';
+                             *x++ = '_';
+                           }
                        }
 
                      /* Copy the value given, if any.  */
@@ -4033,7 +4334,8 @@ do_spec_1 (spec, inswitch, soft_matched_part)
                          /* Stick -D__ at front of macro name.  */
                          *x++ = '-';
                          *x++ = 'D';
-                         *x++ = '_';
+                         if (*y != '_')
+                           *x++ = '_';
                          *x++ = '_';
 
                          /* Copy the macro name.  */
@@ -4651,6 +4953,37 @@ is_directory (path1, path2, linker)
 
   return (stat (path, &st) >= 0 && S_ISDIR (st.st_mode));
 }
+
+/* Set up the various global variables to indicate that we're processing
+   the input file named FILENAME.  */
+
+static void
+set_input (filename)
+     const char *filename;
+{
+  register const char *p;
+
+  input_filename = filename;
+  input_filename_length = strlen (input_filename);
+  
+  input_basename = input_filename;
+  for (p = input_filename; *p; p++)
+    if (IS_DIR_SEPARATOR (*p))
+      input_basename = p + 1;
+
+  /* Find a suffix starting with the last period,
+     and set basename_length to exclude that suffix.  */
+  basename_length = strlen (input_basename);
+  p = input_basename + basename_length;
+  while (p != input_basename && *p != '.') --p;
+  if (*p == '.' && p != input_basename)
+    {
+      basename_length = p - input_basename;
+      input_suffix = p + 1;
+    }
+  else
+    input_suffix = "";
+}
 \f
 /* On fatal signals, delete all the temporary files.  */
 
@@ -4666,6 +4999,8 @@ fatal_error (signum)
   kill (getpid (), signum);
 }
 
+extern int main PARAMS ((int, char **));
+
 int
 main (argc, argv)
      int argc;
@@ -4875,7 +5210,7 @@ main (argc, argv)
         standard_startfile_prefix on that as well.  */
       if (IS_DIR_SEPARATOR (*standard_startfile_prefix)
            || *standard_startfile_prefix == '$'
-#ifdef HAVE_DOS_BASED_FILESYSTEM
+#ifdef HAVE_DOS_BASED_FILE_SYSTEM
            /* Check for disk name on MS-DOS-based systems.  */
           || (standard_startfile_prefix[1] == ':'
              && (IS_DIR_SEPARATOR (standard_startfile_prefix[2])))
@@ -5049,9 +5384,8 @@ main (argc, argv)
 
       /* Tell do_spec what to substitute for %i.  */
 
-      input_filename = infiles[i].name;
-      input_filename_length = strlen (input_filename);
       input_file_number = i;
+      set_input (infiles[i].name);
 
       /* Use the same thing in %o, unless cp->spec says otherwise.  */
 
@@ -5066,31 +5400,12 @@ main (argc, argv)
        {
          /* Ok, we found an applicable compiler.  Run its spec.  */
          /* First say how much of input_filename to substitute for %b  */
-         register const char *p;
          int len;
 
          if (cp->spec[0][0] == '#')
            error ("%s: %s compiler not installed on this system",
                   input_filename, &cp->spec[0][1]);
 
-         input_basename = input_filename;
-         for (p = input_filename; *p; p++)
-           if (IS_DIR_SEPARATOR (*p))
-             input_basename = p + 1;
-
-         /* Find a suffix starting with the last period,
-            and set basename_length to exclude that suffix.  */
-         basename_length = strlen (input_basename);
-         p = input_basename + basename_length;
-         while (p != input_basename && *p != '.') --p;
-         if (*p == '.' && p != input_basename)
-           {
-             basename_length = p - input_basename;
-             input_suffix = p + 1;
-           }
-         else
-           input_suffix = "";
-
          len = 0;
          for (j = 0; j < sizeof cp->spec / sizeof cp->spec[0]; j++)
            if (cp->spec[j])
@@ -5132,6 +5447,12 @@ main (argc, argv)
       clear_failure_queue ();
     }
 
+  /* Reset the output file name to the first input file name, for use
+     with %b in LINK_SPEC on a target that prefers not to emit a.out
+     by default.  */
+  if (n_infiles > 0)
+    set_input (infiles[0].name);
+
   if (error_count == 0)
     {
       /* Make sure INPUT_FILE_NUMBER points to first available open
@@ -5156,8 +5477,8 @@ main (argc, argv)
        }
       /* Rebuild the COMPILER_PATH and LIBRARY_PATH environment variables
         for collect.  */
-      putenv_from_prefixes (&exec_prefixes, "COMPILER_PATH=");
-      putenv_from_prefixes (&startfile_prefixes, "LIBRARY_PATH=");
+      putenv_from_prefixes (&exec_prefixes, "COMPILER_PATH");
+      putenv_from_prefixes (&startfile_prefixes, LIBRARY_PATH_ENV);
 
       value = do_spec (link_command_spec);
       if (value < 0)
@@ -5190,7 +5511,9 @@ main (argc, argv)
       printf ("<URL:http://www.gnu.org/software/gcc/faq.html#bugreport>\n");
     }
   
-  return (error_count > 0 ? (signal_count ? 2 : 1) : 0);
+  return (signal_count != 0 ? 2
+         : error_count > 0 ? (pass_exit_codes ? greatest_status : 1)
+         : 0);
 }
 
 /* Find the proper compilation spec for the file name NAME,
@@ -5323,7 +5646,7 @@ fancy_abort ()
 /* Output an error message and exit */
 
 void
-fatal VPROTO((const char *msgid, ...))
+fatal VPARAMS ((const char *msgid, ...))
 {
 #ifndef ANSI_PROTOTYPES
   const char *msgid;
@@ -5345,7 +5668,7 @@ fatal VPROTO((const char *msgid, ...))
 }
 
 static void
-error VPROTO((const char *msgid, ...))
+error VPARAMS ((const char *msgid, ...))
 {
 #ifndef ANSI_PROTOTYPES
   const char *msgid;
@@ -5366,7 +5689,7 @@ error VPROTO((const char *msgid, ...))
 }
 
 static void
-notice VPROTO((const char *msgid, ...))
+notice VPARAMS ((const char *msgid, ...))
 {
 #ifndef ANSI_PROTOTYPES
   const char *msgid;