Speed up genmultilib; Add MULTIB_EXTRA_OPTS
[gcc.git] / gcc / gcc.c
index cb0ede84611300b2b3ac0649f86758561456533c..46ca22bc5434dd33408f014cbae249629f2a5b6d 100644 (file)
--- a/gcc/gcc.c
+++ b/gcc/gcc.c
@@ -491,12 +491,21 @@ static char *startfile_spec = STARTFILE_SPEC;
 static char *switches_need_spaces = SWITCHES_NEED_SPACES;
 
 /* Some compilers have limits on line lengths, and the multilib_select
-   string can be very long, so we build it at run time.  */
+   and/or multilib_matches strings can be very long, so we build them at
+   run time.  */
 static struct obstack multilib_obstack;
-static char *multilib_raw[] = {
-#include "multilib.h"
-};
 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 };
@@ -564,7 +573,8 @@ static struct compiler default_compilers[] =
      linking is not done".  */
   {".cc", "#C++"}, {".cxx", "#C++"}, {".cpp", "#C++"}, {".c++", "#C++"},
   {".C", "#C++"}, {".ads", "#Ada"}, {".adb", "#Ada"}, {".ada", "#Ada"},
-  {".f", "#Fortran"},
+  {".f", "#Fortran"}, {".for", "#Fortran"}, {".F", "#Fortran"},
+  {".fpp", "#Fortran"},
   /* Next come the entries for C.  */
   {".c", "@c"},
   {"@c",
@@ -1222,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
     {
@@ -2243,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
          {
@@ -4026,10 +4045,11 @@ main (argc, argv)
 
   obstack_init (&obstack);
 
-  /* Build multilib_select from the separate lines that make up each multilib
-     selection.  */
+  /* 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)
@@ -4037,6 +4057,29 @@ main (argc, argv)
 
     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
@@ -4824,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;
 }
@@ -5088,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;
     }