OSDN Git Service

back out the 3-0 branch version
[pf3gnuchains/gcc-fork.git] / gcc / gcc.c
index 30ae0b1..8477c00 100644 (file)
--- a/gcc/gcc.c
+++ b/gcc/gcc.c
@@ -1,6 +1,6 @@
 /* Compiler driver program that can handle many languages.
    Copyright (C) 1987, 1989, 1992, 1993, 1994, 1995, 1996, 1997, 1998,
-   1999, 2000 Free Software Foundation, Inc.
+   1999, 2000, 2001 Free Software Foundation, Inc.
 
 This file is part of GNU CC.
 
@@ -32,6 +32,44 @@ CC recognizes how to compile each input file by suffixes in the file names.
 Once it knows which kind of compilation to perform, the procedure for
 compilation is specified by a string called a "spec".  */
 
+/* A Short Introduction to Adding a Command-Line Option.
+
+   Before adding a command-line option, consider if it is really
+   necessary.  Each additional command-line option adds complexity and
+   is difficult to remove in subsequent versions.
+
+   In the following, consider adding the command-line argument
+   `--bar'.
+
+   1. Each command-line option is specified in the specs file.  The
+   notation is described below in the comment entitled "The Specs
+   Language".  Read it.
+
+   2. In this file, add an entry to "option_map" equating the long
+   `--' argument version and any shorter, single letter version.  Read
+   the comments in the declaration of "struct option_map" for an
+   explanation.  Do not omit the first `-'.
+
+   3. Look in the "specs" file to determine which program or option
+   list should be given the argument, e.g., "cc1_options".  Add the
+   appropriate syntax for the shorter option version to the
+   corresponding "const char *" entry in this file.  Omit the first
+   `-' from the option.  For example, use `-bar', rather than `--bar'.
+
+   4. If the argument takes an argument, e.g., `--baz argument1',
+   modify either DEFAULT_SWITCH_TAKES_ARG or
+   DEFAULT_WORD_SWITCH_TAKES_ARG in this file.  Omit the first `-'
+   from `--baz'.
+
+   5. Document the option in this file's display_help().  If the
+   option is passed to a subprogram, modify its corresponding
+   function, e.g., cppinit.c:print_help() or toplev.c:display_help(),
+   instead.
+
+   6. Compile and test.  Make sure that your new specs file is being
+   read.  For example, use a debugger to investigate the value of
+   "specs_file" in main().  */
+
 #include "config.h"
 #include "system.h"
 #include <signal.h>
@@ -136,6 +174,10 @@ static int print_help_list;
 
 static int verbose_flag;
 
+/* Flag indicating to print target specific command line options. */
+
+static int target_help_flag;
+
 /* Flag indicating whether we should report subprocess execution times
    (if this is supported by the system - see pexecute.c).  */
 
@@ -229,7 +271,6 @@ static void add_prefix              PARAMS ((struct path_prefix *, const char *,
                                         const char *, int, int, int *));
 static void translate_options  PARAMS ((int *, const char *const **));
 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));
@@ -247,12 +288,9 @@ 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              PARAMS ((const char *, ...))
-  ATTRIBUTE_PRINTF_1;
 static void notice             PARAMS ((const char *, ...))
   ATTRIBUTE_PRINTF_1;
 static void display_help       PARAMS ((void));
@@ -264,8 +302,13 @@ static int execute                 PARAMS ((void));
 static void clear_args                 PARAMS ((void));
 static void fatal_error                        PARAMS ((int));
 static void set_input                  PARAMS ((const char *));
+static void init_gcc_specs              PARAMS ((struct obstack *,
+                                                const char *,
+                                                const char *));
 \f
