diff --git a/clang/lib/Driver/Driver.cpp b/clang/lib/Driver/Driver.cpp --- a/clang/lib/Driver/Driver.cpp +++ b/clang/lib/Driver/Driver.cpp @@ -489,15 +489,15 @@ /// /// This routine provides the logic to compute a target triple from various /// args passed to the driver and the default triple string. -static llvm::Triple computeTargetTriple(const Driver &D, - StringRef TargetTriple, - const ArgList &Args, - StringRef DarwinArchName = "") { +static llvm::Triple computeTargetTriple( + const Driver &D, StringRef TargetTriple, const ArgList &Args, + llvm::Triple *UnnormalizedTriple = nullptr, StringRef DarwinArchName = "") { // FIXME: Already done in Compilation *Driver::BuildCompilation if (const Arg *A = Args.getLastArg(options::OPT_target)) TargetTriple = A->getValue(); llvm::Triple Target(llvm::Triple::normalize(TargetTriple)); + llvm::Triple Unnormalized(TargetTriple); // GNU/Hurd's triples should have been -hurd-gnu*, but were historically made // -gnu* only, and we can not change this, so we have to detect that case as @@ -560,6 +560,14 @@ } } + // llvm-project's runtime libraries support a small subset of GCC multilib + // combinations, currently just -m32/-m64. Transform the unnormalized triple + // to construct include and library paths. + auto SetArch = [&](llvm::Triple::ArchType Type) { + Target.setArch(Type); + Unnormalized.setArch(Type); + }; + // Handle pseudo-target flags '-m64', '-mx32', '-m32' and '-m16'. Arg *A = Args.getLastArg(options::OPT_m64, options::OPT_mx32, options::OPT_m32, options::OPT_m16); @@ -592,7 +600,7 @@ } if (AT != llvm::Triple::UnknownArch && AT != Target.getArch()) { - Target.setArch(AT); + SetArch(AT); if (Target.isWindowsGNUEnvironment()) toolchains::MinGW::fixTripleArch(D, Target, Args); } @@ -651,6 +659,9 @@ Target.setArch(llvm::Triple::riscv64); } + if (UnnormalizedTriple) + *UnnormalizedTriple = Unnormalized; + return Target; } @@ -1247,9 +1258,18 @@ // Perform the default argument translations. DerivedArgList *TranslatedArgs = TranslateInputArgs(*UArgs); + // Unnormalized is --target= or LLVM_DEFAULT_TARGET_TRIPLE, with a small set + // of Clang specific multilib transformation. + llvm::Triple Unnormalized; + const llvm::Triple Normalized = + computeTargetTriple(*this, TargetTriple, *UArgs, &Unnormalized); + // Fuchsia prefers to use normalized triples. + if (Normalized.isOSFuchsia()) + TargetTriple = Normalized.str(); + else + TargetTriple = Unnormalized.str(); // Owned by the host. - const ToolChain &TC = getToolChain( - *UArgs, computeTargetTriple(*this, TargetTriple, *UArgs)); + const ToolChain &TC = getToolChain(*UArgs, Normalized); // The compilation takes ownership of Args. Compilation *C = new Compilation(*this, TC, UArgs.release(), TranslatedArgs, @@ -4856,8 +4876,8 @@ if (!ArchName.empty()) TC = &getToolChain(C.getArgs(), - computeTargetTriple(*this, TargetTriple, - C.getArgs(), ArchName)); + computeTargetTriple(*this, TargetTriple, C.getArgs(), + nullptr, ArchName)); else TC = &C.getDefaultToolChain(); diff --git a/clang/lib/Driver/ToolChain.cpp b/clang/lib/Driver/ToolChain.cpp --- a/clang/lib/Driver/ToolChain.cpp +++ b/clang/lib/Driver/ToolChain.cpp @@ -498,13 +498,20 @@ ToolChain::path_list ToolChain::getRuntimePaths() const { path_list Paths; - auto addPathForTriple = [this, &Paths](const llvm::Triple &Triple) { + auto addPathForTriple = [this, &Paths](const std::string &TripleStr) { SmallString<128> P(D.ResourceDir); - llvm::sys::path::append(P, "lib", Triple.str()); + llvm::sys::path::append(P, "lib", TripleStr); Paths.push_back(std::string(P.str())); }; - addPathForTriple(getTriple()); + // Prefer unnormalized D.getTargetTriple() (from --target= or + // LLVM_DEFAULT_TARGET_TRIPLE, with a small set of Clang specific multilib + // transformation). + addPathForTriple(D.getTargetTriple()); + // Add the normalized triple as fallback. This is a hack for + // --target=x86_64-linux-gnu to pick up the x86_64-unknown-linux-gnu runtime + // path. TODO remove the hack when the user migrates away. + addPathForTriple(Triple.str()); // Android targets may include an API level at the end. We still want to fall // back on a path without the API level. @@ -512,7 +519,7 @@ getTriple().getEnvironmentName() != "android") { llvm::Triple TripleWithoutLevel = getTriple(); TripleWithoutLevel.setEnvironmentName("android"); - addPathForTriple(TripleWithoutLevel); + addPathForTriple(TripleWithoutLevel.str()); } return Paths; @@ -521,9 +528,14 @@ ToolChain::path_list ToolChain::getStdlibPaths() const { path_list Paths; SmallString<128> P(D.Dir); - llvm::sys::path::append(P, "..", "lib", getTripleString()); + llvm::sys::path::append(P, "..", "lib", D.getTargetTriple()); Paths.push_back(std::string(P.str())); + // Add the normalized triple as fallback. TODO remove the hack. + P = D.Dir; + llvm::sys::path::append(P, "..", "lib", Triple.str()); + Paths.push_back(std::string(P)); + return Paths; } diff --git a/clang/lib/Driver/ToolChains/Gnu.cpp b/clang/lib/Driver/ToolChains/Gnu.cpp --- a/clang/lib/Driver/ToolChains/Gnu.cpp +++ b/clang/lib/Driver/ToolChains/Gnu.cpp @@ -2904,10 +2904,18 @@ return false; // First add the per-target include path if it exists. - std::string TargetDir = Path + "/" + Target + "/c++/" + Version; + std::string TargetDir = + Path + "/" + D.getTargetTriple() + "/c++/" + Version; if (D.getVFS().exists(TargetDir)) addSystemInclude(DriverArgs, CC1Args, TargetDir); + // Add the normalized triple as fallback. TODO remove the hack. + if (D.getTargetTriple() != Target) { + std::string NormalizedTargetDir = Path + "/" + Target + "/c++/" + Version; + if (D.getVFS().exists(NormalizedTargetDir)) + addSystemInclude(DriverArgs, CC1Args, NormalizedTargetDir); + } + // Second add the generic one. addSystemInclude(DriverArgs, CC1Args, Path + "/c++/" + Version); return true; diff --git a/clang/test/Driver/Inputs/debian_per_target_tree/usr/lib/llvm-14/lib/x86_64-linux-gnu/.keep b/clang/test/Driver/Inputs/debian_per_target_tree/usr/lib/llvm-14/lib/x86_64-linux-gnu/.keep new file mode 100644 diff --git a/clang/test/Driver/Inputs/debian_per_target_unknown_tree/usr/lib/llvm-14/bin/.keep b/clang/test/Driver/Inputs/debian_per_target_unknown_tree/usr/lib/llvm-14/bin/.keep new file mode 100644 diff --git a/clang/test/Driver/Inputs/debian_per_target_unknown_tree/usr/lib/llvm-14/include/c++/v1/.keep b/clang/test/Driver/Inputs/debian_per_target_unknown_tree/usr/lib/llvm-14/include/c++/v1/.keep new file mode 100644 diff --git a/clang/test/Driver/Inputs/debian_per_target_unknown_tree/usr/lib/llvm-14/include/i386-unknown-linux-gnu/c++/v1/.keep b/clang/test/Driver/Inputs/debian_per_target_unknown_tree/usr/lib/llvm-14/include/i386-unknown-linux-gnu/c++/v1/.keep new file mode 100644 diff --git a/clang/test/Driver/Inputs/debian_per_target_unknown_tree/usr/lib/llvm-14/include/x86_64-unknown-linux-gnu/c++/v1/.keep b/clang/test/Driver/Inputs/debian_per_target_unknown_tree/usr/lib/llvm-14/include/x86_64-unknown-linux-gnu/c++/v1/.keep new file mode 100644 diff --git a/clang/test/Driver/Inputs/debian_per_target_unknown_tree/usr/lib/llvm-14/lib/clang/14.0.0/lib/i386-unknown-linux-gnu/libclang_rt.builtins.a b/clang/test/Driver/Inputs/debian_per_target_unknown_tree/usr/lib/llvm-14/lib/clang/14.0.0/lib/i386-unknown-linux-gnu/libclang_rt.builtins.a new file mode 100644 diff --git a/clang/test/Driver/Inputs/debian_per_target_unknown_tree/usr/lib/llvm-14/lib/clang/14.0.0/lib/x86_64-unknown-linux-gnu/libclang_rt.builtins.a b/clang/test/Driver/Inputs/debian_per_target_unknown_tree/usr/lib/llvm-14/lib/clang/14.0.0/lib/x86_64-unknown-linux-gnu/libclang_rt.builtins.a new file mode 100644 diff --git a/clang/test/Driver/Inputs/debian_per_target_unknown_tree/usr/lib/llvm-14/lib/i386-unknown-linux-gnu/.keep b/clang/test/Driver/Inputs/debian_per_target_unknown_tree/usr/lib/llvm-14/lib/i386-unknown-linux-gnu/.keep new file mode 100644 diff --git a/clang/test/Driver/Inputs/debian_per_target_unknown_tree/usr/lib/llvm-14/lib/x86_64-unknown-linux-gnu/.keep b/clang/test/Driver/Inputs/debian_per_target_unknown_tree/usr/lib/llvm-14/lib/x86_64-unknown-linux-gnu/.keep new file mode 100644 diff --git a/clang/test/Driver/linux-cross.cpp b/clang/test/Driver/linux-cross.cpp --- a/clang/test/Driver/linux-cross.cpp +++ b/clang/test/Driver/linux-cross.cpp @@ -152,19 +152,20 @@ // DEBIAN_AARCH64-SAME: {{^}} "-L[[SYSROOT]]/usr/lib" /// Test native x86-64 with -DLLVM_ENABLE_PER_TARGET_RUNTIME_DIR=on. -/// FIXME -internal-isystem .*bin/../include/x86_64-linux-gnu/c++/v1 and -L[[PREFIX]]/bin/../lib/x86_64-linux-gnu are missing. // RUN: %clang -### %s --target=x86_64-linux-gnu --sysroot=%S/Inputs/debian_multiarch_tree \ // RUN: -ccc-install-dir %S/Inputs/debian_per_target_tree/usr/lib/llvm-14/bin -resource-dir=%S/Inputs/debian_per_target_tree/usr/lib/llvm-14/lib/clang/14.0.0 \ // RUN: --stdlib=libc++ --rtlib=compiler-rt 2>&1 | FileCheck %s --check-prefix=DEBIAN_X86_64_PER_TARGET // DEBIAN_X86_64_PER_TARGET: "-resource-dir" "[[RESOURCE:[^"]+]]" // DEBIAN_X86_64_PER_TARGET: "-internal-isystem" -// DEBIAN_X86_64_PER_TARGET-SAME: {{^}} "[[PREFIX:[^"]+llvm-14]]/bin/../include/c++/v1" +// DEBIAN_X86_64_PER_TARGET-SAME: {{^}} "[[PREFIX:[^"]+llvm-14]]/bin/../include/x86_64-linux-gnu/c++/v1" +// DEBIAN_X86_64_PER_TARGET-SAME: {{^}} "-internal-isystem" "[[PREFIX]]/bin/../include/c++/v1" // DEBIAN_X86_64_PER_TARGET-SAME: {{^}} "-internal-isystem" "[[RESOURCE]]/include" // DEBIAN_X86_64_PER_TARGET-SAME: {{^}} "-internal-isystem" "[[SYSROOT:[^"]+]]/usr/local/include" // DEBIAN_X86_64_PER_TARGET-SAME: {{^}} "-internal-isystem" "[[SYSROOT]]/usr/lib/gcc/x86_64-linux-gnu/10/../../../../x86_64-linux-gnu/include" // DEBIAN_X86_64_PER_TARGET: "-L -// DEBIAN_X86_64_PER_TARGET-SAME: {{^}}[[SYSROOT]]/usr/lib/gcc/x86_64-linux-gnu/10" +// DEBIAN_X86_64_PER_TARGET-SAME: {{^}}[[PREFIX]]/bin/../lib/x86_64-linux-gnu" +// DEBIAN_X86_64_PER_TARGET-SAME: {{^}} "-L[[SYSROOT]]/usr/lib/gcc/x86_64-linux-gnu/10" /// Debian patches MULTILIB_OSDIRNAMES (../lib64 -> ../lib), so gcc uses 'lib' instead of 'lib64'. /// This difference does not matter in practice. // DEBIAN_X86_64_PER_TARGET-SAME: {{^}} "-L[[SYSROOT]]/usr/lib/gcc/x86_64-linux-gnu/10/../../../../lib64" @@ -177,21 +178,53 @@ /// $sysroot/lib and $sysroot/usr/lib. Fallback when GCC installation is unavailable. // DEBIAN_X86_64_PER_TARGET-SAME: {{^}} "-L[[SYSROOT]]/lib" // DEBIAN_X86_64_PER_TARGET-SAME: {{^}} "-L[[SYSROOT]]/usr/lib" +// DEBIAN_X86_64_PER_TARGET-SAME: "[[RESOURCE]]/lib/x86_64-linux-gnu/libclang_rt.builtins.a" + +/// A variant of the above where the hierarchy uses x86_64-unknown-linux-gnu where --target= is unnormalized. +/// This is a hack for --target=x86_64-linux-gnu to pick up the x86_64-unknown-linux-gnu include/library path. +// RUN: %clang -### %s --target=x86_64-linux-gnu --sysroot=%S/Inputs/debian_multiarch_tree \ +// RUN: -ccc-install-dir %S/Inputs/debian_per_target_unknown_tree/usr/lib/llvm-14/bin -resource-dir=%S/Inputs/debian_per_target_unknown_tree/usr/lib/llvm-14/lib/clang/14.0.0 \ +// RUN: --stdlib=libc++ --rtlib=compiler-rt 2>&1 | FileCheck %s --check-prefix=DEBIAN_X86_64_PER_TARGET_UNKNOWN +// DEBIAN_X86_64_PER_TARGET_UNKNOWN: "-resource-dir" "[[RESOURCE:[^"]+]]" +// DEBIAN_X86_64_PER_TARGET_UNKNOWN: "-internal-isystem" +// DEBIAN_X86_64_PER_TARGET_UNKNOWN-SAME: {{^}} "[[PREFIX:[^"]+llvm-14]]/bin/../include/x86_64-unknown-linux-gnu/c++/v1" +// DEBIAN_X86_64_PER_TARGET_UNKNOWN-SAME: {{^}} "-internal-isystem" "[[PREFIX]]/bin/../include/c++/v1" +// DEBIAN_X86_64_PER_TARGET_UNKNOWN-SAME: {{^}} "-internal-isystem" "[[RESOURCE]]/include" +// DEBIAN_X86_64_PER_TARGET_UNKNOWN-SAME: {{^}} "-internal-isystem" "[[SYSROOT:[^"]+]]/usr/local/include" +// DEBIAN_X86_64_PER_TARGET_UNKNOWN-SAME: {{^}} "-internal-isystem" "[[SYSROOT]]/usr/lib/gcc/x86_64-linux-gnu/10/../../../../x86_64-linux-gnu/include" + +// DEBIAN_X86_64_PER_TARGET_UNKNOWN: "-L +// DEBIAN_X86_64_PER_TARGET_UNKNOWN-SAME: {{^}}[[PREFIX]]/bin/../lib/x86_64-unknown-linux-gnu" +// DEBIAN_X86_64_PER_TARGET_UNKNOWN-SAME: {{^}} "-L[[SYSROOT]]/usr/lib/gcc/x86_64-linux-gnu/10" +/// Debian patches MULTILIB_OSDIRNAMES (../lib64 -> ../lib), so gcc uses 'lib' instead of 'lib64'. +/// This difference does not matter in practice. +// DEBIAN_X86_64_PER_TARGET_UNKNOWN-SAME: {{^}} "-L[[SYSROOT]]/usr/lib/gcc/x86_64-linux-gnu/10/../../../../lib64" +// DEBIAN_X86_64_PER_TARGET_UNKNOWN-SAME: {{^}} "-L[[SYSROOT]]/lib/x86_64-linux-gnu" +// DEBIAN_X86_64_PER_TARGET_UNKNOWN-SAME: {{^}} "-L[[SYSROOT]]/lib/../lib64" +// DEBIAN_X86_64_PER_TARGET_UNKNOWN-SAME: {{^}} "-L[[SYSROOT]]/usr/lib/x86_64-linux-gnu" +// DEBIAN_X86_64_PER_TARGET_UNKNOWN-SAME: {{^}} "-L[[SYSROOT]]/usr/lib/../lib64" +/// /usr/x86_64-linux-gnu does not exist, so there is no /usr/lib/gcc/x86_64-linux-gnu/10/../../../../x86_64-linux-gnu/lib. +/// -ccc-install-dir is not within sysroot. No bin/../lib. +/// $sysroot/lib and $sysroot/usr/lib. Fallback when GCC installation is unavailable. +// DEBIAN_X86_64_PER_TARGET_UNKNOWN-SAME: {{^}} "-L[[SYSROOT]]/lib" +// DEBIAN_X86_64_PER_TARGET_UNKNOWN-SAME: {{^}} "-L[[SYSROOT]]/usr/lib" +// DEBIAN_X86_64_PER_TARGET_UNKNOWN-SAME: "[[RESOURCE]]/lib/x86_64-unknown-linux-gnu/libclang_rt.builtins.a" /// Test -m32. -/// FIXME -internal-isystem .*bin/../include/i386-linux-gnu/c++/v1 and -L[[PREFIX]]/bin/../lib/i386-linux-gnu are missing. // RUN: %clang -### %s --target=x86_64-linux-gnu -m32 --sysroot=%S/Inputs/debian_multiarch_tree \ // RUN: -ccc-install-dir %S/Inputs/debian_per_target_tree/usr/lib/llvm-14/bin -resource-dir=%S/Inputs/debian_per_target_tree/usr/lib/llvm-14/lib/clang/14.0.0 \ // RUN: --stdlib=libc++ --rtlib=compiler-rt 2>&1 | FileCheck %s --check-prefix=DEBIAN_X86_64_M32_PER_TARGET // DEBIAN_X86_64_M32_PER_TARGET: "-resource-dir" "[[RESOURCE:[^"]+]]" // DEBIAN_X86_64_M32_PER_TARGET: "-internal-isystem" -// DEBIAN_X86_64_M32_PER_TARGET-SAME: {{^}} "[[PREFIX:[^"]+llvm-14]]/bin/../include/c++/v1" +// DEBIAN_X86_64_M32_PER_TARGET-SAME: {{^}} "[[PREFIX:[^"]+llvm-14]]/bin/../include/i386-linux-gnu/c++/v1" +// DEBIAN_X86_64_M32_PER_TARGET-SAME: {{^}} "-internal-isystem" "[[PREFIX]]/bin/../include/c++/v1" // DEBIAN_X86_64_M32_PER_TARGET-SAME: {{^}} "-internal-isystem" "[[RESOURCE]]/include" // DEBIAN_X86_64_M32_PER_TARGET-SAME: {{^}} "-internal-isystem" "[[SYSROOT:[^"]+]]/usr/local/include" // DEBIAN_X86_64_M32_PER_TARGET-SAME: {{^}} "-internal-isystem" "[[SYSROOT]]/usr/lib/gcc/x86_64-linux-gnu/10/../../../../x86_64-linux-gnu/include" // DEBIAN_X86_64_M32_PER_TARGET: "-L -// DEBIAN_X86_64_M32_PER_TARGET-SAME: {{^}}[[SYSROOT]]/usr/lib/gcc/x86_64-linux-gnu/10/32" +// DEBIAN_X86_64_M32_PER_TARGET-SAME: {{^}}[[PREFIX]]/bin/../lib/i386-linux-gnu" +// DEBIAN_X86_64_M32_PER_TARGET-SAME: {{^}} "-L[[SYSROOT]]/usr/lib/gcc/x86_64-linux-gnu/10/32" // DEBIAN_X86_64_M32_PER_TARGET-SAME: {{^}} "-L[[SYSROOT]]/usr/lib/gcc/x86_64-linux-gnu/10/../../../../lib32" // DEBIAN_X86_64_M32_PER_TARGET-SAME: {{^}} "-L[[SYSROOT]]/lib/i386-linux-gnu" // DEBIAN_X86_64_M32_PER_TARGET-SAME: {{^}} "-L[[SYSROOT]]/lib/../lib32" @@ -199,6 +232,7 @@ // DEBIAN_X86_64_M32_PER_TARGET-SAME: {{^}} "-L[[SYSROOT]]/usr/lib/../lib32" // DEBIAN_X86_64_M32_PER_TARGET-SAME: {{^}} "-L[[SYSROOT]]/lib" // DEBIAN_X86_64_M32_PER_TARGET-SAME: {{^}} "-L[[SYSROOT]]/usr/lib" +// DEBIAN_X86_64_M32_PER_TARGET-SAME: "[[RESOURCE]]/lib/i386-linux-gnu/libclang_rt.builtins.a" /// LDSO_ARCH is i386 for all x86-32 variants. // RUN: %clang -### %s --target=i686-linux-musl --sysroot= \