Speed up genmultilib; Add MULTIB_EXTRA_OPTS
[gcc.git] / gcc / gcc.c
index 9e9304b79a4fe77c98a6e3bdac1ac0a3c9b4bdf3..46ca22bc5434dd33408f014cbae249629f2a5b6d 100644 (file)
--- a/gcc/gcc.c
+++ b/gcc/gcc.c
@@ -39,10 +39,6 @@ compilation is specified by a string called a "spec".  */
 
 #ifndef _WIN32
 #include <sys/file.h>   /* May get R_OK, etc. on some systems.  */
-#else
-#include <process.h>
-int __spawnv ();
-int __spawnvp ();
 #endif
 
 #include "config.h"
@@ -56,15 +52,22 @@ int __spawnvp ();
 #endif
 #include <stdio.h>
 
-/* Include multi-lib information.  */
-#include "multilib.h"
-
 #ifndef R_OK
 #define R_OK 4
 #define W_OK 2
 #define X_OK 1
 #endif
 
+/* ??? Need to find a GCC header to put these in.  */
+extern int pexecute PROTO ((const char *, char * const *, const char *,
+                           const char *, char **, char **, int));
+extern int pwait PROTO ((int, int *, int));
+/* Flag arguments to pexecute.  */
+#define PEXECUTE_FIRST   1
+#define PEXECUTE_LAST    2
+#define PEXECUTE_SEARCH  4
+#define PEXECUTE_VERBOSE 8
+
 #ifndef WIFSIGNALED
 #define WIFSIGNALED(S) (((S) & 0xff) != 0 && ((S) & 0xff) != 0x7f)
 #endif
@@ -78,7 +81,7 @@ int __spawnvp ();
 #define WEXITSTATUS(S) (((S) & 0xff00) >> 8)
 #endif
 
-/* Define O_RDONLY if the system hasn't defined it for us. */
+/* Define O_RDONLY if the system hasn't defined it for us.  */
 #ifndef O_RDONLY
 #define O_RDONLY 0
 #endif
@@ -102,7 +105,7 @@ int __spawnvp ();
 #define EXECUTABLE_SUFFIX ""
 #endif
 
-/* By default, the suffix for object files is ".o". */
+/* By default, the suffix for object files is ".o".  */
 #ifdef OBJECT_SUFFIX
 #define HAVE_OBJECT_SUFFIX
 #else
@@ -143,8 +146,6 @@ extern char *sys_errlist[];
 extern char *strerror();
 #endif
 
-extern int execv (), execvp ();
-
 /* If a stage of compilation returns an exit status >= 1,
    compilation of that file ceases.  */
 
@@ -160,7 +161,7 @@ static int print_search_dirs;
 
 static char *print_file_name = NULL;
 
-/* As print_file_name, but search for executable file. */
+/* As print_file_name, but search for executable file.  */
 
 static char *print_prog_name = NULL;
 
@@ -253,7 +254,7 @@ static void set_multilib_dir        PROTO((void));
 static void print_multilib_info        PROTO((void));
 static void pfatal_with_name   PROTO((char *));
 static void perror_with_name   PROTO((char *));
-static void perror_exec                PROTO((char *));
+static void pfatal_pexecute    PROTO((char *, char *));
 #ifdef HAVE_VPRINTF
 static void fatal              PVPROTO((char *, ...));
 static void error              PVPROTO((char *, ...));
@@ -475,13 +476,6 @@ proper position among the other output files.  */
 #endif
 #endif
 
-/* MULTILIB_SELECT comes from multilib.h.  It gives a
-   string interpreted by set_multilib_dir to select a library
-   subdirectory based on the compiler options.  */
-#ifndef MULTILIB_SELECT
-#define MULTILIB_SELECT ". ;"
-#endif
-
 static char *cpp_spec = CPP_SPEC;
 static char *cpp_predefines = CPP_PREDEFINES;
 static char *cc1_spec = CC1_SPEC;
@@ -495,7 +489,23 @@ static char *libgcc_spec = LIBGCC_SPEC;
 static char *endfile_spec = ENDFILE_SPEC;
 static char *startfile_spec = STARTFILE_SPEC;
 static char *switches_need_spaces = SWITCHES_NEED_SPACES;
