[cfe-commits] r141011 - /cfe/trunk/lib/Driver/ToolChains.cpp

Chandler Carruth chandlerc at gmail.com
Mon Oct 3 11:16:55 PDT 2011


Author: chandlerc
Date: Mon Oct  3 13:16:54 2011
New Revision: 141011

URL: http://llvm.org/viewvc/llvm-project?rev=141011&view=rev
Log:
Refactor the detection of a GCC installation into a helper class. This
is designed to allow the detection to record more rich information about
the installation than just a single path.

Mostly, the functionality remains the same. This is primarily
a factoring change. However, the new factoring immediately fixes one
issue where on ubuntu we didn't walk up enough layers to reach the
parent lib path. I'll have a test tree for that once I finish making the
Ubuntu tree work reasonably.

Modified:
    cfe/trunk/lib/Driver/ToolChains.cpp

Modified: cfe/trunk/lib/Driver/ToolChains.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Driver/ToolChains.cpp?rev=141011&r1=141010&r2=141011&view=diff
==============================================================================
--- cfe/trunk/lib/Driver/ToolChains.cpp (original)
+++ cfe/trunk/lib/Driver/ToolChains.cpp Mon Oct  3 13:16:54 2011
@@ -1475,83 +1475,184 @@
   return UnknownDistro;
 }
 
