dmantipov updated this revision to Diff 293949.
dmantipov added a comment.

IIUC compiler driver is not intended to be multithreaded. But OK, here is the 
version with llvm::call_once(...).


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D87187/new/

https://reviews.llvm.org/D87187

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

Index: clang/lib/Driver/Distro.cpp
===================================================================
--- clang/lib/Driver/Distro.cpp
+++ clang/lib/Driver/Distro.cpp
@@ -15,69 +15,100 @@
 #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"))
@@ -95,6 +126,7 @@
     return Distro::UnknownDistro;
   }
 
+  // ...for Debian
   File = VFS.getBufferForFile("/etc/debian_version");
   if (File) {
     StringRef Data = File.get()->getBuffer();
@@ -130,6 +162,7 @@
         .Default(Distro::UnknownDistro);
   }
 
+  // ...for SUSE
   File = VFS.getBufferForFile("/etc/SuSE-release");
   if (File) {
     StringRef Data = File.get()->getBuffer();
@@ -153,6 +186,7 @@
     return Distro::UnknownDistro;
   }
 
+  // ...and others.
   if (VFS.exists("/etc/exherbo-release"))
     return Distro::Exherbo;
 
@@ -168,5 +202,36 @@
   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) {
+    static Distro::DistroType LinuxDistro = Distro::UninitializedDistro;
+    static llvm::once_flag DistroDetectFlag;
+    // If we're backed by a real file system, perform
+    // the detection only once and save the result.
+    llvm::call_once(DistroDetectFlag, [&VFS]() {
+      LinuxDistro = DetectDistro(VFS);
+    });
+    return LinuxDistro;
+  }
+  return Distro::UnknownDistro;
+}
+
 Distro::Distro(llvm::vfs::FileSystem &VFS, const llvm::Triple &TargetOrHost)
-    : DistroVal(DetectDistro(VFS, TargetOrHost)) {}
+    : DistroVal(GetDistro(VFS, TargetOrHost)) {}
Index: clang/include/clang/Driver/Distro.h
===================================================================
--- clang/include/clang/Driver/Distro.h
+++ clang/include/clang/Driver/Distro.h
@@ -23,6 +23,8 @@
 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().
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
  • [P... Dmitry Antipov via Phabricator via cfe-commits
    • ... Dmitry Antipov via Phabricator via cfe-commits
    • ... Sylvestre Ledru via Phabricator via cfe-commits
    • ... Alexandre Ganea via Phabricator via cfe-commits
    • ... Reid "Away June-Sep" Kleckner via Phabricator via cfe-commits
    • ... Reid "Away June-Sep" Kleckner via Phabricator via cfe-commits
    • ... Dmitry Antipov via Phabricator via cfe-commits
    • ... Dmitry Antipov via Phabricator via cfe-commits
    • ... Reid Kleckner via Phabricator via cfe-commits
    • ... Dmitry Antipov via Phabricator via cfe-commits
    • ... Alexandre Ganea via Phabricator via cfe-commits
    • ... Reid Kleckner via Phabricator via cfe-commits
    • ... Dmitry Antipov via Phabricator via cfe-commits
    • ... Alexandre Ganea via Phabricator via cfe-commits
    • ... Dmitry Antipov via Phabricator via cfe-commits

Reply via email to