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

Chandler Carruth chandlerc at gmail.com
Tue Oct 4 14:22:36 PDT 2011


Author: chandlerc
Date: Tue Oct  4 16:22:33 2011
New Revision: 141120

URL: http://llvm.org/viewvc/llvm-project?rev=141120&view=rev
Log:
Rework the search for a GCC installation still further. This combines
two fundamental changes, as they ended up being interrelated.

The first is to walk from the root down through the filesystem so that
we prune subtrees which do not exist early. This greatly reduces the
filesystem traffic of this routine. We store the "best" GCC version we
encounter, and look at all of the GCC installations available.

Also, we look through GCC versions by scanning the directory rather than
using a hard-coded list of versions. This has several benefits. It makes
it much more efficient to locate a GCC installation even in the presence
of a large number of different options by simply reading the directory
once. It also future-proofs us as new GCC versions are released and
installed. We no longer have a hard coded list of version numbers, and
won't need to manually updated it. We can still filter out known-bad
versions as needed. Currently I've left in filtering for all GCC
installations prior to 4.1.1, as that was the first one supported
previously.

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=141120&r1=141119&r2=141120&view=diff
==============================================================================
--- cfe/trunk/lib/Driver/ToolChains.cpp (original)
+++ cfe/trunk/lib/Driver/ToolChains.cpp Tue Oct  4 16:22:33 2011
@@ -1490,6 +1490,42 @@
 /// information about it. It starts from the host information provided to the
 /// Driver, and has logic for fuzzing that where appropriate.
 class GCCInstallationDetector {
+  /// \brief Struct to store and manipulate GCC versions.
+  ///
+  /// We rely on assumptions about the form and structure of GCC version
+  /// numbers: they consist of at most three '.'-separated components, and each
+  /// component is a non-negative integer.
+  struct GCCVersion {
+    unsigned Major, Minor, Patch;
+
+    static GCCVersion Parse(StringRef VersionText) {
+      const GCCVersion BadVersion = {};
+      std::pair<StringRef, StringRef> First = VersionText.split('.');
+      std::pair<StringRef, StringRef> Second = First.second.split('.');
+
+      GCCVersion GoodVersion = {};
+      if (First.first.getAsInteger(10, GoodVersion.Major))
+        return BadVersion;
+      if (Second.first.getAsInteger(10, GoodVersion.Minor))
+        return BadVersion;
+      if (!Second.first.empty())
+        if (Second.first.getAsInteger(10, GoodVersion.Patch))
+          return BadVersion;
+      return GoodVersion;
+    }
+
+    bool operator<(const GCCVersion &RHS) const {
+      if (Major < RHS.Major) return true;
+      if (Major > RHS.Major) return false;
+      if (Minor < RHS.Minor) return true;
+      if (Minor > RHS.Minor) return false;
+      return Patch < RHS.Patch;
+    }
+    bool operator>(const GCCVersion &RHS) const { return RHS < *this; }
+    bool operator<=(const GCCVersion &RHS) const { return !(*this > RHS); }
+    bool operator>=(const GCCVersion &RHS) const { return !(*this < RHS); }
+  };
+
   bool IsValid;
   std::string GccTriple;
 
@@ -1600,63 +1636,62 @@
     // specific triple is detected.
     CandidateTriples.push_back(D.DefaultHostTriple);
 
-    // Loop over the various components which exist and select the best GCC
-    // installation available. GCC installs are ranked based on age, triple
-    // accuracy, and architecture specificity in that order. The inverted walk
-    // requires testing the filesystem more times than is ideal, but shouldn't
-    // matter in practice as this is once on startup.
-    // FIXME: Instead of this, we should walk from the root down through each
-    // layer, and if it is "better" than prior installations found, use it.
-    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"};
+    // Compute the set of prefixes for our search.
     SmallVector<std::string, 8> Prefixes(D.PrefixDirs.begin(),
                                          D.PrefixDirs.end());
     Prefixes.push_back(D.SysRoot + "/usr");
-    IsValid = true;
-    for (unsigned i = 0; i < llvm::array_lengthof(GccVersions); ++i) {
-      for (unsigned j = 0, je = CandidateTriples.size(); j < je; ++j) {
-        GccTriple = CandidateTriples[j];
-        for (unsigned k = 0, ke = CandidateLibDirs.size(); k < ke; ++k) {
-          const std::string LibDir = CandidateLibDirs[k].str() + "/";
-          for (unsigned l = 0, le = Prefixes.size(); l < le; ++l) {
-            if (!PathExists(Prefixes[l]))
-              continue;
-
-            const std::string TripleDir = Prefixes[l] + LibDir + GccTriple;
-            GccInstallPath = TripleDir + "/" + GccVersions[i];
-            GccParentLibPath = GccInstallPath + "/../../..";
-            if (PathExists(GccInstallPath + "/crtbegin.o"))
-              return;
-
-            // Try an install directory with an extra triple in it.
-            GccInstallPath =
-              TripleDir + "/gcc/" + GccTriple + "/" + GccVersions[i];
-            GccParentLibPath = GccInstallPath + "/../../../..";
-            if (PathExists(GccInstallPath + "/crtbegin.o"))
-              return;
-
-            if (GccTriple != "i386-linux-gnu")
-              continue;
-
-            // Ubuntu 11.04 uses an unusual path.
-            GccInstallPath =
-              TripleDir + "/gcc/i686-linux-gnu/" + GccVersions[i];
-            GccParentLibPath = GccInstallPath + "/../../../..";
-            if (PathExists(GccInstallPath + "/crtbegin.o"))
-              return;
+
+    // Loop over the various components which exist and select the best GCC
+    // installation available. GCC installs are ranked by version number.
+    static const GCCVersion MinVersion = { 4, 1, 1 };
+    GCCVersion BestVersion = {};
+    for (unsigned i = 0, ie = Prefixes.size(); i < ie; ++i) {
+      if (!PathExists(Prefixes[i]))
+        continue;
+      for (unsigned j = 0, je = CandidateLibDirs.size(); j < je; ++j) {
+        const std::string LibDir = Prefixes[i] + CandidateLibDirs[j].str();
+        if (!PathExists(LibDir))
+          continue;
+        for (unsigned k = 0, ke = CandidateTriples.size(); k < ke; ++k) {
+          StringRef CandidateTriple = CandidateTriples[k];
+          const std::string TripleDir = LibDir + "/" + CandidateTriple.str();
+          if (!PathExists(TripleDir))
+            continue;
+
+          // There are various different suffixes on the triple directory we
+          // check for. We also record what is necessary to walk from each back
+          // up to the lib directory.
+          const std::string Suffixes[] = { "", "/gcc/" + CandidateTriple.str(),
+                                           "/gcc/i686-linux-gnu" };
+          const std::string InstallSuffixes[] = { "/../../..", "/../../../..",
+                                                  "/../../../.." };
+          const unsigned NumSuffixes = (llvm::array_lengthof(Suffixes) -
+                                        (CandidateTriple != "i386-linux-gnu"));
+          for (unsigned l = 0; l < NumSuffixes; ++l) {
+            StringRef Suffix = Suffixes[l];
+            llvm::error_code EC;
+            for (llvm::sys::fs::directory_iterator LI(TripleDir + Suffix, EC),
+                                                   LE;
+                 !EC && LI != LE; LI = LI.increment(EC)) {
+              StringRef VersionText = llvm::sys::path::filename(LI->path());
+              GCCVersion CandidateVersion = GCCVersion::Parse(VersionText);
+              if (CandidateVersion < MinVersion)
+                continue;
+              if (CandidateVersion <= BestVersion)
+                continue;
+              if (!PathExists(LI->path() + "/crtbegin.o"))
+                continue;
+
+              BestVersion = CandidateVersion;
+              GccTriple = CandidateTriple.str();
+              GccInstallPath = LI->path();
+              GccParentLibPath = GccInstallPath + InstallSuffixes[l];
+              IsValid = true;
+            }
           }
         }
       }
     }
-    GccTriple.clear();
-    GccInstallPath.clear();
-    GccParentLibPath.clear();
-    IsValid = false;
   }
 
   /// \brief Check whether we detected a valid GCC install.





More information about the cfe-commits mailing list