-static char *multilib_select = MULTILIB_SELECT;
+
+/* Some compilers have limits on line lengths, and the multilib_select
+   and/or multilib_matches strings can be very long, so we build them at
+   run time.  */
+static struct obstack multilib_obstack;
+static char *multilib_select;
+static char *multilib_matches;
+static char *multilib_defaults;
+#include "multilib.h"
+
+/* Check whether a particular argument is a default argument.  */
+
+#ifndef MULTILIB_DEFAULTS
+#define MULTILIB_DEFAULTS { "" }
+#endif
+
+static char *multilib_defaults_raw[] = MULTILIB_DEFAULTS;
 
 #ifdef EXTRA_SPECS
 static struct { char *name, *spec; } extra_specs[] = { EXTRA_SPECS };
@@ -557,6 +567,15 @@ static int n_compilers;
 
 static struct compiler default_compilers[] =
 {
+  /* Add lists of suffixes of known languages here.  If those languages
+     were no present when we built the driver, we will hit these copies
+     and given a more meaningful error than "file not used since
+     linking is not done".  */
+  {".cc", "#C++"}, {".cxx", "#C++"}, {".cpp", "#C++"}, {".c++", "#C++"},
+  {".C", "#C++"}, {".ads", "#Ada"}, {".adb", "#Ada"}, {".ada", "#Ada"},
+  {".f", "#Fortran"}, {".for", "#Fortran"}, {".F", "#Fortran"},
+  {".fpp", "#Fortran"},
+  /* Next come the entries for C.  */
   {".c", "@c"},
   {"@c",
    "cpp -lang-c%{ansi:89} %{nostdinc*} %{C} %{v} %{A*} %{I*} %{P} %I\
@@ -973,8 +992,8 @@ char *
 my_strerror(e)
      int e;
 {
-
 #ifdef HAVE_STRERROR
+
   return strerror(e);
 
 #else
@@ -1135,23 +1154,24 @@ skip_whitespace (p)
   return p;
 }
 \f
-/* Structure to keep track of the specs that have been defined so far.  These
-   are accessed using %(specname) or %[specname] in a compiler or link spec. */
+/* Structure to keep track of the specs that have been defined so far.
+   These are accessed using %(specname) or %[specname] in a compiler
+   or link spec.  */
 
 struct spec_list
 {
-  char *name;                 /* Name of the spec. */
-  char *spec;                 /* The spec itself. */
-  struct spec_list *next;     /* Next spec in linked list. */
+  char *name;                 /* Name of the spec.  */
+  char *spec;                 /* The spec itself.  */
+  struct spec_list *next;     /* Next spec in linked list.  */
 };
 
-/* List of specs that have been defined so far. */
+/* List of specs that have been defined so far.  */
 
 static struct spec_list *specs = (struct spec_list *) 0;
 \f
 /* Change the value of spec NAME to SPEC.  If SPEC is empty, then the spec is
    removed; If the spec starts with a + then SPEC is added to the end of the
-   current spec. */
+   current spec.  */
 
 static void
 set_spec (name, spec)
@@ -1212,6 +1232,12 @@ set_spec (name, spec)
     cross_compile = atoi (sl->spec);
   else if (! strcmp (name, "multilib"))
     multilib_select = sl->spec;
+  else if (! strcmp (name, "multilib_matches"))
+    multilib_matches = sl->spec;
+  else if (! strcmp (name, "multilib_extra"))
+    multilib_extra = sl->spec;
+  else if (! strcmp (name, "multilib_defaults"))
+    multilib_defaults = sl->spec;
 #ifdef EXTRA_SPECS
   else
     {
@@ -1270,12 +1296,12 @@ static int signal_count;
 
 static char *programname;
 \f
-/* Structures to keep track of prefixes to try when looking for files. */
+/* Structures to keep track of prefixes to try when looking for files.  */
 
 struct prefix_list
 {
-  char *prefix;               /* String to prepend to the path. */
-  struct prefix_list *next;   /* Next in linked list. */
+  char *prefix;               /* String to prepend to the path.  */
+  struct prefix_list *next;   /* Next in linked list.  */
   int require_machine_suffix; /* Don't use without machine_suffix.  */
   /* 2 means try both machine_suffix and just_machine_suffix.  */
   int *used_flag_ptr;        /* 1 if a file was found with this prefix.  */
@@ -1288,11 +1314,11 @@ struct path_prefix
   char *name;                 /* Name of this list (used in config stuff) */
 };
 
-/* List of prefixes to try when looking for executables. */
+/* List of prefixes to try when looking for executables.  */
 
 static struct path_prefix exec_prefixes = { 0, 0, "exec" };
 
-/* List of prefixes to try when looking for startup (crt0) files. */
+/* List of prefixes to try when looking for startup (crt0) files.  */
 
 static struct path_prefix startfile_prefixes = { 0, 0, "startfile" };
 
@@ -1633,7 +1659,8 @@ build_search_list (paths, prefix, check_dir_p)
   return obstack_finish (&collect_obstack);
 }
 
-/* Rebuild the COMPILER_PATH and LIBRARY_PATH environment variables for collect.  */
+/* Rebuild the COMPILER_PATH and LIBRARY_PATH environment variables
+   for collect.  */
 
 static void
 putenv_from_prefixes (paths, env_var)
@@ -1645,7 +1672,7 @@ putenv_from_prefixes (paths, env_var)
 \f
 /* Search for NAME using the prefix list PREFIXES.  MODE is passed to
    access to check permissions.
-   Return 0 if not found, otherwise return its name, allocated with malloc. */
+   Return 0 if not found, otherwise return its name, allocated with malloc.  */
 
 static char *
 find_a_file (pprefix, name, mode)
@@ -1847,7 +1874,7 @@ unused_prefix_warnings (pprefix)
     }
 }
 
