gcc.c: Include multilib.h.
authorDoug Evans <dje@gnu.org>
Wed, 15 Jun 1994 08:04:07 +0000 (08:04 +0000)
committerDoug Evans <dje@gnu.org>
Wed, 15 Jun 1994 08:04:07 +0000 (08:04 +0000)
* gcc.c: Include multilib.h.
(print_multi_lib, print_multi_directory, multilib_select,
multilib_dir): New static variables.
(option_map): Added --print-multi-lib and --print-multi-directory.
(set_spec): Get multilib_select from specs file.
(process_command): Dump multilib_select into specs file.  Handle
-print-multi-lib and -print-multi-directory.
(do_spec_1): Try multilib_dir for %D case.
(find_file): Try multilib_dir.
(main): Call set_multilib_dir.  Handle print_multi_lib and
print_multi_directory.
(used_arg, set_multilib_dir, print_multilib_info): New functions.

From-SVN: r7491

gcc/gcc.c

index 56b99ed..00ffa38 100644 (file)
--- a/gcc/gcc.c
+++ b/gcc/gcc.c
@@ -45,6 +45,9 @@ compilation is specified by a string called a "spec".  */
 #endif
 #include <stdio.h>
 
+/* Include multi-lib information.  */
+#include "multilib.h"
+
 #ifndef R_OK
 #define R_OK 4
 #define W_OK 2
@@ -151,6 +154,16 @@ static char *print_file_name = NULL;
 
 static 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;
+
+/* 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 indicating whether we should print the command and arguments */
 
 static int verbose_flag;
@@ -224,6 +237,9 @@ static int is_directory             PROTO((char *, char *, int));
 static void validate_switches  PROTO((char *));
 static void validate_all_switches PROTO((void));
 static void give_switch                PROTO((int, int));
+static int used_arg            PROTO((char *, int));
+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 *));
@@ -304,6 +320,7 @@ or with constant text in a single argument.
        used here.  This can be used to run a post-processor after the
        assembler has done it's job.
  %D    Dump out a -L option for each directory in startfile_prefix.
+       If multilib_dir is set, extra entries are generated with it affixed.
  %l     process LINK_SPEC as a spec.
  %L     process LIB_SPEC as a spec.
  %S     process STARTFILE_SPEC as a spec.  A capital S is actually used here.
@@ -433,6 +450,13 @@ 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;
@@ -445,6 +469,7 @@ static char *lib_spec = LIB_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;
 
 /* This defines which switch letters take arguments.  */
 
@@ -789,6 +814,8 @@ struct option_map option_map[] =
    {"--print-libgcc-file-name", "-print-libgcc-file-name", 0},
    {"--print-file-name", "-print-file-name=", "aj"},
    {"--print-prog-name", "-print-prog-name=", "aj"},
+   {"--print-multi-lib", "-print-multi-lib", 0},
+   {"--print-multi-directory", "-print-multi-directory", 0},
    {"--static", "-static", 0},
    {"--shared", "-shared", 0},
    {"--symbolic", "-symbolic", 0},
@@ -1144,6 +1171,8 @@ set_spec (name, spec)
     switches_need_spaces = sl->spec;
   else if (! strcmp (name, "cross_compile"))
     cross_compile = atoi (sl->spec);
+  else if (! strcmp (name, "multilib"))
+    multilib_select = sl->spec;
   /* Free the old spec */
   if (old_spec)
     free (old_spec);
@@ -1269,6 +1298,11 @@ static char *standard_startfile_prefix_2 = "/usr/lib/";
 static char *tooldir_base_prefix = TOOLDIR_BASE_PREFIX;
 static char *tooldir_prefix;
 
+/* Subdirectory to use for locating libraries.  Set by
+   set_multilib_dir based on the compilation options.  */
+
+static char *multilib_dir;
+
 /* Clear out the vector of arguments (after a command is executed).  */
 
 static void
@@ -2340,6 +2374,7 @@ process_command (argc, argv)
          printf ("*signed_char:\n%s\n\n", signed_char_spec);
          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);
 
          exit (0);
        }
