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

Add trivial {/etc,/usr/lib}/os-release parser and fix tests.


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
@@ -19,30 +19,42 @@
 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())
-    return Distro::UnknownDistro;
+static Distro::DistroType DetectOsRelease(llvm::vfs::FileSystem &VFS) {
+  Distro::DistroType Version = Distro::UnknownDistro;
+  llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> File =
+      VFS.getBufferForFile("/etc/os-release");
+  if (!File)
+    File = VFS.getBufferForFile("/usr/lib/os-release");
 
-  // 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;
+  if (File) {
+    SmallVector<StringRef, 16> Lines;
+    File.get()->getBuffer().split(Lines, "\n");
 
+    // 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) {
+  Distro::DistroType Version = Distro::UnknownDistro;
   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;
+    File.get()->getBuffer().split(Lines, "\n");
+
     for (StringRef Line : Lines)
       if (Version == Distro::UnknownDistro && Line.startswith("DISTRIB_CODENAME="))
         Version = llvm::StringSwitch<Distro::DistroType>(Line.substr(17))
@@ -73,11 +85,28 @@
                       .Case("focal", Distro::UbuntuFocal)
                       .Case("groovy", Distro::UbuntuGroovy)
                       .Default(Distro::UnknownDistro);
-    if (Version != Distro::UnknownDistro)
-      return Version;
   }
+  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 +124,7 @@
     return Distro::UnknownDistro;
   }
 
+  // ...for Debian
   File = VFS.getBufferForFile("/etc/debian_version");
   if (File) {
     StringRef Data = File.get()->getBuffer();
@@ -130,6 +160,7 @@
         .Default(Distro::UnknownDistro);
   }
 
+  // ...for SUSE
   File = VFS.getBufferForFile("/etc/SuSE-release");
   if (File) {
     StringRef Data = File.get()->getBuffer();
@@ -153,6 +184,7 @@
     return Distro::UnknownDistro;
   }
 
+  // ...and others.
   if (VFS.exists("/etc/exherbo-release"))
     return Distro::Exherbo;
 
@@ -168,5 +200,37 @@
   return Distro::UnknownDistro;
 }
 
+static Distro::DistroType GetDistro(llvm::vfs::FileSystem &VFS,
+                                    const llvm::Triple &TargetOrHost) {
+  static Distro::DistroType Type = Distro::UninitializedDistro;
+
+  // 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 we're backed by a real file system and had performed detection
+  // already, return the result. This saves a few more OS calls assuming
+  // there was no underlying on-the fly distro change.
+  if (onRealFS && Type != Distro::UninitializedDistro)
+    return Type;
+
+  // 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)
+    Type = Distro::UnknownDistro;
+  else
+    // Perform the detection and save the result.
+    Type = DetectDistro(VFS);
+
+  return Type;
+}
+
 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 = -1,
     // 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

Reply via email to