From: Chandler Carruth Date: Sun, 6 Nov 2011 09:39:46 +0000 (+0000) Subject: Lift the GCCVersion type into the header file and start persisting it in X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=0e29dbb96121386c2e6d03b59eebf2c329a2a578;p=clang Lift the GCCVersion type into the header file and start persisting it in the detected GCC installation. This allows us to expose another aspect of what we detected: the GCC version. This will be used shortly. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@143871 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/lib/Driver/ToolChains.cpp b/lib/Driver/ToolChains.cpp index 0a8aa7a4a7..07be52b20f 100644 --- a/lib/Driver/ToolChains.cpp +++ b/lib/Driver/ToolChains.cpp @@ -1519,87 +1519,62 @@ static LinuxDistro DetectLinuxDistro(llvm::Triple::ArchType Arch) { return UnknownDistro; } -/// \brief Struct to store and manipulate GCC versions. +/// \brief Parse a GCCVersion object out of a string of text. /// -/// 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 except for the last component. For the -/// last component we are very flexible in order to tolerate release candidates -/// or 'x' wildcards. -/// -/// Note that the ordering established among GCCVersions is based on the -/// preferred version string to use. For example we prefer versions without -/// a hard-coded patch number to those with a hard coded patch number. -/// -/// Currently this doesn't provide any logic for textual suffixes to patches in -/// the way that (for example) Debian's version format does. If that ever -/// becomes necessary, it can be added. -struct Linux::GCCVersion { - /// \brief The unparsed text of the version. - StringRef Text; - - /// \brief The parsed major, minor, and patch numbers. - int Major, Minor, Patch; - - /// \brief Any textual suffix on the patch number. - StringRef PatchSuffix; - - static GCCVersion Parse(StringRef VersionText) { - const GCCVersion BadVersion = { VersionText, -1, -1, -1, "" }; - std::pair First = VersionText.split('.'); - std::pair Second = First.second.split('.'); - - GCCVersion GoodVersion = { VersionText, -1, -1, -1, "" }; - if (First.first.getAsInteger(10, GoodVersion.Major) || - GoodVersion.Major < 0) - return BadVersion; - if (Second.first.getAsInteger(10, GoodVersion.Minor) || - GoodVersion.Minor < 0) - return BadVersion; - - // First look for a number prefix and parse that if present. Otherwise just - // stash the entire patch string in the suffix, and leave the number - // unspecified. This covers versions strings such as: - // 4.4 - // 4.4.0 - // 4.4.x - // 4.4.2-rc4 - // 4.4.x-patched - // And retains any patch number it finds. - StringRef PatchText = GoodVersion.PatchSuffix = Second.second; - if (!PatchText.empty()) { - if (unsigned EndNumber = PatchText.find_first_not_of("0123456789")) { - // Try to parse the number and any suffix. - if (PatchText.slice(0, EndNumber).getAsInteger(10, GoodVersion.Patch) || - GoodVersion.Patch < 0) - return BadVersion; - GoodVersion.PatchSuffix = PatchText.substr(EndNumber); - } +/// This is the primary means of forming GCCVersion objects. +/*static*/ Linux::GCCVersion Linux::GCCVersion::Parse(StringRef VersionText) { + const GCCVersion BadVersion = { VersionText, -1, -1, -1, "" }; + std::pair First = VersionText.split('.'); + std::pair Second = First.second.split('.'); + + GCCVersion GoodVersion = { VersionText, -1, -1, -1, "" }; + if (First.first.getAsInteger(10, GoodVersion.Major) || + GoodVersion.Major < 0) + return BadVersion; + if (Second.first.getAsInteger(10, GoodVersion.Minor) || + GoodVersion.Minor < 0) + return BadVersion; + + // First look for a number prefix and parse that if present. Otherwise just + // stash the entire patch string in the suffix, and leave the number + // unspecified. This covers versions strings such as: + // 4.4 + // 4.4.0 + // 4.4.x + // 4.4.2-rc4 + // 4.4.x-patched + // And retains any patch number it finds. + StringRef PatchText = GoodVersion.PatchSuffix = Second.second; + if (!PatchText.empty()) { + if (unsigned EndNumber = PatchText.find_first_not_of("0123456789")) { + // Try to parse the number and any suffix. + if (PatchText.slice(0, EndNumber).getAsInteger(10, GoodVersion.Patch) || + GoodVersion.Patch < 0) + return BadVersion; + GoodVersion.PatchSuffix = PatchText.substr(EndNumber); } - - 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 GoodVersion; +} - // Note that we rank versions with *no* patch specified is better than ones - // hard-coding a patch version. Thus if the RHS has no patch, it always - // wins, and the LHS only wins if it has no patch and the RHS does have - // a patch. - if (RHS.Patch == -1) return true; if (Patch == -1) return false; - if (Patch < RHS.Patch) return true; if (Patch > RHS.Patch) return false; +/// \brief Less-than for GCCVersion, implementing a Strict Weak Ordering. +bool Linux::GCCVersion::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; - // Finally, between completely tied version numbers, the version with the - // suffix loses as we prefer full releases. - if (RHS.PatchSuffix.empty()) return true; - return false; - } - 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); } -}; + // Note that we rank versions with *no* patch specified is better than ones + // hard-coding a patch version. Thus if the RHS has no patch, it always + // wins, and the LHS only wins if it has no patch and the RHS does have + // a patch. + if (RHS.Patch == -1) return true; if (Patch == -1) return false; + if (Patch < RHS.Patch) return true; if (Patch > RHS.Patch) return false; + + // Finally, between completely tied version numbers, the version with the + // suffix loses as we prefer full releases. + if (RHS.PatchSuffix.empty()) return true; + return false; +} /// \brief Construct a GCCInstallationDetector from the driver. /// @@ -1656,7 +1631,7 @@ Linux::GCCInstallationDetector::GCCInstallationDetector(const Driver &D) // Loop over the various components which exist and select the best GCC // installation available. GCC installs are ranked by version number. - GCCVersion BestVersion = GCCVersion::Parse("0.0.0"); + Version = GCCVersion::Parse("0.0.0"); for (unsigned i = 0, ie = Prefixes.size(); i < ie; ++i) { if (!llvm::sys::fs::exists(Prefixes[i])) continue; @@ -1665,7 +1640,7 @@ Linux::GCCInstallationDetector::GCCInstallationDetector(const Driver &D) if (!llvm::sys::fs::exists(LibDir)) continue; for (unsigned k = 0, ke = CandidateTriples.size(); k < ke; ++k) - ScanLibDirForGCCTriple(LibDir, CandidateTriples[k], BestVersion); + ScanLibDirForGCCTriple(LibDir, CandidateTriples[k]); } } } @@ -1730,8 +1705,7 @@ Linux::GCCInstallationDetector::GCCInstallationDetector(const Driver &D) } void Linux::GCCInstallationDetector::ScanLibDirForGCCTriple( - const std::string &LibDir, StringRef CandidateTriple, - GCCVersion &BestVersion) { + const std::string &LibDir, StringRef CandidateTriple) { // There are various different suffixes involving the triple we // check for. We also record what is necessary to walk from each back // up to the lib directory. @@ -1763,12 +1737,12 @@ void Linux::GCCInstallationDetector::ScanLibDirForGCCTriple( static const GCCVersion MinVersion = { "4.1.1", 4, 1, 1, "" }; if (CandidateVersion < MinVersion) continue; - if (CandidateVersion <= BestVersion) + if (CandidateVersion <= Version) continue; if (!llvm::sys::fs::exists(LI->path() + "/crtbegin.o")) continue; - BestVersion = CandidateVersion; + Version = CandidateVersion; GccTriple = CandidateTriple.str(); // FIXME: We hack together the directory name here instead of // using LI to ensure stable path separators across Windows and diff --git a/lib/Driver/ToolChains.h b/lib/Driver/ToolChains.h index 57b14cc8dd..7599cd6b45 100644 --- a/lib/Driver/ToolChains.h +++ b/lib/Driver/ToolChains.h @@ -372,7 +372,38 @@ public: }; class LLVM_LIBRARY_VISIBILITY Linux : public Generic_ELF { - struct GCCVersion; + /// \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 except for the last component. For + /// the last component we are very flexible in order to tolerate release + /// candidates or 'x' wildcards. + /// + /// Note that the ordering established among GCCVersions is based on the + /// preferred version string to use. For example we prefer versions without + /// a hard-coded patch number to those with a hard coded patch number. + /// + /// Currently this doesn't provide any logic for textual suffixes to patches + /// in the way that (for example) Debian's version format does. If that ever + /// becomes necessary, it can be added. + struct GCCVersion { + /// \brief The unparsed text of the version. + StringRef Text; + + /// \brief The parsed major, minor, and patch numbers. + int Major, Minor, Patch; + + /// \brief Any textual suffix on the patch number. + StringRef PatchSuffix; + + static GCCVersion Parse(StringRef VersionText); + bool operator<(const GCCVersion &RHS) const; + 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); } + }; + /// \brief This is a class to find a viable GCC installation for Clang to /// use. @@ -389,6 +420,8 @@ class LLVM_LIBRARY_VISIBILITY Linux : public Generic_ELF { std::string GccInstallPath; std::string GccParentLibPath; + GCCVersion Version; + public: GCCInstallationDetector(const Driver &D); @@ -404,14 +437,16 @@ class LLVM_LIBRARY_VISIBILITY Linux : public Generic_ELF { /// \brief Get the detected GCC parent lib path. StringRef getParentLibPath() const { return GccParentLibPath; } + /// \brief Get the detected GCC version string. + StringRef getVersion() const { return Version.Text; } + private: static void CollectLibDirsAndTriples(llvm::Triple::ArchType HostArch, SmallVectorImpl &LibDirs, SmallVectorImpl &Triples); void ScanLibDirForGCCTriple(const std::string &LibDir, - StringRef CandidateTriple, - GCCVersion &BestVersion); + StringRef CandidateTriple); }; GCCInstallationDetector GCCInstallation;