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,31 @@ } std::string ToolChain::getRuntimePath() const { + // Prefer unnormalized D.getTargetTriple() (e.g. x86_64-linux-gnu) over the + // normalized getTripleString() (e.g. x86_64-unknown-linux-gnu). This is + // essential when LLVM_DEFAULT_TARGET_TRIPLE uses Debian multiarch style + // "x86_64-linux-gnu" (no vendor part). SmallString<128> P(D.ResourceDir); + llvm::sys::path::append(P, D.ResourceDir, "lib", D.getTargetTriple()); + if (getVFS().exists(P)) + return std::string(P); + + P.assign(D.ResourceDir); llvm::sys::path::append(P, "lib", getTripleString()); - return std::string(P.str()); + return std::string(P); } std::string ToolChain::getStdlibPath() const { SmallString<128> P(D.Dir); + // First try the unnormalized triple a la getRuntimePath(). + llvm::sys::path::append(P, "..", "lib", D.getTargetTriple()); + if (getVFS().exists(P)) + return std::string(P); + + // Then try the normalized triple, e.g. x86_64-unknown-linux-gnu. + P.assign(D.ResourceDir); llvm::sys::path::append(P, "..", "lib", getTripleString()); - return std::string(P.str()); + 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,9 +2910,16 @@ return false; // First add the per-target include path if it exists. - std::string TargetDir = Path + "/" + Target + "/c++/" + Version; - if (D.getVFS().exists(TargetDir)) + std::string TargetDir = Path + "/" + D.getTargetTriple() + "/c++/" + Version; + if (D.getVFS().exists(TargetDir)) { + // Unnormalized D.getTargetTriple(), e.g. x86_64-linux-gnu if --target + // does not contain vendor part. addSystemInclude(DriverArgs, CC1Args, TargetDir); + } else { + // Normalized Target, e.g. x86_64-unknown-linux-gnu. + TargetDir = Path + "/" + Target + "/c++/" + Version; + addSystemInclude(DriverArgs, CC1Args, TargetDir); + } // Second add the generic one. addSystemInclude(DriverArgs, CC1Args, Path + "/c++/" + Version); 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/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/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/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,34 @@ // 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" + /// 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