]> granicus.if.org Git - clang/commitdiff
Make a major refactoring to how the GCC installation detection works.
authorChandler Carruth <chandlerc@gmail.com>
Wed, 25 Jan 2012 07:21:38 +0000 (07:21 +0000)
committerChandler Carruth <chandlerc@gmail.com>
Wed, 25 Jan 2012 07:21:38 +0000 (07:21 +0000)
The fundamental shift here is to stop making *any* assumptions about the
*host* triple. Where these assumptions you ask? Why, they were in one of
the two target triples referenced of course. This was the single biggest
place where the previously named "host triple" was actually used as
such. ;] The reason we were reasoning about the host is in order to
detect the use of '-m32' or '-m64' flags to change the target. These
flags shift the default target only slightly, which typically means
a slight deviation from the host. When using these flags, the GCC
installation is under a different triple from the one actually targeted
in the compilation, and we used the host triple to find it.

Too bad that wasn't even correct. Consider an x86 Linux host which has
a PPC64 cross-compiling GCC toolchain installed. This toolchain is also
configured for multiarch compiling and can target PPC32 with eth '-m32'
flag. When targeting 'powerpc-linux-gnu' or some other PPC32 triple, we
have to look for the PPC64 variant of the triple to find the GCC
install, and that triple is neither the host nor target.

The new logic computes the multiarch's alternate triple from the target
triple, and looks under both sides. It also looks more aggressively for
the correct subdirectory of the GCC installation, and exposes the
subdirectory in a nice programmatic way. This '/32' or '/64' suffix is
something we can reuse in many other parts of the toolchain.

An important note -- while this likely fixes a large category of
cross-compile use cases, that's not my primary goal, and I've not done
testing (or added test cases) for scenarios that may now work. If
someone else wants to try more interesting PPC cross compiles, I'd love
to have reports. But my focus is on factoring away the references to the
"host" triple. The refactoring is my goal, and so I'm mostly relying on
the existing (pretty good) test coverage we have here.

Future patches will leverage this new functionality to factor out more
and more of the toolchain's triple manipulation.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@148935 91177308-0d34-0410-b5e6-96231b3b80d8

lib/Driver/ToolChains.cpp
lib/Driver/ToolChains.h

index b62be8bfdb3607c7ca69a6bf9915055986939342..428f37cab7c52bf8ad9bd29d45bc75f3a1de6b55 100644 (file)
@@ -1093,15 +1093,31 @@ bool Generic_GCC::GCCVersion::operator<(const GCCVersion &RHS) const {
   return false;
 }
 
+// FIXME: Factor this helper into llvm::Triple itself.
+static llvm::Triple getMultiarchAlternateTriple(llvm::Triple Triple) {
+  switch (Triple.getArch()) {
+  default: break;
+  case llvm::Triple::x86:    Triple.setArchName("x86_64");    break;
+  case llvm::Triple::x86_64: Triple.setArchName("i386");      break;
+  case llvm::Triple::ppc:    Triple.setArchName("powerpc64"); break;
+  case llvm::Triple::ppc64:  Triple.setArchName("powerpc");   break;
+  }
+  return Triple;
+}
+
 /// \brief Construct a GCCInstallationDetector from the driver.
 ///
 /// This performs all of the autodetection and sets up the various paths.
 /// Once constructed, a GCCInstallation is esentially immutable.