@@ -2354,6 +2389,10 @@ process_command (argc, argv)
          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], "-Xlinker"))
        {
          /* Pass the argument of this option to the linker when we link.  */
@@ -2597,6 +2636,10 @@ process_command (argc, argv)
        ;
       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 (argv[i][0] == '+' && argv[i][1] == 'e')
        {
          /* Compensate for the +e options to the C++ front-end;
@@ -2941,6 +2984,45 @@ do_spec_1 (spec, inswitch, soft_matched_part)
                  if (pl->prefix[0] != '/')
                    continue;
 #endif
+                 /* Try subdirectory if there is one.  */
+                 if (multilib_dir != NULL)
+                   {
+                     if (machine_suffix)
+                       {
+                         if (strlen (pl->prefix) + strlen (machine_suffix)
+                             >= bufsize)
+                           bufsize = (strlen (pl->prefix)
+                                      + strlen (machine_suffix)) * 2 + 1;
+                         buffer = (char *) xrealloc (buffer, bufsize);
+                         strcpy (buffer, pl->prefix);
+                         strcat (buffer, machine_suffix);
+                         if (is_directory (buffer, multilib_dir, 1))
+                           {
+                             do_spec_1 ("-L", 0, NULL_PTR);
+#ifdef SPACE_AFTER_L_OPTION
+                             do_spec_1 (" ", 0, NULL_PTR);
+#endif
+                             do_spec_1 (buffer, 1, NULL_PTR);
+                             do_spec_1 (multilib_dir, 1, NULL_PTR);
+                             /* Make this a separate argument.  */
+                             do_spec_1 (" ", 0, NULL_PTR);
+                           }
+                       }
+                     if (!pl->require_machine_suffix)
+                       {
+                         if (is_directory (pl->prefix, multilib_dir, 1))
+                           {
+                             do_spec_1 ("-L", 0, NULL_PTR);
+#ifdef SPACE_AFTER_L_OPTION
+                             do_spec_1 (" ", 0, NULL_PTR);
+#endif
+                             do_spec_1 (pl->prefix, 1, NULL_PTR);
+                             do_spec_1 (multilib_dir, 1, NULL_PTR);
+                             /* Make this a separate argument.  */
+                             do_spec_1 (" ", 0, NULL_PTR);
+                           }
+                       }
+                   }
                  if (machine_suffix)
                    {
                      if (is_directory (pl->prefix, machine_suffix, 1))
@@ -3836,6 +3918,24 @@ find_file (name)
 {
   char *newname;
 
+  /* Try multilib_dir if it is defined.  */
+  if (multilib_dir != NULL)
+    {
+      char *try;
+
+      try = (char *) alloca (strlen (multilib_dir) + strlen (name) + 2);
+      strcpy (try, multilib_dir);
+      strcat (try, "/");
+      strcat (try, name);
+
+      newname = find_a_file (&startfile_prefix, try, R_OK);
+
+      /* If we don't find it in the multi library dir, then fall
+        through and look for it in the normal places.  */
+      if (newname != NULL)
+       return newname;
+    }
+
   newname = find_a_file (&startfile_prefix, name, R_OK);
   return newname ? newname : name;
 }
@@ -4022,6 +4122,10 @@ main (argc, argv)
 
   validate_all_switches ();
 
+  /* Now that we have the switches and the specs, set
+     the subdirectory based on the options.  */
+  set_multilib_dir ();
+
   /* Warn about any switches that no pass was interested in.  */
 
   for (i = 0; i < n_switches; i++)
@@ -4043,6 +4147,21 @@ main (argc, argv)
       exit (0);
     }
 
+  if (print_multi_lib)
+    {
+      print_multilib_info ();
+      exit (0);
+    }
+
+  if (print_multi_directory)
+    {
+      if (multilib_dir == NULL)
+       printf (".\n");
+      else
+       printf ("%s\n", multilib_dir);
+      exit (0);
+    }
+
   if (verbose_flag)
     {
       fprintf (stderr, "gcc version %s\n", version_string);
@@ -4585,3 +4704,190 @@ validate_switches (start)
        }
     }
 }
