Author: mgorny Date: Mon Nov 28 15:11:14 2016 New Revision: 288060 URL: http://llvm.org/viewvc/llvm-project?rev=288060&view=rev Log: [Driver] Refactor distro detection & classification as a separate API
Refactor the Distro enum along with helper functions into a full-fledged Distro class, inspired by llvm::Triple, and make it a public API. The new class wraps the enum with necessary comparison operators, adding the convenience Is*() methods and a constructor performing the detection. The public API is needed to run the unit tests (D25869). Differential Revision: https://reviews.llvm.org/D25949 Added: cfe/trunk/include/clang/Driver/Distro.h cfe/trunk/lib/Driver/Distro.cpp Modified: cfe/trunk/lib/Driver/CMakeLists.txt cfe/trunk/lib/Driver/ToolChains.cpp Added: cfe/trunk/include/clang/Driver/Distro.h URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Driver/Distro.h?rev=288060&view=auto ============================================================================== --- cfe/trunk/include/clang/Driver/Distro.h (added) +++ cfe/trunk/include/clang/Driver/Distro.h Mon Nov 28 15:11:14 2016 @@ -0,0 +1,122 @@ +//===--- Distro.h - Linux distribution detection support --------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_DRIVER_DISTRO_H +#define LLVM_CLANG_DRIVER_DISTRO_H + +#include "clang/Basic/VirtualFileSystem.h" + +namespace clang { +namespace driver { + +/// Distro - Helper class for detecting and classifying Linux distributions. +/// +/// This class encapsulates the clang Linux distribution detection mechanism +/// as well as helper functions that match the specific (versioned) results +/// into wider distribution classes. +class Distro { +public: + enum DistroType { + // NB: Releases of a particular Linux distro should be kept together + // in this enum, because some tests are done by integer comparison against + // the first and last known member in the family, e.g. IsRedHat(). + ArchLinux, + DebianLenny, + DebianSqueeze, + DebianWheezy, + DebianJessie, + DebianStretch, + Exherbo, + RHEL5, + RHEL6, + RHEL7, + Fedora, + OpenSUSE, + UbuntuHardy, + UbuntuIntrepid, + UbuntuJaunty, + UbuntuKarmic, + UbuntuLucid, + UbuntuMaverick, + UbuntuNatty, + UbuntuOneiric, + UbuntuPrecise, + UbuntuQuantal, + UbuntuRaring, + UbuntuSaucy, + UbuntuTrusty, + UbuntuUtopic, + UbuntuVivid, + UbuntuWily, + UbuntuXenial, + UbuntuYakkety, + UbuntuZesty, + UnknownDistro + }; + +private: + /// The distribution, possibly with specific version. + DistroType DistroVal; + +public: + /// @name Constructors + /// @{ + + /// Default constructor leaves the distribution unknown. + Distro() : DistroVal() {} + + /// Constructs a Distro type for specific distribution. + Distro(DistroType D) : DistroVal(D) {} + + /// Detects the distribution using specified VFS. + explicit Distro(clang::vfs::FileSystem& VFS); + + bool operator==(const Distro &Other) const { + return DistroVal == Other.DistroVal; + } + + bool operator!=(const Distro &Other) const { + return DistroVal != Other.DistroVal; + } + + bool operator>=(const Distro &Other) const { + return DistroVal >= Other.DistroVal; + } + + bool operator<=(const Distro &Other) const { + return DistroVal <= Other.DistroVal; + } + + /// @} + /// @name Convenience Predicates + /// @{ + + bool IsRedhat() const { + return DistroVal == Fedora || (DistroVal >= RHEL5 && DistroVal <= RHEL7); + } + + bool IsOpenSUSE() const { + return DistroVal == OpenSUSE; + } + + bool IsDebian() const { + return DistroVal >= DebianLenny && DistroVal <= DebianStretch; + } + + bool IsUbuntu() const { + return DistroVal >= UbuntuHardy && DistroVal <= UbuntuZesty; + } + + /// @} +}; + +} // end namespace driver +} // end namespace clang + +#endif Modified: cfe/trunk/lib/Driver/CMakeLists.txt URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Driver/CMakeLists.txt?rev=288060&r1=288059&r2=288060&view=diff ============================================================================== --- cfe/trunk/lib/Driver/CMakeLists.txt (original) +++ cfe/trunk/lib/Driver/CMakeLists.txt Mon Nov 28 15:11:14 2016 @@ -12,6 +12,7 @@ add_clang_library(clangDriver Action.cpp Compilation.cpp CrossWindowsToolChain.cpp + Distro.cpp Driver.cpp DriverOptions.cpp Job.cpp Added: cfe/trunk/lib/Driver/Distro.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Driver/Distro.cpp?rev=288060&view=auto ============================================================================== --- cfe/trunk/lib/Driver/Distro.cpp (added) +++ cfe/trunk/lib/Driver/Distro.cpp Mon Nov 28 15:11:14 2016 @@ -0,0 +1,131 @@ +//===--- Distro.cpp - Linux distribution detection support ------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "clang/Driver/Distro.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/ADT/StringSwitch.h" +#include "llvm/Support/ErrorOr.h" +#include "llvm/Support/MemoryBuffer.h" + +using namespace clang::driver; +using namespace clang; + +static Distro::DistroType DetectDistro(vfs::FileSystem &VFS) { + llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> File = + VFS.getBufferForFile("/etc/lsb-release"); + if (File) { + StringRef Data = File.get()->getBuffer(); + SmallVector<StringRef, 16> Lines; + Data.split(Lines, "\n"); + Distro::DistroType Version = Distro::UnknownDistro; + for (StringRef Line : Lines) + if (Version == Distro::UnknownDistro && Line.startswith("DISTRIB_CODENAME=")) + Version = llvm::StringSwitch<Distro::DistroType>(Line.substr(17)) + .Case("hardy", Distro::UbuntuHardy) + .Case("intrepid", Distro::UbuntuIntrepid) + .Case("jaunty", Distro::UbuntuJaunty) + .Case("karmic", Distro::UbuntuKarmic) + .Case("lucid", Distro::UbuntuLucid) + .Case("maverick", Distro::UbuntuMaverick) + .Case("natty", Distro::UbuntuNatty) + .Case("oneiric", Distro::UbuntuOneiric) + .Case("precise", Distro::UbuntuPrecise) + .Case("quantal", Distro::UbuntuQuantal) + .Case("raring", Distro::UbuntuRaring) + .Case("saucy", Distro::UbuntuSaucy) + .Case("trusty", Distro::UbuntuTrusty) + .Case("utopic", Distro::UbuntuUtopic) + .Case("vivid", Distro::UbuntuVivid) + .Case("wily", Distro::UbuntuWily) + .Case("xenial", Distro::UbuntuXenial) + .Case("yakkety", Distro::UbuntuYakkety) + .Case("zesty", Distro::UbuntuZesty) + .Default(Distro::UnknownDistro); + if (Version != Distro::UnknownDistro) + return Version; + } + + File = VFS.getBufferForFile("/etc/redhat-release"); + if (File) { + StringRef Data = File.get()->getBuffer(); + if (Data.startswith("Fedora release")) + return Distro::Fedora; + if (Data.startswith("Red Hat Enterprise Linux") || + Data.startswith("CentOS") || + Data.startswith("Scientific Linux")) { + if (Data.find("release 7") != StringRef::npos) + return Distro::RHEL7; + else if (Data.find("release 6") != StringRef::npos) + return Distro::RHEL6; + else if (Data.find("release 5") != StringRef::npos) + return Distro::RHEL5; + } + return Distro::UnknownDistro; + } + + File = VFS.getBufferForFile("/etc/debian_version"); + if (File) { + StringRef Data = File.get()->getBuffer(); + // Contents: < major.minor > or < codename/sid > + int MajorVersion; + if (!Data.split('.').first.getAsInteger(10, MajorVersion)) { + switch (MajorVersion) { + case 5: + return Distro::DebianLenny; + case 6: + return Distro::DebianSqueeze; + case 7: + return Distro::DebianWheezy; + case 8: + return Distro::DebianJessie; + case 9: + return Distro::DebianStretch; + default: + return Distro::UnknownDistro; + } + } + return llvm::StringSwitch<Distro::DistroType>(Data.split("\n").first) + .Case("squeeze/sid", Distro::DebianSqueeze) + .Case("wheezy/sid", Distro::DebianWheezy) + .Case("jessie/sid", Distro::DebianJessie) + .Case("stretch/sid", Distro::DebianStretch) + .Default(Distro::UnknownDistro); + } + + File = VFS.getBufferForFile("/etc/SuSE-release"); + if (File) { + StringRef Data = File.get()->getBuffer(); + SmallVector<StringRef, 8> Lines; + Data.split(Lines, "\n"); + for (const StringRef& Line : Lines) { + if (!Line.trim().startswith("VERSION")) + continue; + std::pair<StringRef, StringRef> SplitLine = Line.split('='); + int Version; + // OpenSUSE/SLES 10 and older are not supported and not compatible + // with our rules, so just treat them as Distro::UnknownDistro. + if (!SplitLine.second.trim().getAsInteger(10, Version) && + Version > 10) + return Distro::OpenSUSE; + return Distro::UnknownDistro; + } + return Distro::UnknownDistro; + } + + if (VFS.exists("/etc/exherbo-release")) + return Distro::Exherbo; + + if (VFS.exists("/etc/arch-release")) + return Distro::ArchLinux; + + return Distro::UnknownDistro; +} + +Distro::Distro(vfs::FileSystem &VFS) : DistroVal(DetectDistro(VFS)) {} Modified: cfe/trunk/lib/Driver/ToolChains.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Driver/ToolChains.cpp?rev=288060&r1=288059&r2=288060&view=diff ============================================================================== --- cfe/trunk/lib/Driver/ToolChains.cpp (original) +++ cfe/trunk/lib/Driver/ToolChains.cpp Mon Nov 28 15:11:14 2016 @@ -14,6 +14,7 @@ #include "clang/Basic/VirtualFileSystem.h" #include "clang/Config/config.h" // for GCC_INSTALL_PREFIX #include "clang/Driver/Compilation.h" +#include "clang/Driver/Distro.h" #include "clang/Driver/Driver.h" #include "clang/Driver/DriverDiagnostic.h" #include "clang/Driver/Options.h" @@ -3885,171 +3886,6 @@ void Solaris::AddClangCXXStdlibIncludeAr } } -/// Distribution (very bare-bones at the moment). - -enum Distro { - // NB: Releases of a particular Linux distro should be kept together - // in this enum, because some tests are done by integer comparison against - // the first and last known member in the family, e.g. IsRedHat(). - ArchLinux, - DebianLenny, - DebianSqueeze, - DebianWheezy, - DebianJessie, - DebianStretch, - Exherbo, - RHEL5, - RHEL6, - RHEL7, - Fedora, - OpenSUSE, - UbuntuHardy, - UbuntuIntrepid, - UbuntuJaunty, - UbuntuKarmic, - UbuntuLucid, - UbuntuMaverick, - UbuntuNatty, - UbuntuOneiric, - UbuntuPrecise, - UbuntuQuantal, - UbuntuRaring, - UbuntuSaucy, - UbuntuTrusty, - UbuntuUtopic, - UbuntuVivid, - UbuntuWily, - UbuntuXenial, - UbuntuYakkety, - UbuntuZesty, - UnknownDistro -}; - -static bool IsRedhat(enum Distro Distro) { - return Distro == Fedora || (Distro >= RHEL5 && Distro <= RHEL7); -} - -static bool IsOpenSUSE(enum Distro Distro) { return Distro == OpenSUSE; } - -static bool IsDebian(enum Distro Distro) { - return Distro >= DebianLenny && Distro <= DebianStretch; -} - -static bool IsUbuntu(enum Distro Distro) { - return Distro >= UbuntuHardy && Distro <= UbuntuZesty; -} - -static Distro DetectDistro(vfs::FileSystem &VFS) { - llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> File = - VFS.getBufferForFile("/etc/lsb-release"); - if (File) { - StringRef Data = File.get()->getBuffer(); - SmallVector<StringRef, 16> Lines; - Data.split(Lines, "\n"); - Distro Version = UnknownDistro; - for (StringRef Line : Lines) - if (Version == UnknownDistro && Line.startswith("DISTRIB_CODENAME=")) - Version = llvm::StringSwitch<Distro>(Line.substr(17)) - .Case("hardy", UbuntuHardy) - .Case("intrepid", UbuntuIntrepid) - .Case("jaunty", UbuntuJaunty) - .Case("karmic", UbuntuKarmic) - .Case("lucid", UbuntuLucid) - .Case("maverick", UbuntuMaverick) - .Case("natty", UbuntuNatty) - .Case("oneiric", UbuntuOneiric) - .Case("precise", UbuntuPrecise) - .Case("quantal", UbuntuQuantal) - .Case("raring", UbuntuRaring) - .Case("saucy", UbuntuSaucy) - .Case("trusty", UbuntuTrusty) - .Case("utopic", UbuntuUtopic) - .Case("vivid", UbuntuVivid) - .Case("wily", UbuntuWily) - .Case("xenial", UbuntuXenial) - .Case("yakkety", UbuntuYakkety) - .Case("zesty", UbuntuZesty) - .Default(UnknownDistro); - if (Version != UnknownDistro) - return Version; - } - - File = VFS.getBufferForFile("/etc/redhat-release"); - if (File) { - StringRef Data = File.get()->getBuffer(); - if (Data.startswith("Fedora release")) - return Fedora; - if (Data.startswith("Red Hat Enterprise Linux") || - Data.startswith("CentOS") || - Data.startswith("Scientific Linux")) { - if (Data.find("release 7") != StringRef::npos) - return RHEL7; - else if (Data.find("release 6") != StringRef::npos) - return RHEL6; - else if (Data.find("release 5") != StringRef::npos) - return RHEL5; - } - return UnknownDistro; - } - - File = VFS.getBufferForFile("/etc/debian_version"); - if (File) { - StringRef Data = File.get()->getBuffer(); - // Contents: < major.minor > or < codename/sid > - int MajorVersion; - if (!Data.split('.').first.getAsInteger(10, MajorVersion)) { - switch (MajorVersion) { - case 5: - return DebianLenny; - case 6: - return DebianSqueeze; - case 7: - return DebianWheezy; - case 8: - return DebianJessie; - case 9: - return DebianStretch; - default: - return UnknownDistro; - } - } - return llvm::StringSwitch<Distro>(Data.split("\n").first) - .Case("squeeze/sid", DebianSqueeze) - .Case("wheezy/sid", DebianWheezy) - .Case("jessie/sid", DebianJessie) - .Case("stretch/sid", DebianStretch) - .Default(UnknownDistro); - } - - File = VFS.getBufferForFile("/etc/SuSE-release"); - if (File) { - StringRef Data = File.get()->getBuffer(); - SmallVector<StringRef, 8> Lines; - Data.split(Lines, "\n"); - for (const StringRef& Line : Lines) { - if (!Line.trim().startswith("VERSION")) - continue; - std::pair<StringRef, StringRef> SplitLine = Line.split('='); - int Version; - // OpenSUSE/SLES 10 and older are not supported and not compatible - // with our rules, so just treat them as UnknownDistro. - if (!SplitLine.second.trim().getAsInteger(10, Version) && - Version > 10) - return OpenSUSE; - return UnknownDistro; - } - return UnknownDistro; - } - - if (VFS.exists("/etc/exherbo-release")) - return Exherbo; - - if (VFS.exists("/etc/arch-release")) - return ArchLinux; - - return UnknownDistro; -} - /// \brief Get our best guess at the multiarch triple for a target. /// /// Debian-based systems are starting to use a multiarch setup where they use @@ -4228,9 +4064,9 @@ Linux::Linux(const Driver &D, const llvm GCCInstallation.getTriple().str() + "/bin") .str()); - Distro Distro = DetectDistro(D.getVFS()); + Distro Distro(D.getVFS()); - if (IsOpenSUSE(Distro) || IsUbuntu(Distro)) { + if (Distro.IsOpenSUSE() || Distro.IsUbuntu()) { ExtraOpts.push_back("-z"); ExtraOpts.push_back("relro"); } @@ -4250,23 +4086,23 @@ Linux::Linux(const Driver &D, const llvm // ABI requires a mapping between the GOT and the symbol table. // Android loader does not support .gnu.hash. if (!IsMips && !IsAndroid) { - if (IsRedhat(Distro) || IsOpenSUSE(Distro) || - (IsUbuntu(Distro) && Distro >= UbuntuMaverick)) + if (Distro.IsRedhat() || Distro.IsOpenSUSE() || + (Distro.IsUbuntu() && Distro >= Distro::UbuntuMaverick)) ExtraOpts.push_back("--hash-style=gnu"); - if (IsDebian(Distro) || IsOpenSUSE(Distro) || Distro == UbuntuLucid || - Distro == UbuntuJaunty || Distro == UbuntuKarmic) + if (Distro.IsDebian() || Distro.IsOpenSUSE() || Distro == Distro::UbuntuLucid || + Distro == Distro::UbuntuJaunty || Distro == Distro::UbuntuKarmic) ExtraOpts.push_back("--hash-style=both"); } - if (IsRedhat(Distro) && Distro != RHEL5 && Distro != RHEL6) + if (Distro.IsRedhat() && Distro != Distro::RHEL5 && Distro != Distro::RHEL6) ExtraOpts.push_back("--no-add-needed"); #ifdef ENABLE_LINKER_BUILD_ID ExtraOpts.push_back("--build-id"); #endif - if (IsOpenSUSE(Distro)) + if (Distro.IsOpenSUSE()) ExtraOpts.push_back("--enable-new-dtags"); // The selection of paths to try here is designed to match the patterns which @@ -4432,7 +4268,7 @@ std::string Linux::getDynamicLinker(cons const llvm::Triple::ArchType Arch = getArch(); const llvm::Triple &Triple = getTriple(); - const enum Distro Distro = DetectDistro(getDriver().getVFS()); + const Distro Distro(getDriver().getVFS()); if (Triple.isAndroid()) return Triple.isArch64Bit() ? "/system/bin/linker64" : "/system/bin/linker"; @@ -4550,8 +4386,8 @@ std::string Linux::getDynamicLinker(cons } } - if (Distro == Exherbo && (Triple.getVendor() == llvm::Triple::UnknownVendor || - Triple.getVendor() == llvm::Triple::PC)) + if (Distro == Distro::Exherbo && (Triple.getVendor() == llvm::Triple::UnknownVendor || + Triple.getVendor() == llvm::Triple::PC)) return "/usr/" + Triple.str() + "/lib/" + Loader; return "/" + LibDir + "/" + Loader; } _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits