OSDN Git Service

IA64 uses // instead of # for comments in its assembly file.
[pf3gnuchains/gcc-fork.git] / gcc / gcc.c
index a199f02..6a0dae5 100644 (file)
--- a/gcc/gcc.c
+++ b/gcc/gcc.c
@@ -280,23 +280,6 @@ static const char *cross_compile = "1";
 static const char *cross_compile = "0";
 #endif
 
-#ifdef MODIFY_TARGET_NAME
-
-/* Information on how to alter the target name based on a command-line
-   switch.  The only case we support now is simply appending or deleting a
-   string to or from the end of the first part of the configuration name.  */
-
-enum add_del {ADD, DELETE};
-
-static const struct modify_target
-{
-  const char *const sw;
-  const enum add_del add_del;
-  const char *const str;
-}
-modify_target[] = MODIFY_TARGET_NAME;
-#endif
-
 /* Greatest exit code of sub-processes that has been encountered up to
    now.  */
 static int greatest_status = 1;
@@ -399,6 +382,7 @@ static const char *replace_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 **);
+static const char *find_plugindir_spec_function (int, const char **);
 static const char *print_asm_header_spec_function (int, const char **);
 static const char *compare_debug_dump_opt_spec_function (int, const char **);
 static const char *compare_debug_self_opt_spec_function (int, const char **);
@@ -680,18 +664,6 @@ proper position among the other output files.  */
   "%{!shared:%{pg:gcrt0%O%s}%{!pg:%{p:mcrt0%O%s}%{!p:crt0%O%s}}}"
 #endif
 
-/* config.h can define SWITCHES_NEED_SPACES to control which options
-   require spaces between the option and the argument.
-
-   We define SWITCHES_NEED_SPACES to include "o" by default.  This
-   causes "-ofoo.o" to be split into "-o foo.o" during the initial
-   processing of the command-line, before being seen by the specs
-   machinery.  This makes sure we record "foo.o" as the temporary file
-   to be deleted in the case of error, rather than "-ofoo.o".  */
-#ifndef SWITCHES_NEED_SPACES
-#define SWITCHES_NEED_SPACES "o"
-#endif
-
 /* config.h can define ENDFILE_SPEC to override the default crtn files.  */
 #ifndef ENDFILE_SPEC
 #define ENDFILE_SPEC ""
@@ -827,7 +799,6 @@ static const char *link_gomp_spec = "";
 static const char *libgcc_spec = LIBGCC_SPEC;
 static const char *endfile_spec = ENDFILE_SPEC;
 static const char *startfile_spec = STARTFILE_SPEC;
-static const char *switches_need_spaces = SWITCHES_NEED_SPACES;
 static const char *linker_name_spec = LINKER_NAME;
 static const char *linker_plugin_file_spec = "";
 static const char *lto_wrapper_spec = "";
@@ -862,7 +833,7 @@ static const char *cpp_unique_options =
  %{M} %{MM} %{MF*} %{MG} %{MP} %{MQ*} %{MT*}\
  %{!E:%{!M:%{!MM:%{!MT:%{!MQ:%{MD|MMD:%{o*:-MQ %*}}}}}}}\
  %{remap} %{g3|ggdb3|gstabs3|gcoff3|gxcoff3|gvms3:-dD}\
- %{!iplugindir*:%{fplugin*:-iplugindir=%:find-file(plugin)}}\
+ %{!iplugindir*:%{fplugin*:%:find-plugindir()}}\
  %{H} %C %{D*&U*&A*} %{i*} %Z %i\
  %{fmudflap:-D_MUDFLAP -include mf-runtime.h}\
  %{fmudflapth:-D_MUDFLAP -D_MUDFLAPTH -include mf-runtime.h}\
@@ -885,7 +856,7 @@ static const char *cpp_debug_options = "%{d*}";
 /* NB: This is shared amongst all front-ends, except for Ada.  */
 static const char *cc1_options =
 "%{pg:%{fomit-frame-pointer:%e-pg and -fomit-frame-pointer are incompatible}}\
- %{!iplugindir*:%{fplugin*:-iplugindir=%:find-file(plugin)}}\
+ %{!iplugindir*:%{fplugin*:%:find-plugindir()}}\
  %1 %{!Q:-quiet} %{!dumpbase:-dumpbase %B} %{d*} %{m*} %{a*}\
  %{fcompare-debug-second:%:compare-debug-auxbase-opt(%b)} \
  %{!fcompare-debug-second:%{c|S:%{o*:-auxbase-strip %*}%{!o*:-auxbase %b}}}%{!c:%{!S:-auxbase %b}} \
@@ -1392,7 +1363,7 @@ translate_options (int *argcp, const char *const **argvp)
 
                  else if (strchr (arginfo, '*') != 0)
                    {
-                     error ("incomplete '%s' option", option_map[j].name);
+                     error ("incomplete %qs option", option_map[j].name);
                      break;
                    }
 
