r288060 - [Driver] Refactor distro detection & classification as a separate API

Michal Gorny via cfe-commits cfe-commits at lists.llvm.org
Mon Nov 28 13:11:14 PST 2016


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;
 }




More information about the cfe-commits mailing list