-Generic_GCC::GCCInstallationDetector::GCCInstallationDetector(const Driver &D)
-  : IsValid(false),
-    // FIXME: GCCTriple is using the target triple as both the target and host
-    // triple here.
-    GCCTriple(D.TargetTriple) {
+///
+/// FIXME: We shouldn't need an explicit TargetTriple parameter here, and
+/// should instead pull the target out of the driver. This is currently
+/// necessary because the driver doesn't store the final version of the target
+/// triple.
+Generic_GCC::GCCInstallationDetector::GCCInstallationDetector(
+    const Driver &D,
+    const llvm::Triple &TargetTriple)
+    : IsValid(false) {
   // FIXME: Using CXX_INCLUDE_ROOT is here is a bit of a hack, but
   // avoids adding yet another option to configure/cmake.
   // It would probably be cleaner to break it in two variables
@@ -1130,17 +1146,17 @@ Generic_GCC::GCCInstallationDetector::GCCInstallationDetector(const Driver &D)
     return;
   }
 
-  llvm::Triple::ArchType HostArch = GCCTriple.getArch();
+  llvm::Triple MultiarchTriple = getMultiarchAlternateTriple(TargetTriple);
+  llvm::Triple::ArchType TargetArch = TargetTriple.getArch();
   // The library directories which may contain GCC installations.
-  SmallVector<StringRef, 4> CandidateLibDirs;
+  SmallVector<StringRef, 4> CandidateLibDirs, CandidateMultiarchLibDirs;
   // The compatible GCC triples for this particular architecture.
-  SmallVector<StringRef, 10> CandidateTriples;
-  CollectLibDirsAndTriples(HostArch, CandidateLibDirs, CandidateTriples);
-
-  // Always include the default host triple as the final fallback if no
-  // specific triple is detected.
-  // FIXME: This is using the Driver's target triple as the host triple!
-  CandidateTriples.push_back(D.TargetTriple.str());
+  SmallVector<StringRef, 10> CandidateTripleAliases;
+  SmallVector<StringRef, 10> CandidateMultiarchTripleAliases;
+  CollectLibDirsAndTriples(TargetTriple, MultiarchTriple, CandidateLibDirs,
+                           CandidateTripleAliases,
+                           CandidateMultiarchLibDirs,
+                           CandidateMultiarchTripleAliases);
 
   // Compute the set of prefixes for our search.
   SmallVector<std::string, 8> Prefixes(D.PrefixDirs.begin(),
@@ -1159,99 +1175,162 @@ Generic_GCC::GCCInstallationDetector::GCCInstallationDetector(const Driver &D)
       const std::string LibDir = Prefixes[i] + CandidateLibDirs[j].str();
       if (!llvm::sys::fs::exists(LibDir))
         continue;
-      for (unsigned k = 0, ke = CandidateTriples.size(); k < ke; ++k)
-        ScanLibDirForGCCTriple(HostArch, LibDir, CandidateTriples[k]);
+      for (unsigned k = 0, ke = CandidateTripleAliases.size(); k < ke; ++k)
+        ScanLibDirForGCCTriple(TargetArch, LibDir, CandidateTripleAliases[k]);
+    }
+    for (unsigned j = 0, je = CandidateMultiarchLibDirs.size(); j < je; ++j) {
+      const std::string LibDir
+        = Prefixes[i] + CandidateMultiarchLibDirs[j].str();
+      if (!llvm::sys::fs::exists(LibDir))
+        continue;
+      for (unsigned k = 0, ke = CandidateMultiarchTripleAliases.size(); k < ke;
+           ++k)
+        ScanLibDirForGCCTriple(TargetArch, LibDir,
+                               CandidateMultiarchTripleAliases[k],
+                               /*NeedsMultiarchSuffix=*/true);
     }
   }
 }
 
 /*static*/ void Generic_GCC::GCCInstallationDetector::CollectLibDirsAndTriples(
-    llvm::Triple::ArchType HostArch, SmallVectorImpl<StringRef> &LibDirs,
-    SmallVectorImpl<StringRef> &Triples) {
-  if (HostArch == llvm::Triple::arm || HostArch == llvm::Triple::thumb) {
-    static const char *const ARMLibDirs[] = { "/lib" };
-    static const char *const ARMTriples[] = {
-      "arm-linux-gnueabi",
-      "arm-linux-androideabi"
-    };
+    const llvm::Triple &TargetTriple,
+    const llvm::Triple &MultiarchTriple,
+    SmallVectorImpl<StringRef> &LibDirs,
+    SmallVectorImpl<StringRef> &TripleAliases,
+    SmallVectorImpl<StringRef> &MultiarchLibDirs,
+    SmallVectorImpl<StringRef> &MultiarchTripleAliases) {
+  // Declare a bunch of static data sets that we'll select between below. These
+  // are specifically designed to always refer to string literals to avoid any
+  // lifetime or initialization issues.
+  static const char *const ARMLibDirs[] = { "/lib" };
+  static const char *const ARMTriples[] = {
+    "arm-linux-gnueabi",
+    "arm-linux-androideabi"
+  };
+
+  static const char *const X86_64LibDirs[] = { "/lib64", "/lib" };
+  static const char *const X86_64Triples[] = {
+    "x86_64-linux-gnu",
+    "x86_64-unknown-linux-gnu",
+    "x86_64-pc-linux-gnu",
+    "x86_64-redhat-linux6E",
+    "x86_64-redhat-linux",
+    "x86_64-suse-linux",
+    "x86_64-manbo-linux-gnu",
+    "x86_64-linux-gnu",
+    "x86_64-slackware-linux"
+  };
+  static const char *const X86LibDirs[] = { "/lib32", "/lib" };
+  static const char *const X86Triples[] = {
+    "i686-linux-gnu",
+    "i686-pc-linux-gnu",
+    "i486-linux-gnu",
+    "i386-linux-gnu",
+    "i686-redhat-linux",
+    "i586-redhat-linux",
+    "i386-redhat-linux",
+    "i586-suse-linux",
+    "i486-slackware-linux"
+  };
+
+  static const char *const MIPSLibDirs[] = { "/lib" };
+  static const char *const MIPSTriples[] = { "mips-linux-gnu" };
+  static const char *const MIPSELLibDirs[] = { "/lib" };
+  static const char *const MIPSELTriples[] = { "mipsel-linux-gnu" };
+
+  static const char *const PPCLibDirs[] = { "/lib32", "/lib" };
+  static const char *const PPCTriples[] = {
+    "powerpc-linux-gnu",
+    "powerpc-unknown-linux-gnu",
+    "powerpc-suse-linux"
+  };
+  static const char *const PPC64LibDirs[] = { "/lib64", "/lib" };
+  static const char *const PPC64Triples[] = {
+    "powerpc64-unknown-linux-gnu",
+    "powerpc64-suse-linux",
+    "ppc64-redhat-linux"
+  };
+
+  switch (TargetTriple.getArch()) {
+  case llvm::Triple::arm:
+  case llvm::Triple::thumb:
     LibDirs.append(ARMLibDirs, ARMLibDirs + llvm::array_lengthof(ARMLibDirs));
-    Triples.append(ARMTriples, ARMTriples + llvm::array_lengthof(ARMTriples));
-  } else if (HostArch == llvm::Triple::x86_64) {
-    static const char *const X86_64LibDirs[] = { "/lib64", "/lib" };
-    static const char *const X86_64Triples[] = {
-      "x86_64-linux-gnu",
-      "x86_64-unknown-linux-gnu",
-      "x86_64-pc-linux-gnu",
-      "x86_64-redhat-linux6E",
-      "x86_64-redhat-linux",
-      "x86_64-suse-linux",
-      "x86_64-manbo-linux-gnu",
-      "x86_64-linux-gnu",
-      "x86_64-slackware-linux"
-    };
-    LibDirs.append(X86_64LibDirs,
-                   X86_64LibDirs + llvm::array_lengthof(X86_64LibDirs));
-    Triples.append(X86_64Triples,
-                   X86_64Triples + llvm::array_lengthof(X86_64Triples));
-  } else if (HostArch == llvm::Triple::x86) {
-    static const char *const X86LibDirs[] = { "/lib32", "/lib" };
-    static const char *const X86Triples[] = {
-      "i686-linux-gnu",
-      "i686-pc-linux-gnu",
-      "i486-linux-gnu",
-      "i386-linux-gnu",
-      "i686-redhat-linux",
-      "i586-redhat-linux",
-      "i386-redhat-linux",
-      "i586-suse-linux",
-      "i486-slackware-linux"
-    };
+    TripleAliases.append(
+      ARMTriples, ARMTriples + llvm::array_lengthof(ARMTriples));
+    break;
+  case llvm::Triple::x86_64:
+    LibDirs.append(
+      X86_64LibDirs, X86_64LibDirs + llvm::array_lengthof(X86_64LibDirs));
+    TripleAliases.append(
+      X86_64Triples, X86_64Triples + llvm::array_lengthof(X86_64Triples));
+    MultiarchLibDirs.append(
+      X86LibDirs, X86LibDirs + llvm::array_lengthof(X86LibDirs));
+    MultiarchTripleAliases.append(
+      X86Triples, X86Triples + llvm::array_lengthof(X86Triples));
+    break;
+  case llvm::Triple::x86:
     LibDirs.append(X86LibDirs, X86LibDirs + llvm::array_lengthof(X86LibDirs));
-    Triples.append(X86Triples, X86Triples + llvm::array_lengthof(X86Triples));
-  } else if (HostArch == llvm::Triple::mips) {
-    static const char *const MIPSLibDirs[] = { "/lib" };
-    static const char *const MIPSTriples[] = { "mips-linux-gnu" };
-    LibDirs.append(MIPSLibDirs,
-                   MIPSLibDirs + llvm::array_lengthof(MIPSLibDirs));
-    Triples.append(MIPSTriples,
-                   MIPSTriples + llvm::array_lengthof(MIPSTriples));
-  } else if (HostArch == llvm::Triple::mipsel) {
-    static const char *const MIPSELLibDirs[] = { "/lib" };
-    static const char *const MIPSELTriples[] = { "mipsel-linux-gnu" };
-    LibDirs.append(MIPSELLibDirs,
-                   MIPSELLibDirs + llvm::array_lengthof(MIPSELLibDirs));
-    Triples.append(MIPSELTriples,
-                   MIPSELTriples + llvm::array_lengthof(MIPSELTriples));
-  } else if (HostArch == llvm::Triple::ppc) {
-    static const char *const PPCLibDirs[] = { "/lib32", "/lib" };
-    static const char *const PPCTriples[] = {
-      "powerpc-linux-gnu",
-      "powerpc-unknown-linux-gnu",
-      "powerpc-suse-linux"
-    };
+    TripleAliases.append(
+      X86Triples, X86Triples + llvm::array_lengthof(X86Triples));
+    MultiarchLibDirs.append(
+      X86_64LibDirs, X86_64LibDirs + llvm::array_lengthof(X86_64LibDirs));
+    MultiarchTripleAliases.append(
+      X86_64Triples, X86_64Triples + llvm::array_lengthof(X86_64Triples));
+    break;
+  case llvm::Triple::mips:
+    LibDirs.append(
+      MIPSLibDirs, MIPSLibDirs + llvm::array_lengthof(MIPSLibDirs));
+    TripleAliases.append(
+      MIPSTriples, MIPSTriples + llvm::array_lengthof(MIPSTriples));
+    break;
+  case llvm::Triple::mipsel:
+    LibDirs.append(
+      MIPSELLibDirs, MIPSELLibDirs + llvm::array_lengthof(MIPSELLibDirs));
+    TripleAliases.append(
+      MIPSELTriples, MIPSELTriples + llvm::array_lengthof(MIPSELTriples));
+    break;
+  case llvm::Triple::ppc:
     LibDirs.append(PPCLibDirs, PPCLibDirs + llvm::array_lengthof(PPCLibDirs));
-    Triples.append(PPCTriples, PPCTriples + llvm::array_lengthof(PPCTriples));
-  } else if (HostArch == llvm::Triple::ppc64) {
-    static const char *const PPC64LibDirs[] = { "/lib64", "/lib" };
-    static const char *const PPC64Triples[] = {
-      "powerpc64-unknown-linux-gnu",
-      "powerpc64-suse-linux",
-      "ppc64-redhat-linux"
-    };
-    LibDirs.append(PPC64LibDirs,
-                   PPC64LibDirs + llvm::array_lengthof(PPC64LibDirs));
-    Triples.append(PPC64Triples,
-                   PPC64Triples + llvm::array_lengthof(PPC64Triples));
+    TripleAliases.append(
+      PPCTriples, PPCTriples + llvm::array_lengthof(PPCTriples));
+    MultiarchLibDirs.append(
+      PPC64LibDirs, PPC64LibDirs + llvm::array_lengthof(PPC64LibDirs));
+    MultiarchTripleAliases.append(
+      PPC64Triples, PPC64Triples + llvm::array_lengthof(PPC64Triples));
+    break;
+  case llvm::Triple::ppc64:
+    LibDirs.append(
+      PPC64LibDirs, PPC64LibDirs + llvm::array_lengthof(PPC64LibDirs));
+    TripleAliases.append(
+      PPC64Triples, PPC64Triples + llvm::array_lengthof(PPC64Triples));
+    MultiarchLibDirs.append(
+      PPCLibDirs, PPCLibDirs + llvm::array_lengthof(PPCLibDirs));
+    MultiarchTripleAliases.append(
+      PPCTriples, PPCTriples + llvm::array_lengthof(PPCTriples));
+    break;
+
+  default:
+    // By default, just rely on the standard lib directories and the original
+    // triple.
+    break;
   }
+
+  // Always append the drivers target triple to the end, in case it doesn't
+  // match any of our aliases.
+  TripleAliases.push_back(TargetTriple.str());
+
+  // Also include the multiarch variant if it's different.
+  if (TargetTriple.str() != MultiarchTriple.str())
+    MultiarchTripleAliases.push_back(MultiarchTriple.str());
 }
 
 void Generic_GCC::GCCInstallationDetector::ScanLibDirForGCCTriple(
-    llvm::Triple::ArchType HostArch, const std::string &LibDir,
-    StringRef CandidateTriple) {
+    llvm::Triple::ArchType TargetArch, const std::string &LibDir,
+    StringRef CandidateTriple, bool NeedsMultiarchSuffix) {
   // There are various different suffixes involving the triple we
   // check for. We also record what is necessary to walk from each back
   // up to the lib directory.
-  const std::string Suffixes[] = {
+  const std::string LibSuffixes[] = {
     "/gcc/" + CandidateTriple.str(),
     "/" + CandidateTriple.str() + "/gcc/" + CandidateTriple.str(),
 
@@ -1267,12 +1346,12 @@ void Generic_GCC::GCCInstallationDetector::ScanLibDirForGCCTriple(
     "/../../../.."
   };
   // Only look at the final, weird Ubuntu suffix for i386-linux-gnu.
-  const unsigned NumSuffixes = (llvm::array_lengthof(Suffixes) -
-                                (HostArch != llvm::Triple::x86));
-  for (unsigned i = 0; i < NumSuffixes; ++i) {
-    StringRef Suffix = Suffixes[i];
+  const unsigned NumLibSuffixes = (llvm::array_lengthof(LibSuffixes) -
+                                   (TargetArch != llvm::Triple::x86));
+  for (unsigned i = 0; i < NumLibSuffixes; ++i) {
+    StringRef LibSuffix = LibSuffixes[i];
     llvm::error_code EC;
-    for (llvm::sys::fs::directory_iterator LI(LibDir + Suffix, EC), LE;
+    for (llvm::sys::fs::directory_iterator LI(LibDir + LibSuffix, EC), LE;
          !EC && LI != LE; LI = LI.increment(EC)) {
       StringRef VersionText = llvm::sys::path::filename(LI->path());
       GCCVersion CandidateVersion = GCCVersion::Parse(VersionText);
@@ -1284,31 +1363,36 @@ void Generic_GCC::GCCInstallationDetector::ScanLibDirForGCCTriple(
 
       // Some versions of SUSE and Fedora on ppc64 put 32-bit libs
       // in what would normally be GCCInstallPath and put the 64-bit
-      // libs in a subdirectory named 64. We need the 64-bit libs
-      // for linking.
-      bool UseSlash64 = false;
-      if (HostArch == llvm::Triple::ppc64 &&
-            llvm::sys::fs::exists(LI->path() + "/64/crtbegin.o"))
-        UseSlash64 = true;
-
-      if (!llvm::sys::fs::exists(LI->path() + "/crtbegin.o"))
-        continue;
+      // libs in a subdirectory named 64. The simple logic we follow is that
+      // *if* there is a subdirectory of the right name with crtbegin.o in it,
+      // we use that. If not, and if not a multiarch triple, we look for
+      // crtbegin.o without the subdirectory.
+      StringRef MultiarchSuffix
+        = (TargetArch == llvm::Triple::x86_64 ||
+           TargetArch == llvm::Triple::ppc64) ? "/64" : "/32";
+      if (llvm::sys::fs::exists(LI->path() + MultiarchSuffix + "/crtbegin.o")) {
+        GCCMultiarchSuffix = MultiarchSuffix.str();
+      } else {
+        if (NeedsMultiarchSuffix ||
+            !llvm::sys::fs::exists(LI->path() + "/crtbegin.o"))
+          continue;
+        GCCMultiarchSuffix.clear();
+      }
 
       Version = CandidateVersion;
       GCCTriple.setTriple(CandidateTriple);
       // FIXME: We hack together the directory name here instead of
       // using LI to ensure stable path separators across Windows and
       // Linux.
-      GCCInstallPath = LibDir + Suffixes[i] + "/" + VersionText.str();
+      GCCInstallPath = LibDir + LibSuffixes[i] + "/" + VersionText.str();
       GCCParentLibPath = GCCInstallPath + InstallSuffixes[i];
-      if (UseSlash64) GCCInstallPath = GCCInstallPath + "/64";
       IsValid = true;
     }
   }
 }
 
 Generic_GCC::Generic_GCC(const HostInfo &Host, const llvm::Triple& Triple)
-  : ToolChain(Host, Triple), GCCInstallation(getDriver()) {
+  : ToolChain(Host, Triple), GCCInstallation(getDriver(), Triple) {
   getProgramPaths().push_back(getDriver().getInstalledDir());
   if (getDriver().getInstalledDir() != getDriver().Dir)
     getProgramPaths().push_back(getDriver().Dir);
@@ -1970,24 +2054,12 @@ Linux::Linux(const HostInfo &Host, const llvm::Triple &Triple)
   const std::string MultiarchTriple = getMultiarchTriple(Triple, SysRoot);
 
   // Add the multilib suffixed paths where they are available.
-  bool SuffixedGCCInstallation = false;
   if (GCCInstallation.isValid()) {
-    StringRef Suffix32;
-    StringRef Suffix64;
     const llvm::Triple &GCCTriple = GCCInstallation.getTriple();
-    if (GCCTriple.getArch() == llvm::Triple::x86_64 ||
-        GCCTriple.getArch() == llvm::Triple::ppc64) {
-      Suffix32 = "/32";
-      Suffix64 = "";
-    } else {
-      Suffix32 = "";
-      Suffix64 = "/64";
-    }
-    const std::string Suffix = Is32Bits ? Suffix32 : Suffix64;
-    SuffixedGCCInstallation = !Suffix.empty();
-
     const std::string &LibPath = GCCInstallation.getParentLibPath();
-    addPathIfExists(GCCInstallation.getInstallPath() + Suffix, Paths);
+    addPathIfExists((GCCInstallation.getInstallPath() +
+                     GCCInstallation.getMultiarchSuffix()),
+                    Paths);
     addPathIfExists(LibPath + "/../" + GCCTriple.str() + "/lib/../" + Multilib,
                     Paths);
     addPathIfExists(LibPath + "/" + MultiarchTriple, Paths);
@@ -2008,7 +2080,7 @@ Linux::Linux(const HostInfo &Host, const llvm::Triple &Triple)
   if (GCCInstallation.isValid()) {
     const std::string &LibPath = GCCInstallation.getParentLibPath();
     const llvm::Triple &GCCTriple = GCCInstallation.getTriple();
-    if (SuffixedGCCInstallation)
+    if (!GCCInstallation.getMultiarchSuffix().empty())
       addPathIfExists(GCCInstallation.getInstallPath(), Paths);
     addPathIfExists(LibPath + "/../" + GCCTriple.str() + "/lib", Paths);
     addPathIfExists(LibPath, Paths);
index 6b152f442e623f4d35ef49b4f5bbb9d902daaa49..2b7c432e1a63090508cce444fa3240ad44cb7a59 100644 (file)
@@ -73,12 +73,13 @@ protected:
 
     // FIXME: These might be better as path objects.
     std::string GCCInstallPath;
+    std::string GCCMultiarchSuffix;
     std::string GCCParentLibPath;
 
     GCCVersion Version;
 
   public:
-    GCCInstallationDetector(const Driver &D);
+    GCCInstallationDetector(const Driver &D, const llvm::Triple &TargetTriple);
 
     /// \brief Check whether we detected a valid GCC install.
     bool isValid() const { return IsValid; }
@@ -89,6 +90,9 @@ protected:
     /// \brief Get the detected GCC installation path.
     StringRef getInstallPath() const { return GCCInstallPath; }
 
+    /// \brief Get the detected GCC installation path suffix for multiarch GCCs.
+    StringRef getMultiarchSuffix() const { return GCCMultiarchSuffix; }
+
     /// \brief Get the detected GCC parent lib path.
     StringRef getParentLibPath() const { return GCCParentLibPath; }
 
@@ -96,13 +100,18 @@ protected:
     StringRef getVersion() const { return Version.Text; }
 
   private:
-    static void CollectLibDirsAndTriples(llvm::Triple::ArchType HostArch,
-                                         SmallVectorImpl<StringRef> &LibDirs,
-                                         SmallVectorImpl<StringRef> &Triples);
-
-    void ScanLibDirForGCCTriple(llvm::Triple::ArchType HostArch,
+    static void CollectLibDirsAndTriples(
+      const llvm::Triple &TargetTriple,
+      const llvm::Triple &MultiarchTriple,
+      SmallVectorImpl<StringRef> &LibDirs,
+      SmallVectorImpl<StringRef> &TripleAliases,
+      SmallVectorImpl<StringRef> &MultiarchLibDirs,
+      SmallVectorImpl<StringRef> &MultiarchTripleAliases);
+
+    void ScanLibDirForGCCTriple(llvm::Triple::ArchType TargetArch,
                                 const std::string &LibDir,
-                                StringRef CandidateTriple);
+                                StringRef CandidateTriple,
+                                bool NeedsMultiarchSuffix = false);
   };
 
   GCCInstallationDetector GCCInstallation;