[clang] edc1130 - [Driver] Enable selecting multiple multilibs

Michael Platings via cfe-commits cfe-commits at lists.llvm.org
Tue Jun 13 22:47:24 PDT 2023


Author: Michael Platings
Date: 2023-06-14T06:46:41+01:00
New Revision: edc1130c0ac0e52ac5e347127972313ba928fe9a

URL: https://github.com/llvm/llvm-project/commit/edc1130c0ac0e52ac5e347127972313ba928fe9a
DIFF: https://github.com/llvm/llvm-project/commit/edc1130c0ac0e52ac5e347127972313ba928fe9a.diff

LOG: [Driver] Enable selecting multiple multilibs

This will enable layering multilibs on top of each other.
For example a multilib containing only a no-exceptions libc++ could be
layered on top of a multilib containing C libs. This avoids the need
to duplicate the C library for every libc++ variant.

This change doesn't expose the functionality externally, it only opens
the functionality up to be potentially used by ToolChain classes.

Differential Revision: https://reviews.llvm.org/D143059

Added: 
    

Modified: 
    clang/include/clang/Driver/Multilib.h
    clang/include/clang/Driver/ToolChain.h
    clang/lib/Driver/Driver.cpp
    clang/lib/Driver/Multilib.cpp
    clang/lib/Driver/ToolChain.cpp
    clang/lib/Driver/ToolChains/BareMetal.cpp
    clang/lib/Driver/ToolChains/CSKYToolChain.cpp
    clang/lib/Driver/ToolChains/Fuchsia.cpp
    clang/lib/Driver/ToolChains/Gnu.cpp
    clang/lib/Driver/ToolChains/Gnu.h
    clang/lib/Driver/ToolChains/Hexagon.cpp
    clang/lib/Driver/ToolChains/Hurd.cpp
    clang/lib/Driver/ToolChains/Linux.cpp
    clang/lib/Driver/ToolChains/MipsLinux.cpp
    clang/lib/Driver/ToolChains/OHOS.cpp
    clang/lib/Driver/ToolChains/RISCVToolchain.cpp
    clang/test/Driver/fuchsia.cpp
    clang/unittests/Driver/MultilibBuilderTest.cpp
    clang/unittests/Driver/MultilibTest.cpp

Removed: 
    


