]> granicus.if.org Git - clang/commitdiff
Rework the selection of builtin library search paths on Linux to
authorChandler Carruth <chandlerc@gmail.com>
Mon, 3 Oct 2011 05:28:29 +0000 (05:28 +0000)
committerChandler Carruth <chandlerc@gmail.com>
Mon, 3 Oct 2011 05:28:29 +0000 (05:28 +0000)
precisely match the pattern and logic used by the GCC driver on Linux as
of a recent SVN checkout.

This happens to follow a *much* more principled approach. There is
a strict hierarchy of paths examined, first with multilib-suffixing,
second without such suffixing. Any and all of these directories which
exist will be added to the library search path when using GCC.

There were many places where Clang followed different paths, omitted
critical entries, and worst of all (in terms of challenges to debugging)
got the entries in a subtly wrong order.

If this breaks Clang on a distro you use, please let me know, and I'll
work with you to figure out what is needed to work on that distro. I've
checked the behavior of the latest release of Ubuntu, OpenSUSE, Fedora,
and Gentoo. I'll be testing it on those as well as Debian stable and
unstable and ArchLinux. I may even dig out a Slackware install.

No real regression tests yet, those will follow once I add enough
support for sysroot to simulate various distro layouts in the testsuite.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@140981 91177308-0d34-0410-b5e6-96231b3b80d8

lib/Driver/ToolChains.cpp
test/Driver/linux-ld.c

index b32fb570f390179d6e63f0c4e39f1ecef79b24b1..1b2ff2ecb7374327bcb67e0c1412d45156f37b09 100644 (file)
@@ -1549,6 +1549,13 @@ static std::string findGCCBaseLibDir(const Driver &D,
   return "";
 }
 
+static void addPathIfExists(const std::string &Path,
+                            ToolChain::path_list &Paths) {
+  bool Exists;
+  if (!llvm::sys::fs::exists(Path, Exists) && Exists)
+    Paths.push_back(Path);
+}
+
 Linux::Linux(const HostInfo &Host, const llvm::Triple &Triple)
   : Generic_ELF(Host, Triple) {
   llvm::Triple::ArchType Arch =
@@ -1626,25 +1633,6 @@ Linux::Linux(const HostInfo &Host, const llvm::Triple &Triple)
   }
 
   std::string Base = findGCCBaseLibDir(getDriver(), GccTriple);
-  path_list &Paths = getFilePaths();
-  bool Is32Bits = (getArch() == llvm::Triple::x86 ||
-                   getArch() == llvm::Triple::ppc);
-
-  const std::string Suffix32 = Arch == llvm::Triple::x86_64 ? "/32" : "";
-  const std::string Suffix64 = Is32Bits ? "/64" : "";
-  const std::string Suffix = Is32Bits ? Suffix32 : Suffix64;
-
-  std::string Lib32 = "lib";
-  if (!llvm::sys::fs::exists("/lib32", Exists) && Exists)
-    Lib32 = "lib32";
-
-  std::string Lib64 = "lib";
-  bool Symlink;
-  if (!llvm::sys::fs::exists("/lib64", Exists) && Exists &&
-      (llvm::sys::fs::is_symlink("/lib64", Symlink) || !Symlink))
-    Lib64 = "lib64";
-
-  std::string Lib = Is32Bits ? Lib32 : Lib64;
 
   // OpenSuse stores the linker with the compiler, add that to the search
   // path.
@@ -1685,27 +1673,50 @@ Linux::Linux(const HostInfo &Host, const llvm::Triple &Triple)
   if (IsOpenSuse(Distro))
     ExtraOpts.push_back("--enable-new-dtags");
 
-  if (Distro == ArchLinux)
-    Lib = "lib";
+  // The selection of paths to try here is designed to match the patterns which
+  // the GCC driver itself uses, as this is part of the GCC-compatible driver.
+  // This was determined by running GCC in a fake filesystem, creating all
+  // possible permutations of these directories, and seeing which ones it added
+  // to the link paths.
+  path_list &Paths = getFilePaths();
+  const bool Is32Bits = (getArch() == llvm::Triple::x86 ||
+                         getArch() == llvm::Triple::ppc);
+
+  const std::string Suffix32 = Arch == llvm::Triple::x86_64 ? "/32" : "";
+  const std::string Suffix64 = Is32Bits ? "/64" : "";
+  const std::string Suffix = Is32Bits ? Suffix32 : Suffix64;
+  const std::string Multilib = Is32Bits ? "lib32" : "lib64";
 