-/* Specs are strings containing lines, each of which (if not blank)
+/* The Specs Language
+
+Specs are strings containing lines, each of which (if not blank)
 is made up of a program name, and arguments separated by spaces.
 The program name must be exact and start from root, since no path
 is searched and it is unreliable to depend on the current working directory.
@@ -314,6 +357,10 @@ or with constant text in a single argument.
         of a temporary file, just like %u.  This temporary file is not
         meant for communication between processes, but rather as a junk
         disposal mechanism.
+ %.SUFFIX
+        substitutes .SUFFIX for the suffixes of a matched switch's args when
+        it is subsequently output with %*. SUFFIX is terminated by the next
+        space or %.
  %d    marks the argument containing or following the %d as a
        temporary file name, so that that file will be deleted if CC exits
        successfully.  Unlike %g, this contributes no text to the argument.
@@ -349,6 +396,7 @@ or with constant text in a single argument.
        and substitute the full name found.
  %eSTR  Print STR as an error message.  STR is terminated by a newline.
         Use this when inconsistent options are detected.
+ %nSTR  Print STR as an notice.  STR is terminated by a newline.
  %x{OPTION}    Accumulate an option for %X.
  %X    Output the accumulated linker options specified by compilations.
  %Y    Output the accumulated assembler options specified by compilations.
@@ -369,10 +417,12 @@ or with constant text in a single argument.
  %l     process LINK_SPEC as a spec.
  %L     process LIB_SPEC as a spec.
  %G     process LIBGCC_SPEC as a spec.
+ %M     output multilib_dir with directory separators replaced with "_";
+       if multilib_dir is not set or is ".", output "".
  %S     process STARTFILE_SPEC as a spec.  A capital S is actually used here.
  %E     process ENDFILE_SPEC as a spec.  A capital E is actually used here.
  %c    process SIGNED_CHAR_SPEC as a spec.
- %C     process CPP_SPEC as a spec.  A capital C is actually used here.
+ %C     process CPP_SPEC as a spec.
  %1    process CC1_SPEC as a spec.
  %2    process CC1PLUS_SPEC as a spec.
  %|    output "-" if the input for the current command is coming from a pipe.
@@ -383,11 +433,15 @@ or with constant text in a single argument.
        If that switch was not specified, this substitutes nothing.
        Here S is a metasyntactic variable.
  %{S*}  substitutes all the switches specified to CC whose names start
-       with -S.  This is used for -o, -D, -I, etc; switches that take
+       with -S.  This is used for -o, -I, etc; switches that take
        arguments.  CC considers `-o foo' as being one switch whose
        name starts with `o'.  %{o*} would substitute this text,
        including the space; thus, two arguments would be generated.
  %{^S*} likewise, but don't put a blank between a switch and any args.
+ %{S*&T*} likewise, but preserve order of S and T options (the order
+       of S and T in the spec is not significant).  Can be any number
+       of ampersand-separated variables; for each the wild card is
+       optional.  Useful for CPP as %{D*&U*&A*}.
  %{S*:X} substitutes X if one or more switches whose names start with -S are
        specified to CC.  Note that the tail part of the -S option
        (i.e. the part matched by the `*') will be substituted for each
@@ -575,8 +629,10 @@ static const char *trad_capable_cpp =
 static const char *cpp_options =
 "%{C:%{!E:%eGNU C does not support -C without using -E}}\
  %{std*} %{nostdinc*}\
- %{C} %{v} %{A*} %{I*} %{P} %{$} %I\
- %{M} %{MM} %{MD:-MD %b.d} %{MMD:-MMD %b.d} %{MG}\
+ %{C} %{v} %{I*} %{P} %{$} %I\
+ %{MD:-M -MF %W{!o: %b.d}%W{o*:%.d%*}}\
+ %{MMD:-MM -MF %W{!o: %b.d}%W{o*:%.d%*}}\
+ %{M} %{MM} %W{MF*} %{MG} %{MP} %{MQ*} %{MT*} %{M|MD|MM|MMD:%{o*:-MQ %*}}\
  %{!no-gcc:-D__GNUC__=%v1 -D__GNUC_MINOR__=%v2 -D__GNUC_PATCHLEVEL__=%v3}\
  %{!undef:%{!ansi:%{!std=*:%p}%{std=gnu*:%p}} %P} %{trigraphs}\
  %c %{Os:-D__OPTIMIZE_SIZE__} %{O*:%{!O0:-D__OPTIMIZE__}}\
@@ -586,9 +642,9 @@ static const char *cpp_options =
  %{!ffreestanding:%{!fno-hosted:-D__STDC_HOSTED__=1}}\
  %{fshow-column} %{fno-show-column}\
  %{fleading-underscore} %{fno-leading-underscore}\
- %{ftabstop=*}\
- %{g*} %{W*} %{w} %{pedantic*} %{H} %{d*} %C %{U*} %{D*} %{i*} %Z %i\
- %{E:%W{o*}}%{M:%W{o*}}%{MM:%W{o*}}";
+ %{fno-operator-names} %{ftabstop=*} %{remap}\
+ %{g3:-dD} %{W*} %{w} %{pedantic*} %{H} %{d*} %C %{D*&U*&A*} %{i*} %Z %i\
+ %{E:%{!M*:%W{o*}}}";
 
 /* NB: This is shared amongst all front-ends.  */
 static const char *cc1_options =
@@ -597,8 +653,9 @@ static const char *cc1_options =
  %{g*} %{O*} %{W*} %{w} %{pedantic*} %{std*} %{ansi}\
  %{traditional} %{v:-version} %{pg:-p} %{p} %{f*}\
  %{aux-info*} %{Qn:-fno-ident} %{--help:--help}\
+ %{--target-help:--target-help}\
  %{!fsyntax-only:%{S:%W{o*}%{!o*:-o %b.s}}}\
- %{fsyntax-only:-o %j}";
+ %{fsyntax-only:-o %j} %{-param*}";
 
 static const char *asm_options =
 "%a %Y %{c:%W{o*}%{!o*:-o %w%b%O}}%{!c:-o %d%w%u%O}";
@@ -653,8 +710,9 @@ static struct user_specs *user_specs_head, *user_specs_tail;
   || !strcmp (STR, "imacros") || !strcmp (STR, "aux-info") \
   || !strcmp (STR, "idirafter") || !strcmp (STR, "iprefix") \
   || !strcmp (STR, "iwithprefix") || !strcmp (STR, "iwithprefixbefore") \
-  || !strcmp (STR, "isystem") || !strcmp (STR, "specs") \
-  || !strcmp (STR, "MF") || !strcmp (STR, "MT"))
+  || !strcmp (STR, "isystem") || !strcmp (STR, "-param") \
+  || !strcmp (STR, "specs") \
+  || !strcmp (STR, "MF") || !strcmp (STR, "MT") || !strcmp (STR, "MQ"))
 
 #ifndef WORD_SWITCH_TAKES_ARG
 #define WORD_SWITCH_TAKES_ARG(STR) DEFAULT_WORD_SWITCH_TAKES_ARG (STR)