+\f
+/* Check whether a particular argument was used.  */
+
+static int
+used_arg (p, len)
+     char *p;
+     int len;
+{
+  int i;
+
+  for (i = 0; i < n_switches; i++)
+    if (! strncmp (switches[i].part1, p, len)
+       && strlen (switches[i].part1) == len)
+      return 1;
+  return 0;
+}
+
+/* Work out the subdirectory to use based on the
+   options.  The format of multilib_select is a list of elements.
+   Each element is a subdirectory name followed by a list of options
+   followed by a semicolon.  gcc will consider each line in turn.  If
+   none of the options beginning with an exclamation point are
+   present, and all of the other options are present, that
+   subdirectory will be used.  */
+
+static void
+set_multilib_dir ()
+{
+  char *p = multilib_select;
+  int this_path_len;
+  char *this_path, *this_arg;
+  int failed;
+
+  while (*p != '\0')
+    {
+      /* Ignore newlines.  */
+      if (*p == '\n')
+       {
+         ++p;
+         continue;
+       }
+
+      /* Get the initial path.  */
+      this_path = p;
+      while (*p != ' ')
+       {
+         if (*p == '\0')
+           abort ();
+         ++p;
+       }
+      this_path_len = p - this_path;
+
+      /* Check the arguments.  */
+      failed = 0;
+      ++p;
+      while (*p != ';')
+       {
+         if (*p == '\0')
+           abort ();
+
+         if (failed)
+           {
+             ++p;
+             continue;
+           }
+
+         this_arg = p;
+         while (*p != ' ' && *p != ';')
+           {
+             if (*p == '\0')
+               abort ();
+             ++p;
+           }
+
+         if (*this_arg == '!')
+           failed = used_arg (this_arg + 1, p - (this_arg + 1));
+         else
+           failed = ! used_arg (this_arg, p - this_arg);
+
+         if (*p == ' ')
+           ++p;
+       }
+
+      if (! failed)
+       {
+         if (this_path_len != 1
+             || this_path[0] != '.')
+           {
+             multilib_dir = xmalloc (this_path_len + 1);
+             strncpy (multilib_dir, this_path, this_path_len);
+             multilib_dir[this_path_len] = '\0';
+           }
+         break;
+       }
+
+      ++p;
+    }      
+}
+
+/* Print out the multiple library subdirectory selection
+   information.  This prints out a series of lines.  Each line looks
+   like SUBDIRECTORY;@OPTION@OPTION, with as many options as is
+   required.  Only the desired options are printed out, the negative
+   matches.  The options are print without a leading dash.  There are
+   no spaces to make it easy to use the information in the shell.
+   Each subdirectory is printed only once.  This assumes the ordering
+   generated by the genmultilib script.  */
+
+static void
+print_multilib_info ()
+{
+  char *p = multilib_select;
+  char *last_path, *this_path;
+  int last_path_len, skip, use_arg;
+
+  while (*p != '\0')
+    {
+      /* Ignore newlines.  */
+      if (*p == '\n')
+       {
+         ++p;
+         continue;
+       }
+
+      /* Get the initial path.  */
+      this_path = p;
+      while (*p != ' ')
+       {
+         if (*p == '\0')
+           abort ();
+         ++p;
+       }
+
+      /* If this is a duplicate, skip it.  */
+      skip = (p - this_path == last_path_len
+             && ! strncmp (last_path, this_path, last_path_len));
+
+      last_path = this_path;
+      last_path_len = p - this_path;
+
+      if (! skip)
+       {
+         char *p1;
+
+         for (p1 = last_path; p1 < p; p1++)
+           putchar (*p1);
+         putchar (';');
+       }
+
+      ++p;
+      while (*p != ';')
+       {
+         int use_arg;
+
+         if (*p == '\0')
+           abort ();
+
+         if (skip)
+           {
+             ++p;
+             continue;
+           }
+
+         use_arg = *p != '!';
+
+         if (use_arg)
+           putchar ('@');
+
+         while (*p != ' ' && *p != ';')
+           {
+             if (*p == '\0')
+               abort ();
+             if (use_arg)
+               putchar (*p);
+             ++p;
+           }
+
+         if (*p == ' ')
+           ++p;
+       }
+
+      if (! skip)
+       putchar ('\n');
+
+      ++p;
+    }
+}