@@ -1403,7 +1374,7 @@ translate_options (int *argcp, const char *const **argvp)
                        {
                          if (i + 1 == argc)
                            {
-                             error ("missing argument to '%s' option",
+                             error ("missing argument to %qs option",
                                     option_map[j].name);
                              break;
                            }
@@ -1416,7 +1387,7 @@ translate_options (int *argcp, const char *const **argvp)
                  else if (strchr (arginfo, 'o') == 0)
                    {
                      if (arg != 0)
-                       error ("extraneous argument to '%s' option",
+                       error ("extraneous argument to %qs option",
                               option_map[j].name);
                      arg = 0;
                    }
@@ -1474,7 +1445,7 @@ translate_options (int *argcp, const char *const **argvp)
            }
        }
       else
-       /* Ordinary operands, or +e options.  */
+       /* Ordinary operands.  */
        newv[newindex++] = argv[i++];
     }
 
@@ -1667,7 +1638,6 @@ static struct spec_list static_specs[] =
   INIT_STATIC_SPEC ("link_gomp",               &link_gomp_spec),
   INIT_STATIC_SPEC ("libgcc",                  &libgcc_spec),
   INIT_STATIC_SPEC ("startfile",               &startfile_spec),
-  INIT_STATIC_SPEC ("switches_need_spaces",    &switches_need_spaces),
   INIT_STATIC_SPEC ("cross_compile",           &cross_compile),
   INIT_STATIC_SPEC ("version",                 &compiler_version),
   INIT_STATIC_SPEC ("multilib",                        &multilib_select),
@@ -1719,6 +1689,7 @@ static const struct spec_function static_spec_functions[] =
   { "version-compare",         version_compare_spec_function },
   { "include",                 include_spec_function },
   { "find-file",               find_file_spec_function },
+  { "find-plugindir",          find_plugindir_spec_function },
   { "print-asm-header",                print_asm_header_spec_function },
   { "compare-debug-dump-opt",  compare_debug_dump_opt_spec_function },
   { "compare-debug-self-opt",  compare_debug_self_opt_spec_function },
@@ -2281,8 +2252,8 @@ read_specs (const char *filename, int main_p)
 
              for (newsl = specs; newsl; newsl = newsl->next)
                if (strcmp (newsl->name, p2) == 0)
-                 fatal_error ("%s: attempt to rename spec '%s' to "
-                              "already defined spec '%s'",
+                 fatal_error ("%s: attempt to rename spec %qs to "
+                              "already defined spec %qs",
                    filename, p1, p2);
 
              if (verbose_flag)
@@ -2907,7 +2878,7 @@ add_sysrooted_prefix (struct path_prefix *pprefix, const char *prefix,
                      int require_machine_suffix, int os_multilib)
 {
   if (!IS_ABSOLUTE_PATH (prefix))
-    fatal_error ("system path '%s' is not absolute", prefix);
+    fatal_error ("system path %qs is not absolute", prefix);
 
   if (target_system_root)
     {
@@ -3095,7 +3066,7 @@ execute (void)
                                   ? PEX_RECORD_TIMES : 0),
                  progname, temp_filename);
   if (pex == NULL)
-    pfatal_with_name (_("pex_init failed"));
+    fatal_error ("pex_init failed: %m");
 
   for (i = 0; i < n_commands; i++)
     {
@@ -3134,13 +3105,13 @@ execute (void)
 
     statuses = (int *) alloca (n_commands * sizeof (int));
     if (!pex_get_status (pex, n_commands, statuses))
-      pfatal_with_name (_("failed to get exit status"));
+      fatal_error ("failed to get exit status: %m");
 
     if (report_times || report_times_to_file)
       {
        times = (struct pex_time *) alloca (n_commands * sizeof (struct pex_time));
        if (!pex_get_times (pex, n_commands, times))
-         pfatal_with_name (_("failed to get process times"));
+         fatal_error ("failed to get process times: %m");
       }
 
     pex_free (pex);
@@ -3266,6 +3237,8 @@ static struct switchstr *switches;
 
 static int n_switches;
 
+static int n_switches_alloc;
+
 /* Set to zero if -fcompare-debug is disabled, positive if it's
    enabled and we're running the first compilation, negative if it's
    enabled and we're running the second compilation.  For most of the
@@ -3311,6 +3284,8 @@ static struct infile *infiles;
 
 int n_infiles;
 
+static int n_infiles_alloc;
+
 /* True if multiple input files are being compiled to a single
    assembly file.  */
 
@@ -3495,6 +3470,51 @@ add_linker_option (const char *option, int len)
   linker_options [n_linker_options - 1] = save_string (option, len);
 }
 \f
+/* Allocate space for an input file in infiles.  */
+
+static void
+alloc_infile (void)
+{
+  if (n_infiles_alloc == 0)
+    {
+      n_infiles_alloc = 16;
+      infiles = XNEWVEC (struct infile, n_infiles_alloc);
+    }
+  else if (n_infiles_alloc == n_infiles)
+    {
+      n_infiles_alloc *= 2;
+      infiles = XRESIZEVEC (struct infile, infiles, n_infiles_alloc);
+    }
+}
+
+/* Store an input file with the given NAME and LANGUAGE in
+   infiles.  */
+
+static void
+add_infile (const char *name, const char *language)
+{
+  alloc_infile ();
+  infiles[n_infiles].name = name;
+  infiles[n_infiles++].language = language;
+}
+
+/* Allocate space for a switch in switches.  */
+
+static void
+alloc_switch (void)
+{
+  if (n_switches_alloc == 0)
+    {
+      n_switches_alloc = 16;
+      switches = XNEWVEC (struct switchstr, n_switches_alloc);
+    }
+  else if (n_switches_alloc == n_switches)
+    {
+      n_switches_alloc *= 2;
+      switches = XRESIZEVEC (struct switchstr, switches, n_switches_alloc);
+    }
+}
+
 /* Create the vector `switches' and its contents.
    Store its length in `n_switches'.  */
 
@@ -3506,11 +3526,6 @@ process_command (int argc, const char **argv)
   char *temp1;
   const char *spec_lang = 0;
   int last_language_n_infiles;
-  int lang_n_infiles = 0;
-#ifdef MODIFY_TARGET_NAME
-  int is_modify_target_name;
-  unsigned int j;
-#endif
   const char *tooldir_prefix;
   char *(*get_relative_prefix) (const char *, const char *,
                                const char *) = NULL;
@@ -3724,12 +3739,22 @@ process_command (int argc, const char **argv)
        }
     }
 
