[clang] 96318f6 - [Driver] Perform Linux distribution detection only once

Dmitry Antipov via cfe-commits cfe-commits at lists.llvm.org
Fri Sep 25 22:50:43 PDT 2020


Author: Dmitry Antipov
Date: 2020-09-26T08:44:08+03:00
New Revision: 96318f64a7864747ebbb4e33cb75b0dea465abfc

URL: https://github.com/llvm/llvm-project/commit/96318f64a7864747ebbb4e33cb75b0dea465abfc
DIFF: https://github.com/llvm/llvm-project/commit/96318f64a7864747ebbb4e33cb75b0dea465abfc.diff

LOG: [Driver] Perform Linux distribution detection only once

Differential Revision: https://reviews.llvm.org/D87187

Added: 
    

Modified: 
    clang/include/clang/Driver/Distro.h
    clang/lib/Driver/Distro.cpp

Removed: 
    


################################################################################
diff  --git a/clang/include/clang/Driver/Distro.h b/clang/include/clang/Driver/Distro.h
index 038d4ce75d80..1ebc682d8414 100644
--- a/clang/include/clang/Driver/Distro.h
+++ b/clang/include/clang/Driver/Distro.h
@@ -23,6 +23,8 @@ namespace driver {
 class Distro {
 public:
   enum DistroType {
+    // Special value means that no detection was performed yet.
+    UninitializedDistro,
     // 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().

diff  --git a/clang/lib/Driver/Distro.cpp b/clang/lib/Driver/Distro.cpp
index 4d58ad1ae78c..02a71cbd5a9c 100644
--- a/clang/lib/Driver/Distro.cpp
+++ b/clang/lib/Driver/Distro.cpp
@@ -15,76 +15,106 @@
 #include "llvm/Support/ErrorOr.h"
 #include "llvm/Support/Host.h"
 #include "llvm/Support/MemoryBuffer.h"
+#include "llvm/Support/Threading.h"
 
 using namespace clang::driver;
 using namespace clang;
 
-static Distro::DistroType DetectDistro(llvm::vfs::FileSystem &VFS,
-                                       const llvm::Triple &TargetOrHost) {
-  // If we don't target Linux, no need to check the distro. This saves a few
-  // OS calls.
-  if (!TargetOrHost.isOSLinux())
+static Distro::DistroType DetectOsRelease(llvm::vfs::FileSystem &VFS) {
+  llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> File =
+      VFS.getBufferForFile("/etc/os-release");
+  if (!File)
+    File = VFS.getBufferForFile("/usr/lib/os-release");
+  if (!File)
     return Distro::UnknownDistro;
 
-  // If the host is not running Linux, and we're backed by a real file system,
-  // no need to check the distro. This is the case where someone is
-  // cross-compiling from BSD or Windows to Linux, and it would be meaningless
-  // to try to figure out the "distro" of the non-Linux host.
-  IntrusiveRefCntPtr<llvm::vfs::FileSystem> RealFS =
-      llvm::vfs::getRealFileSystem();
-  llvm::Triple HostTriple(llvm::sys::getProcessTriple());
-  if (!HostTriple.isOSLinux() && &VFS == RealFS.get())
-    return Distro::UnknownDistro;
+  SmallVector<StringRef, 16> Lines;
+  File.get()->getBuffer().split(Lines, "\n");
+  Distro::DistroType Version = Distro::UnknownDistro;
+
+  // Obviously this can be improved a lot.
+  for (StringRef Line : Lines)
+    if (Version == Distro::UnknownDistro && Line.startswith("ID="))
+      Version = llvm::StringSwitch<Distro::DistroType>(Line.substr(3))
+                    .Case("fedora", Distro::Fedora)
+                    .Case("gentoo", Distro::Gentoo)
+                    .Case("arch", Distro::ArchLinux)
+                    // On SLES, /etc/os-release was introduced in SLES 11.
+                    .Case("sles", Distro::OpenSUSE)
+                    .Case("opensuse", Distro::OpenSUSE)
+                    .Case("exherbo", Distro::Exherbo)
+                    .Default(Distro::UnknownDistro);
+  return Version;
+}
 
+static Distro::DistroType DetectLsbRelease(llvm::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)
-                      .Case("artful", Distro::UbuntuArtful)
-                      .Case("bionic", Distro::UbuntuBionic)
-                      .Case("cosmic", Distro::UbuntuCosmic)
-                      .Case("disco", Distro::UbuntuDisco)
-                      .Case("eoan", Distro::UbuntuEoan)
-                      .Case("focal", Distro::UbuntuFocal)
-                      .Case("groovy", Distro::UbuntuGroovy)
-                      .Default(Distro::UnknownDistro);
-    if (Version != Distro::UnknownDistro)
-      return Version;
-  }
+  if (!File)
+    return Distro::UnknownDistro;
+
+  SmallVector<StringRef, 16> Lines;
+  File.get()->getBuffer().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)
+                    .Case("artful", Distro::UbuntuArtful)
+                    .Case("bionic", Distro::UbuntuBionic)
+                    .Case("cosmic", Distro::UbuntuCosmic)
+                    .Case("disco", Distro::UbuntuDisco)
+                    .Case("eoan", Distro::UbuntuEoan)
+                    .Case("focal", Distro::UbuntuFocal)
+                    .Case("groovy", Distro::UbuntuGroovy)
+                    .Default(Distro::UnknownDistro);
+  return Version;
+}
+
+static Distro::DistroType DetectDistro(llvm::vfs::FileSystem &VFS) {
+  Distro::DistroType Version = Distro::UnknownDistro;
+
+  // Newer freedesktop.org's compilant systemd-based systems
+  // should provide /etc/os-release or /usr/lib/os-release.
+  Version = DetectOsRelease(VFS);
+  if (Version != Distro::UnknownDistro)
+    return Version;
+
+  // Older systems might provide /etc/lsb-release.
+  Version = DetectLsbRelease(VFS);
+  if (Version != Distro::UnknownDistro)
+    return Version;
+
+  // Otherwise try some distro-specific quirks for RedHat...
+  llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> File =
+      VFS.getBufferForFile("/etc/redhat-release");
 
-  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")) {
+        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)
@@ -95,6 +125,7 @@ static Distro::DistroType DetectDistro(llvm::vfs::FileSystem &VFS,
     return Distro::UnknownDistro;
   }
 
+  // ...for Debian
   File = VFS.getBufferForFile("/etc/debian_version");
   if (File) {
     StringRef Data = File.get()->getBuffer();
@@ -130,18 +161,20 @@ static Distro::DistroType DetectDistro(llvm::vfs::FileSystem &VFS,
         .Default(Distro::UnknownDistro);
   }
 
+  // ...for SUSE
   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) {
+    for (const StringRef &Line : Lines) {
       if (!Line.trim().startswith("VERSION"))
         continue;
       std::pair<StringRef, StringRef> SplitLine = Line.split('=');
       // Old versions have split VERSION and PATCHLEVEL
       // Newer versions use VERSION = x.y
-      std::pair<StringRef, StringRef> SplitVer = SplitLine.second.trim().split('.');
+      std::pair<StringRef, StringRef> SplitVer =
+          SplitLine.second.trim().split('.');
       int Version;
 
       // OpenSUSE/SLES 10 and older are not supported and not compatible
@@ -153,6 +186,7 @@ static Distro::DistroType DetectDistro(llvm::vfs::FileSystem &VFS,
     return Distro::UnknownDistro;
   }
 
+  // ...and others.
   if (VFS.exists("/etc/exherbo-release"))
     return Distro::Exherbo;
 
@@ -168,5 +202,34 @@ static Distro::DistroType DetectDistro(llvm::vfs::FileSystem &VFS,
   return Distro::UnknownDistro;
 }
 
+static Distro::DistroType GetDistro(llvm::vfs::FileSystem &VFS,
+                                    const llvm::Triple &TargetOrHost) {
+  // If we don't target Linux, no need to check the distro. This saves a few
+  // OS calls.
+  if (!TargetOrHost.isOSLinux())
+    return Distro::UnknownDistro;
+
+  // True if we're backed by a real file system.
+  const bool onRealFS = (llvm::vfs::getRealFileSystem() == &VFS);
+
+  // If the host is not running Linux, and we're backed by a real file
+  // system, no need to check the distro. This is the case where someone
+  // is cross-compiling from BSD or Windows to Linux, and it would be
+  // meaningless to try to figure out the "distro" of the non-Linux host.
+  llvm::Triple HostTriple(llvm::sys::getProcessTriple());
+  if (!HostTriple.isOSLinux() && onRealFS)
+    return Distro::UnknownDistro;
+
+  if (onRealFS) {
+    // If we're backed by a real file system, perform
+    // the detection only once and save the result.
+    static Distro::DistroType LinuxDistro = DetectDistro(VFS);
+    return LinuxDistro;
+  }
+  // This is mostly for passing tests which uses llvm::vfs::InMemoryFileSystem,
+  // which is not "real".
+  return DetectDistro(VFS);
+}
+
 Distro::Distro(llvm::vfs::FileSystem &VFS, const llvm::Triple &TargetOrHost)
-    : DistroVal(DetectDistro(VFS, TargetOrHost)) {}
+    : DistroVal(GetDistro(VFS, TargetOrHost)) {}


        


More information about the cfe-commits mailing list