@@ -679,6 +737,10 @@ struct compiler
                                   whose names end in this suffix.  */
 
   const char *spec;            /* To use this compiler, run this spec.  */
+
+  const char *cpp_spec;         /* If non-NULL, substitute this spec
+                                  for `%C', rather than the usual
+                                  cpp_spec.  */
 };
 
 /* Pointer to a vector of `struct compiler' that gives the spec for
@@ -704,20 +766,21 @@ static struct compiler default_compilers[] =
      were not present when we built the driver, we will hit these copies
      and be given a more meaningful error than "file not used since
      linking is not done".  */
-  {".m",  "#Objective-C"},
-  {".cc", "#C++"}, {".cxx", "#C++"}, {".cpp", "#C++"},
-  {".c++", "#C++"}, {".C", "#C++"},
-  {".ads", "#Ada"}, {".adb", "#Ada"}, {".ada", "#Ada"},
-  {".f", "#Fortran"}, {".for", "#Fortran"}, {".F", "#Fortran"},
-  {".fpp", "#Fortran"}, {".r", "#Ratfor"},
-  {".p", "#Pascal"}, {".pas", "#Pascal"},
-  {".ch", "#Chill"}, {".chi", "#Chill"},
-  {".java", "#Java"}, {".class", "#Java"},
-  {".zip", "#Java"}, {".jar", "#Java"},
+  {".m",  "#Objective-C", 0}, {".mi",  "#Objective-C", 0},
+  {".cc", "#C++", 0}, {".cxx", "#C++", 0}, {".cpp", "#C++", 0},
+  {".cp", "#C++", 0}, {".c++", "#C++", 0}, {".C", "#C++", 0},
+  {".ii", "#C++", 0},
+  {".ads", "#Ada", 0}, {".adb", "#Ada", 0}, {".ada", "#Ada", 0},
+  {".f", "#Fortran", 0}, {".for", "#Fortran", 0}, {".fpp", "#Fortran", 0},
+  {".F", "#Fortran", 0}, {".FOR", "#Fortran", 0}, {".FPP", "#Fortran", 0},
+  {".r", "#Ratfor", 0},
+  {".p", "#Pascal", 0}, {".pas", "#Pascal", 0},
+  {".ch", "#Chill", 0}, {".chi", "#Chill", 0},
+  {".java", "#Java", 0}, {".class", "#Java", 0},
+  {".zip", "#Java", 0}, {".jar", "#Java", 0},
   /* Next come the entries for C.  */
-  {".c", "@c"},
+  {".c", "@c", 0},
   {"@c",
-#if USE_CPPLIB
    /* cc1 has an integrated ISO C preprocessor.  We should invoke the
       external preprocessor if -save-temps or -traditional is given.  */
      "%{E|M|MM:%(trad_capable_cpp) -lang-c %{ansi:-std=c89} %(cpp_options)}\
@@ -731,33 +794,27 @@ static struct compiler default_compilers[] =
                    cc1 -fpreprocessed %{!pipe:%g.i} %(cc1_options)}\
            %{!traditional:%{!ftraditional:%{!traditional-cpp:\
                cc1 -lang-c %{ansi:-std=c89} %(cpp_options) %(cc1_options)}}}}\
-        %{!fsyntax-only:%(invoke_as)}}}}"
-#else /* ! USE_CPPLIB */
-     "%(trad_capable_cpp) -lang-c %{ansi:-std=c89} %(cpp_options) \
-                         %{!M:%{!MM:%{!E:%{!pipe:%g.i} |\n\
-      cc1 %{!pipe:%g.i} %(cc1_options) %{!fsyntax-only:%(invoke_as)}}}}"
-#endif /* ! USE_CPPLIB */
-  },
+        %{!fsyntax-only:%(invoke_as)}}}}", 0},
   {"-",
    "%{!E:%e-E required when input is from standard input}\
-    %(trad_capable_cpp) -lang-c %{ansi:-std=c89} %(cpp_options)"},
-  {".h", "@c-header"},
+    %(trad_capable_cpp) -lang-c %{ansi:-std=c89} %(cpp_options)", 0},
+  {".h", "@c-header", 0},
   {"@c-header",
    "%{!E:%eCompilation of header file requested} \
-    %(trad_capable_cpp) -lang-c %{ansi:-std=c89} %(cpp_options)"},
-  {".i", "@cpp-output"},
+    %(trad_capable_cpp) -lang-c %{ansi:-std=c89} %(cpp_options)", 0},
+  {".i", "@cpp-output", 0},
   {"@cpp-output",
-   "%{!M:%{!MM:%{!E:cc1 %i %(cc1_options) %{!fsyntax-only:%(invoke_as)}}}}"},
-  {".s", "@assembler"},
+   "%{!M:%{!MM:%{!E:cc1 -fpreprocessed %i %(cc1_options) %{!fsyntax-only:%(invoke_as)}}}}", 0},
+  {".s", "@assembler", 0},
   {"@assembler",
-   "%{!M:%{!MM:%{!E:%{!S:as %(asm_options) %i %A }}}}"},
-  {".S", "@assembler-with-cpp"},
+   "%{!M:%{!MM:%{!E:%{!S:as %(asm_options) %i %A }}}}", 0},
+  {".S", "@assembler-with-cpp", 0},
   {"@assembler-with-cpp",
    "%(trad_capable_cpp) -lang-asm %(cpp_options)\
-       %{!M:%{!MM:%{!E:%(invoke_as)}}}"},
+       %{!M:%{!MM:%{!E:%(invoke_as)}}}", 0},
 #include "specs.h"
   /* Mark end of table */
