OSDN Git Service

* gcc.c (DEFAULT_SWITCH_CURTAILS_COMPILATION,
[pf3gnuchains/gcc-fork.git] / gcc / gcc.c
index 35a1b1e..30029d5 100644 (file)
--- a/gcc/gcc.c
+++ b/gcc/gcc.c
@@ -30,44 +30,6 @@ 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 gcc.h.  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 "coretypes.h"
@@ -140,44 +102,9 @@ int is_cpp_driver;
 /* Flag set to nonzero if an @file argument has been supplied to gcc.  */
 static bool at_file_supplied;
 
-/* Flag saying to pass the greatest exit code returned by a sub-process
-   to the calling program.  */
-static int pass_exit_codes;
-
 /* Definition of string containing the arguments given to configure.  */
 #include "configargs.h"
 
-/* Flag saying to print the directories gcc will search through looking for
-   programs, libraries, etc.  */
-
-static int print_search_dirs;
-
-/* Flag saying to print the full filename of this file
-   as found through our usual search mechanism.  */
-
-static const char *print_file_name = NULL;
-
-/* As print_file_name, but search for executable file.  */
-
-static const char *print_prog_name = NULL;
-
-/* Flag saying to print the relative path we'd use to
-   find libgcc.a given the current compiler flags.  */
-
-static int print_multi_directory;
-
-static int print_sysroot;
-
-/* Flag saying to print the relative path we'd use to
-   find OS libraries given the current compiler flags.  */
-
-static int print_multi_os_directory;
-
-/* Flag saying to print the list of subdirectories and
-   compiler flags used to select them in a standard form.  */
-
-static int print_multi_lib;
-
 /* Flag saying to print the command line options understood by gcc and its
    sub-processes.  */
 
@@ -187,11 +114,6 @@ static int print_help_list;
 
 static int print_version;
 
-/* Flag saying to print the sysroot suffix used for searching for
-   headers.  */
-
-static int print_sysroot_headers_suffix;
-
 /* Flag indicating whether we should print the command and arguments */
 
 static int verbose_flag;
@@ -207,11 +129,6 @@ static int verbose_only_flag;
 
 static int print_subprocess_help;
 
-/* Flag indicating whether we should report subprocess execution times
-   (if this is supported by the system - see pexecute.c).  */
-
-static int report_times;
-
 /* Whether we should report subprocess execution times to a file.  */
 
 FILE *report_times_to_file = NULL;
@@ -250,15 +167,6 @@ static enum save_temps {
 static char *save_temps_prefix = 0;
 static size_t save_temps_length = 0;
 
-/* Nonzero means pass multiple source files to the compiler at one time.  */
-
-static int combine_flag = 0;
-
-/* Nonzero means use pipes to communicate between subprocesses.
-   Overridden by either of the above two flags.  */
-
-static int use_pipes;
-
 /* The compiler version.  */
 
 static const char *compiler_version;
@@ -295,14 +203,6 @@ static struct obstack obstack;
 
 static struct obstack collect_obstack;
 
-/* This is a list of a wrapper program and its arguments.
-   e.g. wrapper_string of "strace,-c"
-   will cause all programs to run as
-       strace -c program arguments
-   instead of just
-       program arguments */
-static const char  *wrapper_string;
-
 /* Forward declaration for prototypes.  */
 struct path_prefix;
 struct prefix_list;
@@ -325,7 +225,6 @@ static void add_prefix (struct path_prefix *, const char *, const char *,
                        int, int, int);
 static void add_sysrooted_prefix (struct path_prefix *, const char *,
                                  const char *, int, int, int);
-static void translate_options (int *, const char *const **);
 static char *skip_whitespace (char *);
 static void delete_if_ordinary (const char *);
 static void delete_temp_files (void);
@@ -362,7 +261,7 @@ static void display_help (void);
 static void add_preprocessor_option (const char *, int);
 static void add_assembler_option (const char *, int);
 static void add_linker_option (const char *, int);
-static void process_command (int, const char **);
+static void process_command (unsigned int, struct cl_decoded_option *);
 static int execute (void);
 static void alloc_args (void);
 static void clear_args (void);
@@ -379,6 +278,7 @@ static const char *getenv_spec_function (int, const char **);
 static const char *if_exists_spec_function (int, const char **);
 static const char *if_exists_else_spec_function (int, const char **);
 static const char *replace_outfile_spec_function (int, const char **);
+static const char *remove_outfile_spec_function (int, const char **);
 static const char *version_compare_spec_function (int, const char **);
 static const char *include_spec_function (int, const char **);
 static const char *find_file_spec_function (int, const char **);
@@ -645,6 +545,16 @@ proper position among the other output files.  */
 #define MFLIB_SPEC "%{fmudflap|fmudflapth: -export-dynamic}"
 #endif
 
+/* When using -fsplit-stack we need to wrap pthread_create, in order
+   to initialize the stack guard.  We always use wrapping, rather than
+   shared library ordering, and we keep the wrapper function in
+   libgcc.  This is not yet a real spec, though it could become one;
+   it is currently just stuffed into LINK_SPEC.  FIXME: This wrapping
+   only works with GNU ld and gold.  FIXME: This is incompatible with
+   -fmudflap when linking statically, which wants to do its own
+   wrapping.  */
+#define STACK_SPLIT_SPEC " %{fsplit-stack: --wrap=pthread_create}"
+
 /* config.h can define LIBGCC_SPEC to override how and when libgcc.a is
    included.  */
 #ifndef LIBGCC_SPEC
@@ -757,7 +667,8 @@ proper position among the other output files.  */
    "%X %{o*} %{A} %{d} %{e*} %{m} %{N} %{n} %{r}\
     %{s} %{t} %{u*} %{x} %{z} %{Z} %{!A:%{!nostdlib:%{!nostartfiles:%S}}}\
     %{static:} %{L*} %(mfwrap) %(link_libgcc) %o\
-    %{fopenmp|ftree-parallelize-loops=*:%:include(libgomp.spec)%(link_gomp)} %(mflib)\
+    %{fopenmp|ftree-parallelize-loops=*:%:include(libgomp.spec)%(link_gomp)}\
+    %(mflib) " STACK_SPLIT_SPEC "\
     %{fprofile-arcs|fprofile-generate*|coverage:-lgcov}\
     %{!nostdlib:%{!nodefaultlibs:%(link_ssp) %(link_gcc_c_sequence)}}\
     %{!A:%{!nostdlib:%{!nostartfiles:%E}}} %{T*} }}}}}}"
@@ -863,9 +774,10 @@ static const char *cc1_options =
  %{!fcompare-debug-second:%{c|S:%{o*:-auxbase-strip %*}%{!o*:-auxbase %b}}}%{!c:%{!S:-auxbase %b}} \
  %{g*} %{O*} %{W*&pedantic*} %{w} %{std*&ansi&trigraphs}\
  %{v:-version} %{pg:-p} %{p} %{f*} %{undef}\
- %{Qn:-fno-ident} %{--help:--help}\
- %{--target-help:--target-help}\
- %{--help=*:--help=%(VALUE)}\
+ %{Qn:-fno-ident} %{-help:--help}\
+ %{-target-help:--target-help}\
+ %{-version:--version}\
+ %{-help=*:--help=%*}\
  %{!fsyntax-only:%{S:%W{o*}%{!o*:-o %b.s}}}\
  %{fsyntax-only:-o %j} %{-param*}\
  %{fmudflap|fmudflapth:-fno-builtin -fno-merge-constants}\
@@ -947,17 +859,6 @@ struct user_specs
 static struct user_specs *user_specs_head, *user_specs_tail;
 
 \f
-#ifdef HAVE_TARGET_EXECUTABLE_SUFFIX
-/* This defines which switches stop a full compilation.  */
-#define DEFAULT_SWITCH_CURTAILS_COMPILATION(CHAR) \
-  ((CHAR) == 'c' || (CHAR) == 'S' || (CHAR) == 'E')
-
-#ifndef SWITCH_CURTAILS_COMPILATION
-#define SWITCH_CURTAILS_COMPILATION(CHAR) \
-  DEFAULT_SWITCH_CURTAILS_COMPILATION(CHAR)
-#endif
-#endif
-
 /* Record the mapping from file suffixes for compilation specs.  */
 
 struct compiler
@@ -1020,7 +921,7 @@ static const struct compiler default_compilers[] =
   {".java", "#Java", 0, 0, 0}, {".class", "#Java", 0, 0, 0},
   {".zip", "#Java", 0, 0, 0}, {".jar", "#Java", 0, 0, 0},
   /* Next come the entries for C.  */
-  {".c", "@c", 0, 1, 1},
+  {".c", "@c", 0, 0, 1},
   {"@c",
    /* cc1 has an integrated ISO C preprocessor.  We should invoke the
       external preprocessor if -save-temps is given.  */
@@ -1028,20 +929,13 @@ static const struct compiler default_compilers[] =
       %{!E:%{!M:%{!MM:\
           %{traditional|ftraditional:\
 %eGNU C no longer supports -traditional without -E}\
-       %{!combine:\
-         %{save-temps*|traditional-cpp|no-integrated-cpp:%(trad_capable_cpp) \
-               %(cpp_options) -o %{save-temps*:%b.i} %{!save-temps*:%g.i} \n\
-                   cc1 -fpreprocessed %{save-temps*:%b.i} %{!save-temps*:%g.i} \
-                       %(cc1_options)}\
-         %{!save-temps*:%{!traditional-cpp:%{!no-integrated-cpp:\
-               cc1 %(cpp_unique_options) %(cc1_options)}}}\
-          %{!fsyntax-only:%(invoke_as)}} \
-      %{combine:\
-         %{save-temps*|traditional-cpp|no-integrated-cpp:%(trad_capable_cpp) \
-               %(cpp_options) -o %{save-temps*:%b.i} %{!save-temps*:%g.i}}\
-         %{!save-temps*:%{!traditional-cpp:%{!no-integrated-cpp:\
-               cc1 %(cpp_unique_options) %(cc1_options)}}\
-                %{!fsyntax-only:%(invoke_as)}}}}}}", 0, 1, 1},
+      %{save-temps*|traditional-cpp|no-integrated-cpp:%(trad_capable_cpp) \
+         %(cpp_options) -o %{save-temps*:%b.i} %{!save-temps*:%g.i} \n\
+           cc1 -fpreprocessed %{save-temps*:%b.i} %{!save-temps*:%g.i} \
+         %(cc1_options)}\
+      %{!save-temps*:%{!traditional-cpp:%{!no-integrated-cpp:\
+         cc1 %(cpp_unique_options) %(cc1_options)}}}\
+      %{!fsyntax-only:%(invoke_as)}}}}", 0, 0, 1},
   {"-",
    "%{!E:%e-E or -x required when input is from standard input}\
     %(trad_capable_cpp) %(cpp_options) %(cpp_debug_options)", 0, 0, 0},
