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