-  Paths.push_back(Base + Suffix);
+  // FIXME: Because we add paths only when they exist on the system, I think we
+  // should remove the concept of 'HasMultilib'. It's more likely to break the
+  // behavior than to preserve any useful invariant on the system.
   if (HasMultilib(Arch, Distro)) {
+    // FIXME: This OpenSuse-specific path shouldn't be needed any more, but
+    // I don't want to remove it without finding someone to test.
     if (IsOpenSuse(Distro) && Is32Bits)
       Paths.push_back(Base + "/../../../../" + GccTriple + "/lib/../lib");
-    Paths.push_back(Base + "/../../../../" + Lib);
+
+    // Add the multilib suffixed paths.
+    if (!Base.empty() && !GccTriple.empty()) {
+      addPathIfExists(Base + Suffix, Paths);
+      addPathIfExists(Base + "/../../../../" + GccTriple + "/lib/../" +
+                      Multilib, Paths);
+      addPathIfExists(Base + "/../../../../" + Multilib, Paths);
+    }
+    addPathIfExists("/lib/../" + Multilib, Paths);
+    addPathIfExists("/usr/lib/../" + Multilib, Paths);
   }
 
-  // FIXME: This is in here to find crt1.o. It is provided by libc, and
-  // libc (like gcc), can be installed in any directory. Once we are
-  // fetching this from a config file, we should have a libc prefix.
-  Paths.push_back("/lib/../" + Lib);
-  Paths.push_back("/usr/lib/../" + Lib);
+  // Add the non-multiplib suffixed paths (if potentially different).
+  if (!Base.empty() && !GccTriple.empty()) {
+    if (!Suffix.empty())
+      addPathIfExists(Base, Paths);
+    addPathIfExists(Base + "/../../../../" + GccTriple + "/lib", Paths);
+    addPathIfExists(Base + "/../../..", Paths);
+  }
+  addPathIfExists("/lib", Paths);
+  addPathIfExists("/usr/lib", Paths);
 
-  if (!Suffix.empty())
-    Paths.push_back(Base);
-  if (IsOpenSuse(Distro))
-    Paths.push_back(Base + "/../../../../" + GccTriple + "/lib");
-  Paths.push_back(Base + "/../../..");
   if (Arch == getArch() && IsUbuntu(Distro))
     Paths.push_back("/usr/lib/" + GccTriple);
 }
index bdf699ae1ba0b810039bc27062eb23cb8ec86a1a..745b03c7a6a3890c1eead892b932c47ba4fe91a0 100644 (file)
@@ -2,8 +2,8 @@
 //
 // RUN: %clang -no-canonical-prefixes -ccc-host-triple i386-unknown-linux %s -### -o %t.o 2>&1 \
 // RUN:   | FileCheck --check-prefix=CHECK-LD-32 %s
-// CHECK-LD-32: "{{.*}}ld{{(.exe)?}}" {{.*}} "-L/lib/../lib{{(32)?}}" "-L/usr/lib/../lib{{(32)?}}"
+// CHECK-LD-32: "{{.*}}ld{{(.exe)?}}" {{.*}} "-L/lib" "-L/usr/lib"
 //
 // RUN: %clang -no-canonical-prefixes -ccc-host-triple x86_64-unknown-linux %s -### -o %t.o 2>&1 \
 // RUN:   | FileCheck --check-prefix=CHECK-LD-64 %s
-// CHECK-LD-64: "{{.*}}ld{{(.exe)?}}" {{.*}} "-L/lib/../lib{{(64)?}}" "-L/usr/lib/../lib{{(64)?}}"
+// CHECK-LD-64: "{{.*}}ld{{(.exe)?}}" {{.*}} "-L/lib" "-L/usr/lib"