-/* Get rid of all prefixes built up so far in *PLISTP. */
+/* Get rid of all prefixes built up so far in *PLISTP.  */
 
 static void
 free_path_prefix (pprefix)
@@ -1865,201 +1892,6 @@ free_path_prefix (pprefix)
     }
   pprefix->plist = (struct prefix_list *) 0;
 }
-\f
-/* stdin file number.  */
-#define STDIN_FILE_NO 0
-
-/* stdout file number.  */
-#define STDOUT_FILE_NO 1
-
-/* value of `pipe': port index for reading.  */
-#define READ_PORT 0
-
-/* value of `pipe': port index for writing.  */
-#define WRITE_PORT 1
-
-/* Pipe waiting from last process, to be used as input for the next one.
-   Value is STDIN_FILE_NO if no pipe is waiting
-   (i.e. the next command is the first of a group).  */
-
-static int last_pipe_input;
-
-/* Fork one piped subcommand.  FUNC is the system call to use
-   (either execv or execvp).  ARGV is the arg vector to use.
-   NOT_LAST is nonzero if this is not the last subcommand
-   (i.e. its output should be piped to the next one.)  */
-
-#ifdef __MSDOS__
-
-#include <process.h>
-static int
-pexecute (search_flag, program, argv, not_last)
-     int search_flag;
-     char *program;
-     char *argv[];
-     int not_last;
-{
-#ifdef __GO32__
-  int i = (search_flag ? spawnv : spawnvp) (1, program, argv);
-#else
-  char *scmd, *rf;
-  FILE *argfile;
-  int i, el = search_flag ? 0 : 4;
-
-  scmd = (char *)malloc (strlen (program) + strlen (temp_filename) + 6 + el);
-  rf = scmd + strlen(program) + 2 + el;
-  sprintf (scmd, "%s%s @%s.gp", program,
-          (search_flag ? "" : ".exe"), temp_filename);
-  argfile = fopen (rf, "w");
-  if (argfile == 0)
-    pfatal_with_name (rf);
-
-  for (i=1; argv[i]; i++)
-    {
-      char *cp;
-      for (cp = argv[i]; *cp; cp++)
-       {
-         if (*cp == '"' || *cp == '\'' || *cp == '\\' || isspace (*cp))
-           fputc ('\\', argfile);
-         fputc (*cp, argfile);
-       }
-      fputc ('\n', argfile);
-    }
-  fclose (argfile);
-
-  i = system (scmd);
-
-  remove (rf);
-#endif
-  
-  if (i == -1)
-    {
-      perror_exec (program);
-      return MIN_FATAL_STATUS << 8;
-    }
-  return i << 8;
-}
-
-#endif
-
-#if !defined(__MSDOS__) && !defined(OS2) && !defined(_WIN32)
-
-static int
-pexecute (search_flag, program, argv, not_last)
-     int search_flag;
-     char *program;
-     char *argv[];
-     int not_last;
-{
-  int (*func)() = (search_flag ? execv : execvp);
-  int pid;
-  int pdes[2];
-  int input_desc = last_pipe_input;
-  int output_desc = STDOUT_FILE_NO;
-  int retries, sleep_interval;
-
-  /* If this isn't the last process, make a pipe for its output,
-     and record it as waiting to be the input to the next process.  */
-
-  if (not_last)
-    {
-      if (pipe (pdes) < 0)
-       pfatal_with_name ("pipe");
-      output_desc = pdes[WRITE_PORT];
-      last_pipe_input = pdes[READ_PORT];
-    }
-  else
-    last_pipe_input = STDIN_FILE_NO;
-
-  /* Fork a subprocess; wait and retry if it fails.  */
-  sleep_interval = 1;
-  for (retries = 0; retries < 4; retries++)
-    {
-      pid = vfork ();
-      if (pid >= 0)
-       break;
-      sleep (sleep_interval);
-      sleep_interval *= 2;
-    }
-
-  switch (pid)
-    {
-    case -1:
-#ifdef vfork
-      pfatal_with_name ("fork");
-#else
-      pfatal_with_name ("vfork");
-#endif
-      /* NOTREACHED */
-      return 0;
-
-    case 0: /* child */
-      /* Move the input and output pipes into place, if nec.  */
-      if (input_desc != STDIN_FILE_NO)
-       {
-         close (STDIN_FILE_NO);
-         dup (input_desc);
-         close (input_desc);
-       }
-      if (output_desc != STDOUT_FILE_NO)
-       {
-         close (STDOUT_FILE_NO);
-         dup (output_desc);
-         close (output_desc);
-       }
-
-      /* Close the parent's descs that aren't wanted here.  */
-      if (last_pipe_input != STDIN_FILE_NO)
-       close (last_pipe_input);
-
-      /* Exec the program.  */
-      (*func) (program, argv);
-      perror_exec (program);
-      exit (-1);
-      /* NOTREACHED */
-      return 0;
-
-    default:
-      /* In the parent, after forking.
-        Close the descriptors that we made for this child.  */
-      if (input_desc != STDIN_FILE_NO)
-       close (input_desc);
-      if (output_desc != STDOUT_FILE_NO)
-       close (output_desc);
-
-      /* Return child's process number.  */
-      return pid;
-    }
-}
-
-#endif /* not __MSDOS__ and not OS2 and not _WIN32 */
-
-#if defined(OS2)
-
-static int
-pexecute (search_flag, program, argv, not_last)
-     int search_flag;
-     char *program;
-     char *argv[];
-     int not_last;
-{
-  return (search_flag ? spawnv : spawnvp) (1, program, argv);
-}
-#endif /* OS2 */
-
-#if defined(_WIN32)
-
-static int
-pexecute (search_flag, program, argv, not_last)
-     int search_flag;
-     char *program;
-     char *argv[];
-     int not_last;
-{
-  return (search_flag ? __spawnv : __spawnvp) (1, program, argv);
-}
-#endif /* _WIN32 */
-
 \f
 /* Execute the command specified by the arguments on the current line of spec.
    When using pipes, this includes several piped-together commands
@@ -2104,8 +1936,8 @@ execute ()
   for (n_commands = 1, i = 0; i < argbuf_index; i++)
     if (strcmp (argbuf[i], "|") == 0)
       {                                /* each command.  */
