Index: clang/include/clang/Driver/Multilib.h =================================================================== --- clang/include/clang/Driver/Multilib.h +++ clang/include/clang/Driver/Multilib.h @@ -34,10 +34,11 @@ std::string OSSuffix; std::string IncludeSuffix; flags_list Flags; + int Priority; public: Multilib(StringRef GCCSuffix = {}, StringRef OSSuffix = {}, - StringRef IncludeSuffix = {}); + StringRef IncludeSuffix = {}, int Priority = 0); /// Get the detected GCC installation path suffix for the multi-arch /// target variant. Always starts with a '/', unless empty @@ -77,6 +78,10 @@ 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, /// and replaced with either: Index: clang/lib/Driver/Multilib.cpp =================================================================== --- clang/lib/Driver/Multilib.cpp +++ clang/lib/Driver/Multilib.cpp @@ -51,8 +51,9 @@ } Multilib::Multilib(StringRef GCCSuffix, StringRef OSSuffix, - StringRef IncludeSuffix) - : GCCSuffix(GCCSuffix), OSSuffix(OSSuffix), IncludeSuffix(IncludeSuffix) { + StringRef IncludeSuffix, int Priority) + : GCCSuffix(GCCSuffix), OSSuffix(OSSuffix), IncludeSuffix(IncludeSuffix), + Priority(Priority) { normalizePathSegment(this->GCCSuffix); normalizePathSegment(this->OSSuffix); normalizePathSegment(this->IncludeSuffix); @@ -265,8 +266,19 @@ return true; } - // TODO: pick the "best" multlib when more than one is suitable - assert(false); + // Sort multilibs by priority and select the one with the highest priority. + llvm::sort(Filtered.begin(), Filtered.end(), + [](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; } Index: clang/unittests/Driver/MultilibTest.cpp =================================================================== --- clang/unittests/Driver/MultilibTest.cpp +++ clang/unittests/Driver/MultilibTest.cpp @@ -349,3 +349,27 @@ Latte.combineWith(Milk); ASSERT_EQ(Latte.size(), (unsigned)2); } + +TEST(MultilibTest, SetPriority) { + MultilibSet MS; + MS.push_back(Multilib("noexcept", {}, {}, 1).flag("+fno-exceptions")); + MS.push_back(Multilib("asan", {}, {}, 2).flag("+fsanitize=address")); + + Multilib::flags_list Flags1; + Flags1.push_back("+fno-exceptions"); + Flags1.push_back("-fsanitize=address"); + Multilib SelectionNoExcept; + ASSERT_TRUE(MS.select(Flags1, SelectionNoExcept)) + << "Flag set was {\"+fno-exceptions\"}, but selection not found"; + ASSERT_TRUE(SelectionNoExcept.gccSuffix() == "/noexcept") + << "Selection picked " << SelectionNoExcept << " which was not expected"; + + Multilib::flags_list Flags2; + Flags2.push_back("+fno-exceptions"); + Flags2.push_back("+fsanitize=address"); + Multilib SelectionASan; + ASSERT_TRUE(MS.select(Flags2, SelectionASan)) + << "Flag set was {\"+fsanitize=address\"}, but selection not found"; + ASSERT_TRUE(SelectionASan.gccSuffix() == "/asan") + << "Selection picked " << SelectionASan << " which was not expected"; +}