@@ -1061,7 +955,7 @@ static const struct compiler default_compilers[] =
                cc1 %(cpp_unique_options) %(cc1_options)\
                     %{!fdump-ada-spec*:-o %g.s %{!o*:--output-pch=%i.gch}\
                     %W{o*:--output-pch=%*}}%V}}}}}}", 0, 0, 0},
-  {".i", "@cpp-output", 0, 1, 0},
+  {".i", "@cpp-output", 0, 0, 0},
   {"@cpp-output",
    "%{!M:%{!MM:%{!E:cc1 -fpreprocessed %i %(cc1_options) %{!fsyntax-only:%(invoke_as)}}}}", 0, 1, 0},
   {".s", "@assembler", 0, 1, 0},
@@ -1110,342 +1004,6 @@ static char **assembler_options;
 static int n_preprocessor_options;
 static char **preprocessor_options;
 \f
-/* Define how to map long options into short ones.  */
-
-/* This structure describes one mapping.  */
-struct option_map
-{
-  /* The long option's name.  */
-  const char *const name;
-  /* The equivalent short option.  */
-  const char *const equivalent;
-  /* Argument info.  A string of flag chars; NULL equals no options.
-     a => argument required.
-     o => argument optional.
-     j => join argument to equivalent, making one word.
-     * => require other text after NAME as an argument.  */
-  const char *const arg_info;
-};
-
-/* This is the table of mappings.  Mappings are tried sequentially
-   for each option encountered; the first one that matches, wins.  */
-
-static const struct option_map option_map[] =
- {
-   {"--all-warnings", "-Wall", 0},
-   {"--ansi", "-ansi", 0},
-   {"--assemble", "-S", 0},
-   {"--assert", "-A", "a"},
-   {"--classpath", "-fclasspath=", "aj"},
-   {"--bootclasspath", "-fbootclasspath=", "aj"},
-   {"--CLASSPATH", "-fclasspath=", "aj"},
-   {"--combine", "-combine", 0},
-   {"--comments", "-C", 0},
-   {"--comments-in-macros", "-CC", 0},
-   {"--compile", "-c", 0},
-   {"--debug", "-g", "oj"},
-   {"--define-macro", "-D", "aj"},
-   {"--dependencies", "-M", 0},
-   {"--dump", "-d", "a"},
-   {"--dumpbase", "-dumpbase", "a"},
-   {"--dumpdir", "-dumpdir", "a"},
-   {"--encoding", "-fencoding=", "aj"},
-   {"--entry", "-e", 0},
-   {"--extra-warnings", "-W", 0},
-   {"--extdirs", "-fextdirs=", "aj"},
-   {"--for-assembler", "-Wa", "a"},
-   {"--for-linker", "-Xlinker", "a"},
-   {"--force-link", "-u", "a"},
-   {"--coverage", "-coverage", 0},
-   {"--imacros", "-imacros", "a"},
-   {"--include", "-include", "a"},
-   {"--include-barrier", "-I-", 0},
-   {"--include-directory", "-I", "aj"},
-   {"--include-directory-after", "-idirafter", "a"},
-   {"--include-prefix", "-iprefix", "a"},
-   {"--include-with-prefix", "-iwithprefix", "a"},
-   {"--include-with-prefix-before", "-iwithprefixbefore", "a"},
-   {"--include-with-prefix-after", "-iwithprefix", "a"},
-   {"--language", "-x", "a"},
-   {"--library-directory", "-L", "a"},
-   {"--machine", "-m", "aj"},
-   {"--machine-", "-m", "*j"},
-   {"--no-canonical-prefixes", "-no-canonical-prefixes", 0},
-   {"--no-integrated-cpp", "-no-integrated-cpp", 0},
-   {"--no-line-commands", "-P", 0},
-   {"--no-precompiled-includes", "-noprecomp", 0},
-   {"--no-standard-includes", "-nostdinc", 0},
-   {"--no-standard-libraries", "-nostdlib", 0},
-   {"--no-warnings", "-w", 0},
-   {"--optimize", "-O", "oj"},
-   {"--output", "-o", "a"},
-   {"--output-class-directory", "-foutput-class-dir=", "ja"},
-   {"--param", "--param", "a"},
-   {"--pass-exit-codes", "-pass-exit-codes", 0},
-   {"--pedantic", "-pedantic", 0},
-   {"--pedantic-errors", "-pedantic-errors", 0},
-   {"--pie", "-pie", 0},
-   {"--pipe", "-pipe", 0},
-   {"--prefix", "-B", "a"},
-   {"--preprocess", "-E", 0},
-   {"--print-search-dirs", "-print-search-dirs", 0},
-   {"--print-file-name", "-print-file-name=", "aj"},
-   {"--print-libgcc-file-name", "-print-libgcc-file-name", 0},
-   {"--print-missing-file-dependencies", "-MG", 0},
-   {"--print-multi-lib", "-print-multi-lib", 0},
-   {"--print-multi-directory", "-print-multi-directory", 0},
-   {"--print-multi-os-directory", "-print-multi-os-directory", 0},
-   {"--print-prog-name", "-print-prog-name=", "aj"},
-   {"--print-sysroot", "-print-sysroot", 0},
-   {"--print-sysroot-headers-suffix", "-print-sysroot-headers-suffix", 0},
-   {"--profile", "-p", 0},
-   {"--resource", "-fcompile-resource=", "aj"},
-   {"--save-temps", "-save-temps", 0},
-   {"--shared", "-shared", 0},
-   {"--specs", "-specs=", "aj"},
-   {"--static", "-static", 0},
-   {"--std", "-std=", "aj"},
-   {"--symbolic", "-symbolic", 0},
-   {"--sysroot", "--sysroot=", "aj"},
-   {"--time", "-time", 0},
-   {"--trace-includes", "-H", 0},
-   {"--traditional", "-traditional", 0},
-   {"--traditional-cpp", "-traditional-cpp", 0},
-   {"--trigraphs", "-trigraphs", 0},
-   {"--undefine-macro", "-U", "aj"},
-   {"--user-dependencies", "-MM", 0},
-   {"--verbose", "-v", 0},
-   {"--warn-", "-W", "*j"},
-   {"--write-dependencies", "-MD", 0},
-   {"--write-user-dependencies", "-MMD", 0},
-   {"--", "-f", "*j"}
- };
-\f
-
-#ifdef TARGET_OPTION_TRANSLATE_TABLE
-static const struct {
-  const char *const option_found;
-  const char *const replacements;
-} target_option_translations[] =
-{
-  TARGET_OPTION_TRANSLATE_TABLE,
-  { 0, 0 }
-};
-#endif
-
-/* Translate the options described by *ARGCP and *ARGVP.
-   Make a new vector and store it back in *ARGVP,
-   and store its length in *ARGCP.  */
-
-static void
-translate_options (int *argcp, const char *const **argvp)
-{
-  int i;
-  int argc = *argcp;
-  const char *const *argv = *argvp;
-  int newvsize = (argc + 2) * 2 * sizeof (const char *);
-  const char **newv = XNEWVAR (const char *, newvsize);
-  int newindex = 0;
-
-  i = 0;
-  newv[newindex++] = argv[i++];
-
-  while (i < argc)
-    {
-#ifdef TARGET_OPTION_TRANSLATE_TABLE
-      int tott_idx;
-
-      for (tott_idx = 0;
-          target_option_translations[tott_idx].option_found;
-          tott_idx++)
-       {
-         if (strcmp (target_option_translations[tott_idx].option_found,
-                     argv[i]) == 0)
-           {
-             int spaces = 1;
-             const char *sp;
-             char *np;
-
-             for (sp = target_option_translations[tott_idx].replacements;
-                  *sp; sp++)
-               {
-                 if (*sp == ' ')
-                   spaces ++;
-               }
-
-             newvsize += spaces * sizeof (const char *);
-             newv =  XRESIZEVAR (const char *, newv, newvsize);
-
-             sp = target_option_translations[tott_idx].replacements;
-             np = xstrdup (sp);
-
-             while (1)
-               {
-                 while (*np == ' ')
-                   np++;
-                 if (*np == 0)
-                   break;
-                 newv[newindex++] = np;
-                 while (*np != ' ' && *np)
-                   np++;
-                 if (*np == 0)
-                   break;
-                 *np++ = 0;
-               }
-
-             i ++;
-             break;
-           }
-       }
-      if (target_option_translations[tott_idx].option_found)
-       continue;
-#endif
-
-      /* Translate -- options.  */
-      if (argv[i][0] == '-' && argv[i][1] == '-')
-       {
-         size_t j;
-         /* Find a mapping that applies to this option.  */
-         for (j = 0; j < ARRAY_SIZE (option_map); j++)
-           {
-             size_t optlen = strlen (option_map[j].name);
-             size_t arglen = strlen (argv[i]);
-             size_t complen = arglen > optlen ? optlen : arglen;
-             const char *arginfo = option_map[j].arg_info;
-
-             if (arginfo == 0)
-               arginfo = "";
-
-             if (!strncmp (argv[i], option_map[j].name, complen))
-               {
-                 const char *arg = 0;
-
-                 if (arglen < optlen)
-                   {
-                     size_t k;
-                     for (k = j + 1; k < ARRAY_SIZE (option_map); k++)
-                       if (strlen (option_map[k].name) >= arglen
-                           && !strncmp (argv[i], option_map[k].name, arglen))
-                         {
-                           error ("ambiguous abbreviation %s", argv[i]);
-                           break;
-                         }
-
-                     if (k != ARRAY_SIZE (option_map))
-                       break;
-                   }
-
-                 if (arglen > optlen)
-                   {
-                     /* If the option has an argument, accept that.  */
-                     if (argv[i][optlen] == '=')
-                       arg = argv[i] + optlen + 1;
-
-                     /* If this mapping requires extra text at end of name,
-                        accept that as "argument".  */
-                     else if (strchr (arginfo, '*') != 0)
-                       arg = argv[i] + optlen;
-
-                     /* Otherwise, extra text at end means mismatch.
-                        Try other mappings.  */
-                     else
-                       continue;
-                   }
-
-                 else if (strchr (arginfo, '*') != 0)
-                   {
-                     error ("incomplete %qs option", option_map[j].name);
-                     break;
-                   }
-
-                 /* Handle arguments.  */
-                 if (strchr (arginfo, 'a') != 0)
-                   {
-                     if (arg == 0)
-                       {
-                         if (i + 1 == argc)
-                           {
-                             error ("missing argument to %qs option",
-                                    option_map[j].name);
-                             break;
-                           }
-
-                         arg = argv[++i];
-                       }
-                   }
-                 else if (strchr (arginfo, '*') != 0)
-                   ;
-                 else if (strchr (arginfo, 'o') == 0)
-                   {
-                     if (arg != 0)
-                       error ("extraneous argument to %qs option",
-                              option_map[j].name);
-                     arg = 0;
-                   }
-
-                 /* Store the translation as one argv elt or as two.  */
-                 if (arg != 0 && strchr (arginfo, 'j') != 0)
-                   newv[newindex++] = concat (option_map[j].equivalent, arg,
-                                              NULL);
-                 else if (arg != 0)
-                   {
-                     newv[newindex++] = option_map[j].equivalent;
-                     newv[newindex++] = arg;
-                   }
-                 else
-                   newv[newindex++] = option_map[j].equivalent;
-
-                 break;
-               }
-           }
-         i++;
-       }
-
-      /* Handle old-fashioned options--just copy them through,
-        with their arguments.  */
-      else if (argv[i][0] == '-')
-       {
-         const char *p = argv[i] + 1;
-         int c = *p;
-         int nskip = 1;
-
-         if (SWITCH_TAKES_ARG (c) > (p[1] != 0))
-           nskip += SWITCH_TAKES_ARG (c) - (p[1] != 0);
-         else if (WORD_SWITCH_TAKES_ARG (p))
-           nskip += WORD_SWITCH_TAKES_ARG (p);
-         else if ((c == 'B' || c == 'b' || c == 'x')
-                  && p[1] == 0)
-           nskip += 1;
-         else if (! strcmp (p, "Xlinker"))
-           nskip += 1;
-         else if (! strcmp (p, "Xpreprocessor"))
-           nskip += 1;
-         else if (! strcmp (p, "Xassembler"))
-           nskip += 1;
-
-         /* Watch out for an option at the end of the command line that
-            is missing arguments, and avoid skipping past the end of the
-            command line.  */
-         if (nskip + i > argc)
-           nskip = argc - i;
-
-         while (nskip > 0)
-           {
-             newv[newindex++] = argv[i++];
-             nskip--;
-           }
-       }
-      else
-       /* Ordinary operands.  */
-       newv[newindex++] = argv[i++];
-    }
-
-  newv[newindex] = 0;
-
-  *argvp = newv;
-  *argcp = newindex;
-}
-\f
 static char *
 skip_whitespace (char *p)
 {
@@ -1677,6 +1235,7 @@ static const struct spec_function static_spec_functions[] =
   { "if-exists",               if_exists_spec_function },
   { "if-exists-else",          if_exists_else_spec_function },
   { "replace-outfile",         replace_outfile_spec_function },
+  { "remove-outfile",          remove_outfile_spec_function },
   { "version-compare",         version_compare_spec_function },
   { "include",                 include_spec_function },
   { "find-file",               find_file_spec_function },
@@ -3382,7 +2941,6 @@ display_help (void)
   fputs (_("  -Xassembler <arg>        Pass <arg> on to the assembler\n"), stdout);
   fputs (_("  -Xpreprocessor <arg>     Pass <arg> on to the preprocessor\n"), stdout);
   fputs (_("  -Xlinker <arg>           Pass <arg> on to the linker\n"), stdout);
-  fputs (_("  -combine                 Pass multiple source files to compiler at once\n"), stdout);
   fputs (_("  -save-temps              Do not delete intermediate files\n"), stdout);
   fputs (_("  -save-temps=<arg>        Do not delete intermediate files\n"), stdout);
   fputs (_("\
@@ -3506,20 +3064,462 @@ alloc_switch (void)
     }
 }
 
+/* Save an option OPT with N_ARGS arguments in array ARGS, marking it
+   as validated if VALIDATED.  */
+
+static void
+save_switch (const char *opt, size_t n_args, const char *const *args,
+            bool validated)
+{
+  alloc_switch ();
+  switches[n_switches].part1 = opt + 1;
+  if (n_args == 0)
+    switches[n_switches].args = 0;
+  else
+    {
+      switches[n_switches].args = XNEWVEC (const char *, n_args + 1);
+      memcpy (switches[n_switches].args, args, n_args * sizeof (const char *));
+      switches[n_switches].args[n_args] = NULL;
+    }
+
+  switches[n_switches].live_cond = 0;
+  switches[n_switches].validated = validated;
+  switches[n_switches].ordering = 0;
+  n_switches++;
+}
+
+/* Handle an option DECODED that is unknown to the option-processing
+   machinery, but may be known to specs.  */
+
+static bool
+driver_unknown_option_callback (const struct cl_decoded_option *decoded)
+{
+  save_switch (decoded->canonical_option[0],
+              decoded->canonical_option_num_elements - 1,
+              &decoded->canonical_option[1], false);
+
+  return false;
+}
+
+/* Handle an option DECODED that is not marked as CL_DRIVER.
+   LANG_MASK will always be CL_DRIVER.  */
+
+static void
+driver_wrong_lang_callback (const struct cl_decoded_option *decoded,
+                           unsigned int lang_mask ATTRIBUTE_UNUSED)
+{
+  /* At this point, non-driver options are accepted (and expected to
+     be passed down by specs) unless marked to be rejected by the
+     driver.  Options to be rejected by the driver but accepted by the
+     compilers proper are treated just like completely unknown
+     options.  */
+  const struct cl_option *option = &cl_options[decoded->opt_index];
+
+  if (option->flags & CL_REJECT_DRIVER)
+    error ("unrecognized command line option %qs",
+          decoded->orig_option_with_args_text);
+  else
+    driver_unknown_option_callback (decoded);
+}
+
+/* Note that an option (index OPT_INDEX, argument ARG, value VALUE)
+   has been successfully handled with a handler for mask MASK.  */
+
+static void
+driver_post_handling_callback (const struct cl_decoded_option *decoded ATTRIBUTE_UNUSED,
+                              unsigned int mask ATTRIBUTE_UNUSED)
+{
+  /* Nothing to do here.  */
+}
+
+static const char *spec_lang = 0;
+static int last_language_n_infiles;
+
+/* Handle a driver option; arguments and return value as for
+   handle_option.  */
+
+static bool
+driver_handle_option (struct gcc_options *opts,
+                     struct gcc_options *opts_set,
+                     const struct cl_decoded_option *decoded,
+                     unsigned int lang_mask ATTRIBUTE_UNUSED, int kind,
+                     const struct cl_option_handlers *handlers ATTRIBUTE_UNUSED)
+{
+  size_t opt_index = decoded->opt_index;
+  const char *arg = decoded->arg;
+  const char *compare_debug_replacement_opt;
+  int value = decoded->value;
+  bool validated = false;
+  bool do_save = true;
+
+  gcc_assert (opts == &global_options);
+  gcc_assert (opts_set == &global_options_set);
+  gcc_assert (kind == DK_UNSPECIFIED);
+
+  switch (opt_index)
+    {
+    case OPT_dumpspecs:
+      {
+       struct spec_list *sl;
+       init_spec ();
+       for (sl = specs; sl; sl = sl->next)
+         printf ("*%s:\n%s\n\n", sl->name, *(sl->ptr_spec));
+       if (link_command_spec)
+         printf ("*link_command:\n%s\n\n", link_command_spec);
+       exit (0);
+      }
+
+    case OPT_dumpversion:
+      printf ("%s\n", spec_version);
+      exit (0);
+
+    case OPT_dumpmachine:
+      printf ("%s\n", spec_machine);
+      exit (0);
+
+    case OPT__version:
+      print_version = 1;
+
+      /* CPP driver cannot obtain switch from cc1_options.  */
+      if (is_cpp_driver)
+       add_preprocessor_option ("--version", strlen ("--version"));
+      add_assembler_option ("--version", strlen ("--version"));
+      add_linker_option ("--version", strlen ("--version"));
+      break;
+
+    case OPT__help:
+      print_help_list = 1;
+
+      /* CPP driver cannot obtain switch from cc1_options.  */
+      if (is_cpp_driver)
+       add_preprocessor_option ("--help", 6);
+      add_assembler_option ("--help", 6);
+      add_linker_option ("--help", 6);
+      break;
+
+    case OPT__help_:
+      print_subprocess_help = 2;
+      break;
+
+    case OPT__target_help:
+      print_subprocess_help = 1;
+
+      /* CPP driver cannot obtain switch from cc1_options.  */
+      if (is_cpp_driver)
+       add_preprocessor_option ("--target-help", 13);
+      add_assembler_option ("--target-help", 13);
+      add_linker_option ("--target-help", 13);
+      break;
+
+    case OPT_pass_exit_codes:
+    case OPT_print_search_dirs:
+    case OPT_print_file_name_:
+    case OPT_print_prog_name_:
+    case OPT_print_multi_lib:
+    case OPT_print_multi_directory:
+    case OPT_print_sysroot:
+    case OPT_print_multi_os_directory:
+    case OPT_print_sysroot_headers_suffix:
+    case OPT_time:
+    case OPT_wrapper:
+      /* These options set the variables specified in common.opt
+        automatically, and do not need to be saved for spec
+        processing.  */
+      do_save = false;
+      break;
+
+    case OPT_print_libgcc_file_name:
+      print_file_name = "libgcc.a";
+      do_save = false;
+      break;
+
+    case OPT_fcompare_debug_second:
+      compare_debug_second = 1;
+      break;
+
+    case OPT_fcompare_debug:
+      switch (value)
+       {
+       case 0:
+         compare_debug_replacement_opt = "-fcompare-debug=";
+         arg = "";
+         goto compare_debug_with_arg;
+
+       case 1:
+         compare_debug_replacement_opt = "-fcompare-debug=-gtoggle";
+         arg = "-gtoggle";
+         goto compare_debug_with_arg;
+
+       default:
+         gcc_unreachable ();
+       }
+      break;
+
+    case OPT_fcompare_debug_:
+      compare_debug_replacement_opt = decoded->canonical_option[0];
+    compare_debug_with_arg:
+      gcc_assert (decoded->canonical_option_num_elements == 1);
+      gcc_assert (arg != NULL);
+      if (arg)
+       compare_debug = 1;
+      else
+       compare_debug = -1;
+      if (compare_debug < 0)
+       compare_debug_opt = NULL;
+      else
+       compare_debug_opt = arg;
+      save_switch (compare_debug_replacement_opt, 0, NULL, validated);
+      return true;
+
+    case OPT_Wa_:
+      {
+       int prev, j;
+       /* Pass the rest of this option to the assembler.  */
+
+       /* Split the argument at commas.  */
+       prev = 0;
+       for (j = 0; arg[j]; j++)
+         if (arg[j] == ',')
+           {
+             add_assembler_option (arg + prev, j - prev);
+             prev = j + 1;
+           }
+
+       /* Record the part after the last comma.  */
+       add_assembler_option (arg + prev, j - prev);
+      }
+      do_save = false;
+      break;
+
+    case OPT_Wp_:
+      {
+       int prev, j;
+       /* Pass the rest of this option to the preprocessor.  */
+
+       /* Split the argument at commas.  */
+       prev = 0;
+       for (j = 0; arg[j]; j++)
+         if (arg[j] == ',')
+           {
+             add_preprocessor_option (arg + prev, j - prev);
+             prev = j + 1;
+           }
+
+       /* Record the part after the last comma.  */
+       add_preprocessor_option (arg + prev, j - prev);
+      }
+      do_save = false;
+      break;
+
+    case OPT_Wl_:
+      {
+       int prev, j;
+       /* Split the argument at commas.  */
+       prev = 0;
+       for (j = 0; arg[j]; j++)
+         if (arg[j] == ',')
+           {
+             add_infile (save_string (arg + prev, j - prev), "*");
+             prev = j + 1;
+           }
+       /* Record the part after the last comma.  */
+       add_infile (arg + prev, "*");
+      }
+      do_save = false;
+      break;
+
+    case OPT_Xlinker:
+      add_infile (arg, "*");
+      do_save = false;
+      break;
+
+    case OPT_Xpreprocessor:
+      add_preprocessor_option (arg, strlen (arg));
+      do_save = false;
+      break;
+
+    case OPT_Xassembler:
+      add_assembler_option (arg, strlen (arg));
+      do_save = false;
+      break;
+
+    case OPT_l:
+      /* POSIX allows separation of -l and the lib arg; canonicalize
+        by concatenating -l with its arg */
+      add_infile (concat ("-l", arg, NULL), "*");
+      do_save = false;
+      break;
+
+    case OPT_L:
+      /* Similarly, canonicalize -L for linkers that may not accept
+        separate arguments.  */
+      save_switch (concat ("-L", arg, NULL), 0, NULL, validated);
+      return true;
+
+    case OPT_save_temps:
+      save_temps_flag = SAVE_TEMPS_CWD;
+      validated = true;
+      break;
+
+    case OPT_save_temps_:
+      if (strcmp (arg, "cwd") == 0)
+       save_temps_flag = SAVE_TEMPS_CWD;
+      else if (strcmp (arg, "obj") == 0
+              || strcmp (arg, "object") == 0)
+       save_temps_flag = SAVE_TEMPS_OBJ;
+      else
+       fatal_error ("%qs is an unknown -save-temps option",
+                    decoded->orig_option_with_args_text);
+      break;
+
+    case OPT_no_canonical_prefixes:
+      /* Already handled as a special case, so ignored here.  */
+      do_save = false;
+      break;
+
+    case OPT_pipe:
+      validated = true;
+      /* These options set the variables specified in common.opt
+        automatically, but do need to be saved for spec
+        processing.  */
+      break;
+
+    case OPT_specs_:
+      {
+       struct user_specs *user = XNEW (struct user_specs);
+
+       user->next = (struct user_specs *) 0;
+       user->filename = arg;
+       if (user_specs_tail)
+         user_specs_tail->next = user;
+       else
+         user_specs_head = user;
+       user_specs_tail = user;
+      }
+      do_save = false;
+      break;
+
+    case OPT__sysroot_:
+      target_system_root = arg;
+      target_system_root_changed = 1;
+      do_save = false;
+      break;
+
+    case OPT_time_:
+      if (report_times_to_file)
+       fclose (report_times_to_file);
+      report_times_to_file = fopen (arg, "a");
+      do_save = false;
+      break;
+
+    case OPT____:
+      /* "-###"
+        This is similar to -v except that there is no execution
+        of the commands and the echoed arguments are quoted.  It
+        is intended for use in shell scripts to capture the
+        driver-generated command line.  */
+      verbose_only_flag++;
+      verbose_flag++;
+      do_save = false;
+      break;
+
+    case OPT_B:
+      {
+       size_t len = strlen (arg);
+
+       /* Catch the case where the user has forgotten to append a
+          directory separator to the path.  Note, they may be using
+          -B to add an executable name prefix, eg "i386-elf-", in
+          order to distinguish between multiple installations of
+          GCC in the same directory.  Hence we must check to see
+          if appending a directory separator actually makes a
+          valid directory name.  */
+       if (!IS_DIR_SEPARATOR (arg[len - 1])
+           && is_directory (arg, false))
+         {
+           char *tmp = XNEWVEC (char, len + 2);
+           strcpy (tmp, arg);
+           tmp[len] = DIR_SEPARATOR;
+           tmp[++len] = 0;
+           arg = tmp;
+         }
+
+       add_prefix (&exec_prefixes, arg, NULL,
+                   PREFIX_PRIORITY_B_OPT, 0, 0);
+       add_prefix (&startfile_prefixes, arg, NULL,
+                   PREFIX_PRIORITY_B_OPT, 0, 0);
+       add_prefix (&include_prefixes, arg, NULL,
+                   PREFIX_PRIORITY_B_OPT, 0, 0);
+      }
+      validated = true;
+      break;
+
+    case OPT_v:        /* Print our subcommands and print versions.  */
+      verbose_flag++;
+      break;
+
+    case OPT_x:
+      spec_lang = arg;
+      if (!strcmp (spec_lang, "none"))
+       /* Suppress the warning if -xnone comes after the last input
+          file, because alternate command interfaces like g++ might
+          find it useful to place -xnone after each input file.  */
+       spec_lang = 0;
+      else
+       last_language_n_infiles = n_infiles;
+      do_save = false;
+      break;
+
+    case OPT_o:
+      have_o = 1;
+#if defined(HAVE_TARGET_EXECUTABLE_SUFFIX) || defined(HAVE_TARGET_OBJECT_SUFFIX)
+      arg = convert_filename (arg, ! have_c, 0);
+#endif
+      /* Save the output name in case -save-temps=obj was used.  */
+      save_temps_prefix = xstrdup (arg);
+      /* On some systems, ld cannot handle "-o" without a space.  So
+        split the option from its argument.  */
+      save_switch ("-o", 1, &arg, validated);
+      return true;
+
+    case OPT_static_libgcc:
+    case OPT_shared_libgcc:
+    case OPT_static_libgfortran:
+    case OPT_static_libstdc__:
+      /* These are always valid, since gcc.c itself understands the
+        first two, gfortranspec.c understands -static-libgfortran and
+        g++spec.c understands -static-libstdc++ */
+      validated = true;
+      break;
+
+    default:
+      /* Various driver options need no special processing at this
+        point, having been handled in a prescan above or being
+        handled by specs.  */
+      break;
+    }
+
+  if (do_save)
+    save_switch (decoded->canonical_option[0],
+                decoded->canonical_option_num_elements - 1,
+                &decoded->canonical_option[1], validated);
+  return true;
+}
+
 /* Create the vector `switches' and its contents.
    Store its length in `n_switches'.  */
 
 static void
-process_command (int argc, const char **argv)
+process_command (unsigned int decoded_options_count,
+                struct cl_decoded_option *decoded_options)
 {
-  int i;
   const char *temp;
   char *temp1;
-  const char *spec_lang = 0;
-  int last_language_n_infiles;
   const char *tooldir_prefix;
   char *(*get_relative_prefix) (const char *, const char *,
                                const char *) = NULL;
+  struct cl_option_handlers handlers;
+  unsigned int j;
 
   GET_ENVIRONMENT (gcc_exec_prefix, "GCC_EXEC_PREFIX");
 
@@ -3540,18 +3540,13 @@ process_command (int argc, const char **argv)
        }
     }
 