-  {0, 0}
+  {0, 0, 0}
 };
 
 /* Number of elements in default_compilers, not counting the terminator.  */
@@ -844,6 +901,7 @@ struct option_map option_map[] =
    {"--optimize", "-O", "oj"},
    {"--output", "-o", "a"},
    {"--output-class-directory", "-foutput-class-dir=", "ja"},
+   {"--param", "--param", "a"},
    {"--pedantic", "-pedantic", 0},
    {"--pedantic-errors", "-pedantic-errors", 0},
    {"--pipe", "-pipe", 0},
@@ -1242,6 +1300,35 @@ static struct spec_list *extra_specs = (struct spec_list *) 0;
 
 static struct spec_list *specs = (struct spec_list *) 0;
 \f
+/* Add appropriate libgcc specs to OBSTACK, taking into account
+   various permutations of -shared-libgcc, -shared, and such.  */
+
+static void
+init_gcc_specs (obstack, shared_name, static_name)
+     struct obstack *obstack;
+     const char *shared_name;
+     const char *static_name;
+{
+  char buffer[128];
+
+  /* If we see -shared-libgcc, then use the shared version.  */
+  sprintf (buffer, "%%{shared-libgcc:%s}", shared_name);
+  obstack_grow (obstack, buffer, strlen (buffer));
+  /* If we see -static-libgcc, then use the shared version.  */
+  sprintf (buffer, "%%{static-libgcc:%s}", static_name);
+  obstack_grow (obstack, buffer, strlen (buffer));
+  /* Otherwise, if we see -shared, then use the shared version.  */
+  sprintf (buffer,
+          "%%{!shared-libgcc:%%{!static-libgcc:%%{shared:%s}}}", 
+          shared_name);
+  obstack_grow (obstack, buffer, strlen (buffer));
+  /* Otherwise, use the static version.  */
+  sprintf (buffer, 
+          "%%{!shared-libgcc:%%{!static-libgcc:%%{!shared:%s}}}", 
+          static_name);
+  obstack_grow (obstack, buffer, strlen (buffer));
+}
+
 /* Initialize the specs lookup routines.  */
 
 static void
@@ -1280,6 +1367,83 @@ init_spec ()
       next = sl;
     }
 
+#ifdef ENABLE_SHARED_LIBGCC
+  /* ??? If neither -shared-libgcc nor --static-libgcc was
+     seen, then we should be making an educated guess.  Some proposed
+     heuristics for ELF include:
+
+       (1) If "-Wl,--export-dynamic", then it's a fair bet that the
+           program will be doing dynamic loading, which will likely
+           need the shared libgcc.
+
+       (2) If "-ldl", then it's also a fair bet that we're doing
+           dynamic loading.
+
+       (3) For each ET_DYN we're linking against (either through -lfoo
+           or /some/path/foo.so), check to see whether it or one of
+           its dependancies depends on a shared libgcc.
+
+       (4) If "-shared"
+
+           If the runtime is fixed to look for program headers instead
+           of calling __register_frame_info at all, for each object,
+           use the shared libgcc if any EH symbol referenced.
+
+           If crtstuff is fixed to not invoke __register_frame_info
+           automatically, for each object, use the shared libgcc if
+           any non-empty unwind section found.
+
+     Doing any of this probably requires invoking an external program to
+     do the actual object file scanning.  */
+  {
+    const char *p = libgcc_spec;
+    int in_sep = 1;
+    /* Transform the extant libgcc_spec into one that uses the shared libgcc
+       when given the proper command line arguments.  */
+    while (*p)
+      {
+        if (in_sep && *p == '-' && strncmp (p, "-lgcc", 5) == 0)
+         {
+           init_gcc_specs (&obstack,
+#ifdef NO_SHARED_LIBGCC_MULTILIB
+                           "-lgcc_s"
+#else
+                           "-lgcc_s%M"
+#endif
+                           ,
+                           "-lgcc");
+           p += 5;
+           in_sep = 0;
+         }
+       else if (in_sep && *p == 'l' && strncmp (p, "libgcc.a%s", 10) == 0)
+         {
+           /* Ug.  We don't know shared library extensions.  Hope that
+              systems that use this form don't do shared libraries.  */
+           init_gcc_specs (&obstack,
+#ifdef NO_SHARED_LIBGCC_MULTILIB
+                           "-lgcc_s"
+#else
+                           "-lgcc_s%M"
+#endif
+                           ,
+                           "libgcc.a%s");
+           p += 10;
+           in_sep = 0;
+         }
+       else
+         {
+           obstack_1grow (&obstack, *p);
+           in_sep = (*p == ' ');
+           p += 1;
+         }
+      }
+
+    obstack_1grow (&obstack, '\0');
+    libgcc_spec = obstack_finish (&obstack);
+  }
+#endif
+
   specs = sl;
 }
 \f
@@ -1751,7 +1915,7 @@ static struct temp_file *failure_delete_queue;
    FAIL_DELETE nonzero means delete it if a compilation step fails;
    otherwise delete it in any case.  */
 
-static void
+void
 record_temp_file (filename, always_delete, fail_delete)
      const char *filename;
      int always_delete;