-  /* Scan argv twice.  Here, the first time, just count how many switches
-     there will be in their vector, and how many input files in theirs.
-     Here we also parse the switches that cc itself uses (e.g. -v).  */
+  /* Process the options and store input files and switches in their
+     vectors.  */
+
+  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;
@@ -3755,59 +3780,50 @@ process_command (int argc, const char **argv)
          /* translate_options () has turned --version into -fversion.  */
          print_version = 1;
 
-         /* We will be passing a dummy file on to the sub-processes.  */
-         n_infiles++;
-         n_switches++;
-
          /* 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;
 
-         /* We will be passing a dummy file on to the sub-processes.  */
-         n_infiles++;
-         n_switches++;
-
          /* 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;
 
-         /* We will be passing a dummy file on to the sub-processes.  */
-         n_infiles++;
-         n_switches++;
+         goto normal_switch;
        }
       else if (strcmp (argv[i], "-ftarget-help") == 0)
        {
          /* translate_options() has turned --target-help into -ftarget-help.  */
          print_subprocess_help = 1;
 
-         /* We will be passing a dummy file on to the sub-processes.  */
-         n_infiles++;
-         n_switches++;
-
          /* 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;
-         n_switches++;
        }
       else if (! strcmp (argv[i], "-print-search-dirs"))
        print_search_dirs = 1;
@@ -3830,16 +3846,18 @@ process_command (int argc, const char **argv)
       else if (! strcmp (argv[i], "-fcompare-debug-second"))
        {
          compare_debug_second = 1;
-         n_switches++;
+         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="
@@ -3857,7 +3875,7 @@ process_command (int argc, const char **argv)
            compare_debug_opt = NULL;
          else
            compare_debug_opt = opt;
-         n_switches++;
+         goto normal_switch;
        }
       else if (! strncmp (argv[i], "-Wa,", 4))
        {
@@ -3893,63 +3911,73 @@ process_command (int argc, const char **argv)
          /* Record the part after the last comma.  */
          add_preprocessor_option (argv[i] + prev, j - prev);
        }