-/// \brief Find an installed GCC lib base directory.
-///
-/// Tries both the auto-detected GccTriple passed in as well as the
-/// Driver-specified default host triple. Sets the GccTriple to the triple
-/// actually used.
-static std::string findGCCBaseLibDir(const Driver &D, std::string &GccTriple) {
-  // FIXME: Using CXX_INCLUDE_ROOT is here is a bit of a hack, but
-  // avoids adding yet another option to configure/cmake.
-  // It would probably be cleaner to break it in two variables
-  // CXX_GCC_ROOT with just /foo/bar
-  // CXX_GCC_VER with 4.5.2
-  // Then we would have
-  // CXX_INCLUDE_ROOT = CXX_GCC_ROOT/include/c++/CXX_GCC_VER
-  // and this function would return
-  // CXX_GCC_ROOT/lib/gcc/CXX_INCLUDE_ARCH/CXX_GCC_VER
-  llvm::SmallString<128> CxxIncludeRoot(CXX_INCLUDE_ROOT);
-  if (CxxIncludeRoot != "") {
-    // This is of the form /foo/bar/include/c++/4.5.2/
-    if (CxxIncludeRoot.back() == '/')
-      llvm::sys::path::remove_filename(CxxIncludeRoot); // remove the /
-    StringRef Version = llvm::sys::path::filename(CxxIncludeRoot);
-    llvm::sys::path::remove_filename(CxxIncludeRoot); // remove the version
-    llvm::sys::path::remove_filename(CxxIncludeRoot); // remove the c++
-    llvm::sys::path::remove_filename(CxxIncludeRoot); // remove the include
-    std::string ret(CxxIncludeRoot.c_str());
-    ret.append("/lib/gcc/");
-    ret.append(CXX_INCLUDE_ARCH);
-    ret.append("/");
-    ret.append(Version);
-    return ret;
-  }
-  static const char* GccVersions[] = {"4.6.1", "4.6.0", "4.6",
-                                      "4.5.3", "4.5.2", "4.5.1", "4.5",
-                                      "4.4.6", "4.4.5", "4.4.4", "4.4.3", "4.4",
-                                      "4.3.4", "4.3.3", "4.3.2", "4.3",
-                                      "4.2.4", "4.2.3", "4.2.2", "4.2.1",
-                                      "4.2", "4.1.1"};
+/// \brief Trivial helper function to simplify code checking path existence.
+static bool PathExists(std::string Path) {
   bool Exists;
-  llvm::SmallVector<std::string, 8> Paths(D.PrefixDirs.begin(),
-      D.PrefixDirs.end());
-  Paths.push_back(D.SysRoot + "/usr/");
-  const std::string Triples[] = {GccTriple, D.DefaultHostTriple};
-  for (llvm::SmallVector<std::string, 8>::const_iterator it = Paths.begin(),
-       ie = Paths.end(); it != ie; ++it) {
-    for (unsigned i = 0; i < sizeof(GccVersions)/sizeof(char*); ++i) {
-      for (unsigned j = 0; j < sizeof(Triples)/sizeof(Triples[0]); ++j) {
-        GccTriple = Triples[j];
-        std::string Suffix = Triples[j] + "/" + GccVersions[i];
-        std::string t1 = *it + "lib/gcc/" + Suffix;
-        if (!llvm::sys::fs::exists(t1 + "/crtbegin.o", Exists) && Exists)
-          return t1;
-        std::string t2 = *it + "lib64/gcc/" + Suffix;
-        if (!llvm::sys::fs::exists(t2 + "/crtbegin.o", Exists) && Exists)
-          return t2;
-        std::string t3 = *it + "lib/" + GccTriple + "/gcc/" + Suffix;
-        if (!llvm::sys::fs::exists(t3 + "/crtbegin.o", Exists) && Exists)
-          return t3;
-        if (GccTriple == "i386-linux-gnu") {
+  if (!llvm::sys::fs::exists(Path, Exists))
+    return Exists;
+  return false;
+}
+
+namespace {
+/// \brief This is a class to find a viable GCC installation for Clang to use.
+///
+/// This class tries to find a GCC installation on the system, and report
+/// information about it. It starts from the host information provided to the
+/// Driver, and has logic for fuzzing that where appropriate.
+class GCCInstallationDetector {
+  bool IsValid;
+  std::string GccTriple;
+
+  // FIXME: These might be better as path objects.
+  std::string GccInstallPath;
+  std::string GccParentLibPath;
+
+  llvm::SmallString<128> CxxIncludeRoot;
+
+public:
+  /// \brief Construct a GCCInstallationDetector from the driver.
+  ///
+  /// This performs all of the autodetection and sets up the various paths.
+  /// Once constructed, a GCCInstallation is esentially immutable.
+  GCCInstallationDetector(const Driver &D)
+    : IsValid(false),
+      GccTriple(D.DefaultHostTriple),
+      CxxIncludeRoot(CXX_INCLUDE_ROOT) {
+    // FIXME: Using CXX_INCLUDE_ROOT is here is a bit of a hack, but
+    // avoids adding yet another option to configure/cmake.
+    // It would probably be cleaner to break it in two variables
+    // CXX_GCC_ROOT with just /foo/bar
+    // CXX_GCC_VER with 4.5.2
+    // Then we would have
+    // CXX_INCLUDE_ROOT = CXX_GCC_ROOT/include/c++/CXX_GCC_VER
+    // and this function would return
+    // CXX_GCC_ROOT/lib/gcc/CXX_INCLUDE_ARCH/CXX_GCC_VER
+    if (CxxIncludeRoot != "") {
+      // This is of the form /foo/bar/include/c++/4.5.2/
+      if (CxxIncludeRoot.back() == '/')
+        llvm::sys::path::remove_filename(CxxIncludeRoot); // remove the /
+      StringRef Version = llvm::sys::path::filename(CxxIncludeRoot);
+      llvm::sys::path::remove_filename(CxxIncludeRoot); // remove the version
+      llvm::sys::path::remove_filename(CxxIncludeRoot); // remove the c++
+      llvm::sys::path::remove_filename(CxxIncludeRoot); // remove the include
+      GccInstallPath = CxxIncludeRoot.str();
+      GccInstallPath.append("/lib/gcc/");
+      GccInstallPath.append(CXX_INCLUDE_ARCH);
+      GccInstallPath.append("/");
+      GccInstallPath.append(Version);
+      GccParentLibPath = GccInstallPath + "/../../../..";
+      IsValid = true;
+      return;
+    }
+
+    llvm::Triple::ArchType HostArch = llvm::Triple(GccTriple).getArch();
+    std::string DetectedGccTriple;
+    if (HostArch == llvm::Triple::arm || HostArch == llvm::Triple::thumb) {
+      if (PathExists("/usr/lib/gcc/arm-linux-gnueabi"))
+        DetectedGccTriple = "arm-linux-gnueabi";
+    } else if (HostArch == llvm::Triple::x86_64) {
+      if (PathExists("/usr/lib/gcc/x86_64-linux-gnu"))
+        DetectedGccTriple = "x86_64-linux-gnu";
+      else if (PathExists("/usr/lib/gcc/x86_64-unknown-linux-gnu"))
+        DetectedGccTriple = "x86_64-unknown-linux-gnu";
+      else if (PathExists("/usr/lib/gcc/x86_64-pc-linux-gnu"))
+        DetectedGccTriple = "x86_64-pc-linux-gnu";
+      else if (PathExists("/usr/lib/gcc/x86_64-redhat-linux6E"))
+        DetectedGccTriple = "x86_64-redhat-linux6E";
+      else if (PathExists("/usr/lib/gcc/x86_64-redhat-linux"))
+        DetectedGccTriple = "x86_64-redhat-linux";
+      else if (PathExists("/usr/lib64/gcc/x86_64-suse-linux"))
+        DetectedGccTriple = "x86_64-suse-linux";
+      else if (PathExists("/usr/lib/gcc/x86_64-manbo-linux-gnu"))
+        DetectedGccTriple = "x86_64-manbo-linux-gnu";
+      else if (PathExists("/usr/lib/x86_64-linux-gnu/gcc"))
+        DetectedGccTriple = "x86_64-linux-gnu";
+      else if (PathExists("/usr/lib64/gcc/x86_64-slackware-linux"))
+        DetectedGccTriple = "x86_64-slackware-linux";
+    } else if (HostArch == llvm::Triple::x86) {
+      if (PathExists("/usr/lib/gcc/i686-linux-gnu"))
+        DetectedGccTriple = "i686-linux-gnu";
+      else if (PathExists("/usr/lib/i386-linux-gnu"))
+        DetectedGccTriple = "i386-linux-gnu";
+      else if (PathExists("/usr/lib/gcc/i686-pc-linux-gnu"))
+        DetectedGccTriple = "i686-pc-linux-gnu";
+      else if (PathExists("/usr/lib/gcc/i486-linux-gnu"))
+        DetectedGccTriple = "i486-linux-gnu";
+      else if (PathExists("/usr/lib/gcc/i686-redhat-linux"))
+        DetectedGccTriple = "i686-redhat-linux";
+      else if (PathExists("/usr/lib/gcc/i586-suse-linux"))
+        DetectedGccTriple = "i586-suse-linux";
+      else if (PathExists("/usr/lib/gcc/i486-slackware-linux"))
+        DetectedGccTriple = "i486-slackware-linux";
+    } else if (HostArch == llvm::Triple::ppc) {
+      if (PathExists("/usr/lib/powerpc-linux-gnu"))
+        DetectedGccTriple = "powerpc-linux-gnu";
+      else if (PathExists("/usr/lib/gcc/powerpc-unknown-linux-gnu"))
+        DetectedGccTriple = "powerpc-unknown-linux-gnu";
+    } else if (HostArch == llvm::Triple::ppc64) {
+      if (PathExists("/usr/lib/gcc/powerpc64-unknown-linux-gnu"))
+        DetectedGccTriple = "powerpc64-unknown-linux-gnu";
+      else if (PathExists("/usr/lib64/gcc/powerpc64-unknown-linux-gnu"))
+        DetectedGccTriple = "powerpc64-unknown-linux-gnu";
+    }
+
+    static const char* GccVersions[] = {
+      "4.6.1", "4.6.0", "4.6",
+      "4.5.3", "4.5.2", "4.5.1", "4.5",
+      "4.4.6", "4.4.5", "4.4.4", "4.4.3", "4.4",
+      "4.3.4", "4.3.3", "4.3.2", "4.3",
+      "4.2.4", "4.2.3", "4.2.2", "4.2.1", "4.2",
+      "4.1.1"};
+    SmallVector<std::string, 8> Paths(D.PrefixDirs.begin(),
+                                      D.PrefixDirs.end());
+    Paths.push_back(D.SysRoot + "/usr/");
+    const std::string Triples[] = {DetectedGccTriple, D.DefaultHostTriple};
+    IsValid = true;  // In case we're able to find a GCC install.
+    for (SmallVector<std::string, 8>::const_iterator I = Paths.begin(),
+                                                     E = Paths.end();
+         I != E; ++I) {
+      for (unsigned i = 0; i < sizeof(GccVersions)/sizeof(char*); ++i) {
+        for (unsigned j = 0; j < sizeof(Triples)/sizeof(Triples[0]); ++j) {
+          GccTriple = Triples[j];
+          std::string Suffix = Triples[j] + "/" + GccVersions[i];
+          GccInstallPath = *I + "lib/gcc/" + Suffix;
+          GccParentLibPath = GccInstallPath + "/../../..";
+          if (PathExists(GccInstallPath + "/crtbegin.o"))
+            return;
+          GccInstallPath = *I + "lib64/gcc/" + Suffix;
+          GccParentLibPath = GccInstallPath + "/../../..";
+          if (PathExists(GccInstallPath + "/crtbegin.o"))
+            return;
+          GccInstallPath = *I + "lib/" + GccTriple + "/gcc/" + Suffix;
+          GccParentLibPath = GccInstallPath + "/../../../..";
+          if (PathExists(GccInstallPath + "/crtbegin.o"))
+            return;
+
+          if (GccTriple != "i386-linux-gnu")
+            continue;
+
           // Ubuntu 11.04 uses an unusual path.
-          std::string t4 =
-              std::string(*it + "lib/i386-linux-gnu/gcc/i686-linux-gnu/") +
-              GccVersions[i];
-          if (!llvm::sys::fs::exists(t4 + "/crtbegin.o", Exists) && Exists)
-            return t4;
+          GccInstallPath = *I + "lib/i386-linux-gnu/gcc/i686-linux-gnu/" +
+            GccVersions[i];
+          GccParentLibPath = GccInstallPath + "/../../../..";
+          if (PathExists(GccInstallPath + "/crtbegin.o"))
+            return;
         }
       }
     }
+    GccTriple.clear();
+    GccInstallPath.clear();
+    GccParentLibPath.clear();
+    IsValid = false;
   }
-  GccTriple.clear();
-  return "";
+
+  /// \brief Check whether we detected a valid GCC install.
+  bool isValid() const { return IsValid; }
+
+  /// \brief Get the GCC triple for the detected install.
+  const std::string &getTriple() const { return GccTriple; }
+
+  /// \brief Get the detected GCC installation path.
+  const std::string &getInstallPath() const { return GccInstallPath; }
+
+  /// \brief Get the detected GCC parent lib path.
+  const std::string &getParentLibPath() const { return GccParentLibPath; }
+};
 }
 
 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);
+  if (PathExists(Path)) Paths.push_back(Path);
 }
 
 Linux::Linux(const HostInfo &Host, const llvm::Triple &Triple)
@@ -1559,84 +1660,13 @@
   llvm::Triple::ArchType Arch =
     llvm::Triple(getDriver().DefaultHostTriple).getArch();
   const std::string &SysRoot = getDriver().SysRoot;
-
-  bool Exists;
-  std::string GccTriple = "";
-  if (Arch == llvm::Triple::arm || Arch == llvm::Triple::thumb) {
-    if (!llvm::sys::fs::exists("/usr/lib/gcc/arm-linux-gnueabi", Exists) &&
-        Exists)
-      GccTriple = "arm-linux-gnueabi";
-  } else if (Arch == llvm::Triple::x86_64) {
-    if (!llvm::sys::fs::exists("/usr/lib/gcc/x86_64-linux-gnu", Exists) &&
-        Exists)
-      GccTriple = "x86_64-linux-gnu";
-    else if (!llvm::sys::fs::exists("/usr/lib/gcc/x86_64-unknown-linux-gnu",
-             Exists) && Exists)
-      GccTriple = "x86_64-unknown-linux-gnu";
-    else if (!llvm::sys::fs::exists("/usr/lib/gcc/x86_64-pc-linux-gnu",
-             Exists) && Exists)
-      GccTriple = "x86_64-pc-linux-gnu";
-    else if (!llvm::sys::fs::exists("/usr/lib/gcc/x86_64-redhat-linux6E",
-             Exists) && Exists)
-      GccTriple = "x86_64-redhat-linux6E";
-    else if (!llvm::sys::fs::exists("/usr/lib/gcc/x86_64-redhat-linux",
-             Exists) && Exists)
-      GccTriple = "x86_64-redhat-linux";
-    else if (!llvm::sys::fs::exists("/usr/lib64/gcc/x86_64-suse-linux",
-             Exists) && Exists)
-      GccTriple = "x86_64-suse-linux";
-    else if (!llvm::sys::fs::exists("/usr/lib/gcc/x86_64-manbo-linux-gnu",
-             Exists) && Exists)
-      GccTriple = "x86_64-manbo-linux-gnu";
-    else if (!llvm::sys::fs::exists("/usr/lib/x86_64-linux-gnu/gcc",
-             Exists) && Exists)
-      GccTriple = "x86_64-linux-gnu";
-    else if (!llvm::sys::fs::exists("/usr/lib64/gcc/x86_64-slackware-linux", 
-             Exists) && Exists)
-      GccTriple = "x86_64-slackware-linux";
-  } else if (Arch == llvm::Triple::x86) {
-    if (!llvm::sys::fs::exists("/usr/lib/gcc/i686-linux-gnu", Exists) && Exists)
-      GccTriple = "i686-linux-gnu";
-    else if (!llvm::sys::fs::exists("/usr/lib/i386-linux-gnu", Exists) &&
-             Exists)
-      GccTriple = "i386-linux-gnu";
-    else if (!llvm::sys::fs::exists("/usr/lib/gcc/i686-pc-linux-gnu", Exists) &&
-             Exists)
-      GccTriple = "i686-pc-linux-gnu";
-    else if (!llvm::sys::fs::exists("/usr/lib/gcc/i486-linux-gnu", Exists) &&
-             Exists)
-      GccTriple = "i486-linux-gnu";
-    else if (!llvm::sys::fs::exists("/usr/lib/gcc/i686-redhat-linux", Exists) &&
-             Exists)
-      GccTriple = "i686-redhat-linux";
-    else if (!llvm::sys::fs::exists("/usr/lib/gcc/i586-suse-linux", Exists) &&
-             Exists)
-      GccTriple = "i586-suse-linux";
-    else if (!llvm::sys::fs::exists("/usr/lib/gcc/i486-slackware-linux", Exists)
-            && Exists)
-      GccTriple = "i486-slackware-linux";
-  } else if (Arch == llvm::Triple::ppc) {
-    if (!llvm::sys::fs::exists("/usr/lib/powerpc-linux-gnu", Exists) && Exists)
-      GccTriple = "powerpc-linux-gnu";
-    else if (!llvm::sys::fs::exists("/usr/lib/gcc/powerpc-unknown-linux-gnu",
-                                    Exists) && Exists)
-      GccTriple = "powerpc-unknown-linux-gnu";
-  } else if (Arch == llvm::Triple::ppc64) {
-    if (!llvm::sys::fs::exists("/usr/lib/gcc/powerpc64-unknown-linux-gnu",
-                               Exists) && Exists)
-      GccTriple = "powerpc64-unknown-linux-gnu";
-    else if (!llvm::sys::fs::exists("/usr/lib64/gcc/"
-                                    "powerpc64-unknown-linux-gnu", Exists) &&
-             Exists)
-      GccTriple = "powerpc64-unknown-linux-gnu";
-  }
-
-  std::string Base = findGCCBaseLibDir(getDriver(), GccTriple);
+  GCCInstallationDetector GCCInstallation(getDriver());
 
   // OpenSuse stores the linker with the compiler, add that to the search
   // path.
   ToolChain::path_list &PPaths = getProgramPaths();
-  PPaths.push_back(Base + "/../../../../" + GccTriple + "/bin");
+  PPaths.push_back(GCCInstallation.getParentLibPath() + "/../" +
+                   GCCInstallation.getTriple() + "/bin");
 
   Linker = GetProgramPath("ld");
 
@@ -1690,34 +1720,38 @@
   // 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");
-
     // Add the multilib suffixed paths.
-    if (!Base.empty() && !GccTriple.empty()) {
-      addPathIfExists(Base + Suffix, Paths);
-      addPathIfExists(Base + "/../../../../" + GccTriple + "/lib/../" +
-                      Multilib, Paths);
-      addPathIfExists(Base + "/../../../../" + Multilib, Paths);
+    if (GCCInstallation.isValid()) {
+      const std::string &LibPath = GCCInstallation.getParentLibPath();
+      const std::string &GccTriple = GCCInstallation.getTriple();
+      // 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(LibPath + "/../" + GccTriple + "/lib/../lib");
+
+      addPathIfExists(GCCInstallation.getInstallPath() + Suffix, Paths);
+      addPathIfExists(LibPath + "/../" + GccTriple + "/lib/../" + Multilib,
+                      Paths);
+      addPathIfExists(LibPath + "/../" + Multilib, Paths);
     }
     addPathIfExists(SysRoot + "/lib/../" + Multilib, Paths);
     addPathIfExists(SysRoot + "/usr/lib/../" + Multilib, Paths);
   }
 
   // Add the non-multiplib suffixed paths (if potentially different).
-  if (!Base.empty() && !GccTriple.empty()) {
+  if (GCCInstallation.isValid()) {
+    const std::string &LibPath = GCCInstallation.getParentLibPath();
+    const std::string &GccTriple = GCCInstallation.getTriple();
     if (!Suffix.empty() || !HasMultilib(Arch, Distro))
-      addPathIfExists(Base, Paths);
-    addPathIfExists(Base + "/../../../../" + GccTriple + "/lib", Paths);
-    addPathIfExists(Base + "/../../..", Paths);
+      addPathIfExists(GCCInstallation.getInstallPath(), Paths);
+    addPathIfExists(LibPath + "/../" + GccTriple + "/lib", Paths);
+    addPathIfExists(LibPath, Paths);
   }
   addPathIfExists(SysRoot + "/lib", Paths);
   addPathIfExists(SysRoot + "/usr/lib", Paths);
 
-  if (Arch == getArch() && IsUbuntu(Distro))
-    Paths.push_back(SysRoot + "/usr/lib/" + GccTriple);
+  if (GCCInstallation.isValid() && Arch == getArch() && IsUbuntu(Distro))
+    Paths.push_back(SysRoot + "/usr/lib/" + GCCInstallation.getTriple());
 }
 
 bool Linux::HasNativeLLVMSupport() const {





More information about the cfe-commits mailing list