@@ -2244,7 +2408,7 @@ find_a_file (pprefix, name, mode)
   int len = pprefix->max_len + strlen (name) + strlen (file_suffix) + 1;
 
 #ifdef DEFAULT_ASSEMBLER
-  if (! strcmp(name, "as") && access (DEFAULT_ASSEMBLER, mode) == 0)
+  if (! strcmp (name, "as") && access (DEFAULT_ASSEMBLER, mode) == 0)
     return xstrdup (DEFAULT_ASSEMBLER);
 #endif
 
@@ -2260,12 +2424,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_FILE_SYSTEM
-      /* Check for disk name on MS-DOS-based systems.  */
-      || (name[0] && name[1] == ':' && IS_DIR_SEPARATOR (name[2]))
-#endif
-      )
+  if (IS_ABSOLUTE_PATHNAME (name))
     {
       if (access (name, mode) == 0)
        {
@@ -2661,7 +2820,8 @@ struct switchstr
   const char *part1;
   const char **args;
   int live_cond;
-  int validated;
+  unsigned char validated;
+  unsigned char ordering;
 };
 
 static struct switchstr *switches;
@@ -2728,7 +2888,7 @@ convert_filename (name, do_exe)
     }
 #endif
 
-#ifdef HAVE_EXECUTABLE_SUFFIX
+#if defined(HAVE_EXECUTABLE_SUFFIX) && !defined(NO_AUTO_EXE_SUFFIX)
   /* If there is no filetype, make it the executable suffix (which includes
      the ".").  But don't get confused if we have just "-o".  */
   if (! do_exe || EXECUTABLE_SUFFIX[0] == 0 || (len == 2 && name[0] == '-'))
@@ -2760,6 +2920,7 @@ display_help ()
 
   fputs (_("  -pass-exit-codes         Exit with highest error code from a phase\n"), stdout);
   fputs (_("  --help                   Display this information\n"), stdout);
+  fputs (_("  --target-help            Display target specific command line options\n"), stdout);
   if (! verbose_flag)
     fputs (_("  (Use '-v --help' to display command line options of sub-processes)\n"), stdout);
   fputs (_("  -dumpspecs               Display all of the built in spec strings\n"), stdout);
