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 @@ -419,15 +419,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 @@ -491,6 +491,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); @@ -523,7 +531,7 @@ } if (AT != llvm::Triple::UnknownArch && AT != Target.getArch()) - Target.setArch(AT); + SetArch(AT); } // Handle -miamcu flag. @@ -579,6 +587,9 @@ Target.setArch(llvm::Triple::riscv64); } + if (UnnormalizedTriple) + *UnnormalizedTriple = Unnormalized; + return Target; } @@ -1179,9 +1190,12 @@ // Perform the default argument translations. DerivedArgList *TranslatedArgs = TranslateInputArgs(*UArgs); + llvm::Triple Unnormalized; + const llvm::Triple Normalized = + computeTargetTriple(*this, TargetTriple, *UArgs, &Unnormalized); + 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, @@ -4625,8 +4639,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 @@ -488,15 +488,19 @@ } std::string ToolChain::getRuntimePath() const { - SmallString<128> P(D.ResourceDir); - llvm::sys::path::append(P, "lib", getTripleString()); - return std::string(P.str()); + // Use unnormalized D.getTargetTriple() (from --target= or + // LLVM_DEFAULT_TARGET_TRIPLE, with a small set of multilib transformation). + // This is essential when LLVM_DEFAULT_TARGET_TRIPLE uses Debian multiarch + // style "x86_64-linux-gnu" (no vendor part). + SmallString<128> P; + llvm::sys::path::append(P, D.ResourceDir, "lib", D.getTargetTriple()); + return std::string(P); } std::string ToolChain::getStdlibPath() const { - SmallString<128> P(D.Dir); - llvm::sys::path::append(P, "..", "lib", getTripleString()); - return std::string(P.str()); + SmallString<128> P; + llvm::sys::path::append(P, D.Dir, "..", "lib", D.getTargetTriple()); + return std::string(P); } std::string ToolChain::getArchSpecificLibPath() const { 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 @@ -2910,7 +2910,8 @@ 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); diff --git a/clang/test/Driver/Inputs/debian_per_target_tree/usr/lib/llvm-14/bin/.keep b/clang/test/Driver/Inputs/debian_per_target_tree/usr/lib/llvm-14/bin/.keep new file mode 100644 diff --git a/clang/test/Driver/Inputs/debian_per_target_tree/usr/lib/llvm-14/include/c++/v1/.keep b/clang/test/Driver/Inputs/debian_per_target_tree/usr/lib/llvm-14/include/c++/v1/.keep new file mode 100644 diff --git a/clang/test/Driver/Inputs/debian_per_target_tree/usr/lib/llvm-14/include/i386-linux-gnu/c++/v1/.keep b/clang/test/Driver/Inputs/debian_per_target_tree/usr/lib/llvm-14/include/i386-linux-gnu/c++/v1/.keep new file mode 100644 diff --git a/clang/test/Driver/Inputs/debian_per_target_tree/usr/lib/llvm-14/include/x86_64-linux-gnu/c++/v1/.keep b/clang/test/Driver/Inputs/debian_per_target_tree/usr/lib/llvm-14/include/x86_64-linux-gnu/c++/v1/.keep new file mode 100644 diff --git a/clang/test/Driver/Inputs/debian_per_target_tree/usr/lib/llvm-14/lib/clang/14.0.0/lib/i386-linux-gnu/libclang_rt.builtins.a b/clang/test/Driver/Inputs/debian_per_target_tree/usr/lib/llvm-14/lib/clang/14.0.0/lib/i386-linux-gnu/libclang_rt.builtins.a new file mode 100644 diff --git a/clang/test/Driver/Inputs/debian_per_target_tree/usr/lib/llvm-14/lib/clang/14.0.0/lib/x86_64-linux-gnu/libclang_rt.builtins.a b/clang/test/Driver/Inputs/debian_per_target_tree/usr/lib/llvm-14/lib/clang/14.0.0/lib/x86_64-linux-gnu/libclang_rt.builtins.a new file mode 100644 diff --git a/clang/test/Driver/Inputs/debian_per_target_tree/usr/lib/llvm-14/lib/i386-linux-gnu/.keep b/clang/test/Driver/Inputs/debian_per_target_tree/usr/lib/llvm-14/lib/i386-linux-gnu/.keep new file mode 100644 diff --git a/clang/test/Driver/Inputs/resource_dir_with_per_target_subdir_debian/lib/i386-linux-gnu/libclang_rt.builtins.a b/clang/test/Driver/Inputs/resource_dir_with_per_target_subdir_debian/lib/i386-linux-gnu/libclang_rt.builtins.a new file mode 100644 diff --git a/clang/test/Driver/Inputs/resource_dir_with_per_target_subdir_debian/lib/x86_64-linux-gnu/libclang_rt.builtins.a b/clang/test/Driver/Inputs/resource_dir_with_per_target_subdir_debian/lib/x86_64-linux-gnu/libclang_rt.builtins.a 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 @@ -151,6 +151,59 @@ // DEBIAN_AARCH64-SAME: {{^}} "-L[[SYSROOT]]/lib" // DEBIAN_AARCH64-SAME: {{^}} "-L[[SYSROOT]]/usr/lib" +/// Test native x86-64 with -DLLVM_ENABLE_PER_TARGET_RUNTIME_DIR=on. +// 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/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: {{^}}[[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" +// DEBIAN_X86_64_PER_TARGET-SAME: {{^}} "-L[[SYSROOT]]/lib/x86_64-linux-gnu" +// DEBIAN_X86_64_PER_TARGET-SAME: {{^}} "-L[[SYSROOT]]/lib/../lib64" +// DEBIAN_X86_64_PER_TARGET-SAME: {{^}} "-L[[SYSROOT]]/usr/lib/x86_64-linux-gnu" +// DEBIAN_X86_64_PER_TARGET-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-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" + +/// Test -m32. +// 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/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: {{^}}[[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" +// DEBIAN_X86_64_M32_PER_TARGET-SAME: {{^}} "-L[[SYSROOT]]/usr/lib/i386-linux-gnu" +// 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= \ // RUN: --stdlib=platform --rtlib=platform 2>&1 | FileCheck %s --check-prefix=MUSL_I686