################################################################################
diff  --git a/clang/include/clang/Driver/Multilib.h b/clang/include/clang/Driver/Multilib.h
index 493be70cfc35b..1416559414f89 100644
--- a/clang/include/clang/Driver/Multilib.h
+++ b/clang/include/clang/Driver/Multilib.h
@@ -116,11 +116,9 @@ class MultilibSet {
   const_iterator begin() const { return Multilibs.begin(); }
   const_iterator end() const { return Multilibs.end(); }
 
-  /// Select compatible variants
-  multilib_list select(const Multilib::flags_list &Flags) const;
-
-  /// Pick the best multilib in the set, \returns false if none are compatible
-  bool select(const Multilib::flags_list &Flags, Multilib &M) const;
+  /// Select compatible variants, \returns false if none are compatible
+  bool select(const Multilib::flags_list &Flags,
+              llvm::SmallVector<Multilib> &) const;
 
   unsigned size() const { return Multilibs.size(); }
 

diff  --git a/clang/include/clang/Driver/ToolChain.h b/clang/include/clang/Driver/ToolChain.h
index 3b3932f1e3432..7b5c430aacc7e 100644
--- a/clang/include/clang/Driver/ToolChain.h
+++ b/clang/include/clang/Driver/ToolChain.h
@@ -187,7 +187,7 @@ class ToolChain {
 
 protected:
   MultilibSet Multilibs;
-  Multilib SelectedMultilib;
+  llvm::SmallVector<Multilib> SelectedMultilibs;
 
   ToolChain(const Driver &D, const llvm::Triple &T,
             const llvm::opt::ArgList &Args);
@@ -283,7 +283,9 @@ class ToolChain {
 
   const MultilibSet &getMultilibs() const { return Multilibs; }
 
-  const Multilib &getMultilib() const { return SelectedMultilib; }
+  const llvm::SmallVector<Multilib> &getSelectedMultilibs() const {
+    return SelectedMultilibs;
+  }
 
   /// Get flags suitable for multilib selection, based on the provided clang
   /// command line arguments. The command line arguments aren't suitable to be

diff  --git a/clang/lib/Driver/Driver.cpp b/clang/lib/Driver/Driver.cpp
index 87c31f993d758..8f92606960b3a 100644
--- a/clang/lib/Driver/Driver.cpp
+++ b/clang/lib/Driver/Driver.cpp
@@ -2229,13 +2229,14 @@ bool Driver::HandleImmediateArgs(const Compilation &C) {
   }
 
   if (C.getArgs().hasArg(options::OPT_print_multi_directory)) {
-    const Multilib &Multilib = TC.getMultilib();
-    if (Multilib.gccSuffix().empty())
-      llvm::outs() << ".\n";
-    else {
-      StringRef Suffix(Multilib.gccSuffix());
-      assert(Suffix.front() == '/');
-      llvm::outs() << Suffix.substr(1) << "\n";
+    for (const Multilib &Multilib : TC.getSelectedMultilibs()) {
+      if (Multilib.gccSuffix().empty())
+        llvm::outs() << ".\n";
+      else {
+        StringRef Suffix(Multilib.gccSuffix());
+        assert(Suffix.front() == '/');
+        llvm::outs() << Suffix.substr(1) << "\n";
+      }
     }
     return false;
   }

diff  --git a/clang/lib/Driver/Multilib.cpp b/clang/lib/Driver/Multilib.cpp
index 0e988d040a4e3..a37dffc8a6f1d 100644
--- a/clang/lib/Driver/Multilib.cpp
+++ b/clang/lib/Driver/Multilib.cpp
@@ -93,27 +93,18 @@ MultilibSet &MultilibSet::FilterOut(FilterCallback F) {
 
 void MultilibSet::push_back(const Multilib &M) { Multilibs.push_back(M); }
 
-MultilibSet::multilib_list
-MultilibSet::select(const Multilib::flags_list &Flags) const {
+bool MultilibSet::select(const Multilib::flags_list &Flags,
+                         llvm::SmallVector<Multilib> &Selected) const {
   llvm::StringSet<> FlagSet(expandFlags(Flags));
-  multilib_list Result;
-  llvm::copy_if(Multilibs, std::back_inserter(Result),
+  Selected.clear();
+  llvm::copy_if(Multilibs, std::back_inserter(Selected),
                 [&FlagSet](const Multilib &M) {
                   for (const std::string &F : M.flags())
                     if (!FlagSet.contains(F))
                       return false;
                   return true;
                 });
-  return Result;
-}
-
-bool MultilibSet::select(const Multilib::flags_list &Flags,
-                         Multilib &Selected) const {
-  multilib_list Result = select(Flags);
-  if (Result.empty())
-    return false;
-  Selected = Result.back();
-  return true;
+  return !Selected.empty();
 }
 
 llvm::StringSet<>

diff  --git a/clang/lib/Driver/ToolChain.cpp b/clang/lib/Driver/ToolChain.cpp
index 44b2a3d8f9d0b..0903b0ad7eb89 100644
--- a/clang/lib/Driver/ToolChain.cpp
+++ b/clang/lib/Driver/ToolChain.cpp
@@ -591,7 +591,9 @@ std::string ToolChain::getCompilerRTPath() const {
   SmallString<128> Path(getDriver().ResourceDir);
   if (isBareMetal()) {
     llvm::sys::path::append(Path, "lib", getOSLibName());
-    Path += SelectedMultilib.gccSuffix();
+    if (!SelectedMultilibs.empty()) {
+      Path += SelectedMultilibs.back().gccSuffix();
+    }
   } else if (Triple.isOSUnknown()) {
     llvm::sys::path::append(Path, "lib");
   } else {

diff  --git a/clang/lib/Driver/ToolChains/BareMetal.cpp b/clang/lib/Driver/ToolChains/BareMetal.cpp
index c167f8608945e..748f24e151aa5 100644
--- a/clang/lib/Driver/ToolChains/BareMetal.cpp
+++ b/clang/lib/Driver/ToolChains/BareMetal.cpp
@@ -54,7 +54,7 @@ static bool findRISCVMultilibs(const Driver &D,
 
     Result.Multilibs =
         MultilibSetBuilder().Either(Imac, Imafdc).makeMultilibSet();
-    return Result.Multilibs.select(Flags, Result.SelectedMultilib);
+    return Result.Multilibs.select(Flags, Result.SelectedMultilibs);
   }
   if (TargetTriple.isRISCV32()) {
     MultilibBuilder Imac =
@@ -88,7 +88,7 @@ static bool findRISCVMultilibs(const Driver &D,
 
     Result.Multilibs =
         MultilibSetBuilder().Either(I, Im, Iac, Imac, Imafc).makeMultilibSet();
-    return Result.Multilibs.select(Flags, Result.SelectedMultilib);
+    return Result.Multilibs.select(Flags, Result.SelectedMultilibs);
   }
   return false;
 }
@@ -168,7 +168,7 @@ static bool findMultilibsFromYAML(const ToolChain &TC, const Driver &D,
   if (ErrorOrMultilibSet.getError())
     return false;
   Result.Multilibs = ErrorOrMultilibSet.get();
-  return Result.Multilibs.select(Flags, Result.SelectedMultilib);
+  return Result.Multilibs.select(Flags, Result.SelectedMultilibs);
 }
 
 static constexpr llvm::StringLiteral MultilibFilename = "multilib.yaml";
@@ -200,14 +200,14 @@ void BareMetal::findMultilibs(const Driver &D, const llvm::Triple &Triple,
   DetectedMultilibs Result;
   if (isRISCVBareMetal(Triple)) {
     if (findRISCVMultilibs(D, Triple, Args, Result)) {
-      SelectedMultilib = Result.SelectedMultilib;
+      SelectedMultilibs = Result.SelectedMultilibs;
       Multilibs = Result.Multilibs;
     }
   } else {
     llvm::SmallString<128> MultilibPath(computeBaseSysRoot(D, Triple));
     llvm::sys::path::append(MultilibPath, MultilibFilename);
     findMultilibsFromYAML(*this, D, MultilibPath, Args, Result);
-    SelectedMultilib = Result.SelectedMultilib;
+    SelectedMultilibs = Result.SelectedMultilibs;
     Multilibs = Result.Multilibs;
   }
 }
@@ -222,8 +222,10 @@ Tool *BareMetal::buildLinker() const {
 }
 
 std::string BareMetal::computeSysRoot() const {
-  return computeBaseSysRoot(getDriver(), getTriple()) +
-         SelectedMultilib.osSuffix();
+  std::string Result = computeBaseSysRoot(getDriver(), getTriple());
+  if (!SelectedMultilibs.empty())
+    Result += SelectedMultilibs.back().osSuffix();
+  return Result;
 }
 
 void BareMetal::AddClangSystemIncludeArgs(const ArgList &DriverArgs,

diff  --git a/clang/lib/Driver/ToolChains/CSKYToolChain.cpp b/clang/lib/Driver/ToolChains/CSKYToolChain.cpp
index de286faaca6d8..0728ad14129a9 100644
--- a/clang/lib/Driver/ToolChains/CSKYToolChain.cpp
+++ b/clang/lib/Driver/ToolChains/CSKYToolChain.cpp
@@ -38,13 +38,13 @@ CSKYToolChain::CSKYToolChain(const Driver &D, const llvm::Triple &Triple,
   GCCInstallation.init(Triple, Args);
   if (GCCInstallation.isValid()) {
     Multilibs = GCCInstallation.getMultilibs();
-    SelectedMultilib = GCCInstallation.getMultilib();
+    SelectedMultilibs.assign({GCCInstallation.getMultilib()});
     path_list &Paths = getFilePaths();
     // Add toolchain/multilib specific file paths.
-    addMultilibsFilePaths(D, Multilibs, SelectedMultilib,
+    addMultilibsFilePaths(D, Multilibs, SelectedMultilibs.back(),
                           GCCInstallation.getInstallPath(), Paths);
     getFilePaths().push_back(GCCInstallation.getInstallPath().str() +
-                             SelectedMultilib.osSuffix());
+                             SelectedMultilibs.back().osSuffix());
     ToolChain::path_list &PPaths = getProgramPaths();
     // Multilib cross-compiler GCC installations put ld in a triple-prefixed
     // directory off of the parent of the GCC installation.
@@ -52,11 +52,12 @@ CSKYToolChain::CSKYToolChain(const Driver &D, const llvm::Triple &Triple,
                            GCCInstallation.getTriple().str() + "/bin")
                          .str());
     PPaths.push_back((GCCInstallation.getParentLibPath() + "/../bin").str());
+    getFilePaths().push_back(computeSysRoot() + "/lib" +
+                             SelectedMultilibs.back().osSuffix());
   } else {
     getProgramPaths().push_back(D.Dir);
+    getFilePaths().push_back(computeSysRoot() + "/lib");
   }
-  getFilePaths().push_back(computeSysRoot() + "/lib" +
-                           SelectedMultilib.osSuffix());
 }
 
 Tool *CSKYToolChain::buildLinker() const {

diff  --git a/clang/lib/Driver/ToolChains/Fuchsia.cpp b/clang/lib/Driver/ToolChains/Fuchsia.cpp
index 5a540a3c5d57d..65692cc7f954c 100644
--- a/clang/lib/Driver/ToolChains/Fuchsia.cpp
+++ b/clang/lib/Driver/ToolChains/Fuchsia.cpp
@@ -314,12 +314,17 @@ Fuchsia::Fuchsia(const Driver &D, const llvm::Triple &Triple,
 
   Multilibs.setFilePathsCallback(FilePaths);
 
-  if (Multilibs.select(Flags, SelectedMultilib))
-    if (!SelectedMultilib.isDefault())
+  if (Multilibs.select(Flags, SelectedMultilibs)) {
+    // Ensure that -print-multi-directory only outputs one multilib directory.
+    Multilib LastSelected = SelectedMultilibs.back();
+    SelectedMultilibs = {LastSelected};
+
+    if (!SelectedMultilibs.back().isDefault())
       if (const auto &PathsCallback = Multilibs.filePathsCallback())
-        for (const auto &Path : PathsCallback(SelectedMultilib))
+        for (const auto &Path : PathsCallback(SelectedMultilibs.back()))
           // Prepend the multilib path to ensure it takes the precedence.
           getFilePaths().insert(getFilePaths().begin(), Path);
+  }
 }
 
 std::string Fuchsia::ComputeEffectiveClangTriple(const ArgList &Args,

diff  --git a/clang/lib/Driver/ToolChains/Gnu.cpp b/clang/lib/Driver/ToolChains/Gnu.cpp
index 80e3c0f570a28..7d4d8e054b0a2 100644
--- a/clang/lib/Driver/ToolChains/Gnu.cpp
+++ b/clang/lib/Driver/ToolChains/Gnu.cpp
@@ -1151,7 +1151,7 @@ static bool findMipsCsMultilibs(const Multilib::flags_list &Flags,
   if (CSMipsMultilibs.size() < DebianMipsMultilibs.size())
     std::iter_swap(Candidates, Candidates + 1);
   for (const MultilibSet *Candidate : Candidates) {
-    if (Candidate->select(Flags, Result.SelectedMultilib)) {
+    if (Candidate->select(Flags, Result.SelectedMultilibs)) {
       if (Candidate == &DebianMipsMultilibs)
         Result.BiarchSibling = Multilib();
       Result.Multilibs = *Candidate;
@@ -1200,7 +1200,7 @@ static bool findMipsAndroidMultilibs(llvm::vfs::FileSystem &VFS, StringRef Path,
     MS = &AndroidMipselMultilibs;
   else if (VFS.exists(Path + "/32"))
     MS = &AndroidMips64elMultilibs;
-  if (MS->select(Flags, Result.SelectedMultilib)) {
+  if (MS->select(Flags, Result.SelectedMultilibs)) {
     Result.Multilibs = *MS;
     return true;
   }
@@ -1234,7 +1234,7 @@ static bool findMipsMuslMultilibs(const Multilib::flags_list &Flags,
           {"/../sysroot" + M.osSuffix() + "/usr/include"});
     });
   }
-  if (MuslMipsMultilibs.select(Flags, Result.SelectedMultilib)) {
+  if (MuslMipsMultilibs.select(Flags, Result.SelectedMultilibs)) {
     Result.Multilibs = MuslMipsMultilibs;
     return true;
   }
@@ -1419,7 +1419,7 @@ static bool findMipsMtiMultilibs(const Multilib::flags_list &Flags,
             });
   }
   for (auto *Candidate : {&MtiMipsMultilibsV1, &MtiMipsMultilibsV2}) {
-    if (Candidate->select(Flags, Result.SelectedMultilib)) {
+    if (Candidate->select(Flags, Result.SelectedMultilibs)) {
       Result.Multilibs = *Candidate;
       return true;
     }
@@ -1525,7 +1525,7 @@ static bool findMipsImgMultilibs(const Multilib::flags_list &Flags,
             });
   }
   for (auto *Candidate : {&ImgMultilibsV1, &ImgMultilibsV2}) {
-    if (Candidate->select(Flags, Result.SelectedMultilib)) {
+    if (Candidate->select(Flags, Result.SelectedMultilibs)) {
       Result.Multilibs = *Candidate;
       return true;
     }
@@ -1598,7 +1598,7 @@ bool clang::driver::findMIPSMultilibs(const Driver &D,
   Result.Multilibs.push_back(Default);
   Result.Multilibs.FilterOut(NonExistent);
 
-  if (Result.Multilibs.select(Flags, Result.SelectedMultilib)) {
+  if (Result.Multilibs.select(Flags, Result.SelectedMultilibs)) {
     Result.BiarchSibling = Multilib();
     return true;
   }
@@ -1645,7 +1645,7 @@ static void findAndroidArmMultilibs(const Driver &D,
   addMultilibFlag(IsArmV7Mode, "-march=armv7-a", Flags);
   addMultilibFlag(IsThumbMode, "-mthumb", Flags);
 
-  if (AndroidArmMultilibs.select(Flags, Result.SelectedMultilib))
+  if (AndroidArmMultilibs.select(Flags, Result.SelectedMultilibs))
     Result.Multilibs = AndroidArmMultilibs;
 }
 
@@ -1671,7 +1671,7 @@ static bool findMSP430Multilibs(const Driver &D,
   addMultilibFlag(Args.hasFlag(options::OPT_fexceptions,
                                options::OPT_fno_exceptions, false),
                   "-exceptions", Flags);
-  if (Result.Multilibs.select(Flags, Result.SelectedMultilib))
+  if (Result.Multilibs.select(Flags, Result.SelectedMultilibs))
     return true;
 
   return false;
@@ -1738,7 +1738,7 @@ static void findCSKYMultilibs(const Driver &D, const llvm::Triple &TargetTriple,
           .makeMultilibSet()
           .FilterOut(NonExistent);
 
-  if (CSKYMultilibs.select(Flags, Result.SelectedMultilib))
+  if (CSKYMultilibs.select(Flags, Result.SelectedMultilibs))
     Result.Multilibs = CSKYMultilibs;
 }
 
@@ -1793,7 +1793,7 @@ static void findRISCVBareMetalMultilibs(const Driver &D,
     }
   }
 
-  if (RISCVMultilibs.select(Flags, Result.SelectedMultilib))
+  if (RISCVMultilibs.select(Flags, Result.SelectedMultilibs))
     Result.Multilibs = RISCVMultilibs;
 }
 
@@ -1835,7 +1835,7 @@ static void findRISCVMultilibs(const Driver &D,
   addMultilibFlag(ABIName == "lp64f", "-mabi=lp64f", Flags);
   addMultilibFlag(ABIName == "lp64d", "-mabi=lp64d", Flags);
 
-  if (RISCVMultilibs.select(Flags, Result.SelectedMultilib))
+  if (RISCVMultilibs.select(Flags, Result.SelectedMultilibs))
     Result.Multilibs = RISCVMultilibs;
 }
 
@@ -1944,11 +1944,12 @@ static bool findBiarchMultilibs(const Driver &D,
   addMultilibFlag(TargetTriple.isArch32Bit(), "-m32", Flags);
   addMultilibFlag(TargetTriple.isArch64Bit() && IsX32, "-mx32", Flags);
 
-  if (!Result.Multilibs.select(Flags, Result.SelectedMultilib))
+  if (!Result.Multilibs.select(Flags, Result.SelectedMultilibs))
     return false;
 
-  if (Result.SelectedMultilib == Alt64 || Result.SelectedMultilib == Alt32 ||
-      Result.SelectedMultilib == Altx32)
+  if (Result.SelectedMultilibs.back() == Alt64 ||
+      Result.SelectedMultilibs.back() == Alt32 ||
+      Result.SelectedMultilibs.back() == Altx32)
     Result.BiarchSibling = Default;
 
   return true;
@@ -2713,7 +2714,9 @@ bool Generic_GCC::GCCInstallationDetector::ScanGCCForMultilibs(
   }
 
   Multilibs = Detected.Multilibs;
-  SelectedMultilib = Detected.SelectedMultilib;
+  SelectedMultilib = Detected.SelectedMultilibs.empty()
+                         ? Multilib()
+                         : Detected.SelectedMultilibs.back();
   BiarchSibling = Detected.BiarchSibling;
 
   return true;
@@ -2983,6 +2986,7 @@ void Generic_GCC::AddMultilibPaths(const Driver &D,
                                    path_list &Paths) {
   // Add the multilib suffixed paths where they are available.
   if (GCCInstallation.isValid()) {
+    assert(!SelectedMultilibs.empty());
     const llvm::Triple &GCCTriple = GCCInstallation.getTriple();
     const std::string &LibPath =
         std::string(GCCInstallation.getParentLibPath());
@@ -2990,13 +2994,14 @@ void Generic_GCC::AddMultilibPaths(const Driver &D,
     // Sourcery CodeBench MIPS toolchain holds some libraries under
     // a biarch-like suffix of the GCC installation.
     if (const auto &PathsCallback = Multilibs.filePathsCallback())
-      for (const auto &Path : PathsCallback(SelectedMultilib))
+      for (const auto &Path : PathsCallback(SelectedMultilibs.back()))
         addPathIfExists(D, GCCInstallation.getInstallPath() + Path, Paths);
 
     // Add lib/gcc/$triple/$version, with an optional /multilib suffix.
-    addPathIfExists(
-        D, GCCInstallation.getInstallPath() + SelectedMultilib.gccSuffix(),
-        Paths);
+    addPathIfExists(D,
+                    GCCInstallation.getInstallPath() +
+                        SelectedMultilibs.back().gccSuffix(),
+                    Paths);
 
     // Add lib/gcc/$triple/$libdir
     // For GCC built with --enable-version-specific-runtime-libs.
@@ -3023,7 +3028,7 @@ void Generic_GCC::AddMultilibPaths(const Driver &D,
     // Clang diverges from GCC's behavior.
     addPathIfExists(D,
                     LibPath + "/../" + GCCTriple.str() + "/lib/../" + OSLibDir +
-                        SelectedMultilib.osSuffix(),
+                        SelectedMultilibs.back().osSuffix(),
                     Paths);
 
     // If the GCC installation we found is inside of the sysroot, we want to

diff  --git a/clang/lib/Driver/ToolChains/Gnu.h b/clang/lib/Driver/ToolChains/Gnu.h
index c7975c9c60394..6d335c9edb225 100644
--- a/clang/lib/Driver/ToolChains/Gnu.h
+++ b/clang/lib/Driver/ToolChains/Gnu.h
@@ -23,8 +23,8 @@ struct DetectedMultilibs {
   /// The set of multilibs that the detected installation supports.
   MultilibSet Multilibs;
 
-  /// The primary multilib appropriate for the given flags.
-  Multilib SelectedMultilib;
+  /// The multilibs appropriate for the given flags.
+  llvm::SmallVector<Multilib> SelectedMultilibs;
 
   /// On Biarch systems, this corresponds to the default multilib when
   /// targeting the non-default multilib. Otherwise, it is empty.

diff  --git a/clang/lib/Driver/ToolChains/Hexagon.cpp b/clang/lib/Driver/ToolChains/Hexagon.cpp
index c21cff21680a4..b06297435fcfc 100644
--- a/clang/lib/Driver/ToolChains/Hexagon.cpp
+++ b/clang/lib/Driver/ToolChains/Hexagon.cpp
@@ -542,7 +542,9 @@ HexagonToolChain::getSmallDataThreshold(const ArgList &Args) {
 std::string HexagonToolChain::getCompilerRTPath() const {
   SmallString<128> Dir(getDriver().SysRoot);
   llvm::sys::path::append(Dir, "usr", "lib");
-  Dir += SelectedMultilib.gccSuffix();
+  if (!SelectedMultilibs.empty()) {
+    Dir += SelectedMultilibs.back().gccSuffix();
+  }
   return std::string(Dir.str());
 }
 

diff  --git a/clang/lib/Driver/ToolChains/Hurd.cpp b/clang/lib/Driver/ToolChains/Hurd.cpp
index 48b9ccadf36f2..2dfc90ef37f75 100644
--- a/clang/lib/Driver/ToolChains/Hurd.cpp
+++ b/clang/lib/Driver/ToolChains/Hurd.cpp
@@ -65,7 +65,7 @@ Hurd::Hurd(const Driver &D, const llvm::Triple &Triple, const ArgList &Args)
     : Generic_ELF(D, Triple, Args) {
   GCCInstallation.init(Triple, Args);
   Multilibs = GCCInstallation.getMultilibs();
-  SelectedMultilib = GCCInstallation.getMultilib();
+  SelectedMultilibs.assign({GCCInstallation.getMultilib()});
   std::string SysRoot = computeSysRoot();
   ToolChain::path_list &PPaths = getProgramPaths();
 

diff  --git a/clang/lib/Driver/ToolChains/Linux.cpp b/clang/lib/Driver/ToolChains/Linux.cpp
index 920da6e4bfd49..33a431a54da67 100644
--- a/clang/lib/Driver/ToolChains/Linux.cpp
+++ b/clang/lib/Driver/ToolChains/Linux.cpp
@@ -213,7 +213,7 @@ Linux::Linux(const Driver &D, const llvm::Triple &Triple, const ArgList &Args)
     : Generic_ELF(D, Triple, Args) {
   GCCInstallation.init(Triple, Args);
   Multilibs = GCCInstallation.getMultilibs();
-  SelectedMultilib = GCCInstallation.getMultilib();
+  SelectedMultilibs.assign({GCCInstallation.getMultilib()});
   llvm::Triple::ArchType Arch = Triple.getArch();
   std::string SysRoot = computeSysRoot();
   ToolChain::path_list &PPaths = getProgramPaths();
@@ -257,8 +257,8 @@ Linux::Linux(const Driver &D, const llvm::Triple &Triple, const ArgList &Args)
   const bool IsRISCV = Triple.isRISCV();
   const bool IsCSKY = Triple.isCSKY();
 
-  if (IsCSKY)
-    SysRoot = SysRoot + SelectedMultilib.osSuffix();
+  if (IsCSKY && !SelectedMultilibs.empty())
+    SysRoot = SysRoot + SelectedMultilibs.back().osSuffix();
 
   if ((IsMips || IsCSKY) && !SysRoot.empty())
     ExtraOpts.push_back("--sysroot=" + SysRoot);

diff  --git a/clang/lib/Driver/ToolChains/MipsLinux.cpp b/clang/lib/Driver/ToolChains/MipsLinux.cpp
index 9c58583bca770..6157970233ae5 100644
--- a/clang/lib/Driver/ToolChains/MipsLinux.cpp
+++ b/clang/lib/Driver/ToolChains/MipsLinux.cpp
@@ -30,7 +30,7 @@ MipsLLVMToolChain::MipsLLVMToolChain(const Driver &D,
   DetectedMultilibs Result;
   findMIPSMultilibs(D, Triple, "", Args, Result);
   Multilibs = Result.Multilibs;
-  SelectedMultilib = Result.SelectedMultilib;
+  SelectedMultilibs = Result.SelectedMultilibs;
 
   // Find out the library suffix based on the ABI.
   LibSuffix = tools::mips::getMipsABILibSuffix(Args, Triple);

diff  --git a/clang/lib/Driver/ToolChains/OHOS.cpp b/clang/lib/Driver/ToolChains/OHOS.cpp
index 0fdcafe898d70..1e50c9d71d59c 100644
--- a/clang/lib/Driver/ToolChains/OHOS.cpp
+++ b/clang/lib/Driver/ToolChains/OHOS.cpp
@@ -50,7 +50,7 @@ static bool findOHOSMuslMultilibs(const Multilib::flags_list &Flags,
       Multilib("/a7_hard_neon-vfpv4", {}, {},
                {"-mcpu=cortex-a7", "-mfloat-abi=hard", "-mfpu=neon-vfpv4"}));
 
-  if (Multilibs.select(Flags, Result.SelectedMultilib)) {
+  if (Multilibs.select(Flags, Result.SelectedMultilibs)) {
     Result.Multilibs = Multilibs;
     return true;
   }
@@ -136,7 +136,10 @@ OHOS::OHOS(const Driver &D, const llvm::Triple &Triple, const ArgList &Args)
   DetectedMultilibs Result;
   findOHOSMultilibs(D, *this, Triple, "", Args, Result);
   Multilibs = Result.Multilibs;
-  SelectedMultilib = Result.SelectedMultilib;
+  SelectedMultilibs = Result.SelectedMultilibs;
+  if (!SelectedMultilibs.empty()) {
+    SelectedMultilib = SelectedMultilibs.back();
+  }
 
   getFilePaths().clear();
   for (const auto &CandidateLibPath : getArchSpecificLibPaths())

diff  --git a/clang/lib/Driver/ToolChains/RISCVToolchain.cpp b/clang/lib/Driver/ToolChains/RISCVToolchain.cpp
index a3cd9b2bfa90d..e2e5dea2da2b7 100644
--- a/clang/lib/Driver/ToolChains/RISCVToolchain.cpp
+++ b/clang/lib/Driver/ToolChains/RISCVToolchain.cpp
@@ -53,10 +53,10 @@ RISCVToolChain::RISCVToolChain(const Driver &D, const llvm::Triple &Triple,
   GCCInstallation.init(Triple, Args);
   if (GCCInstallation.isValid()) {
     Multilibs = GCCInstallation.getMultilibs();
-    SelectedMultilib = GCCInstallation.getMultilib();
+    SelectedMultilibs.assign({GCCInstallation.getMultilib()});
     path_list &Paths = getFilePaths();
     // Add toolchain/multilib specific file paths.
-    addMultilibsFilePaths(D, Multilibs, SelectedMultilib,
+    addMultilibsFilePaths(D, Multilibs, SelectedMultilibs.back(),
                           GCCInstallation.getInstallPath(), Paths);
     getFilePaths().push_back(GCCInstallation.getInstallPath().str());
     ToolChain::path_list &PPaths = getProgramPaths();

diff  --git a/clang/test/Driver/fuchsia.cpp b/clang/test/Driver/fuchsia.cpp
index 01ebcb146ca60..caccca19b80e2 100644
--- a/clang/test/Driver/fuchsia.cpp
+++ b/clang/test/Driver/fuchsia.cpp
@@ -139,3 +139,14 @@
 // CHECK-MULTILIB-HWASAN-NOEXCEPT-X86: "-L{{.*}}{{/|\\\\}}..{{/|\\\\}}lib{{/|\\\\}}x86_64-unknown-fuchsia{{/|\\\\}}hwasan+noexcept"
 // CHECK-MULTILIB-COMPAT-X86: "-L{{.*}}{{/|\\\\}}..{{/|\\\\}}lib{{/|\\\\}}x86_64-unknown-fuchsia{{/|\\\\}}compat"
 // CHECK-MULTILIB-X86: "-L{{.*}}{{/|\\\\}}..{{/|\\\\}}lib{{/|\\\\}}x86_64-unknown-fuchsia"
+
+// Check that -print-multi-directory only outputs one multilib directory.
+// This may be relaxed later but for now preserve existing behaviour.
+// RUN: %clangxx -print-multi-directory --target=x86_64-unknown-fuchsia -fsanitize=address -fno-exceptions \
+// RUN:     -ccc-install-dir %S/Inputs/basic_fuchsia_tree/bin \
+// RUN:     -resource-dir=%S/Inputs/resource_dir_with_per_target_subdir \
+// RUN:     | FileCheck %s -check-prefixes=CHECK-PRINT-MULTI-LIB
+// CHECK-PRINT-MULTI-LIB-NOT: .
+// CHECK-PRINT-MULTI-LIB-NOT: noexcept
+// CHECK-PRINT-MULTI-LIB-NOT: asan
+// CHECK-PRINT-MULTI-LIB: asan+noexcept

diff  --git a/clang/unittests/Driver/MultilibBuilderTest.cpp b/clang/unittests/Driver/MultilibBuilderTest.cpp
index 6958f01f73a2f..60fe10ac3ba55 100644
--- a/clang/unittests/Driver/MultilibBuilderTest.cpp
+++ b/clang/unittests/Driver/MultilibBuilderTest.cpp
@@ -163,18 +163,20 @@ TEST(MultilibBuilderTest, SetSelection1) {
                         .makeMultilibSet();
 
   Multilib::flags_list FlagM64 = {"-m64"};
-  Multilib SelectionM64;
+  llvm::SmallVector<Multilib> SelectionM64;
   ASSERT_TRUE(MS1.select(FlagM64, SelectionM64))
       << "Flag set was {\"-m64\"}, but selection not found";
-  ASSERT_TRUE(SelectionM64.gccSuffix() == "/64")
-      << "Selection picked " << SelectionM64 << " which was not expected";
+  ASSERT_TRUE(SelectionM64.back().gccSuffix() == "/64")
+      << "Selection picked " << SelectionM64.back()
+      << " which was not expected";
 
   Multilib::flags_list FlagNoM64 = {"!m64"};
-  Multilib SelectionNoM64;
+  llvm::SmallVector<Multilib> SelectionNoM64;
   ASSERT_TRUE(MS1.select(FlagNoM64, SelectionNoM64))
       << "Flag set was {\"!m64\"}, but selection not found";
-  ASSERT_TRUE(SelectionNoM64.gccSuffix() == "")
-      << "Selection picked " << SelectionNoM64 << " which was not expected";
+  ASSERT_TRUE(SelectionNoM64.back().gccSuffix() == "")
+      << "Selection picked " << SelectionNoM64.back()
+      << " which was not expected";
 }
 
 TEST(MultilibBuilderTest, SetSelection2) {
@@ -197,7 +199,7 @@ TEST(MultilibBuilderTest, SetSelection2) {
     else
       Flags.push_back("!SF");
 
-    Multilib Selection;
+    llvm::SmallVector<Multilib> Selection;
     ASSERT_TRUE(MS2.select(Flags, Selection))
         << "Selection failed for " << (IsEL ? "-EL" : "!EL") << " "
         << (IsSF ? "-SF" : "!SF");
@@ -208,7 +210,8 @@ TEST(MultilibBuilderTest, SetSelection2) {
     if (IsSF)
       Suffix += "/sf";
 
-    ASSERT_EQ(Selection.gccSuffix(), Suffix)
-        << "Selection picked " << Selection << " which was not expected ";
+    ASSERT_EQ(Selection.back().gccSuffix(), Suffix)
+        << "Selection picked " << Selection.back()
+        << " which was not expected ";
   }
 }

diff  --git a/clang/unittests/Driver/MultilibTest.cpp b/clang/unittests/Driver/MultilibTest.cpp
index 087ec35e48149..ed9ac58cecd7b 100644
--- a/clang/unittests/Driver/MultilibTest.cpp
+++ b/clang/unittests/Driver/MultilibTest.cpp
@@ -154,18 +154,18 @@ TEST(MultilibTest, SetPriority) {
       Multilib("/bar", {}, {}, {"+bar"}),
   });
   Multilib::flags_list Flags1 = {"+foo", "-bar"};
-  Multilib Selection1;
+  llvm::SmallVector<Multilib> Selection1;
   ASSERT_TRUE(MS.select(Flags1, Selection1))
       << "Flag set was {\"+foo\"}, but selection not found";
-  ASSERT_TRUE(Selection1.gccSuffix() == "/foo")
-      << "Selection picked " << Selection1 << " which was not expected";
+  ASSERT_TRUE(Selection1.back().gccSuffix() == "/foo")
+      << "Selection picked " << Selection1.back() << " which was not expected";
 
   Multilib::flags_list Flags2 = {"+foo", "+bar"};
-  Multilib Selection2;
+  llvm::SmallVector<Multilib> Selection2;
   ASSERT_TRUE(MS.select(Flags2, Selection2))
       << "Flag set was {\"+bar\"}, but selection not found";
-  ASSERT_TRUE(Selection2.gccSuffix() == "/bar")
-      << "Selection picked " << Selection2 << " which was not expected";
+  ASSERT_TRUE(Selection2.back().gccSuffix() == "/bar")
+      << "Selection picked " << Selection2.back() << " which was not expected";
 }
 
 TEST(MultilibTest, SelectMultiple) {
@@ -173,17 +173,17 @@ TEST(MultilibTest, SelectMultiple) {
       Multilib("/a", {}, {}, {"x"}),
       Multilib("/b", {}, {}, {"y"}),
   });
-  std::vector<Multilib> Selection;
+  llvm::SmallVector<Multilib> Selection;
 
-  Selection = MS.select({"x"});
+  ASSERT_TRUE(MS.select({"x"}, Selection));
   ASSERT_EQ(1u, Selection.size());
   EXPECT_EQ("/a", Selection[0].gccSuffix());
 
-  Selection = MS.select({"y"});
+  ASSERT_TRUE(MS.select({"y"}, Selection));
   ASSERT_EQ(1u, Selection.size());
   EXPECT_EQ("/b", Selection[0].gccSuffix());
 
-  Selection = MS.select({"y", "x"});
+  ASSERT_TRUE(MS.select({"y", "x"}, Selection));
   ASSERT_EQ(2u, Selection.size());
   EXPECT_EQ("/a", Selection[0].gccSuffix());
   EXPECT_EQ("/b", Selection[1].gccSuffix());
@@ -355,7 +355,7 @@ TEST(MultilibTest, Parse) {
 
 TEST(MultilibTest, SelectSoft) {
   MultilibSet MS;
-  Multilib Selected;
+  llvm::SmallVector<Multilib> Selected;
   ASSERT_TRUE(parseYaml(MS, YAML_PREAMBLE R"(
 Variants:
 - Dir: s
@@ -371,7 +371,7 @@ TEST(MultilibTest, SelectSoft) {
 
 TEST(MultilibTest, SelectSoftFP) {
   MultilibSet MS;
-  Multilib Selected;
+  llvm::SmallVector<Multilib> Selected;
   ASSERT_TRUE(parseYaml(MS, YAML_PREAMBLE R"(
 Variants:
 - Dir: f
@@ -386,7 +386,7 @@ TEST(MultilibTest, SelectHard) {
   // If hard float is all that's available then select that only if compiling
   // with hard float.
   MultilibSet MS;
-  Multilib Selected;
+  llvm::SmallVector<Multilib> Selected;
   ASSERT_TRUE(parseYaml(MS, YAML_PREAMBLE R"(
 Variants:
 - Dir: h
@@ -399,7 +399,7 @@ TEST(MultilibTest, SelectHard) {
 
 TEST(MultilibTest, SelectFloatABI) {
   MultilibSet MS;
-  Multilib Selected;
+  llvm::SmallVector<Multilib> Selected;
   ASSERT_TRUE(parseYaml(MS, YAML_PREAMBLE R"(
 Variants:
 - Dir: s
@@ -413,18 +413,18 @@ TEST(MultilibTest, SelectFloatABI) {
   Flags: [-mfloat-abi=soft]
 )"));
   MS.select({"-mfloat-abi=soft"}, Selected);
-  EXPECT_EQ("/s", Selected.gccSuffix());
+  EXPECT_EQ("/s", Selected.back().gccSuffix());
   MS.select({"-mfloat-abi=softfp"}, Selected);
-  EXPECT_EQ("/f", Selected.gccSuffix());
+  EXPECT_EQ("/f", Selected.back().gccSuffix());
   MS.select({"-mfloat-abi=hard"}, Selected);
-  EXPECT_EQ("/h", Selected.gccSuffix());
+  EXPECT_EQ("/h", Selected.back().gccSuffix());
 }
 
 TEST(MultilibTest, SelectFloatABIReversed) {
   // If soft is specified after softfp then softfp will never be
   // selected because soft is compatible with softfp and last wins.
   MultilibSet MS;
-  Multilib Selected;
+  llvm::SmallVector<Multilib> Selected;
   ASSERT_TRUE(parseYaml(MS, YAML_PREAMBLE R"(
 Variants:
 - Dir: h
@@ -438,11 +438,11 @@ TEST(MultilibTest, SelectFloatABIReversed) {
   Flags: [-mfloat-abi=soft]
 )"));
   MS.select({"-mfloat-abi=soft"}, Selected);
-  EXPECT_EQ("/s", Selected.gccSuffix());
+  EXPECT_EQ("/s", Selected.back().gccSuffix());
   MS.select({"-mfloat-abi=softfp"}, Selected);
-  EXPECT_EQ("/s", Selected.gccSuffix());
+  EXPECT_EQ("/s", Selected.back().gccSuffix());
   MS.select({"-mfloat-abi=hard"}, Selected);
-  EXPECT_EQ("/h", Selected.gccSuffix());
+  EXPECT_EQ("/h", Selected.back().gccSuffix());
 }
 
 TEST(MultilibTest, SelectMClass) {
@@ -490,48 +490,48 @@ TEST(MultilibTest, SelectMClass) {
 )";
 
   MultilibSet MS;
-  Multilib Selected;
+  llvm::SmallVector<Multilib> Selected;
   ASSERT_TRUE(parseYaml(MS, MultilibSpec));
 
   ASSERT_TRUE(MS.select({"--target=thumbv6m-none-unknown-eabi", "-mfpu=none"},
                         Selected));
-  EXPECT_EQ("/thumb/v6-m/nofp", Selected.gccSuffix());
+  EXPECT_EQ("/thumb/v6-m/nofp", Selected.back().gccSuffix());
 
   ASSERT_TRUE(MS.select({"--target=thumbv7m-none-unknown-eabi", "-mfpu=none"},
                         Selected));
-  EXPECT_EQ("/thumb/v7-m/nofp", Selected.gccSuffix());
+  EXPECT_EQ("/thumb/v7-m/nofp", Selected.back().gccSuffix());
 
   ASSERT_TRUE(MS.select({"--target=thumbv7em-none-unknown-eabi", "-mfpu=none"},
                         Selected));
-  EXPECT_EQ("/thumb/v7e-m/nofp", Selected.gccSuffix());
+  EXPECT_EQ("/thumb/v7e-m/nofp", Selected.back().gccSuffix());
 
   ASSERT_TRUE(MS.select(
       {"--target=thumbv8m.main-none-unknown-eabi", "-mfpu=none"}, Selected));
-  EXPECT_EQ("/thumb/v8-m.main/nofp", Selected.gccSuffix());
+  EXPECT_EQ("/thumb/v8-m.main/nofp", Selected.back().gccSuffix());
 
   ASSERT_TRUE(MS.select(
       {"--target=thumbv8.1m.main-none-unknown-eabi", "-mfpu=none"}, Selected));
-  EXPECT_EQ("/thumb/v8.1-m.main/nofp/nomve", Selected.gccSuffix());
+  EXPECT_EQ("/thumb/v8.1-m.main/nofp/nomve", Selected.back().gccSuffix());
 
   ASSERT_TRUE(
       MS.select({"--target=thumbv7em-none-unknown-eabihf", "-mfpu=fpv4-sp-d16"},
                 Selected));
-  EXPECT_EQ("/thumb/v7e-m/fpv4_sp_d16", Selected.gccSuffix());
+  EXPECT_EQ("/thumb/v7e-m/fpv4_sp_d16", Selected.back().gccSuffix());
 
   ASSERT_TRUE(MS.select(
       {"--target=thumbv7em-none-unknown-eabihf", "-mfpu=fpv5-d16"}, Selected));
-  EXPECT_EQ("/thumb/v7e-m/fpv5_d16", Selected.gccSuffix());
+  EXPECT_EQ("/thumb/v7e-m/fpv5_d16", Selected.back().gccSuffix());
 
   ASSERT_TRUE(
       MS.select({"--target=thumbv8m.main-none-unknown-eabihf"}, Selected));
-  EXPECT_EQ("/thumb/v8-m.main/fp", Selected.gccSuffix());
+  EXPECT_EQ("/thumb/v8-m.main/fp", Selected.back().gccSuffix());
 
   ASSERT_TRUE(
       MS.select({"--target=thumbv8.1m.main-none-unknown-eabihf"}, Selected));
-  EXPECT_EQ("/thumb/v8.1-m.main/fp", Selected.gccSuffix());
+  EXPECT_EQ("/thumb/v8.1-m.main/fp", Selected.back().gccSuffix());
 
   ASSERT_TRUE(MS.select({"--target=thumbv8.1m.main-none-unknown-eabihf",
                          "-mfpu=none", "-march=thumbv8.1m.main+dsp+mve"},
                         Selected));
-  EXPECT_EQ("/thumb/v8.1-m.main/nofp/mve", Selected.gccSuffix());
+  EXPECT_EQ("/thumb/v8.1-m.main/nofp/mve", Selected.back().gccSuffix());
 }


        


More information about the cfe-commits mailing list