-  /* Convert new-style -- options to old-style.  */
-  translate_options (&argc,
-                    CONST_CAST2 (const char *const **, const char ***,
-                                 &argv));
-
   /* Handle any -no-canonical-prefixes flag early, to assign the function
      that builds relative prefixes.  This function creates default search
      paths that are needed later in normal option handling.  */
 
-  for (i = 1; i < argc; i++)
+  for (j = 1; j < decoded_options_count; j++)
     {
-      if (! strcmp (argv[i], "-no-canonical-prefixes"))
+      if (decoded_options[j].opt_index == OPT_no_canonical_prefixes)
        {
          get_relative_prefix = make_relative_prefix_ignore_links;
          break;
@@ -3561,17 +3556,18 @@ process_command (int argc, const char **argv)
     get_relative_prefix = make_relative_prefix;
 
   /* 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].  */
+     see if we can create it from the pathname specified in
+     decoded_options[0].arg.  */
 
   gcc_libexec_prefix = standard_libexec_prefix;
 #ifndef VMS
   /* FIXME: make_relative_prefix doesn't yet work for VMS.  */
   if (!gcc_exec_prefix)
     {
-      gcc_exec_prefix = get_relative_prefix (argv[0],
+      gcc_exec_prefix = get_relative_prefix (decoded_options[0].arg,
                                             standard_bindir_prefix,
                                             standard_exec_prefix);
-      gcc_libexec_prefix = get_relative_prefix (argv[0],
+      gcc_libexec_prefix = get_relative_prefix (decoded_options[0].arg,
                                             standard_bindir_prefix,
                                             standard_libexec_prefix);
       if (gcc_exec_prefix)
@@ -3598,12 +3594,11 @@ process_command (int argc, const char **argv)
 #endif
   /* From this point onward, gcc_exec_prefix is non-null if the toolchain
      is relocated. The toolchain was either relocated using GCC_EXEC_PREFIX
-     or an automatically created GCC_EXEC_PREFIX from argv[0].  */
+     or an automatically created GCC_EXEC_PREFIX from
+     decoded_options[0].arg.  */
 
   /* Do language-specific adjustment/addition of flags.  */
-  lang_specific_driver (&argc,
-                       CONST_CAST2 (const char *const **, const char ***,
-                                    &argv),
+  lang_specific_driver (&decoded_options, &decoded_options_count,
                        &added_libraries);
 
   if (gcc_exec_prefix)
@@ -3735,538 +3730,73 @@ process_command (int argc, const char **argv)
 
   last_language_n_infiles = -1;
 
-  for (i = 1; i < argc; i++)
-    {
-      const char *p = NULL;
-      int c = 0;
-
-      if (argv[i][0] == '-' && argv[i][1] != 0)
-       {
-         p = &argv[i][1];
-         c = *p;
-       }
-
-      if (! strcmp (argv[i], "-dumpspecs"))
-       {
-         struct spec_list *sl;
-         init_spec ();
-         for (sl = specs; sl; sl = sl->next)
-           printf ("*%s:\n%s\n\n", sl->name, *(sl->ptr_spec));
-         if (link_command_spec)
-           printf ("*link_command:\n%s\n\n", link_command_spec);
-         exit (0);
-       }
-      else if (! strcmp (argv[i], "-dumpversion"))
-       {
-         printf ("%s\n", spec_version);
-         exit (0);
-       }
-      else if (! strcmp (argv[i], "-dumpmachine"))
-       {
-         printf ("%s\n", spec_machine);
-         exit (0);
-       }
-      else if (strcmp (argv[i], "-fversion") == 0)
-       {
-         /* translate_options () has turned --version into -fversion.  */
-         print_version = 1;
-
-         /* CPP driver cannot obtain switch from cc1_options.  */
-         if (is_cpp_driver)
-           add_preprocessor_option ("--version", strlen ("--version"));
-         add_assembler_option ("--version", strlen ("--version"));
-         add_linker_option ("--version", strlen ("--version"));
-
-         goto normal_switch;
-       }
-      else if (strcmp (argv[i], "-fhelp") == 0)
-       {
-         /* translate_options () has turned --help into -fhelp.  */
-         print_help_list = 1;
+  handlers.unknown_option_callback = driver_unknown_option_callback;
+  handlers.wrong_lang_callback = driver_wrong_lang_callback;
+  handlers.post_handling_callback = driver_post_handling_callback;
+  handlers.num_handlers = 1;
+  handlers.handlers[0].handler = driver_handle_option;
+  handlers.handlers[0].mask = CL_DRIVER;
 
-         /* CPP driver cannot obtain switch from cc1_options.  */
-         if (is_cpp_driver)
-           add_preprocessor_option ("--help", 6);
-         add_assembler_option ("--help", 6);
-         add_linker_option ("--help", 6);
-
-         goto normal_switch;
-       }
-      else if (strncmp (argv[i], "-fhelp=", 7) == 0)
-       {
-         /* translate_options () has turned --help into -fhelp.  */
-         print_subprocess_help = 2;
-
-         goto normal_switch;
-       }
-      else if (strcmp (argv[i], "-ftarget-help") == 0)
-       {
-         /* translate_options() has turned --target-help into -ftarget-help.  */
-         print_subprocess_help = 1;
-
-         /* CPP driver cannot obtain switch from cc1_options.  */
-         if (is_cpp_driver)
-           add_preprocessor_option ("--target-help", 13);
-         add_assembler_option ("--target-help", 13);
-         add_linker_option ("--target-help", 13);
-
-         goto normal_switch;
-       }
-      else if (! strcmp (argv[i], "-pass-exit-codes"))
-       {
-         pass_exit_codes = 1;
-       }
-      else if (! strcmp (argv[i], "-print-search-dirs"))
-       print_search_dirs = 1;
-      else if (! strcmp (argv[i], "-print-libgcc-file-name"))
-       print_file_name = "libgcc.a";
-      else if (! strncmp (argv[i], "-print-file-name=", 17))
-       print_file_name = argv[i] + 17;
-      else if (! strncmp (argv[i], "-print-prog-name=", 17))
-       print_prog_name = argv[i] + 17;
-      else if (! strcmp (argv[i], "-print-multi-lib"))
-       print_multi_lib = 1;
-      else if (! strcmp (argv[i], "-print-multi-directory"))
-       print_multi_directory = 1;
-      else if (! strcmp (argv[i], "-print-sysroot"))
-       print_sysroot = 1;
-      else if (! strcmp (argv[i], "-print-multi-os-directory"))
-       print_multi_os_directory = 1;
-      else if (! strcmp (argv[i], "-print-sysroot-headers-suffix"))
-       print_sysroot_headers_suffix = 1;
-      else if (! strcmp (argv[i], "-fcompare-debug-second"))
-       {
-         compare_debug_second = 1;
-         goto normal_switch;
-       }
-      else if (! strcmp (argv[i], "-fno-compare-debug"))
-       {
-         argv[i] = "-fcompare-debug=";
-         p = &argv[i][1];
-         goto compare_debug_with_arg;
-       }
-      else if (! strcmp (argv[i], "-fcompare-debug"))
-       {
-         argv[i] = "-fcompare-debug=-gtoggle";
-         p = &argv[i][1];
-         goto compare_debug_with_arg;
-       }
-#define OPT "-fcompare-debug="
-      else if (! strncmp (argv[i], OPT, sizeof (OPT) - 1))
-       {
-         const char *opt;
-       compare_debug_with_arg:
-         opt = argv[i] + sizeof (OPT) - 1;
-#undef OPT
-         if (*opt)
-           compare_debug = 1;
-         else
-           compare_debug = -1;
-         if (compare_debug < 0)
-           compare_debug_opt = NULL;
-         else
-           compare_debug_opt = opt;
-         goto normal_switch;
-       }
-      else if (! strncmp (argv[i], "-Wa,", 4))
-       {
-         int prev, j;
-         /* Pass the rest of this option to the assembler.  */
-
-         /* Split the argument at commas.  */
-         prev = 4;
-         for (j = 4; argv[i][j]; j++)
-           if (argv[i][j] == ',')
-             {
-               add_assembler_option (argv[i] + prev, j - prev);
-               prev = j + 1;
-             }
-
-         /* Record the part after the last comma.  */
-         add_assembler_option (argv[i] + prev, j - prev);
-       }
-      else if (! strncmp (argv[i], "-Wp,", 4))
-       {
-         int prev, j;
-         /* Pass the rest of this option to the preprocessor.  */
-
-         /* Split the argument at commas.  */
-         prev = 4;
-         for (j = 4; argv[i][j]; j++)
-           if (argv[i][j] == ',')
-             {
-               add_preprocessor_option (argv[i] + prev, j - prev);
-               prev = j + 1;
-             }
-
-         /* Record the part after the last comma.  */
-         add_preprocessor_option (argv[i] + prev, j - prev);
-       }
-      else if (strncmp (argv[i], "-Wl,", 4) == 0)
-       {
-         int prev, j;
-         /* Split the argument at commas.  */
-         prev = 4;
-         for (j = 4; argv[i][j]; j++)
-           if (argv[i][j] == ',')
-             {
-               add_infile (save_string (argv[i] + prev, j - prev), "*");
-               prev = j + 1;
-             }
-         /* Record the part after the last comma.  */
-         add_infile (argv[i] + prev, "*");
-       }
-      else if (strcmp (argv[i], "-Xlinker") == 0)
-       {
-         if (i + 1 == argc)
-           fatal_error ("argument to %<-Xlinker%> is missing");
-
-         add_infile (argv[i+1], "*");
-         i++;
-       }
-      else if (strcmp (argv[i], "-Xpreprocessor") == 0)
-       {
-         if (i + 1 == argc)
-           fatal_error ("argument to %<-Xpreprocessor%> is missing");
-
-         add_preprocessor_option (argv[i+1], strlen (argv[i+1]));
-         i++;
-       }
-      else if (strcmp (argv[i], "-Xassembler") == 0)
-       {
-         if (i + 1 == argc)
-           fatal_error ("argument to %<-Xassembler%> is missing");
-
-         add_assembler_option (argv[i+1], strlen (argv[i+1]));
-         i++;
-       }
-      else if (strcmp (argv[i], "-l") == 0)
-       {
-         if (i + 1 == argc)
-           fatal_error ("argument to %<-l%> is missing");
-
-         /* POSIX allows separation of -l and the lib arg;
-            canonicalize by concatenating -l with its arg */
-         add_infile (concat ("-l", argv[i + 1], NULL), "*");
-         i++;
-       }
-      else if (strncmp (argv[i], "-l", 2) == 0)
-       {
-         add_infile (argv[i], "*");
-       }
-      else if (strcmp (argv[i], "-save-temps") == 0)
-       {
-         save_temps_flag = SAVE_TEMPS_CWD;
-         goto normal_switch;
-       }
-      else if (strncmp (argv[i], "-save-temps=", 12) == 0)
-       {
-         if (strcmp (argv[i]+12, "cwd") == 0)
-           save_temps_flag = SAVE_TEMPS_CWD;
-         else if (strcmp (argv[i]+12, "obj") == 0
-                  || strcmp (argv[i]+12, "object") == 0)
-           save_temps_flag = SAVE_TEMPS_OBJ;
-         else
-           fatal_error ("%qs is an unknown -save-temps option", argv[i]);
-         goto normal_switch;
-       }
-      else if (strcmp (argv[i], "-no-canonical-prefixes") == 0)
-       /* Already handled as a special case, so ignored here.  */
-       ;
-      else if (strcmp (argv[i], "-combine") == 0)
-       {
-         combine_flag = 1;
-         goto normal_switch;
-       }
-      else if (strcmp (argv[i], "-specs") == 0)
-       {
-         struct user_specs *user = XNEW (struct user_specs);
-         if (++i >= argc)
-           fatal_error ("argument to %<-specs%> is missing");
-
-         user->next = (struct user_specs *) 0;
-         user->filename = argv[i];
-         if (user_specs_tail)
-           user_specs_tail->next = user;
-         else
-           user_specs_head = user;
-         user_specs_tail = user;
-       }
-      else if (strncmp (argv[i], "-specs=", 7) == 0)
-       {
-         struct user_specs *user = XNEW (struct user_specs);
-         if (strlen (argv[i]) == 7)
-           fatal_error ("argument to %<-specs=%> is missing");
-
-         user->next = (struct user_specs *) 0;
-         user->filename = argv[i] + 7;
-         if (user_specs_tail)
-           user_specs_tail->next = user;
-         else
-           user_specs_head = user;
-         user_specs_tail = user;
-       }
-      else if (! strncmp (argv[i], "--sysroot=", strlen ("--sysroot=")))
-       {
-         target_system_root = argv[i] + strlen ("--sysroot=");
-         target_system_root_changed = 1;
-       }
-      else if (strcmp (argv[i], "-time") == 0)
-       report_times = 1;
-      else if (strncmp (argv[i], "-time=", sizeof ("-time=") - 1) == 0)
-       {
-         if (report_times_to_file)
-           fclose (report_times_to_file);
-         report_times_to_file = fopen (argv[i] + sizeof ("-time=") - 1, "a");
-       }
-      else if (strcmp (argv[i], "-pipe") == 0)
-       {
-         /* -pipe has to go into the switches array as well as
-            setting a flag.  */
-         use_pipes = 1;
-         goto normal_switch;
-       }
-      else if (strcmp (argv[i], "-wrapper") == 0)
-        {
-         if (++i >= argc)
-           fatal_error ("argument to %<-wrapper%> is missing");
-
-          wrapper_string = argv[i];
-        }
-      else if (strcmp (argv[i], "-###") == 0)
+  for (j = 1; j < decoded_options_count; j++)
+    {
+      switch (decoded_options[j].opt_index)
        {
-         /* This is similar to -v except that there is no execution
-            of the commands and the echoed arguments are quoted.  It
-            is intended for use in shell scripts to capture the
-            driver-generated command line.  */
-         verbose_only_flag++;
-         verbose_flag++;
+       case OPT_S:
+       case OPT_c:
+       case OPT_E:
+         have_c = 1;
+         break;
        }
-      else if (argv[i][0] == '-' && argv[i][1] != 0)
-       {
-         switch (c)
-           {
-           case 'B':
-             {
-               const char *value;
-               int len;
-
-               if (p[1] == 0 && i + 1 == argc)
-                 fatal_error ("argument to %<-B%> is missing");
-               if (p[1] == 0)
-                 value = argv[i + 1];
-               else
-                 value = p + 1;
-
-               len = strlen (value);
-
-               /* Catch the case where the user has forgotten to append a
-                  directory separator to the path.  Note, they may be using
-                  -B to add an executable name prefix, eg "i386-elf-", in
-                  order to distinguish between multiple installations of
-                  GCC in the same directory.  Hence we must check to see
-                  if appending a directory separator actually makes a
-                  valid directory name.  */
-               if (! IS_DIR_SEPARATOR (value [len - 1])
-                   && is_directory (value, false))
-                 {
-                   char *tmp = XNEWVEC (char, len + 2);
-                   strcpy (tmp, value);
-                   tmp[len] = DIR_SEPARATOR;
-                   tmp[++ len] = 0;
-                   value = tmp;
-                 }
-
-               add_prefix (&exec_prefixes, value, NULL,
-                           PREFIX_PRIORITY_B_OPT, 0, 0);
-               add_prefix (&startfile_prefixes, value, NULL,
-                           PREFIX_PRIORITY_B_OPT, 0, 0);
-               add_prefix (&include_prefixes, value, NULL,
-                           PREFIX_PRIORITY_B_OPT, 0, 0);
-             }
-             goto normal_switch;
-
-           case 'v':   /* Print our subcommands and print versions.  */
-             /* If they do anything other than exactly `-v', don't set
-                verbose_flag; rather, continue on to give the error.  */
-             if (p[1] != 0)
-               break;
-             verbose_flag++;
-             goto normal_switch;
-
-           case 'x':
-             if (p[1] == 0 && i + 1 == argc)
-               fatal_error ("argument to %<-x%> is missing");
-             if (p[1] == 0)
-               spec_lang = argv[++i];
-             else
-               spec_lang = p + 1;
-             if (! strcmp (spec_lang, "none"))
-               /* Suppress the warning if -xnone comes after the last input
-                  file, because alternate command interfaces like g++ might
-                  find it useful to place -xnone after each input file.  */
-               spec_lang = 0;
-             else
-               last_language_n_infiles = n_infiles;
-             break;
-
-           case 'S':
-           case 'c':
-           case 'E':
-             if (p[1] == 0)
-               have_c = 1;
-             goto normal_switch;
-
-           case 'o':
-             have_o = 1;
-#if defined(HAVE_TARGET_EXECUTABLE_SUFFIX)
-             if (! have_c)
-               {
-                 int skip;
-
-                 /* Forward scan, just in case -S, -E or -c is specified
-                    after -o.  */
-                 int j = i + 1;
-                 if (p[1] == 0)
-                   ++j;
-                 while (j < argc)
-                   {
-                     if (argv[j][0] == '-')
-                       {
-                         if (SWITCH_CURTAILS_COMPILATION (argv[j][1])
-                             && argv[j][2] == 0)
-                           {
-                             have_c = 1;
-                             break;
-                           }
-                         else if ((skip = SWITCH_TAKES_ARG (argv[j][1])))
-                           j += skip - (argv[j][2] != 0);
-                         else if ((skip = WORD_SWITCH_TAKES_ARG (argv[j] + 1)))
-                           j += skip;
-                       }
-                     j++;
-                   }
-               }
-#endif
-#if defined(HAVE_TARGET_EXECUTABLE_SUFFIX) || defined(HAVE_TARGET_OBJECT_SUFFIX)
-             if (p[1] == 0)
-               argv[i + 1] = convert_filename (argv[i + 1], ! have_c, 0);
-             else
-               {
-                 argv[i] = convert_filename (argv[i], ! have_c, 0);
-                 p = &argv[i][1];
-               }
-#endif
-             /* Save the output name in case -save-temps=obj was used.  */
-             if ((p[1] == 0) && argv[i + 1])
-               save_temps_prefix = xstrdup(argv[i + 1]);
-             else
-               save_temps_prefix = xstrdup(argv[i] + 1);
-             goto normal_switch;
-
-           default:
-           normal_switch:
-
-             alloc_switch ();
-             switches[n_switches].part1 = p;
-             /* Deal with option arguments in separate argv elements.  */
-             if ((SWITCH_TAKES_ARG (c) > (p[1] != 0))
-                 || WORD_SWITCH_TAKES_ARG (p))
-               {
-                 int j = 0;
-                 int n_args = WORD_SWITCH_TAKES_ARG (p);
+      if (have_c)
+       break;
+    }
 
-                 if (n_args == 0)
-                   {
-                     /* Count only the option arguments in separate
-                        argv elements.  */
-                     n_args = SWITCH_TAKES_ARG (c) - (p[1] != 0);
-                   }
-                 if (i + n_args >= argc)
-                   fatal_error ("argument to %<-%s%> is missing", p);
-                 switches[n_switches].args
-                   = XNEWVEC (const char *, n_args + 1);
-                 while (j < n_args)
-                   switches[n_switches].args[j++] = argv[++i];
-                 /* Null-terminate the vector.  */
-                 switches[n_switches].args[j] = 0;
-               }
-             else if (c == 'o')
-               {
-                 /* On some systems, ld cannot handle "-o" without
-                    a space.  So split the option from its argument.  */
-                 char *part1 = XNEWVEC (char, 2);
-                 part1[0] = c;
-                 part1[1] = '\0';
-
-                 switches[n_switches].part1 = part1;
-                 switches[n_switches].args = XNEWVEC (const char *, 2);
-                 switches[n_switches].args[0] = xstrdup (p+1);
-                 switches[n_switches].args[1] = 0;
-               }
-             else
-               switches[n_switches].args = 0;
-
-             switches[n_switches].live_cond = 0;
-             switches[n_switches].validated = 0;
-             switches[n_switches].ordering = 0;
-             /* These are always valid, since gcc.c itself understands the
-                first four, gfortranspec.c understands -static-libgfortran
-                and g++spec.c understands -static-libstdc++ */
-             if (!strcmp (p, "save-temps")
-                 || !strcmp (p, "static-libgcc")
-                 || !strcmp (p, "shared-libgcc")
-                 || !strcmp (p, "pipe")
-                 || !strcmp (p, "static-libgfortran")
-                 || !strcmp (p, "static-libstdc++"))
-               switches[n_switches].validated = 1;
-             else
-               {
-                 char ch = switches[n_switches].part1[0];
-                 if (ch == 'B')
-                   switches[n_switches].validated = 1;
-               }
-             n_switches++;
-           }
-       }
-      else
+  for (j = 1; j < decoded_options_count; j++)
+    {
+      if (decoded_options[j].opt_index == OPT_SPECIAL_input_file)
        {
-          const char *p = strrchr (argv[i], '@');
+         const char *arg = decoded_options[j].arg;
+          const char *p = strrchr (arg, '@');
           char *fname;
          long offset;
          int consumed;
 #ifdef HAVE_TARGET_OBJECT_SUFFIX
-         argv[i] = convert_filename (argv[i], 0, access (argv[i], F_OK));
+         arg = convert_filename (arg, 0, access (arg, F_OK));
 #endif
          /* For LTO static archive support we handle input file
             specifications that are composed of a filename and
             an offset like FNAME@OFFSET.  */
          if (p
-             && p != argv[i]
+             && p != arg
              && sscanf (p, "@%li%n", &offset, &consumed) >= 1
              && strlen (p) == (unsigned int)consumed)
            {
-              fname = (char *)xmalloc (p - argv[i] + 1);
-              memcpy (fname, argv[i], p - argv[i]);
-              fname[p - argv[i]] = '\0';
+              fname = (char *)xmalloc (p - arg + 1);
+              memcpy (fname, arg, p - arg);
+              fname[p - arg] = '\0';
              /* Only accept non-stdin and existing FNAME parts, otherwise
                 try with the full name.  */
              if (strcmp (fname, "-") == 0 || access (fname, F_OK) < 0)
                {
                  free (fname);
-                 fname = xstrdup (argv[i]);
+                 fname = xstrdup (arg);
                }
            }
          else
-           fname = xstrdup (argv[i]);
+           fname = xstrdup (arg);
  
           if (strcmp (fname, "-") != 0 && access (fname, F_OK) < 0)
            perror_with_name (fname);
           else
-           add_infile (argv[i], spec_lang);
+           add_infile (arg, spec_lang);
 
           free (fname);
+         continue;
        }
+
+      read_cmdline_option (&global_options, &global_options_set,
+                          decoded_options + j, CL_DRIVER, &handlers,
+                          global_dc);
     }
 
   /* If -save-temps=obj and -o name, create the prefix to use for %b.
@@ -4363,7 +3893,7 @@ process_command (int argc, const char **argv)
      ``make_relative_prefix'' is not compiled for VMS, so don't call it.  */
   if (target_system_root && !target_system_root_changed && gcc_exec_prefix)
     {
-      char *tmp_prefix = get_relative_prefix (argv[0],
+      char *tmp_prefix = get_relative_prefix (decoded_options[0].arg,
                                              standard_bindir_prefix,
                                              target_system_root);
       if (tmp_prefix && access_check (tmp_prefix, F_OK) == 0)
@@ -6574,6 +6104,8 @@ main (int argc, char **argv)
   const char *p;
   struct user_specs *uptr;
   char **old_argv = argv;
+  struct cl_decoded_option *decoded_options;
+  unsigned int decoded_options_count;
 
   /* Initialize here, not in definition.  The IRIX 6 O32 cc sometimes chokes
      on ?: in file-scope variable initializations.  */
@@ -6592,7 +6124,12 @@ main (int argc, char **argv)
   if (argv != old_argv)
     at_file_supplied = true;
 
-  prune_options (&argc, &argv);
+  global_options = global_options_init;
+
+  decode_cmdline_options_to_array (argc, CONST_CAST2 (const char **, char **,
+                                                     argv),
+                                  CL_DRIVER,
+                                  &decoded_options, &decoded_options_count);
 
 #ifdef GCC_DRIVER_HOST_INITIALIZATION
   /* Perform host dependent initialization when needed.  */
@@ -6682,7 +6219,7 @@ main (int argc, char **argv)
      Make a table of specified input files (infiles, n_infiles).
      Decode switches that are handled locally.  */
 
-  process_command (argc, CONST_CAST2 (const char **, char **, argv));
+  process_command (decoded_options_count, decoded_options);
 
   /* Initialize the vector of specs to just the default.
      This means one element containing 0s, as a terminator.  */
@@ -7084,10 +6621,7 @@ warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\n"
 
   explicit_link_files = XCNEWVEC (char, n_infiles);
 
-  if (combine_flag)
-    combine_inputs = true;
-  else
-    combine_inputs = false;
+  combine_inputs = have_o || flag_wpa;
 
   for (i = 0; (int) i < n_infiles; i++)
     {
@@ -7120,63 +6654,7 @@ warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\n"
     }
 
   if (!combine_inputs && have_c && have_o && lang_n_infiles > 1)
-   fatal_error ("cannot specify -o with -c, -S or -E with multiple files");
-
-  if (combine_flag && save_temps_flag)
-    {
-      bool save_combine_inputs = combine_inputs;
-      /* Must do a separate pre-processing pass for C & Objective-C files, to
-        obtain individual .i files.  */
-
-      combine_inputs = false;
-      for (i = 0; (int) i < n_infiles; i++)
-       {
-         int this_file_error = 0;
-
-         input_file_number = i;
-         set_input (infiles[i].name);
-         if (infiles[i].incompiler
-             && (infiles[i].incompiler)->needs_preprocessing)
-           input_file_compiler = infiles[i].incompiler;
-         else
-           continue;
-
-         if (input_file_compiler)
-           {
-             if (input_file_compiler->spec[0] == '#')
-               {
-                 error ("%s: %s compiler not installed on this system",
-                        gcc_input_filename, &input_file_compiler->spec[1]);
-                 this_file_error = 1;
-               }
-             else
-               {
-                 value = do_spec (input_file_compiler->spec);
-                 infiles[i].preprocessed = true;
-                 if (!have_o_argbuf_index)
-                   fatal_error ("spec %qs is invalid",
-                                input_file_compiler->spec);
-                 infiles[i].name = argbuf[have_o_argbuf_index];
-                 infiles[i].incompiler
-                   = lookup_compiler (infiles[i].name,
-                                      strlen (infiles[i].name),
-                                      infiles[i].language);
-
-                 if (value < 0)
-                   this_file_error = 1;
-               }
-           }
-
-         if (this_file_error)
-           {
-             delete_failure_queue ();
-             errorcount++;
-             break;
-           }
-         clear_failure_queue ();
-       }
-      combine_inputs = save_combine_inputs;
-    }
+    fatal_error ("cannot specify -o with -c, -S or -E with multiple files");
 
   for (i = 0; (int) i < n_infiles; i++)
     {
@@ -7196,12 +6674,9 @@ warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\n"
 
       /* Figure out which compiler from the file's suffix.  */
 
-      if (! combine_inputs)
-       input_file_compiler
-         = lookup_compiler (infiles[i].name, input_filename_length,
-                            infiles[i].language);
-      else
-       input_file_compiler = infiles[i].incompiler;
+      input_file_compiler
+       = lookup_compiler (infiles[i].name, input_filename_length,
+                          infiles[i].language);
 
       if (input_file_compiler)
        {
@@ -7343,10 +6818,10 @@ warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\n"
                          fuse_linker_plugin + strlen (fuse_linker_plugin), 0))
        {
          linker_plugin_file_spec = find_a_file (&exec_prefixes,
-                                                "liblto_plugin.so", R_OK,
+                                                LTOPLUGINSONAME, R_OK,
                                                 false);
          if (!linker_plugin_file_spec)
-           fatal_error ("-fuse-linker-plugin, but liblto_plugin.so not found");
+           fatal_error ("-fuse-linker-plugin, but " LTOPLUGINSONAME " not found");
 
          lto_libgcc_spec = find_a_file (&startfile_prefixes, "libgcc.a",
                                         R_OK, true);
@@ -8357,6 +7832,27 @@ replace_outfile_spec_function (int argc, const char **argv)
   return NULL;
 }
 
+/* remove-outfile built-in spec function.
+ *
+ *    This looks for the first argument in the outfiles array's name and
+ *       removes it.  */
+
+static const char *
+remove_outfile_spec_function (int argc, const char **argv)
+{
+  int i;
+  /* Must have exactly one argument.  */
+  if (argc != 1)
+    abort ();
+
+  for (i = 0; i < n_infiles; i++)
+    {
+      if (outfiles[i] && !strcmp (outfiles[i], argv[0]))
+        outfiles[i] = NULL;
+    }
+  return NULL;
+}
+
 /* Given two version numbers, compares the two numbers.
    A version number must match the regular expression
    ([1-9][0-9]*|0)(\.([1-9][0-9]*|0))*