From b620ab11a339a4b8f3f0975fd016508483833f46 Mon Sep 17 00:00:00 2001 From: serge-sans-paille Date: Wed, 23 Sep 2020 12:47:30 +0000 Subject: [PATCH][clang] Prefer gcc toolchains with libgcc_s.so when not static linking libgcc Fedora ships cross-compilers on all platforms, so a user could end up with a gcc x86_64 cross-compiler installed on an x86_64 system. clang maintains a list of supported triples for each target and when all else is equal will prefer toolchains with triples that appear earlier in the list. The cross-compiler triple on Fedora is x86_64-linux-gnu and this comes before the Fedora system compiler's triple: x86_64-redhat-linux in the triples list, so the cross compiler is always preferred. This is a problem, because the cross compiler is missing libraries, like libgcc_s.so, that clang expects to be there so linker invocations will fail. This patch fixes this by checking for the existence of libgcc_s.so when it is required and taking that into account when selecting a toolchain. --- clang/lib/Driver/ToolChains/Gnu.cpp | 16 ++++++++++++++-- clang/lib/Driver/ToolChains/Gnu.h | 4 +++- .../usr/lib/gcc/x86_64-linux-gnu/7/crtbegin.o | 0 .../usr/lib/gcc/x86_64-redhat-linux/7/crtbegin.o | 0 .../lib/gcc/x86_64-redhat-linux/7/libgcc_s.so | 0 clang/test/Driver/linux-ld.c | 12 ++++++++++++ 6 files changed, 29 insertions(+), 3 deletions(-) create mode 100644 clang/test/Driver/Inputs/fedora_28_tree/usr/lib/gcc/x86_64-linux-gnu/7/crtbegin.o create mode 100644 clang/test/Driver/Inputs/fedora_28_tree/usr/lib/gcc/x86_64-redhat-linux/7/crtbegin.o create mode 100644 clang/test/Driver/Inputs/fedora_28_tree/usr/lib/gcc/x86_64-redhat-linux/7/libgcc_s.so diff --git a/clang/lib/Driver/ToolChains/Gnu.cpp b/clang/lib/Driver/ToolChains/Gnu.cpp index 6f431a1badae..11e1a8558556 100644 --- a/clang/lib/Driver/ToolChains/Gnu.cpp +++ b/clang/lib/Driver/ToolChains/Gnu.cpp @@ -2537,6 +2537,8 @@ void Generic_GCC::GCCInstallationDetector::ScanLibDirForGCCTriple( TargetTriple.getVendor() == llvm::Triple::Freescale || TargetTriple.getVendor() == llvm::Triple::OpenEmbedded}}; + bool NeedLibgccShared = !Args.hasArg(options::OPT_static_libgcc) && + !Args.hasArg(options::OPT_static); for (auto &Suffix : Suffixes) { if (!Suffix.Active) continue; @@ -2554,8 +2556,17 @@ void Generic_GCC::GCCInstallationDetector::ScanLibDirForGCCTriple( continue; // Saw this path before; no need to look at it again. if (CandidateVersion.isOlderThan(4, 1, 1)) continue; - if (CandidateVersion <= Version) - continue; + + bool CandidateHasLibGccShared = false; + if (CandidateVersion <= Version) { + if (NeedLibgccShared && !HasLibGccShared) { + CandidateHasLibGccShared = + D.getVFS().exists(LI->path() + "/libgcc_s.so"); + + } + if (HasLibGccShared || !CandidateHasLibGccShared) + continue; + } if (!ScanGCCForMultilibs(TargetTriple, Args, LI->path(), NeedsBiarchSuffix)) @@ -2569,6 +2580,7 @@ void Generic_GCC::GCCInstallationDetector::ScanLibDirForGCCTriple( GCCInstallPath = (LibDir + "/" + LibSuffix + "/" + VersionText).str(); GCCParentLibPath = (GCCInstallPath + "/../" + Suffix.ReversePath).str(); IsValid = true; + HasLibGccShared = CandidateHasLibGccShared; } } } diff --git a/clang/lib/Driver/ToolChains/Gnu.h b/clang/lib/Driver/ToolChains/Gnu.h index 40fd756a5653..0b103c1fc936 100644 --- a/clang/lib/Driver/ToolChains/Gnu.h +++ b/clang/lib/Driver/ToolChains/Gnu.h @@ -190,6 +190,7 @@ public: /// Driver, and has logic for fuzzing that where appropriate. class GCCInstallationDetector { bool IsValid; + bool HasLibGccShared; llvm::Triple GCCTriple; const Driver &D; @@ -216,7 +217,8 @@ public: const std::string GentooConfigDir = "/etc/env.d/gcc"; public: - explicit GCCInstallationDetector(const Driver &D) : IsValid(false), D(D) {} + explicit GCCInstallationDetector(const Driver &D) + : IsValid(false), HasLibGccShared(false), D(D) {} void init(const llvm::Triple &TargetTriple, const llvm::opt::ArgList &Args, ArrayRef ExtraTripleAliases = None); diff --git a/clang/test/Driver/Inputs/fedora_28_tree/usr/lib/gcc/x86_64-linux-gnu/7/crtbegin.o b/clang/test/Driver/Inputs/fedora_28_tree/usr/lib/gcc/x86_64-linux-gnu/7/crtbegin.o new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/clang/test/Driver/Inputs/fedora_28_tree/usr/lib/gcc/x86_64-redhat-linux/7/crtbegin.o b/clang/test/Driver/Inputs/fedora_28_tree/usr/lib/gcc/x86_64-redhat-linux/7/crtbegin.o new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/clang/test/Driver/Inputs/fedora_28_tree/usr/lib/gcc/x86_64-redhat-linux/7/libgcc_s.so b/clang/test/Driver/Inputs/fedora_28_tree/usr/lib/gcc/x86_64-redhat-linux/7/libgcc_s.so new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/clang/test/Driver/linux-ld.c b/clang/test/Driver/linux-ld.c index cc505588331b..47c6352d333f 100644 --- a/clang/test/Driver/linux-ld.c +++ b/clang/test/Driver/linux-ld.c @@ -681,6 +681,18 @@ // CHECK-FEDORA-31-RISCV64: "{{.*}}/usr/lib/gcc/riscv64-redhat-linux/9{{/|\\\\}}crtend.o" // CHECK-FEDORA-31-RISCV64: "{{.*}}/usr/lib/gcc/riscv64-redhat-linux/9{{/|\\\\}}crtn.o" // +// Check that clang does not select the cross compiler by default on Fedora 28. +// +// RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \ +// RUN: --target=x86_64-unknown-linux-gnu \ +// RUN: --gcc-toolchain="" \ +// RUN: --sysroot=%S/Inputs/fedora_28_tree \ +// RUN: | FileCheck --check-prefix=CHECK-FEDORA-28-X86_64 %s +// +// CHECK-FEDORA-28-X86_64: "{{.*}}ld{{(.exe)?}}" "--sysroot=[[SYSROOT:[^"]+]]" +// CHECK-FEDORA-28-X86_64: "[[SYSROOT]]/usr/lib/gcc/x86_64-redhat-linux/7/crtbegin.o" +// CHECK-FEDORA-28-X86_64: "-L[[SYSROOT]]/usr/lib/gcc/x86_64-redhat-linux/7" +// // RUN: %clang -no-canonical-prefixes %s -### -o %t.o 2>&1 \ // RUN: --target=arm-unknown-linux-gnueabi -rtlib=platform \ // RUN: --gcc-toolchain="" \ -- 2.30.2