-#ifdef __MSDOS__
-        fatal ("-pipe not supported under MS-DOS");
+#if defined (__MSDOS__) || defined (_WIN32) || defined (OS2)
+        fatal ("-pipe not supported");
 #endif
        argbuf[i] = 0;  /* termination of command args.  */
        commands[n_commands].prog = argbuf[i + 1];
@@ -2149,14 +1981,22 @@ execute ()
 
   /* Run each piped subprocess.  */
 
-  last_pipe_input = STDIN_FILE_NO;
   for (i = 0; i < n_commands; i++)
     {
+      char *errmsg_fmt, *errmsg_arg;
       char *string = commands[i].argv[0];
 
-      commands[i].pid = pexecute (string != commands[i].prog,
-                                 string, commands[i].argv,
-                                 i + 1 < n_commands);
+      commands[i].pid = pexecute (string, commands[i].argv,
+                                 programname, temp_filename,
+                                 &errmsg_fmt, &errmsg_arg,
+                                 ((i == 0 ? PEXECUTE_FIRST : 0)
+                                  | (i + 1 == n_commands ? PEXECUTE_LAST : 0)
+                                  | (string == commands[i].prog
+                                     ? PEXECUTE_SEARCH : 0)
+                                  | (verbose_flag ? PEXECUTE_VERBOSE : 0)));
+
+      if (commands[i].pid == -1)
+       pfatal_pexecute (errmsg_fmt, errmsg_arg);
 
       if (string != commands[i].prog)
        free (string);
@@ -2179,15 +2019,7 @@ execute ()
        int status;
        int pid;
 
-#ifdef __MSDOS__
-        status = pid = commands[i].pid;
-#else
-#ifdef _WIN32
-       pid = cwait (&status, commands[i].pid, WAIT_CHILD);
-#else
-       pid = wait (&status);
-#endif
-#endif
+       pid = pwait (commands[i].pid, &status, 0);
        if (pid < 0)
          abort ();
 
@@ -2427,6 +2259,9 @@ process_command (argc, argv)
          printf ("*predefines:\n%s\n\n", cpp_predefines);
          printf ("*cross_compile:\n%d\n\n", cross_compile);
          printf ("*multilib:\n%s\n\n", multilib_select);
+         printf ("*multilib_defaults:\n%s\n\n", multilib_defaults);
+         printf ("*multilib_extra:\n%s\n\n", multilib_extra);
+         printf ("*multilib_matches:\n%s\n\n", multilib_matches);
 
 #ifdef EXTRA_SPECS
          {
@@ -3670,7 +3505,7 @@ do_spec_1 (spec, inswitch, soft_matched_part)
              int len;
 
              /* The string after the S/P is the name of a spec that is to be
-                processed. */
+                processed.  */
              while (*p && *p != ')' && *p != ']')
                p++;
 
@@ -3738,26 +3573,35 @@ do_spec_1 (spec, inswitch, soft_matched_part)
            {
              int c1 = *p++;  /* Select first or second version number.  */
              char *v = compiler_version;
-             char *q, *copy;
+             char *q;
+
+             /* The format of the version string is
+                ([^0-9]*-)?[0-9]+[.][0-9]+([.][0-9]+)?([- ].*)?  */
+
+             /* Ignore leading non-digits.  i.e. "foo-" in "foo-2.7.2".  */
+             while (! isdigit (*v))
+               v++;
+             if (v > compiler_version && v[-1] != '-')
+               abort ();
+
              /* If desired, advance to second version number.  */
              if (c1 == '2')
                {
                  /* Set V after the first period.  */
-                 while (*v != 0 && *v != ' ' && *v != '.')
-                   v++;
-                 if (*v == '.')
+                 while (isdigit (*v))
                    v++;
+                 if (*v != '.')
+                   abort ();
+                 v++;
                }
+
              /* Set Q at the next period or at the end.  */
              q = v;
-             while (*q != 0 && *q != ' ' && *q != '.')
+             while (isdigit (*q))
                q++;
-             /* Empty string means zero.  */
-             if (v == q)
-               {
-                 v = "0";
-                 q = v + 1;
-               }
+             if (*q != 0 && *q != ' ' && *q != '.' && *q != '-')
+               abort ();
+
              /* Put that part into the command.  */
              obstack_grow (&obstack, v, q - v);
              arg_going = 1;
@@ -4009,7 +3853,7 @@ check_live_switch (switchnum, prefix_length)
     case 'W':  case 'f':  case 'm':
       if (! strncmp (name + 1, "no-", 3))
        {
-         /* We have Xno-YYY, search for XYYY. */
+         /* We have Xno-YYY, search for XYYY.  */
          for (i = switchnum + 1; i < n_switches; i++)
            if (switches[i].part1[0] == name[0]
                && ! strcmp (&switches[i].part1[1], &name[4]))
@@ -4201,6 +4045,43 @@ main (argc, argv)
 
   obstack_init (&obstack);
 
+  /* Build multilib_select, et. al from the separate lines that make up each
+     multilib selection.  */
+  {
+    char **q = multilib_raw;
+    int need_space;
+
+    obstack_init (&multilib_obstack);
+    while ((p = *q++) != (char *) 0)
+      obstack_grow (&multilib_obstack, p, strlen (p));
+
+    obstack_1grow (&multilib_obstack, 0);
+    multilib_select = obstack_finish (&multilib_obstack);
+
+    q = multilib_matches_raw;
+    while ((p = *q++) != (char *) 0)
+      obstack_grow (&multilib_obstack, p, strlen (p));
+
+    obstack_1grow (&multilib_obstack, 0);
+    multilib_matches = obstack_finish (&multilib_obstack);
+
+    need_space = FALSE;
+    for (i = 0;
+        i < sizeof (multilib_defaults_raw) / sizeof (multilib_defaults_raw[0]);
+        i++)
+      {
+       if (need_space)
+         obstack_1grow (&multilib_obstack, ' ');
+       obstack_grow (&multilib_obstack,
+                     multilib_defaults_raw[i],
+                     strlen (multilib_defaults_raw[i]));
+       need_space = TRUE;
+      }
+
+    obstack_1grow (&multilib_obstack, 0);
+    multilib_defaults = obstack_finish (&multilib_obstack);
+  }
+
   /* Set up to remember the pathname of gcc and any options
      needed for collect.  We use argv[0] instead of programname because
      we need the complete pathname.  */
@@ -4431,6 +4312,10 @@ main (argc, argv)
          register char *p;
          int len;
 
+         if (cp->spec[0][0] == '#')
+           error ("%s: %s compiler not installed on this system",
+                  input_filename, &cp->spec[0][1]);
+
          input_basename = input_filename;
          for (p = input_filename; *p; p++)
            if (*p == '/' || *p == DIR_SEPARATOR)
@@ -4660,7 +4545,7 @@ concat VPROTO((char *first, ...))
   char *first;
 #endif
 
-  /* First compute the size of the result and get sufficient memory. */
+  /* First compute the size of the result and get sufficient memory.  */
 
   VA_START (args, first);
 #ifndef __STDC__
@@ -4679,7 +4564,7 @@ concat VPROTO((char *first, ...))
   newstr = (char *) xmalloc (length + 1);
   va_end (args);
 
-  /* Now copy the individual pieces to the result string. */
+  /* Now copy the individual pieces to the result string.  */
 
   VA_START (args, first);
 #ifndef __STDC__
@@ -4727,11 +4612,19 @@ perror_with_name (name)
 }
 
 static void
-perror_exec (name)
-     char *name;
+pfatal_pexecute (errmsg_fmt, errmsg_arg)
+     char *errmsg_fmt;
+     char *errmsg_arg;
 {
-  error ("installation problem, cannot exec `%s': %s",
-        name, my_strerror (errno));
+  if (errmsg_arg)
+    {
+      /* Space for trailing '\0' is in %s.  */
+      char *msg = xmalloc (strlen (errmsg_fmt) + strlen (errmsg_arg));
+      sprintf (msg, errmsg_fmt, errmsg_arg);
+      errmsg_fmt = msg;
+    }
+
+  fatal ("%s: %s", errmsg_fmt, my_strerror (errno));
 }
 
 /* More 'friendly' abort that prints the line and file.
@@ -4758,7 +4651,7 @@ fatal VPROTO((char *format, ...))
   VA_START (ap, format);
 
 #ifndef __STDC__
-  format = va_arg (ap, char*);
+  format = va_arg (ap, char *);
 #endif
 
   fprintf (stderr, "%s: ", programname);
@@ -4780,7 +4673,7 @@ error VPROTO((char *format, ...))
   VA_START (ap, format);
 
 #ifndef __STDC__
-  format = va_arg (ap, char*);
+  format = va_arg (ap, char *);
 #endif
 
   fprintf (stderr, "%s: ", programname);
@@ -4974,43 +4867,114 @@ validate_switches (start)
     }
 }
 \f
-/* Check whether a particular argument was used.  */
+/* Check whether a particular argument was used.  The first time we
+   canonialize the switches to keep only the ones we care about.  */
 
 static int
 used_arg (p, len)
      char *p;
      int len;
 {
-  int i;
+  struct mswitchstr {
+    char *str;
+    char *replace;
+    int len;
+    int rep_len;
+  };
+
+  static struct mswitchstr *mswitches;
+  static int n_mswitches;
+  int i, j;
+
+  if (!mswitches)
+    {
+      struct mswitchstr *matches;
+      char *q;
+      int cnt = (*multilib_matches != '\0');
+
+      /* Break multilib_matches into the component strings of string and replacement
+         string */
+      for (p = multilib_matches; *p != '\0'; p++)
+       if (*p == ';')
+         cnt++;
+
+      matches = (struct mswitchstr *) alloca ((sizeof (struct mswitchstr)) * cnt);
+      i = 0;
+      q = multilib_matches;
+      while (*q != '\0')
+       {
+         matches[i].str = q;
+         while (*q != ' ')
+           {
+             if (*q == '\0')
+               abort ();
+             q++;
+           }
+         *q = '\0';
+         matches[i].len = q - matches[i].str;
 
-  for (i = 0; i < n_switches; i++)
-    if (! strncmp (switches[i].part1, p, len)
-       && strlen (switches[i].part1) == len)
-      return 1;
-  return 0;
-}
+         matches[i].replace = ++q;
+         while (*q != ';' && *q != '\0')
+           {
+             if (*q == ' ')
+               abort ();
+             q++;
+           }
+         matches[i].rep_len = q - matches[i].replace;
+         i++;
+         if (*q == ';')
+           *q++ = '\0';
+         else
+           break;
+       }
 
-/* Check whether a particular argument is a default argument.  */
+      /* Now build a list of the replacement string for switches that we care about */
+      mswitches = (struct mswitchstr *) xmalloc ((sizeof (struct mswitchstr)) * n_switches);
+      for (i = 0; i < n_switches; i++)
+       {
+         int xlen = strlen (switches[i].part1);
+         for (j = 0; j < cnt; j++)
+           if (xlen == matches[j].len && ! strcmp (switches[i].part1, matches[j].str))
+             {
+               mswitches[n_mswitches].str = matches[j].replace;
+               mswitches[n_mswitches].len = matches[j].rep_len;
+               mswitches[n_mswitches].replace = (char *)0;
+               mswitches[n_mswitches].rep_len = 0;
+               n_mswitches++;
+               break;
+             }
+       }
+    }
 
-#ifndef MULTILIB_DEFAULTS
-#define MULTILIB_DEFAULTS { NULL }
-#endif
+  for (i = 0; i < n_mswitches; i++)
+    if (len == mswitches[i].len && ! strncmp (p, mswitches[i].str, len))
+      return 1;
 
-static char *multilib_defaults[] = MULTILIB_DEFAULTS;
+  return 0;
+}
 
 static int
 default_arg (p, len)
      char *p;
      int len;
 {
-  int count = sizeof multilib_defaults / sizeof multilib_defaults[0];
+  char *start, *end;
   int i;
 
-  for (i = 0; i < count; i++)
-    if (multilib_defaults[i] != NULL
-       && strncmp (multilib_defaults[i], p, len) == 0
-       && multilib_defaults[i][len] == '\0')
-      return 1;
+  for (start = multilib_defaults; *start != '\0'; start = end+1)
+    {
+      while (*start == ' ' || *start == '\t')
+       start++;
+
+      if (*start == '\0')
+       break;
+
+      for (end = start+1; *end != ' ' && *end != '\t' && *end != '\0'; end++)
+       ;
+
+      if ((end - start) == len && strncmp (p, start, len) == 0)
+       return 1;
+    }
 
   return 0;
 }
@@ -5238,7 +5202,28 @@ print_multilib_info ()
        }
 
       if (! skip)
-       putchar ('\n');
+       {
+         /* If there are extra options, print them now */
+         if (multilib_extra && *multilib_extra)
+           {
+             int print_at = TRUE;
+             char *q;
+
+             for (q = multilib_extra; *q != '\0'; q++)
+               {
+                 if (*q == ' ')
+                   print_at = TRUE;
+                 else
+                   {
+                     if (print_at)
+                       putchar ('@');
+                     putchar (*q);
+                     print_at = FALSE;
+                   }
+               }
+           }
+         putchar ('\n');
+       }
 
       ++p;
     }