-      else if (argv[i][0] == '+' && argv[i][1] == 'e')
-       /* The +e options to the C++ front-end.  */
-       n_switches++;
       else if (strncmp (argv[i], "-Wl,", 4) == 0)
        {
-         int j;
+         int prev, j;
          /* Split the argument at commas.  */
-         for (j = 3; argv[i][j]; j++)
-           n_infiles += (argv[i][j] == ',');
+         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");
+           fatal_error ("argument to %<-Xlinker%> is missing");
 
-         n_infiles++;
+         add_infile (argv[i+1], "*");
          i++;
        }
       else if (strcmp (argv[i], "-Xpreprocessor") == 0)
        {
          if (i + 1 == argc)
-           fatal_error ("argument to '-Xpreprocessor' is missing");
+           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");
+           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");
+           fatal_error ("argument to %<-l%> is missing");
 
-         n_infiles++;
+         /* 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)
-       n_infiles++;
+       {
+         add_infile (argv[i], "*");
+       }
       else if (strcmp (argv[i], "-save-temps") == 0)
        {
          save_temps_flag = SAVE_TEMPS_CWD;
-         n_switches++;
+         goto normal_switch;
        }
       else if (strncmp (argv[i], "-save-temps=", 12) == 0)
        {
-         n_switches++;
          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 ("'%s' is an unknown -save-temps option", argv[i]);
+           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.  */
@@ -3957,13 +3985,13 @@ process_command (int argc, const char **argv)
       else if (strcmp (argv[i], "-combine") == 0)
        {
          combine_flag = 1;
-         n_switches++;
+         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");
+           fatal_error ("argument to %<-specs%> is missing");
 
          user->next = (struct user_specs *) 0;
          user->filename = argv[i];
@@ -3977,7 +4005,7 @@ process_command (int argc, const char **argv)
        {
          struct user_specs *user = XNEW (struct user_specs);
          if (strlen (argv[i]) == 7)
-           fatal_error ("argument to '-specs=' is missing");
+           fatal_error ("argument to %<-specs=%> is missing");
 
          user->next = (struct user_specs *) 0;
          user->filename = argv[i] + 7;
@@ -3987,6 +4015,11 @@ process_command (int argc, const char **argv)
            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)
@@ -4000,16 +4033,14 @@ process_command (int argc, const char **argv)
          /* -pipe has to go into the switches array as well as
             setting a flag.  */
          use_pipes = 1;
-         n_switches++;
+         goto normal_switch;
        }
       else if (strcmp (argv[i], "-wrapper") == 0)
         {
          if (++i >= argc)
-           fatal_error ("argument to '-wrapper' is missing");
+           fatal_error ("argument to %<-wrapper%> is missing");
 
           wrapper_string = argv[i];
-         n_switches++;
-         n_switches++;
         }
       else if (strcmp (argv[i], "-###") == 0)
        {
@@ -4022,9 +4053,6 @@ process_command (int argc, const char **argv)
        }
       else if (argv[i][0] == '-' && argv[i][1] != 0)
        {
-         const char *p = &argv[i][1];
-         int c = *p;
-
          switch (c)
            {
            case 'B':
@@ -4033,9 +4061,9 @@ process_command (int argc, const char **argv)
                int len;
 
                if (p[1] == 0 && i + 1 == argc)
-                 fatal_error ("argument to '-B' is missing");
+                 fatal_error ("argument to %<-B%> is missing");
                if (p[1] == 0)
-                 value = argv[++i];
+                 value = argv[i + 1];
                else
                  value = p + 1;
 
@@ -4064,28 +4092,38 @@ process_command (int argc, const char **argv)
                            PREFIX_PRIORITY_B_OPT, 0, 0);
                add_prefix (&include_prefixes, value, NULL,
                            PREFIX_PRIORITY_B_OPT, 0, 0);
-               n_switches++;
              }
-             break;
+             goto normal_switch;
 
            case 'v':   /* Print our subcommands and print versions.  */
-             n_switches++;
              /* 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;
-                 n_switches++;
-                 break;
-               }
+               have_c = 1;
              goto normal_switch;
 
            case 'o':
@@ -4123,7 +4161,10 @@ process_command (int argc, const char **argv)
              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);
+               {
+                 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])
@@ -4135,55 +4176,105 @@ process_command (int argc, const char **argv)
            default:
            normal_switch:
 
-#ifdef MODIFY_TARGET_NAME
-             is_modify_target_name = 0;
-
-             for (j = 0; j < ARRAY_SIZE (modify_target); j++)
-               if (! strcmp (argv[i], modify_target[j].sw))
-                 {
-                   char *new_name = XNEWVEC (char, strlen (modify_target[j].str)
-                                             + strlen (spec_machine));
-                   const char *p, *r;
-                   char *q;
-                   int made_addition = 0;
-
-                   is_modify_target_name = 1;
-                   for (p = spec_machine, q = new_name; *p != 0; )
-                     {
-                       if (modify_target[j].add_del == DELETE
-                           && (! strncmp (q, modify_target[j].str,
-                                          strlen (modify_target[j].str))))
-                         p += strlen (modify_target[j].str);
-                       else if (modify_target[j].add_del == ADD
-                                && ! made_addition && *p == '-')
-                         {
-                           for (r = modify_target[j].str; *r != 0; )
-                             *q++ = *r++;
-                           made_addition = 1;
-                         }
-
-                       *q++ = *p++;
-                     }
-
-                   spec_machine = new_name;
-                 }
-
-             if (is_modify_target_name)
-               break;
-#endif
+             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 (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++;
-
-             if (SWITCH_TAKES_ARG (c) > (p[1] != 0))
-               i += SWITCH_TAKES_ARG (c) - (p[1] != 0);
-             else if (WORD_SWITCH_TAKES_ARG (p))
-               i += WORD_SWITCH_TAKES_ARG (p);
            }
        }
       else
        {
-         n_infiles++;
-         lang_n_infiles++;
+          const char *p = strrchr (argv[i], '@');
+          char *fname;
+         long offset;
+         int consumed;
+#ifdef HAVE_TARGET_OBJECT_SUFFIX
+         argv[i] = convert_filename (argv[i], 0, access (argv[i], 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]
+             && 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';
+             /* 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]);
+               }
+           }
+         else
+           fname = xstrdup (argv[i]);
+          if (strcmp (fname, "-") != 0 && access (fname, F_OK) < 0)
+           perror_with_name (fname);
+          else
+           add_infile (argv[i], spec_lang);
+
+          free (fname);
        }
     }
 
@@ -4222,13 +4313,11 @@ process_command (int argc, const char **argv)
        {
          compare_debug = 2;
          compare_debug_opt = gcd;
-         n_switches++;
        }
       else if (gcd && *gcd && strcmp (gcd, "0"))
        {
          compare_debug = 3;
          compare_debug_opt = "-gtoggle";
-         n_switches++;
        }
     }
   else if (compare_debug < 0)
@@ -4281,7 +4370,7 @@ process_command (int argc, const char **argv)
      then consider it to relocate with the rest of the GCC installation
      if GCC_EXEC_PREFIX is set.
      ``make_relative_prefix'' is not compiled for VMS, so don't call it.  */
-  if (target_system_root && gcc_exec_prefix)
+  if (target_system_root && !target_system_root_changed && gcc_exec_prefix)
     {
       char *tmp_prefix = get_relative_prefix (argv[0],
                                              standard_bindir_prefix,
@@ -4297,256 +4386,12 @@ process_command (int argc, const char **argv)
   /* More prefixes are enabled in main, after we read the specs file
      and determine whether this is cross-compilation or not.  */
 
-  /* Then create the space for the vectors and scan again.  */
-
-  switches = XNEWVEC (struct switchstr, n_switches + 1);
-  infiles = XNEWVEC (struct infile, n_infiles + 1);
-  n_switches = 0;
-  n_infiles = 0;
-  last_language_n_infiles = -1;
-
-  /* This, time, copy the text of each switch and store a pointer
-     to the copy in the vector of switches.
-     Store all the infiles in their vector.  */
-
-  for (i = 1; i < argc; i++)
-    {
-      /* Just skip the switches that were handled by the preceding loop.  */
-#ifdef MODIFY_TARGET_NAME
-      is_modify_target_name = 0;
-
-      for (j = 0; j < ARRAY_SIZE (modify_target); j++)
-       if (! strcmp (argv[i], modify_target[j].sw))
-         is_modify_target_name = 1;
-
-      if (is_modify_target_name)
-       ;
-      else
-#endif
-      if (! strncmp (argv[i], "-Wa,", 4))
-       ;
-      else if (! strncmp (argv[i], "-Wp,", 4))
-       ;
-      else if (! strcmp (argv[i], "-no-canonical-prefixes"))
-       ;
-      else if (! strcmp (argv[i], "-pass-exit-codes"))
-       ;
-      else if (! strcmp (argv[i], "-print-search-dirs"))
-       ;
-      else if (! strcmp (argv[i], "-print-libgcc-file-name"))
-       ;
-      else if (! strncmp (argv[i], "-print-file-name=", 17))
-       ;
-      else if (! strncmp (argv[i], "-print-prog-name=", 17))
-       ;
-      else if (! strcmp (argv[i], "-print-multi-lib"))
-       ;
-      else if (! strcmp (argv[i], "-print-multi-directory"))
-       ;
-      else if (! strcmp (argv[i], "-print-sysroot"))
-       ;
-      else if (! strcmp (argv[i], "-print-multi-os-directory"))
-       ;
-      else if (! strcmp (argv[i], "-print-sysroot-headers-suffix"))
-       ;
-      else if (! strncmp (argv[i], "--sysroot=", strlen ("--sysroot=")))
-       {
-         target_system_root = argv[i] + strlen ("--sysroot=");
-         target_system_root_changed = 1;
-       }
-      else if (argv[i][0] == '+' && argv[i][1] == 'e')
-       {
-         /* Compensate for the +e options to the C++ front-end;
-            they're there simply for cfront call-compatibility.  We do
-            some magic in default_compilers to pass them down properly.
-            Note we deliberately start at the `+' here, to avoid passing
-            -e0 or -e1 down into the linker.  */
-         switches[n_switches].part1 = &argv[i][0];
-         switches[n_switches].args = 0;
-         switches[n_switches].live_cond = 0;
-         switches[n_switches].validated = 0;
-         n_switches++;
-       }
-      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] == ',')
-             {
-               infiles[n_infiles].language = "*";
-               infiles[n_infiles++].name
-                 = save_string (argv[i] + prev, j - prev);
-               prev = j + 1;
-             }
-         /* Record the part after the last comma.  */
-         infiles[n_infiles].language = "*";
-         infiles[n_infiles++].name = argv[i] + prev;
-       }
-      else if (strcmp (argv[i], "-Xlinker") == 0)
-       {
-         infiles[n_infiles].language = "*";
-         infiles[n_infiles++].name = argv[++i];
-       }
-      /* Xassembler and Xpreprocessor were already handled in the first argv
-        scan, so all we need to do here is ignore them and their argument.  */
-      else if (strcmp (argv[i], "-Xassembler") == 0)
-       i++;
-      else if (strcmp (argv[i], "-Xpreprocessor") == 0)
-       i++;
-      else if (strcmp (argv[i], "-l") == 0)
-       { /* POSIX allows separation of -l and the lib arg;
-            canonicalize by concatenating -l with its arg */
-         infiles[n_infiles].language = "*";
-         infiles[n_infiles++].name = concat ("-l", argv[++i], NULL);
-       }
-      else if (strncmp (argv[i], "-l", 2) == 0)
-       {
-         infiles[n_infiles].language = "*";
-         infiles[n_infiles++].name = argv[i];
-       }
-      else if (strcmp (argv[i], "-wrapper") == 0)
-        i++;
-      else if (strcmp (argv[i], "-specs") == 0)
-       i++;
-      else if (strncmp (argv[i], "-specs=", 7) == 0)
-       ;
-      else if (strcmp (argv[i], "-time") == 0)
-       ;
-      else if (strncmp (argv[i], "-time=", sizeof ("-time=") - 1) == 0)
-       ;
-      else if (strcmp (argv[i], "-###") == 0)
-       ;
-      else if (argv[i][0] == '-' && argv[i][1] != 0)
-       {
-         const char *p = &argv[i][1];
-         int c = *p;
-
-         if (c == '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;
-             continue;
-           }
-         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 (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 (strchr (switches_need_spaces, c))
-           {
-             /* On some systems, ld cannot handle some options 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
-       {
-          const char *p = strrchr (argv[i], '@');
-          char *fname;
-         long offset;
-         int consumed;
-#ifdef HAVE_TARGET_OBJECT_SUFFIX
-         argv[i] = convert_filename (argv[i], 0, access (argv[i], 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]
-             && 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';
-             /* 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]);
-               }
-           }
-         else
-           fname = xstrdup (argv[i]);
-          if (strcmp (fname, "-") != 0 && access (fname, F_OK) < 0)
-           perror_with_name (fname);
-          else
-            {
-              infiles[n_infiles].language = spec_lang;
-              infiles[n_infiles++].name = argv[i];
-            }
-
-          free (fname);
-       }
-    }
-
   if (n_infiles == last_language_n_infiles && spec_lang != 0)
-    warning (0, "'-x %s' after last input file has no effect", spec_lang);
+    warning (0, "%<-x %s%> after last input file has no effect", spec_lang);
 
   if (compare_debug == 2 || compare_debug == 3)
     {
+      alloc_switch ();
       switches[n_switches].part1 = concat ("fcompare-debug=",
                                           compare_debug_opt,
                                           NULL);
@@ -4561,15 +4406,16 @@ process_command (int argc, const char **argv)
   /* Ensure we only invoke each subprocess once.  */
   if (print_subprocess_help || print_help_list || print_version)
     {
-      n_infiles = 1;
+      n_infiles = 0;
 
       /* Create a dummy input file, so that we can pass
         the help option on to the various sub-processes.  */
-      infiles[0].language = "c";
-      infiles[0].name   = "help-dummy";
+      add_infile ("help-dummy", "c");
     }
 
+  alloc_switch ();
   switches[n_switches].part1 = 0;
+  alloc_infile ();
   infiles[n_infiles].name = 0;
 }
 
@@ -4706,7 +4552,7 @@ end_going_arg (void)
 
          if (full_script_path == NULL)
            {
-             error ("unable to locate default linker script '%s' in the library search paths", string);
+             error ("unable to locate default linker script %qs in the library search paths", string);
              /* Script was not found on search path.  */
              return;
            }
@@ -4894,7 +4740,7 @@ do_self_spec (const char *spec)
 
          /* Each switch should start with '-'.  */
          if (c != '-')
-           fatal_error ("switch '%s' does not start with '-'", argbuf[i]);
+           fatal_error ("switch %qs does not start with %<-%>", argbuf[i]);
 
          p++;
          c = *p;
@@ -4918,7 +4764,7 @@ do_self_spec (const char *spec)
                  n_args = SWITCH_TAKES_ARG (c) - (p[1] != 0);
                }
              if (i + n_args >= argbuf_index)
-               fatal_error ("argument to '-%s' is missing", p);
+               fatal_error ("argument to %<-%s%> is missing", p);
              sw->args
                = XNEWVEC (const char *, n_args + 1);
              while (j < n_args)
@@ -4926,9 +4772,9 @@ do_self_spec (const char *spec)
              /* Null-terminate the vector.  */
              sw->args[j] = 0;
            }
-         else if (strchr (switches_need_spaces, c))
+         else if (c == 'o')
            {
-             /* On some systems, ld cannot handle some options without
+             /* 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;
@@ -5124,7 +4970,7 @@ do_spec_1 (const char *spec, int inswitch, const char *soft_matched_part)
        switch (c = *p++)
          {
          case 0:
-           fatal_error ("spec '%s' invalid", spec);
+           fatal_error ("spec %qs invalid", spec);
 
          case 'b':
            if (save_temps_length)
@@ -5273,7 +5119,7 @@ do_spec_1 (const char *spec, int inswitch, const char *soft_matched_part)
                    p += 2;
                    /* We don't support extra suffix characters after %O.  */
                    if (*p == '.' || ISALNUM ((unsigned char) *p))
-                     fatal_error ("spec '%s' has invalid '%%0%c'", spec, *p);
+                     fatal_error ("spec %qs has invalid %<%%0%c%>", spec, *p);
                    if (suffix_length == 0)
                      suffix = TARGET_OBJECT_SUFFIX;
                    else
@@ -5584,7 +5430,7 @@ do_spec_1 (const char *spec, int inswitch, const char *soft_matched_part)
              int cur_index = argbuf_index;
              /* Handle the {...} following the %W.  */
              if (*p != '{')
-               fatal_error ("spec '%s' has invalid '%%W%c", spec, *p);
+               fatal_error ("spec %qs has invalid %<%%W%c%>", spec, *p);
              p = handle_braces (p + 1);
              if (p == 0)
                return -1;
@@ -5604,7 +5450,7 @@ do_spec_1 (const char *spec, int inswitch, const char *soft_matched_part)
 
              /* Skip past the option value and make a copy.  */
              if (*p != '{')
-               fatal_error ("spec '%s' has invalid '%%x%c'", spec, *p);
+               fatal_error ("spec %qs has invalid %<%%x%c%>", spec, *p);
              while (*p++ != '}')
                ;
              string = save_string (p1 + 1, p - p1 - 2);
@@ -5799,7 +5645,7 @@ do_spec_1 (const char *spec, int inswitch, const char *soft_matched_part)
              /* Catch the case where a spec string contains something like
                 '%{foo:%*}'.  i.e. there is no * in the pattern on the left
                 hand side of the :.  */
-             error ("spec failure: '%%*' has not been initialized by pattern match");
+             error ("spec failure: %<%%*%> has not been initialized by pattern match");
            break;
 
            /* Process a string found as the value of a spec given by name.
@@ -5889,7 +5735,7 @@ do_spec_1 (const char *spec, int inswitch, const char *soft_matched_part)
            break;
 
          default:
-           error ("spec failure: unrecognized spec option '%c'", c);
+           error ("spec failure: unrecognized spec option %qc", c);
            break;
          }
        break;
@@ -5951,7 +5797,7 @@ eval_spec_function (const char *func, const char *args)
 
   sf = lookup_spec_function (func);
   if (sf == NULL)
-    fatal_error ("unknown spec function '%s'", func);
+    fatal_error ("unknown spec function %qs", func);
 
   /* Push the spec processing context.  */
   save_argbuf_index = argbuf_index;
@@ -5971,7 +5817,7 @@ eval_spec_function (const char *func, const char *args)
 
   alloc_args ();
   if (do_spec_2 (args) < 0)
-    fatal_error ("error in args to spec function '%s'", func);
+    fatal_error ("error in args to spec function %qs", func);
 
   /* argbuf_index is an index for the next argument to be inserted, and
      so contains the count of the args already inserted.  */
@@ -6288,7 +6134,7 @@ handle_braces (const char *p)
   return p;
 
  invalid:
-  fatal_error ("braced spec '%s' is invalid at '%c'", orig, *p);
+  fatal_error ("braced spec %qs is invalid at %qc", orig, *p);
 
 #undef SKIP_WHITE
 }
@@ -6376,7 +6222,7 @@ process_brace_body (const char *p, const char *atom, const char *end_atom,
   return p;
 
  invalid:
-  fatal_error ("braced spec body '%s' is invalid", body);
+  fatal_error ("braced spec body %qs is invalid", body);
 }
 \f
 /* Return 0 iff switch number SWITCHNUM is obsoleted by a later switch
@@ -7074,7 +6920,7 @@ main (int argc, char **argv)
 
   for (i = 0; (int) i < n_switches; i++)
     if (! switches[i].validated)
-      error ("unrecognized option '-%s'", switches[i].part1);
+      error ("unrecognized option %<-%s%>", switches[i].part1);
 
   /* Obey some of the options.  */
 
@@ -7317,7 +7163,7 @@ warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\n"
                  value = do_spec (input_file_compiler->spec);
                  infiles[i].preprocessed = true;
                  if (!have_o_argbuf_index)
-                   fatal_error ("spec '%s' is invalid",
+                   fatal_error ("spec %qs is invalid",
                                 input_file_compiler->spec);
                  infiles[i].name = argbuf[have_o_argbuf_index];
                  infiles[i].incompiler
@@ -7654,7 +7500,7 @@ pfatal_with_name (const char *name)
 static void
 perror_with_name (const char *name)
 {
-  error ("%s: %s", name, xstrerror (errno));
+  error ("%s: %m", name);
 }
 \f
 static inline void
@@ -7809,7 +7655,7 @@ used_arg (const char *p, int len)
              if (*q == '\0')
                {
                invalid_matches:
-                 fatal_error ("multilib spec '%s' is invalid",
+                 fatal_error ("multilib spec %qs is invalid",
                               multilib_matches);
                }
              q++;
@@ -8001,7 +7847,7 @@ set_multilib_dir (void)
          if (*p == '\0')
            {
            invalid_exclusions:
-             fatal_error ("multilib exclusions '%s' is invalid",
+             fatal_error ("multilib exclusions %qs is invalid",
                           multilib_exclusions);
            }
 
@@ -8059,7 +7905,7 @@ set_multilib_dir (void)
          if (*p == '\0')
            {
            invalid_select:
-             fatal_error ("multilib select '%s' is invalid",
+             fatal_error ("multilib select %qs is invalid",
                           multilib_select);
            }
          ++p;
@@ -8200,7 +8046,7 @@ print_multilib_info (void)
          if (*p == '\0')
            {
            invalid_select:
-             fatal_error ("multilib select '%s' is invalid", multilib_select);
+             fatal_error ("multilib select %qs is invalid", multilib_select);
            }
 
          ++p;
@@ -8238,7 +8084,7 @@ print_multilib_info (void)
                if (*e == '\0')
                  {
                  invalid_exclusion:
-                   fatal_error ("multilib exclusion '%s' is invalid",
+                   fatal_error ("multilib exclusion %qs is invalid",
                                 multilib_exclusions);
                  }
 
@@ -8444,7 +8290,7 @@ getenv_spec_function (int argc, const char **argv)
 
   value = getenv (argv[0]);
   if (!value)
-    fatal_error ("environment variable \"%s\" not defined", argv[0]);
+    fatal_error ("environment variable %qs not defined", argv[0]);
 
   /* We have to escape every character of the environment variable so
      they are not interpreted as active spec characters.  A
@@ -8535,12 +8381,12 @@ compare_version_strings (const char *v1, const char *v2)
     abort ();
   rresult = regexec (&r, v1, 0, NULL, 0);
   if (rresult == REG_NOMATCH)
-    fatal_error ("invalid version number `%s'", v1);
+    fatal_error ("invalid version number %qs", v1);
   else if (rresult != 0)
     abort ();
   rresult = regexec (&r, v2, 0, NULL, 0);
   if (rresult == REG_NOMATCH)
-    fatal_error ("invalid version number `%s'", v2);
+    fatal_error ("invalid version number %qs", v2);
   else if (rresult != 0)
     abort ();
 
@@ -8630,7 +8476,7 @@ version_compare_spec_function (int argc, const char **argv)
       break;
 
     default:
-      fatal_error ("unknown operator '%s' in %%:version-compare", argv[0]);
+      fatal_error ("unknown operator %qs in %%:version-compare", argv[0]);
     }
   if (! result)
     return NULL;
@@ -8657,11 +8503,11 @@ include_spec_function (int argc, const char **argv)
   return NULL;
 }
 
-/* %:find-file spec function.  This function replace its argument by
+/* %:find-file spec function.  This function replaces its argument by
     the file found thru find_file, that is the -print-file-name gcc
     program option. */
 static const char *
-find_file_spec_function (int argc, const char**argv)
+find_file_spec_function (int argc, const char **argv)
 {
   const char *file;
 
@@ -8673,6 +8519,22 @@ find_file_spec_function (int argc, const char**argv)
 }
 
 
+/* %:find-plugindir spec function.  This function replaces its argument
+    by the -iplugindir=<dir> option.  `dir' is found thru find_file, that
+    is the -print-file-name gcc program option. */
+static const char *
+find_plugindir_spec_function (int argc, const char **argv ATTRIBUTE_UNUSED)
+{
+  const char *option;
+
+  if (argc != 0)
+    abort ();
+
+  option = concat ("-iplugindir=", find_file ("plugin"), NULL);
+  return option;
+}
+
+
 /* %:print-asm-header spec function.  Print a banner to say that the
    following output is from the assembler.  */