@@ -2798,9 +2959,9 @@ display_help ()
 "), stdout);
 
   printf (_("\
-\nOptions starting with -g, -f, -m, -O or -W are automatically passed on to\n\
-the various sub-processes invoked by %s.  In order to pass other options\n\
-on to these processes the -W<letter> options must be used.\n\
+\nOptions starting with -g, -f, -m, -O, -W, or --param are automatically\n\
+ passed on to the various sub-processes invoked by %s.  In order to pass\n\
+ other options on to these processes the -W<letter> options must be used.\n\
 "), programname);
 
   /* The rest of the options are displayed by invocations of the various
@@ -2880,6 +3041,7 @@ process_command (argc, argv)
   int lang_n_infiles = 0;
 #ifdef MODIFY_TARGET_NAME
   int is_modify_target_name;
+  int j;
 #endif
 
   GET_ENV_PATH_LIST (gcc_exec_prefix, "GCC_EXEC_PREFIX");
@@ -2918,6 +3080,7 @@ process_command (argc, argv)
   if (gcc_exec_prefix)
     {
       int len = strlen (gcc_exec_prefix);
+
       if (len > (int) sizeof ("/lib/gcc-lib/") - 1
          && (IS_DIR_SEPARATOR (gcc_exec_prefix[len-1])))
        {
@@ -3085,6 +3248,19 @@ process_command (argc, argv)
          add_assembler_option ("--help", 6);
          add_linker_option ("--help", 6);
        }
+      else if (strcmp (argv[i], "-ftarget-help") == 0)
+        {
+          /* translate_options() has turned --target-help into -ftarget-help. */
+          target_help_flag = 1;
+
+          /* We will be passing a dummy file on to the sub-processes.  */
+          n_infiles++;
+          n_switches++;
+
+          add_preprocessor_option ("--target-help", 13);
+          add_assembler_option ("--target-help", 13);
+          add_linker_option ("--target-help", 13);
+        }
       else if (! strcmp (argv[i], "-pass-exit-codes"))
        {
          pass_exit_codes = 1;
@@ -3447,7 +3623,7 @@ process_command (argc, argv)
      directories, so that we can search both the user specified directory
      and the standard place.  */
 
-  if (!IS_DIR_SEPARATOR (*tooldir_prefix))
+  if (!IS_ABSOLUTE_PATHNAME (tooldir_prefix))
     {
       if (gcc_exec_prefix)
        {
@@ -3525,6 +3701,22 @@ process_command (argc, argv)
        ;
       else if (! strcmp (argv[i], "-print-multi-directory"))
        ;
+      else if (strcmp (argv[i], "-ftarget-help") == 0)
+        {
+           /* Create a dummy input file, so that we can pass --target-help on to
+              the various sub-processes.  */
+           infiles[n_infiles].language = "c";
+           infiles[n_infiles++].name   = "target-dummy";
+
+           /* Preserve the --target-help switch so that it can be caught by
+              the cc1 spec string.  */
+           switches[n_switches].part1     = "--target-help";
+           switches[n_switches].args      = 0;
+           switches[n_switches].live_cond = SWITCH_OK;
+           switches[n_switches].validated = 0;
+
+           n_switches++;
+        }
       else if (strcmp (argv[i], "-fhelp") == 0)
        {
          if (verbose_flag)
@@ -3539,7 +3731,7 @@ process_command (argc, argv)
              switches[n_switches].part1     = "--help";
              switches[n_switches].args      = 0;
              switches[n_switches].live_cond = SWITCH_OK;
-             switches[n_switches].validated     = 0;
+             switches[n_switches].validated = 0;
 
              n_switches++;
            }
@@ -3666,8 +3858,11 @@ process_command (argc, argv)
 
          switches[n_switches].live_cond = SWITCH_OK;
          switches[n_switches].validated = 0;
-         /* This is always valid, since gcc.c itself understands it.  */
-         if (!strcmp (p, "save-temps"))
+         switches[n_switches].ordering = 0;
+         /* These are always valid, since gcc.c itself understands it.  */
+         if (!strcmp (p, "save-temps")
+             || !strcmp (p, "static-libgcc")
+             || !strcmp (p, "shared-libgcc"))
            switches[n_switches].validated = 1;
          else
            {
@@ -3683,7 +3878,7 @@ process_command (argc, argv)
          argv[i] = convert_filename (argv[i], 0);
 #endif
 
-         if (strcmp (argv[i], "-") != 0 && access (argv[i], R_OK) < 0)
+         if (strcmp (argv[i], "-") != 0 && access (argv[i], F_OK) < 0)
            {
              perror_with_name (argv[i]);
              error_count++;
@@ -3720,6 +3915,9 @@ static int suffixed_basename_length;
 static const char *input_basename;
 static const char *input_suffix;
 
+/* The compiler used to process the current input file.  */
+static struct compiler *input_file_compiler;
+
 /* These are variables used within do_spec and do_spec_1.  */
 
 /* Nonzero if an arg has been started and not yet terminated
@@ -3742,6 +3940,10 @@ static int this_is_library_file;
 /* Nonzero means that the input of this command is coming from a pipe.  */
 static int input_from_pipe;
 
+/* Nonnull means substitute this for any suffix when outputting a switches
+   arguments. */
+static const char *suffix_subst;
+
 /* Process the spec SPEC and run the commands specified therein.
    Returns 0 if the spec is successfully processed; -1 if failed.  */
 
@@ -3757,6 +3959,7 @@ do_spec (spec)
   this_is_output_file = 0;
   this_is_library_file = 0;
   input_from_pipe = 0;
+  suffix_subst = NULL;
 
   value = do_spec_1 (spec, 0, NULL_PTR);
 
@@ -3928,7 +4131,7 @@ do_spec_1 (spec, inswitch, soft_matched_part)
                  /* Relative directories always come from -B,
                     and it is better not to use them for searching
                     at run time.  In particular, stage1 loses.  */
-                 if (!IS_DIR_SEPARATOR (pl->prefix[0]))
+                 if (!IS_ABSOLUTE_PATHNAME (pl->prefix))
                    continue;
 #endif
                  /* Try subdirectory if there is one.  */
@@ -4033,6 +4236,21 @@ do_spec_1 (spec, inswitch, soft_matched_part)
              return -1;
            }
            break;
+         case 'n':
+           /* %nfoo means report an notice with `foo' on stderr.  */
+           {
+             const char *q = p;
+             char *buf;
+             while (*p != 0 && *p != '\n')
+               p++;
+             buf = (char *) alloca (p - q + 1);
+             strncpy (buf, q, p - q);
+             buf[p - q] = 0;
+             notice ("%s\n", buf);
+             if (*p)
+               p++;
+           }
+           break;
 
          case 'j':
            {
@@ -4286,9 +4504,15 @@ do_spec_1 (spec, inswitch, soft_matched_part)
            break;
 
          case 'C':
-           value = do_spec_1 (cpp_spec, 0, NULL_PTR);
-           if (value != 0)
-             return value;
+           {
+             const char* spec 
+               = (input_file_compiler->cpp_spec 
+                  ? input_file_compiler->cpp_spec 
+                  : cpp_spec);
+             value = do_spec_1 (spec, 0, NULL_PTR);
+             if (value != 0)
+               return value;
+           }
            break;
 
          case 'E':
@@ -4315,6 +4539,23 @@ do_spec_1 (spec, inswitch, soft_matched_part)
              return value;
            break;
 
+         case 'M':
+           if (multilib_dir && strcmp (multilib_dir, ".") != 0)
+             {
+               char *p;
+               const char *q;
+               size_t len;
+
+               len = strlen (multilib_dir);
+               obstack_blank (&obstack, len + 1);
+               p = obstack_next_free (&obstack) - (len + 1);
+
+               *p++ = '_';
+               for (q = multilib_dir; *q ; ++q, ++p)
+                 *p = (IS_DIR_SEPARATOR (*q) ? '_' : *q);
+             }
+           break;
+
          case 'p':
            {
              char *x = (char *) alloca (strlen (cpp_predefines) + 1);
@@ -4494,6 +4735,17 @@ do_spec_1 (spec, inswitch, soft_matched_part)
            obstack_1grow (&obstack, '%');
            break;
 
+         case '.':
+          {
+            unsigned len = 0;
+
+            while (p[len] && p[len] != ' ' && p[len] != '%')
+              len++;
+             suffix_subst = save_string (p - 1, len + 1);
+             p += len;
+           }
+          break;
+          
          case '*':
            if (soft_matched_part)
              {
@@ -4684,10 +4936,12 @@ handle_braces (p)
 {
   const char *filter, *body = NULL, *endbody = NULL;
   int pipe_p = 0;
+  int true_once = 0;   /* If, in %{a|b:d}, at least one of a,b was seen.  */
   int negate;
   int suffix;
   int include_blanks = 1;
   int elide_switch = 0;
+  int ordered = 0;
 
   if (*p == '^')
     {
@@ -4738,16 +4992,17 @@ next_member:
       abort ();
     }
 
+ next_ampersand:
   filter = p;
-  while (*p != ':' && *p != '}' && *p != '|')
+  while (*p != ':' && *p != '}' && *p != '|' && *p != '&')
     p++;
 
-  if (*p == '|' && pipe_p)
+  if (*p == '|' && (pipe_p || ordered))
     abort ();
 
   if (!body)
     {
-      if (*p != '}')
+      if (*p != '}' && *p != '&')
        {
          register int count = 1;
          register const char *q = p;
@@ -4785,15 +5040,23 @@ next_member:
          && do_spec_1 (save_string (body, endbody-body-1), 0, NULL_PTR) < 0)
        return 0;
     }
-  else if (p[-1] == '*' && p[0] == '}')
+  else if (p[-1] == '*' && (p[0] == '}' || p[0] == '&'))
     {
       /* Substitute all matching switches as separate args.  */
       register int i;
-      --p;
+
       for (i = 0; i < n_switches; i++)
-       if (!strncmp (switches[i].part1, filter, p - filter)
-           && check_live_switch (i, p - filter))
-         give_switch (i, 0, include_blanks);
+       if (!strncmp (switches[i].part1, filter, p - 1 - filter)
+           && check_live_switch (i, p - 1 - filter))
+         {
+           if (elide_switch)
+             {
+               switches[i].live_cond = SWITCH_IGNORE;
+               switches[i].validated = 1;
+             }
+           else
+             ordered = 1, switches[i].ordering = 1;
+         }
     }
   else
     {
@@ -4833,6 +5096,7 @@ next_member:
                    do_spec_1 (string, 0, &switches[i].part1[hard_match_len]);
                    /* Pass any arguments this switch has.  */
                    give_switch (i, 1, 1);
+                   suffix_subst = NULL;
                  }
 
              /* We didn't match.  Try again.  */
@@ -4883,16 +5147,13 @@ next_member:
              switches[i].live_cond = SWITCH_IGNORE;
              switches[i].validated = 1;
            }
+         else if (ordered || *p == '&')
+           ordered = 1, switches[i].ordering = 1;
          else if (*p == '}')
-           {
-             give_switch (i, 0, include_blanks);
-           }
+           give_switch (i, 0, include_blanks);
          else
-           {
-             if (do_spec_1 (save_string (body, endbody - body - 1),
-                            0, NULL_PTR) < 0)
-               return 0;
-           }
+           /* Even if many alternatives are matched, only output once.  */
+           true_once = 1;
        }
       else if (pipe_p)
        {
@@ -4907,6 +5168,32 @@ next_member:
   if (*p++ == '|')
     goto next_member;
 
+  if (p[-1] == '&')
+    {
+      body = 0;
+      goto next_ampersand;
+    }
+
+  if (ordered)
+    {
+      int i;
+      /* Doing this set of switches later preserves their command-line
+        ordering.  This is needed for e.g. -U, -D and -A.  */
+      for (i = 0; i < n_switches; i++)
+       if (switches[i].ordering == 1)
+         {
+           switches[i].ordering = 0;
+           give_switch (i, 0, include_blanks);
+         }
+    }
+  /* Process the spec just once, regardless of match count.  */
+  else if (true_once)
+    {
+      if (do_spec_1 (save_string (body, endbody - body - 1),
+                    0, NULL_PTR) < 0)
+       return 0;
+    }
+
   return endbody;
 }
 \f
@@ -5017,9 +5304,29 @@ give_switch (switchnum, omit_first_word, include_blanks)
       const char **p;
       for (p = switches[switchnum].args; *p; p++)
        {
+         const char *arg = *p;
+
          if (include_blanks)
            do_spec_1 (" ", 0, NULL_PTR);
-         do_spec_1 (*p, 1, NULL_PTR);
+         if (suffix_subst)
+           {
+             unsigned length = strlen (arg);
+
+             while (length-- && !IS_DIR_SEPARATOR (arg[length]))
+               if (arg[length] == '.')
+                 {
+                   ((char *)arg)[length] = 0;
+                   break;
+                 }
+             do_spec_1 (arg, 1, NULL_PTR);
+             if (!arg[length])
+               {
+                 ((char *)arg)[length] = '.';
+                 do_spec_1 (suffix_subst, 1, NULL_PTR);
+               }
+           }
+         else
+           do_spec_1 (arg, 1, NULL_PTR);
        }
     }
 
@@ -5178,14 +5485,23 @@ main (argc, argv)
     --p;
   programname = p;
 
+  xmalloc_set_program_name (programname);
+
 #ifdef GCC_DRIVER_HOST_INITIALIZATION
   /* Perform host dependant initialization when needed.  */
   GCC_DRIVER_HOST_INITIALIZATION;
 #endif
 
+/* LC_CTYPE determines the character set used by the terminal so it has be set
+   to output messages correctly.  */
+
 #ifdef HAVE_LC_MESSAGES
+  setlocale (LC_CTYPE, "");
   setlocale (LC_MESSAGES, "");
+#else
+  setlocale (LC_ALL, "");
 #endif
+
   (void) bindtextdomain (PACKAGE, localedir);
   (void) textdomain (PACKAGE);
 
@@ -5201,6 +5517,9 @@ main (argc, argv)
   if (signal (SIGPIPE, SIG_IGN) != SIG_IGN)
     signal (SIGPIPE, fatal_error);
 #endif
+  /* We *MUST* set SIGCHLD to SIG_DFL so that the wait4() call will
+     receive the signal.  A different setting is inheritable */
+  signal (SIGCHLD, SIG_DFL);
 
   argbuf_length = 10;
   argbuf = (const char **) xmalloc (argbuf_length * sizeof (const char *));
@@ -5370,14 +5689,7 @@ main (argc, argv)
         standard_exec_prefix.  This lets us move the installed tree
         as a unit.  If GCC_EXEC_PREFIX is defined, base
         standard_startfile_prefix on that as well.  */
-      if (IS_DIR_SEPARATOR (*standard_startfile_prefix)
-           || *standard_startfile_prefix == '$'
-#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])))
-#endif
-         )
+      if (IS_ABSOLUTE_PATHNAME (standard_startfile_prefix))
        add_prefix (&startfile_prefixes, standard_startfile_prefix, "BINUTILS",
                    PREFIX_PRIORITY_LAST, 0, NULL_PTR);
       else
@@ -5405,7 +5717,8 @@ main (argc, argv)
     }
   else
     {
-      if (!IS_DIR_SEPARATOR (*standard_startfile_prefix) && gcc_exec_prefix)
+      if (!IS_ABSOLUTE_PATHNAME (standard_startfile_prefix)
+         && gcc_exec_prefix)
        add_prefix (&startfile_prefixes,
                    concat (gcc_exec_prefix, machine_suffix,
                            standard_startfile_prefix, NULL_PTR),
@@ -5487,6 +5800,16 @@ main (argc, argv)
       return (0);
     }
 
+  if (target_help_flag)
+   {
+      /* Print if any target specific options.*/
+
+      /* We do not exit here. Instead we have created a fake input file
+         called 'target-dummy' which needs to be compiled, and we pass this
+         on to the various sub-processes, along with the --target-help
+         switch. */
+    }
+
   if (print_help_list)
     {
       display_help ();
@@ -5544,7 +5867,6 @@ main (argc, argv)
 
   for (i = 0; (int) i < n_infiles; i++)
     {
-      register struct compiler *cp = 0;
       int this_file_error = 0;
 
       /* Tell do_spec what to substitute for %i.  */
@@ -5558,17 +5880,18 @@ main (argc, argv)
 
       /* Figure out which compiler from the file's suffix.  */
 
-      cp = lookup_compiler (infiles[i].name, input_filename_length,
-                           infiles[i].language);
-
-      if (cp)
+      input_file_compiler
+       = lookup_compiler (infiles[i].name, input_filename_length,
+                          infiles[i].language);
+      
+      if (input_file_compiler)
        {
          /* Ok, we found an applicable compiler.  Run its spec.  */
 
-         if (cp->spec[0] == '#')
+         if (input_file_compiler->spec[0] == '#')
            error ("%s: %s compiler not installed on this system",
-                  input_filename, &cp->spec[1]);
-         value = do_spec (cp->spec);
+                  input_filename, &input_file_compiler->spec[1]);
+         value = do_spec (input_file_compiler->spec);
          if (value < 0)
            this_file_error = 1;
        }
@@ -5741,7 +6064,7 @@ save_string (s, len)
   return result;
 }
 
-static void
+void
 pfatal_with_name (name)
      const char *name;
 {
@@ -5809,7 +6132,7 @@ fatal VPARAMS ((const char *msgid, ...))
   exit (1);
 }
 
-static void
+void
 error VPARAMS ((const char *msgid, ...))
 {
 #ifndef ANSI_PROTOTYPES
@@ -5892,19 +6215,21 @@ validate_switches (start)
   register const char *p = start;
   const char *filter;
   register int i;
-  int suffix = 0;
+  int suffix;
 
   if (*p == '|')
     ++p;
 
+next_member:
   if (*p == '!')
     ++p;
 
+  suffix = 0;
   if (*p == '.')
     suffix = 1, ++p;
 
   filter = p;
-  while (*p != ':' && *p != '}')
+  while (*p != ':' && *p != '}' && *p != '|' && *p != '&')
     p++;
 
   if (suffix)
@@ -5912,9 +6237,8 @@ validate_switches (start)
   else if (p[-1] == '*')
     {
       /* Mark all matching switches as valid.  */
-      --p;
       for (i = 0; i < n_switches; i++)
-       if (!strncmp (switches[i].part1, filter, p - filter))
+       if (!strncmp (switches[i].part1, filter, p - filter - 1))
          switches[i].validated = 1;
     }
   else
@@ -5927,6 +6251,9 @@ validate_switches (start)
            switches[i].validated = 1;
        }
     }
+
+  if (*p++ == '|' || p[-1] == '&')
+    goto next_member;
 }
 \f
 /* Check whether a particular argument was used.  The first time we