This patch fixes the multilib_os_dir and multiarch_dir for those targets
that use TARGET_COMPUTE_MULTILIB, since the TARGET_COMPUTE_MULTILIB hook
only update/fix the multilib_dir but not the multilib_os_dir and multiarch_dir,
so the multilib_os_dir and multiarch_dir are not set correctly for those 
targets.

Use RISC-V linux target (riscv64-unknown-linux-gnu) as an example:

```
$ riscv64-unknown-linux-gnu-gcc -print-multi-lib
.;
lib32/ilp32;@march=rv32imac@mabi=ilp32
lib32/ilp32d;@march=rv32imafdc@mabi=ilp32d
lib64/lp64;@march=rv64imac@mabi=lp64
lib64/lp64d;@march=rv64imafdc@mabi=lp64d
```

If we use the exactly same -march and -mabi options to compile a source file,
the multilib_os_dir and multiarch_dir are set correctly:

```
$ riscv64-unknown-linux-gnu-gcc -print-multi-os-directory -march=rv64imafdc 
-mabi=lp64d
../lib64/lp64d
$ riscv64-unknown-linux-gnu-gcc -print-multi-directory -march=rv64imafdc 
-mabi=lp64d
lib64/lp64d
```

However if we use the -march=rv64imafdcv -mabi=lp64d option to compile a source
file, the multilib_os_dir and multiarch_dir are not set correctly:
```
$ riscv64-unknown-linux-gnu-gcc -print-multi-os-directory -march=rv64imafdc 
-mabi=lp64d
lib64/lp64d
$ riscv64-unknown-linux-gnu-gcc -print-multi-directory -march=rv64imafdc 
-mabi=lp64d
lib64/lp64d
```

That's because the TARGET_COMPUTE_MULTILIB hook only update/fix the multilib_dir
but not the multilib_os_dir, so the multilib_os_dir is blank and will use same
value as multilib_dir, but that is not correct.

So we introduce second chance to fix the multilib_os_dir if it's not set, we do
also try to fix the multiarch_dir, because it may also not set correctly if
multilib_os_dir is not set.

gcc/ChangeLog:

        * gcc.c (find_multilib_os_dir_by_multilib_dir): New.
        (set_multilib_dir): Fix multilib_os_dir and multiarch_dir
        if multilib_os_dir is not set.
---
 gcc/gcc.cc | 109 ++++++++++++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 108 insertions(+), 1 deletion(-)

diff --git a/gcc/gcc.cc b/gcc/gcc.cc
index 04b3736a5da..6d447683b13 100644
--- a/gcc/gcc.cc
+++ b/gcc/gcc.cc
@@ -9736,6 +9736,104 @@ default_arg (const char *p, int len)
   return 0;
 }
 
+/* Use multilib_dir as key to find corresponding multilib_os_dir and
+   multiarch_dir.  */
+
+static void
+find_multilib_os_dir_by_multilib_dir (const char *multilib_dir,
+                                     const char **p_multilib_os_dir,
+                                     const char **p_multiarch_dir)
+{
+  const char *p = multilib_select;
+  unsigned int this_path_len;
+  const char *this_path;
+  int ok = 0;
+
+  while (*p != '\0')
+    {
+      /* Ignore newlines.  */
+      if (*p == '\n')
+       {
+         ++p;
+         continue;
+       }
+
+      /* Get the initial path.  */
+      this_path = p;
+      while (*p != ' ')
+       {
+         if (*p == '\0')
+           {
+             fatal_error (input_location, "multilib select %qs %qs is invalid",
+                          multilib_select, multilib_reuse);
+           }
+         ++p;
+       }
+      this_path_len = p - this_path;
+
+      ok = 0;
+      ++p;
+
+      /* Skip any arguments, we don't care at this stage.  */
+      while (*++p != ';');
+
+      if (this_path_len != 1
+         || this_path[0] != '.')
+       {
+         char *new_multilib_dir = XNEWVEC (char, this_path_len + 1);
+         char *q;
+
+         strncpy (new_multilib_dir, this_path, this_path_len);
+         new_multilib_dir[this_path_len] = '\0';
+         q = strchr (new_multilib_dir, ':');
+         if (q != NULL)
+           *q = '\0';
+
+         if (strcmp (new_multilib_dir, multilib_dir) == 0)
+           ok = 1;
+       }
+
+      /* Found matched multilib_dir, update multilib_os_dir and
+        multiarch_dir.  */
+      if (ok)
+       {
+         const char *q = this_path, *end = this_path + this_path_len;
+
+         while (q < end && *q != ':')
+           q++;
+         if (q < end)
+           {
+             const char *q2 = q + 1, *ml_end = end;
+             char *new_multilib_os_dir;
+
+             while (q2 < end && *q2 != ':')
+               q2++;
+             if (*q2 == ':')
+               ml_end = q2;
+             if (ml_end - q == 1)
+               *p_multilib_os_dir = xstrdup (".");
+             else
+               {
+                 new_multilib_os_dir = XNEWVEC (char, ml_end - q);
+                 memcpy (new_multilib_os_dir, q + 1, ml_end - q - 1);
+                 new_multilib_os_dir[ml_end - q - 1] = '\0';
+                 *p_multilib_os_dir = new_multilib_os_dir;
+               }
+
+             if (q2 < end && *q2 == ':')
+               {
+                 char *new_multiarch_dir = XNEWVEC (char, end - q2);
+                 memcpy (new_multiarch_dir, q2 + 1, end - q2 - 1);
+                 new_multiarch_dir[end - q2 - 1] = '\0';
+                 *p_multiarch_dir = new_multiarch_dir;
+               }
+             break;
+           }
+       }
+      ++p;
+    }
+}
+
 /* 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. The format
@@ -10014,7 +10112,16 @@ set_multilib_dir (void)
       multilib_os_dir = NULL;
     }
   else if (multilib_dir != NULL && multilib_os_dir == NULL)
-    multilib_os_dir = multilib_dir;
+    {
+      /* Give second chance to search matched multilib_os_dir again by matching
+        the multilib_dir since some target may use TARGET_COMPUTE_MULTILIB
+        hook rather than the builtin way.  */
+     find_multilib_os_dir_by_multilib_dir (multilib_dir, &multilib_os_dir,
+                                          &multiarch_dir);
+
+      if (multilib_os_dir == NULL)
+       multilib_os_dir = multilib_dir;
+    }
 }
 
 /* Print out the multiple library subdirectory selection
-- 
2.34.1

Reply via email to