diff --git a/clang/include/clang/Driver/Multilib.h b/clang/include/clang/Driver/Multilib.h --- a/clang/include/clang/Driver/Multilib.h +++ b/clang/include/clang/Driver/Multilib.h @@ -16,6 +16,7 @@ #include "llvm/Support/Compiler.h" #include #include +#include #include #include #include @@ -29,22 +30,23 @@ /// incrementally. class Multilib { public: - using flags_list = std::vector; + using flag_set = std::set; + using arg_list = std::vector; private: std::string GCCSuffix; std::string OSSuffix; std::string IncludeSuffix; - flags_list Flags; - int Priority; + flag_set Flags; + arg_list PrintArgs; public: /// GCCSuffix, OSSuffix & IncludeSuffix will be appended directly to the /// sysroot string so they must either be empty or begin with a '/' character. /// This is enforced with an assert in the constructor. Multilib(StringRef GCCSuffix = {}, StringRef OSSuffix = {}, - StringRef IncludeSuffix = {}, int Priority = 0, - const flags_list &Flags = flags_list()); + StringRef IncludeSuffix = {}, const flag_set &Flags = flag_set(), + const arg_list &PrintArgs = arg_list()); /// Get the detected GCC installation path suffix for the multi-arch /// target variant. Always starts with a '/', unless empty @@ -58,13 +60,11 @@ /// empty const std::string &includeSuffix() const { return IncludeSuffix; } - /// Get the flags that indicate or contraindicate this multilib's use - /// All elements begin with either '+' or '-' - const flags_list &flags() const { return Flags; } + /// Get the flags that indicate this multilib's use + const flag_set &flags() const { return Flags; } - /// Returns the multilib priority. When more than one multilib matches flags, - /// the one with the highest priority is selected, with 0 being the default. - int priority() const { return Priority; } + /// Returns the arguments that should be used for clang -print-multi-lib + const arg_list &getPrintArgs() const { return PrintArgs; } LLVM_DUMP_METHOD void dump() const; /// print summary of the Multilib @@ -108,8 +108,11 @@ const_iterator begin() const { return Multilibs.begin(); } const_iterator end() const { return Multilibs.end(); } + /// Select compatible variants + multilib_list select(const Multilib::flag_set &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; + bool select(const Multilib::flag_set &Flags, Multilib &M) const; unsigned size() const { return Multilibs.size(); } @@ -129,13 +132,6 @@ } const IncludeDirsFunc &filePathsCallback() const { return FilePathsCallback; } - -private: - /// Apply the filter to Multilibs and return the subset that remains - static multilib_list filterCopy(FilterCallback F, const multilib_list &Ms); - - /// Apply the filter to the multilib_list, removing those that don't match - static void filterInPlace(FilterCallback F, multilib_list &Ms); }; raw_ostream &operator<<(raw_ostream &OS, const MultilibSet &MS); diff --git a/clang/include/clang/Driver/MultilibBuilder.h b/clang/include/clang/Driver/MultilibBuilder.h --- a/clang/include/clang/Driver/MultilibBuilder.h +++ b/clang/include/clang/Driver/MultilibBuilder.h @@ -28,11 +28,10 @@ std::string OSSuffix; std::string IncludeSuffix; flags_list Flags; - int Priority; public: MultilibBuilder(StringRef GCCSuffix, StringRef OSSuffix, - StringRef IncludeSuffix, int Priority = 0); + StringRef IncludeSuffix); /// Initializes GCCSuffix, OSSuffix & IncludeSuffix to the same value. MultilibBuilder(StringRef Suffix = {}); @@ -75,10 +74,6 @@ const flags_list &flags() const { return Flags; } flags_list &flags() { return Flags; } - /// Returns the multilib priority. When more than one multilib matches flags, - /// the one with the highest priority is selected, with 0 being the default. - int priority() const { return Priority; } - /// Add a flag to the flags list /// \p Flag must be a flag accepted by the driver with its leading '-' /// removed, diff --git a/clang/lib/Driver/Multilib.cpp b/clang/lib/Driver/Multilib.cpp --- a/clang/lib/Driver/Multilib.cpp +++ b/clang/lib/Driver/Multilib.cpp @@ -26,10 +26,10 @@ using namespace llvm::sys; Multilib::Multilib(StringRef GCCSuffix, StringRef OSSuffix, - StringRef IncludeSuffix, int Priority, - const flags_list &Flags) + StringRef IncludeSuffix, const flag_set &Flags, + const arg_list &PrintArgs) : GCCSuffix(GCCSuffix), OSSuffix(OSSuffix), IncludeSuffix(IncludeSuffix), - Flags(Flags), Priority(Priority) { + Flags(Flags), PrintArgs(PrintArgs) { assert(GCCSuffix.empty() || (StringRef(GCCSuffix).front() == '/' && GCCSuffix.size() > 1)); assert(OSSuffix.empty() || @@ -45,26 +45,16 @@ void Multilib::print(raw_ostream &OS) const { if (GCCSuffix.empty()) OS << "."; - else { + else OS << StringRef(GCCSuffix).drop_front(); - } OS << ";"; - for (StringRef Flag : Flags) { - if (Flag.front() == '+') - OS << "@" << Flag.substr(1); - } + for (StringRef Flag : PrintArgs) + OS << "@" << Flag.substr(1); } bool Multilib::operator==(const Multilib &Other) const { - // Check whether the flags sets match - // allowing for the match to be order invariant - llvm::StringSet<> MyFlags; - for (const auto &Flag : Flags) - MyFlags.insert(Flag); - - for (const auto &Flag : Other.Flags) - if (MyFlags.find(Flag) == MyFlags.end()) - return false; + if (Flags != Other.Flags) + return false; if (osSuffix() != Other.osSuffix()) return false; @@ -84,56 +74,30 @@ } MultilibSet &MultilibSet::FilterOut(FilterCallback F) { - filterInPlace(F, Multilibs); + llvm::erase_if(Multilibs, F); return *this; } void MultilibSet::push_back(const Multilib &M) { Multilibs.push_back(M); } -static bool isFlagEnabled(StringRef Flag) { - char Indicator = Flag.front(); - assert(Indicator == '+' || Indicator == '-'); - return Indicator == '+'; +MultilibSet::multilib_list +MultilibSet::select(const Multilib::flag_set &Flags) const { + multilib_list Result; + llvm::copy_if(Multilibs, std::back_inserter(Result), + [&Flags](const Multilib &M) { + return std::includes(Flags.begin(), Flags.end(), + M.flags().begin(), M.flags().end()); + }); + return Result; } -bool MultilibSet::select(const Multilib::flags_list &Flags, Multilib &M) const { - llvm::StringMap FlagSet; - - // Stuff all of the flags into the FlagSet such that a true mappend indicates - // the flag was enabled, and a false mappend indicates the flag was disabled. - for (StringRef Flag : Flags) - FlagSet[Flag.substr(1)] = isFlagEnabled(Flag); - - multilib_list Filtered = filterCopy([&FlagSet](const Multilib &M) { - for (StringRef Flag : M.flags()) { - llvm::StringMap::const_iterator SI = FlagSet.find(Flag.substr(1)); - if (SI != FlagSet.end()) - if (SI->getValue() != isFlagEnabled(Flag)) - return true; - } +bool MultilibSet::select(const Multilib::flag_set &Flags, + Multilib &Selected) const { + multilib_list Result = select(Flags); + if (Result.empty()) return false; - }, Multilibs); - - if (Filtered.empty()) - return false; - if (Filtered.size() == 1) { - M = Filtered[0]; - return true; - } - - // Sort multilibs by priority and select the one with the highest priority. - llvm::sort(Filtered, [](const Multilib &a, const Multilib &b) -> bool { - return a.priority() > b.priority(); - }); - - if (Filtered[0].priority() > Filtered[1].priority()) { - M = Filtered[0]; - return true; - } - - // TODO: We should consider returning llvm::Error rather than aborting. - assert(false && "More than one multilib with the same priority"); - return false; + Selected = Result.back(); + return true; } LLVM_DUMP_METHOD void MultilibSet::dump() const { @@ -145,17 +109,6 @@ OS << M << "\n"; } -MultilibSet::multilib_list MultilibSet::filterCopy(FilterCallback F, - const multilib_list &Ms) { - multilib_list Copy(Ms); - filterInPlace(F, Copy); - return Copy; -} - -void MultilibSet::filterInPlace(FilterCallback F, multilib_list &Ms) { - llvm::erase_if(Ms, F); -} - raw_ostream &clang::driver::operator<<(raw_ostream &OS, const MultilibSet &MS) { MS.print(OS); return OS; diff --git a/clang/lib/Driver/MultilibBuilder.cpp b/clang/lib/Driver/MultilibBuilder.cpp --- a/clang/lib/Driver/MultilibBuilder.cpp +++ b/clang/lib/Driver/MultilibBuilder.cpp @@ -41,9 +41,8 @@ } } -MultilibBuilder::MultilibBuilder(StringRef GCC, StringRef OS, StringRef Include, - int Priority) - : GCCSuffix(GCC), OSSuffix(OS), IncludeSuffix(Include), Priority(Priority) { +MultilibBuilder::MultilibBuilder(StringRef GCC, StringRef OS, StringRef Include) + : GCCSuffix(GCC), OSSuffix(OS), IncludeSuffix(Include) { normalizePathSegment(GCCSuffix); normalizePathSegment(OSSuffix); normalizePathSegment(IncludeSuffix); @@ -87,7 +86,13 @@ } Multilib MultilibBuilder::makeMultilib() const { - return Multilib(GCCSuffix, OSSuffix, IncludeSuffix, Priority, Flags); + Multilib::arg_list Args; + for (StringRef Flag : Flags) { + if (Flag.front() == '+') + Args.push_back(("-" + Flag.substr(1)).str()); + } + return Multilib(GCCSuffix, OSSuffix, IncludeSuffix, + Multilib::flag_set(Flags.begin(), Flags.end()), Args); } MultilibSetBuilder &MultilibSetBuilder::Maybe(const MultilibBuilder &M) { diff --git a/clang/lib/Driver/ToolChains/BareMetal.cpp b/clang/lib/Driver/ToolChains/BareMetal.cpp --- a/clang/lib/Driver/ToolChains/BareMetal.cpp +++ b/clang/lib/Driver/ToolChains/BareMetal.cpp @@ -32,7 +32,7 @@ static bool findRISCVMultilibs(const Driver &D, const llvm::Triple &TargetTriple, const ArgList &Args, DetectedMultilibs &Result) { - Multilib::flags_list Flags; + Multilib::flag_set Flags; StringRef Arch = riscv::getRISCVArch(Args, TargetTriple); StringRef Abi = tools::riscv::getRISCVABI(Args, TargetTriple); diff --git a/clang/lib/Driver/ToolChains/CommonArgs.h b/clang/lib/Driver/ToolChains/CommonArgs.h --- a/clang/lib/Driver/ToolChains/CommonArgs.h +++ b/clang/lib/Driver/ToolChains/CommonArgs.h @@ -201,7 +201,7 @@ /// \p Flag must be a flag accepted by the driver with its leading '-' removed, // otherwise '-print-multi-lib' will not emit them correctly. void addMultilibFlag(bool Enabled, const char *const Flag, - Multilib::flags_list &Flags); + Multilib::flag_set &Flags); void addX86AlignBranchArgs(const Driver &D, const llvm::opt::ArgList &Args, llvm::opt::ArgStringList &CmdArgs, bool IsLTO, diff --git a/clang/lib/Driver/ToolChains/CommonArgs.cpp b/clang/lib/Driver/ToolChains/CommonArgs.cpp --- a/clang/lib/Driver/ToolChains/CommonArgs.cpp +++ b/clang/lib/Driver/ToolChains/CommonArgs.cpp @@ -1805,8 +1805,8 @@ } void tools::addMultilibFlag(bool Enabled, const char *const Flag, - Multilib::flags_list &Flags) { - Flags.push_back(std::string(Enabled ? "+" : "-") + Flag); + Multilib::flag_set &Flags) { + Flags.insert(std::string(Enabled ? "+" : "-") + Flag); } void tools::addX86AlignBranchArgs(const Driver &D, const ArgList &Args, diff --git a/clang/lib/Driver/ToolChains/Fuchsia.cpp b/clang/lib/Driver/ToolChains/Fuchsia.cpp --- a/clang/lib/Driver/ToolChains/Fuchsia.cpp +++ b/clang/lib/Driver/ToolChains/Fuchsia.cpp @@ -263,33 +263,33 @@ Multilibs.push_back(Multilib()); // Use the noexcept variant with -fno-exceptions to avoid the extra overhead. - Multilibs.push_back(MultilibBuilder("noexcept", {}, {}, 1) + Multilibs.push_back(MultilibBuilder("noexcept", {}, {}) .flag("-fexceptions") .flag("+fno-exceptions") .makeMultilib()); // ASan has higher priority because we always want the instrumentated version. - Multilibs.push_back(MultilibBuilder("asan", {}, {}, 2) + Multilibs.push_back(MultilibBuilder("asan", {}, {}) .flag("+fsanitize=address") .makeMultilib()); // Use the asan+noexcept variant with ASan and -fno-exceptions. - Multilibs.push_back(MultilibBuilder("asan+noexcept", {}, {}, 3) + Multilibs.push_back(MultilibBuilder("asan+noexcept", {}, {}) .flag("+fsanitize=address") .flag("-fexceptions") .flag("+fno-exceptions") .makeMultilib()); // HWASan has higher priority because we always want the instrumentated // version. - Multilibs.push_back(MultilibBuilder("hwasan", {}, {}, 4) + Multilibs.push_back(MultilibBuilder("hwasan", {}, {}) .flag("+fsanitize=hwaddress") .makeMultilib()); // Use the hwasan+noexcept variant with HWASan and -fno-exceptions. - Multilibs.push_back(MultilibBuilder("hwasan+noexcept", {}, {}, 5) + Multilibs.push_back(MultilibBuilder("hwasan+noexcept", {}, {}) .flag("+fsanitize=hwaddress") .flag("-fexceptions") .flag("+fno-exceptions") .makeMultilib()); // Use Itanium C++ ABI for the compat multilib. - Multilibs.push_back(MultilibBuilder("compat", {}, {}, 6) + Multilibs.push_back(MultilibBuilder("compat", {}, {}) .flag("+fc++-abi=itanium") .makeMultilib()); @@ -298,10 +298,11 @@ return llvm::all_of(RD, [&](std::string P) { return !getVFS().exists(P); }); }); - Multilib::flags_list Flags; - addMultilibFlag( - Args.hasFlag(options::OPT_fexceptions, options::OPT_fno_exceptions, true), - "fexceptions", Flags); + Multilib::flag_set Flags; + bool Exceptions = + Args.hasFlag(options::OPT_fexceptions, options::OPT_fno_exceptions, true); + addMultilibFlag(Exceptions, "fexceptions", Flags); + addMultilibFlag(!Exceptions, "fno-exceptions", Flags); addMultilibFlag(getSanitizerArgs(Args).needsAsanRt(), "fsanitize=address", Flags); addMultilibFlag(getSanitizerArgs(Args).needsHwasanRt(), "fsanitize=hwaddress", diff --git a/clang/lib/Driver/ToolChains/Gnu.cpp b/clang/lib/Driver/ToolChains/Gnu.cpp --- a/clang/lib/Driver/ToolChains/Gnu.cpp +++ b/clang/lib/Driver/ToolChains/Gnu.cpp @@ -1046,7 +1046,7 @@ return Arch == llvm::Triple::msp430; } -static bool findMipsCsMultilibs(const Multilib::flags_list &Flags, +static bool findMipsCsMultilibs(const Multilib::flag_set &Flags, FilterNonExistent &NonExistent, DetectedMultilibs &Result) { // Check for Code Sourcery toolchain multilibs @@ -1144,7 +1144,7 @@ } static bool findMipsAndroidMultilibs(llvm::vfs::FileSystem &VFS, StringRef Path, - const Multilib::flags_list &Flags, + const Multilib::flag_set &Flags, FilterNonExistent &NonExistent, DetectedMultilibs &Result) { @@ -1189,7 +1189,7 @@ return false; } -static bool findMipsMuslMultilibs(const Multilib::flags_list &Flags, +static bool findMipsMuslMultilibs(const Multilib::flag_set &Flags, FilterNonExistent &NonExistent, DetectedMultilibs &Result) { // Musl toolchain multilibs @@ -1223,7 +1223,7 @@ return false; } -static bool findMipsMtiMultilibs(const Multilib::flags_list &Flags, +static bool findMipsMtiMultilibs(const Multilib::flag_set &Flags, FilterNonExistent &NonExistent, DetectedMultilibs &Result) { // CodeScape MTI toolchain v1.2 and early. @@ -1404,7 +1404,7 @@ return false; } -static bool findMipsImgMultilibs(const Multilib::flags_list &Flags, +static bool findMipsImgMultilibs(const Multilib::flag_set &Flags, FilterNonExistent &NonExistent, DetectedMultilibs &Result) { // CodeScape IMG toolchain v1.2 and early. @@ -1517,7 +1517,7 @@ llvm::Triple::ArchType TargetArch = TargetTriple.getArch(); - Multilib::flags_list Flags; + Multilib::flag_set Flags; addMultilibFlag(TargetTriple.isMIPS32(), "m32", Flags); addMultilibFlag(TargetTriple.isMIPS64(), "m64", Flags); addMultilibFlag(isMips16(Args), "mips16", Flags); @@ -1599,7 +1599,7 @@ .makeMultilibSet() .FilterOut(NonExistent); - Multilib::flags_list Flags; + Multilib::flag_set Flags; llvm::StringRef Arch = Args.getLastArgValue(options::OPT_march_EQ); bool IsArmArch = TargetTriple.getArch() == llvm::Triple::arm; bool IsThumbArch = TargetTriple.getArch() == llvm::Triple::thumb; @@ -1635,7 +1635,7 @@ Result.Multilibs.push_back(WithExceptions.makeMultilib()); Result.Multilibs.FilterOut(NonExistent); - Multilib::flags_list Flags; + Multilib::flag_set Flags; addMultilibFlag(Args.hasFlag(options::OPT_fexceptions, options::OPT_fno_exceptions, false), "exceptions", Flags); @@ -1658,7 +1658,7 @@ return; auto ARCHName = *Res; - Multilib::flags_list Flags; + Multilib::flag_set Flags; addMultilibFlag(TheFloatABI == tools::csky::FloatABI::Hard, "hard-fp", Flags); addMultilibFlag(TheFloatABI == tools::csky::FloatABI::SoftFP, "soft-fp", Flags); @@ -1746,7 +1746,7 @@ "/../../../../riscv32-unknown-elf/lib" + M.gccSuffix()}); }); - Multilib::flags_list Flags; + Multilib::flag_set Flags; llvm::StringSet<> Added_ABIs; StringRef ABIName = tools::riscv::getRISCVABI(Args, TargetTriple); StringRef MArch = tools::riscv::getRISCVArch(Args, TargetTriple); @@ -1789,7 +1789,7 @@ .makeMultilibSet() .FilterOut(NonExistent); - Multilib::flags_list Flags; + Multilib::flag_set Flags; bool IsRV64 = TargetTriple.getArch() == llvm::Triple::riscv64; StringRef ABIName = tools::riscv::getRISCVABI(Args, TargetTriple); @@ -1900,7 +1900,7 @@ Result.Multilibs.FilterOut(NonExistent); - Multilib::flags_list Flags; + Multilib::flag_set Flags; addMultilibFlag(TargetTriple.isArch64Bit() && !IsX32, "m64", Flags); addMultilibFlag(TargetTriple.isArch32Bit(), "m32", Flags); addMultilibFlag(TargetTriple.isArch64Bit() && IsX32, "mx32", Flags); diff --git a/clang/unittests/Driver/MultilibBuilderTest.cpp b/clang/unittests/Driver/MultilibBuilderTest.cpp --- a/clang/unittests/Driver/MultilibBuilderTest.cpp +++ b/clang/unittests/Driver/MultilibBuilderTest.cpp @@ -157,14 +157,14 @@ .Maybe(MultilibBuilder("64").flag("+m64")) .makeMultilibSet(); - Multilib::flags_list FlagM64 = {"+m64"}; + Multilib::flag_set FlagM64 = {"+m64"}; 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"; - Multilib::flags_list FlagNoM64 = {"-m64"}; + Multilib::flag_set FlagNoM64 = {"-m64"}; Multilib SelectionNoM64; ASSERT_TRUE(MS1.select(FlagNoM64, SelectionNoM64)) << "Flag set was {\"-m64\"}, but selection not found"; @@ -181,16 +181,16 @@ for (unsigned I = 0; I < 4; ++I) { bool IsEL = I & 0x1; bool IsSF = I & 0x2; - Multilib::flags_list Flags; + Multilib::flag_set Flags; if (IsEL) - Flags.push_back("+EL"); + Flags.insert("+EL"); else - Flags.push_back("-EL"); + Flags.insert("-EL"); if (IsSF) - Flags.push_back("+SF"); + Flags.insert("+SF"); else - Flags.push_back("-SF"); + Flags.insert("-SF"); Multilib Selection; ASSERT_TRUE(MS2.select(Flags, Selection)) @@ -207,3 +207,14 @@ << "Selection picked " << Selection << " which was not expected "; } } + +TEST(MultilibBuilderTest, PrintArgs) { + Multilib M = MultilibBuilder() + .flag("+x") + .flag("-y") + .flag("+a") + .flag("-b") + .flag("+c") + .makeMultilib(); + ASSERT_EQ(Multilib::arg_list({"-x", "-a", "-c"}), M.getPrintArgs()); +} diff --git a/clang/unittests/Driver/MultilibTest.cpp b/clang/unittests/Driver/MultilibTest.cpp --- a/clang/unittests/Driver/MultilibTest.cpp +++ b/clang/unittests/Driver/MultilibTest.cpp @@ -33,14 +33,14 @@ } TEST(MultilibTest, OpEqReflexivity3) { - Multilib M1({}, {}, {}, 0, {"+foo"}); - Multilib M2({}, {}, {}, 0, {"+foo"}); + Multilib M1({}, {}, {}, {"+foo"}); + Multilib M2({}, {}, {}, {"+foo"}); ASSERT_TRUE(M1 == M2) << "Multilibs with the same flag should be the same"; } TEST(MultilibTest, OpEqInequivalence1) { - Multilib M1({}, {}, {}, 0, {"+foo"}); - Multilib M2({}, {}, {}, 0, {"-foo"}); + Multilib M1({}, {}, {}, {"+foo"}); + Multilib M2({}, {}, {}, {"-foo"}); ASSERT_FALSE(M1 == M2) << "Multilibs with conflicting flags are not the same"; ASSERT_FALSE(M2 == M1) << "Multilibs with conflicting flags are not the same (commuted)"; @@ -48,7 +48,7 @@ TEST(MultilibTest, OpEqInequivalence2) { Multilib M1; - Multilib M2({}, {}, {}, 0, {"+foo"}); + Multilib M2({}, {}, {}, {"+foo"}); ASSERT_FALSE(M1 == M2) << "Flags make Multilibs different"; } @@ -124,9 +124,9 @@ } TEST(MultilibTest, Construction3) { - Multilib M({}, {}, {}, 0, {"+f1", "+f2", "-f3"}); - for (Multilib::flags_list::const_iterator I = M.flags().begin(), - E = M.flags().end(); + Multilib M({}, {}, {}, {"+f1", "+f2", "-f3"}); + for (Multilib::flag_set::const_iterator I = M.flags().begin(), + E = M.flags().end(); I != E; ++I) { ASSERT_TRUE(llvm::StringSwitch(*I) .Cases("+f1", "+f2", "-f3", true) @@ -149,20 +149,41 @@ TEST(MultilibTest, SetPriority) { MultilibSet MS({ - Multilib("/foo", {}, {}, 1, {"+foo"}), - Multilib("/bar", {}, {}, 2, {"+bar"}), + Multilib("/foo", {}, {}, {"+foo"}), + Multilib("/bar", {}, {}, {"+bar"}), }); - Multilib::flags_list Flags1 = {"+foo", "-bar"}; + Multilib::flag_set Flags1 = {"+foo", "-bar"}; 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"; - Multilib::flags_list Flags2 = {"+foo", "+bar"}; + Multilib::flag_set Flags2 = {"+foo", "+bar"}; 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"; } + +TEST(MultilibTest, SelectMultiple) { + MultilibSet MS({ + Multilib("/a", {}, {}, {"x"}), + Multilib("/b", {}, {}, {"y"}), + }); + std::vector Selection; + + Selection = MS.select({"x"}); + ASSERT_EQ(1u, Selection.size()); + EXPECT_EQ("/a", Selection[0].gccSuffix()); + + Selection = MS.select({"y"}); + ASSERT_EQ(1u, Selection.size()); + EXPECT_EQ("/b", Selection[0].gccSuffix()); + + Selection = MS.select({"y", "x"}); + ASSERT_EQ(2u, Selection.size()); + EXPECT_EQ("/a", Selection[0].gccSuffix()); + EXPECT_EQ("/b", Selection[1].gccSuffix()); +}