gollvm: add rudimentary linux distro detection support

Add support to the driver for detecting the linux distribution it is
running on. Different distributions install GCC headers and support
libraries in different places, complicating the process of selecting
the proper -L arguments to the linker. This patch will allow the
driver to look at the host's distro as part of the process of setting
up the library paths.

Updates golang/go#36512.

Change-Id: I90dfc8880096d63f1d36b97e068394d51936fe57
Reviewed-on: https://go-review.googlesource.com/c/gollvm/+/224037
Reviewed-by: Cherry Zhang <cherryyz@google.com>
diff --git a/driver/CMakeLists.txt b/driver/CMakeLists.txt
index 3426ce6..eac9ed6 100644
--- a/driver/CMakeLists.txt
+++ b/driver/CMakeLists.txt
@@ -30,6 +30,7 @@
   Command.cpp
   Compilation.cpp
   CompileGo.cpp
+  Distro.cpp
   Driver.cpp
   GccUtils.cpp
   GnuTools.cpp
diff --git a/driver/Distro.cpp b/driver/Distro.cpp
new file mode 100644
index 0000000..028dbea
--- /dev/null
+++ b/driver/Distro.cpp
@@ -0,0 +1,58 @@
+//===-- Distro.cpp --------------------------------------------------------===//
+//
+// Copyright 2020 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+//
+//===----------------------------------------------------------------------===//
+//
+// Defines the DetectDistro utility function (helper for driver).
+//
+//===----------------------------------------------------------------------===//
+
+#include "Distro.h"
+
+#include "llvm/Support/Host.h"
+
+namespace distro {
+
+// DetectDistro tries to detect the linux distro on which we're running.
+//
+// NB: we're sweeping a lot of cross-compilation issues under the rug here; the
+// working assumption is that users will have to rely on a sysroot in such
+// cases.
+
+DistroVariety DetectDistro(gnutools::gccdetect::InspectFS &ifs,
+                           const llvm::Triple &target) {
+  // Not linux? no distro.
+  if (!target.isOSLinux())
+    return DistroUnknown;
+  llvm::Triple HostTriple(llvm::sys::getProcessTriple());
+  if (!HostTriple.isOSLinux())
+    return DistroUnknown;
+
+  if (ifs.exists("/etc/debian_version"))
+    return DistroDebian;
+
+  if (ifs.exists("/etc/lsb-release"))
+    return DistroUbuntu;
+
+  if (ifs.exists("/etc/redhat-release"))
+    return DistroRedhat;
+
+  if (ifs.exists("/etc/SuSE-release"))
+    return DistroOpenSUSE;
+
+  if (ifs.exists("/etc/alpine-release"))
+    return DistroAlpine;
+
+  if (ifs.exists("/etc/arch-release"))
+    return DistroArchLinux;
+
+  if (ifs.exists("/etc/gentoo-release"))
+    return DistroGentoo;
+
+  return DistroUnknown;
+}
+
+}
diff --git a/driver/Distro.h b/driver/Distro.h
new file mode 100644
index 0000000..4bd0a36
--- /dev/null
+++ b/driver/Distro.h
@@ -0,0 +1,38 @@
+//===-- Distro.h --------------------------------------------------===//
+//
+// Copyright 2020 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+//
+//===----------------------------------------------------------------------===//
+//
+// Defines the DetectDistro helper function and return codes.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef GOLLVM_DRIVER_DISTRO_H
+#define GOLLVM_DRIVER_DISTRO_H
+
+#include "GccUtils.h"
+#include "llvm/ADT/Triple.h"
+
+namespace distro {
+
+enum DistroVariety {
+  DistroAlpine,
+  DistroArchLinux,
+  DistroDebian,
+  DistroRedhat,
+  DistroGentoo,
+  DistroOpenSUSE,
+  DistroUbuntu,
+  DistroUnknown
+};
+
+extern DistroVariety DetectDistro(gnutools::gccdetect::InspectFS &ifs,
+                                  const llvm::Triple &target);
+
+} // end namespace distro
+
+#endif // GOLLVM_DRIVER_DISTRO_H
+
diff --git a/driver/LinuxToolChain.cpp b/driver/LinuxToolChain.cpp
index cc41379..5d3a6cc 100644
--- a/driver/LinuxToolChain.cpp
+++ b/driver/LinuxToolChain.cpp
@@ -50,7 +50,8 @@
       gccDetector_(targetTriple,
                    driver.gccToolchainDir(),
                    driver.sysRoot(),
-                   inspectFS_)
+                   inspectFS_),
+      distro_(distro::DetectDistro(inspectFS_, targetTriple))
 {
   gccDetector_.init();
 
diff --git a/driver/LinuxToolChain.h b/driver/LinuxToolChain.h
index e66a023..55639b6 100644
--- a/driver/LinuxToolChain.h
+++ b/driver/LinuxToolChain.h
@@ -15,6 +15,7 @@
 
 #include "ToolChain.h"
 #include "GccUtils.h"
+#include "Distro.h"
 
 namespace toolchains {
 
@@ -34,6 +35,7 @@
  private:
   gnutools::gccdetect::InspectRealFS inspectFS_;
   gnutools::gccdetect::GCCInstallationDetector gccDetector_;
+  distro::DistroVariety distro_;
 };
 
 } // end namespace toolchains
diff --git a/unittests/DriverUtils/DriverUtilsTests.cpp b/unittests/DriverUtils/DriverUtilsTests.cpp
index d6e2fd2..d764207 100644
--- a/unittests/DriverUtils/DriverUtilsTests.cpp
+++ b/unittests/DriverUtils/DriverUtilsTests.cpp
@@ -12,6 +12,7 @@
 
 #include "Driver.h"
 #include "GccUtils.h"
+#include "Distro.h"
 
 #include "gtest/gtest.h"
 
@@ -486,4 +487,20 @@
   EXPECT_TRUE(isOK);
 }
 
+TEST(DriverUtilsTests, DistroDetector) {
+  const char *install = R"RAW_RESULT(
+      /etc/lsb-release
+      /etc/motd
+    )RAW_RESULT";
+  InspectFakeFS ffs(install);
+
+  llvm::Triple target1("aarch64-none-linux-gnu");
+  auto whichDistro1 = distro::DetectDistro(ffs, target1);
+  EXPECT_EQ(whichDistro1, distro::DistroUbuntu);
+
+  llvm::Triple target2("i686--windows-msvc");
+  auto whichDistro2 = distro::DetectDistro(ffs, target2);
+  EXPECT_EQ(whichDistro2, distro::DistroUnknown);
+}
+
 } // namespace