diff options
author | Kito Cheng <kito.cheng@sifive.com> | 2025-03-10 16:26:04 +0800 |
---|---|---|
committer | Kito Cheng <kito.cheng@sifive.com> | 2025-05-27 13:41:45 +0800 |
commit | 447156e4d143d7f513c488dd0b44037524a01fba (patch) | |
tree | 9a808d76d66b5655c2cce8b17353ac0dc92c01a5 | |
parent | a91679a3d9f7cbc079880f201fd8292c1d54baa7 (diff) | |
download | gcc-447156e4d143d7f513c488dd0b44037524a01fba.zip gcc-447156e4d143d7f513c488dd0b44037524a01fba.tar.gz gcc-447156e4d143d7f513c488dd0b44037524a01fba.tar.bz2 |
driver: Fix multilib_os_dir and multiarch_dir for those target use TARGET_COMPUTE_MULTILIB
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.
Changes since v1:
- Fix non-multilib build.
- Fix fix indentation.
gcc/ChangeLog:
* gcc.cc (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.
-rw-r--r-- | gcc/gcc.cc | 108 |
1 files changed, 107 insertions, 1 deletions
@@ -9747,6 +9747,103 @@ 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; + + /* 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 @@ -10025,7 +10122,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 |