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 @@ -24,7 +24,9 @@ namespace driver { /// This corresponds to a single GCC Multilib, or a segment of one controlled -/// by a command line flag +/// by a command line flag. +/// See also MultilibBuilder for building a multilib by mutating it +/// incrementally. class Multilib { public: using flags_list = std::vector; @@ -37,71 +39,37 @@ int Priority; 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); + StringRef IncludeSuffix = {}, int Priority = 0, + const flags_list &Flags = flags_list()); /// Get the detected GCC installation path suffix for the multi-arch /// target variant. Always starts with a '/', unless empty - const std::string &gccSuffix() const { - assert(GCCSuffix.empty() || - (StringRef(GCCSuffix).front() == '/' && GCCSuffix.size() > 1)); - return GCCSuffix; - } - - /// Set the GCC installation path suffix. - Multilib &gccSuffix(StringRef S); + const std::string &gccSuffix() const { return GCCSuffix; } /// Get the detected os path suffix for the multi-arch /// target variant. Always starts with a '/', unless empty - const std::string &osSuffix() const { - assert(OSSuffix.empty() || - (StringRef(OSSuffix).front() == '/' && OSSuffix.size() > 1)); - return OSSuffix; - } - - /// Set the os path suffix. - Multilib &osSuffix(StringRef S); + const std::string &osSuffix() const { return OSSuffix; } /// Get the include directory suffix. Always starts with a '/', unless /// empty - const std::string &includeSuffix() const { - assert(IncludeSuffix.empty() || - (StringRef(IncludeSuffix).front() == '/' && IncludeSuffix.size() > 1)); - return IncludeSuffix; - } - - /// Set the include directory suffix - Multilib &includeSuffix(StringRef S); + 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; } - 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: - /// '-' which contraindicates using this multilib with that flag - /// or: - /// '+' which promotes using this multilib in the presence of that flag - /// otherwise '-print-multi-lib' will not emit them correctly. - Multilib &flag(StringRef F) { - assert(F.front() == '+' || F.front() == '-'); - Flags.push_back(std::string(F)); - return *this; - } - LLVM_DUMP_METHOD void dump() const; /// print summary of the Multilib void print(raw_ostream &OS) const; - /// Check whether any of the 'against' flags contradict the 'for' flags. - bool isValid() const; - /// Check whether the default is selected bool isDefault() const { return GCCSuffix.empty() && OSSuffix.empty() && IncludeSuffix.empty(); } @@ -111,10 +79,10 @@ raw_ostream &operator<<(raw_ostream &OS, const Multilib &M); +/// See also MultilibSetBuilder for combining multilibs into a set. class MultilibSet { public: using multilib_list = std::vector; - using iterator = multilib_list::iterator; using const_iterator = multilib_list::const_iterator; using IncludeDirsFunc = std::function(const Multilib &M)>; @@ -127,40 +95,17 @@ public: MultilibSet() = default; + MultilibSet(multilib_list &&Multilibs) : Multilibs(Multilibs) {} - /// Add an optional Multilib segment - MultilibSet &Maybe(const Multilib &M); - - /// Add a set of mutually incompatible Multilib segments - MultilibSet &Either(const Multilib &M1, const Multilib &M2); - MultilibSet &Either(const Multilib &M1, const Multilib &M2, - const Multilib &M3); - MultilibSet &Either(const Multilib &M1, const Multilib &M2, - const Multilib &M3, const Multilib &M4); - MultilibSet &Either(const Multilib &M1, const Multilib &M2, - const Multilib &M3, const Multilib &M4, - const Multilib &M5); - MultilibSet &Either(ArrayRef Ms); + const multilib_list &getMultilibs() { return Multilibs; } /// Filter out some subset of the Multilibs using a user defined callback MultilibSet &FilterOut(FilterCallback F); - /// Filter out those Multilibs whose gccSuffix matches the given expression - MultilibSet &FilterOut(const char *Regex); - /// Add a completed Multilib to the set void push_back(const Multilib &M); - /// Union this set of multilibs with another - void combineWith(const MultilibSet &MS); - - /// Remove all of the multilibs from the set - void clear() { Multilibs.clear(); } - - iterator begin() { return Multilibs.begin(); } const_iterator begin() const { return Multilibs.begin(); } - - iterator end() { return Multilibs.end(); } const_iterator end() const { return Multilibs.end(); } /// Pick the best multilib in the set, \returns false if none are compatible diff --git a/clang/include/clang/Driver/MultilibBuilder.h b/clang/include/clang/Driver/MultilibBuilder.h new file mode 100644 --- /dev/null +++ b/clang/include/clang/Driver/MultilibBuilder.h @@ -0,0 +1,148 @@ +//===- MultilibBuilder.h +//-----------------------------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_DRIVER_MULTILIBBUILDER_H +#define LLVM_CLANG_DRIVER_MULTILIBBUILDER_H + +#include "clang/Driver/Multilib.h" + +namespace clang { +namespace driver { + +/// This corresponds to a single GCC multilib, or a segment of one controlled +/// by a command line flag. This class can be used to create a Multilib, and +/// contains helper functions to mutate it before creating a Multilib instance +/// with makeMultilib(). +class MultilibBuilder { +public: + using flags_list = std::vector; + +private: + std::string GCCSuffix; + std::string OSSuffix; + std::string IncludeSuffix; + flags_list Flags; + int Priority; + +public: + MultilibBuilder(StringRef GCCSuffix, StringRef OSSuffix, + StringRef IncludeSuffix, int Priority = 0); + + /// Initializes GCCSuffix, OSSuffix & IncludeSuffix to the same value. + MultilibBuilder(StringRef Suffix = {}); + + /// Get the detected GCC installation path suffix for the multi-arch + /// target variant. Always starts with a '/', unless empty + const std::string &gccSuffix() const { + assert(GCCSuffix.empty() || + (StringRef(GCCSuffix).front() == '/' && GCCSuffix.size() > 1)); + return GCCSuffix; + } + + /// Set the GCC installation path suffix. + MultilibBuilder &gccSuffix(StringRef S); + + /// Get the detected os path suffix for the multi-arch + /// target variant. Always starts with a '/', unless empty + const std::string &osSuffix() const { + assert(OSSuffix.empty() || + (StringRef(OSSuffix).front() == '/' && OSSuffix.size() > 1)); + return OSSuffix; + } + + /// Set the os path suffix. + MultilibBuilder &osSuffix(StringRef S); + + /// Get the include directory suffix. Always starts with a '/', unless + /// empty + const std::string &includeSuffix() const { + assert(IncludeSuffix.empty() || (StringRef(IncludeSuffix).front() == '/' && + IncludeSuffix.size() > 1)); + return IncludeSuffix; + } + + /// Set the include directory suffix + MultilibBuilder &includeSuffix(StringRef S); + + /// Get the flags that indicate or contraindicate this multilib's use + /// All elements begin with either '+' or '-' + 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: + /// '-' which contraindicates using this multilib with that flag + /// or: + /// '+' which promotes using this multilib in the presence of that flag + /// otherwise '-print-multi-lib' will not emit them correctly. + MultilibBuilder &flag(StringRef F) { + assert(F.front() == '+' || F.front() == '-'); + Flags.push_back(std::string(F)); + return *this; + } + + Multilib makeMultilib() const; + + /// Check whether any of the 'against' flags contradict the 'for' flags. + bool isValid() const; + + /// Check whether the default is selected + bool isDefault() const { + return GCCSuffix.empty() && OSSuffix.empty() && IncludeSuffix.empty(); + } +}; + +/// This class can be used to create a MultilibSet, and contains helper +/// functions to add combinations of multilibs before creating a MultilibSet +/// instance with makeMultilibSet(). +class MultilibSetBuilder { +public: + using multilib_list = std::vector; + + MultilibSetBuilder() = default; + + /// Add an optional Multilib segment + MultilibSetBuilder &Maybe(const MultilibBuilder &M); + + /// Add a set of mutually incompatible Multilib segments + MultilibSetBuilder &Either(const MultilibBuilder &M1, + const MultilibBuilder &M2); + MultilibSetBuilder &Either(const MultilibBuilder &M1, + const MultilibBuilder &M2, + const MultilibBuilder &M3); + MultilibSetBuilder &Either(const MultilibBuilder &M1, + const MultilibBuilder &M2, + const MultilibBuilder &M3, + const MultilibBuilder &M4); + MultilibSetBuilder &Either(const MultilibBuilder &M1, + const MultilibBuilder &M2, + const MultilibBuilder &M3, + const MultilibBuilder &M4, + const MultilibBuilder &M5); + MultilibSetBuilder &Either(ArrayRef Ms); + + /// Filter out those Multilibs whose gccSuffix matches the given expression + MultilibSetBuilder &FilterOut(const char *Regex); + + MultilibSet makeMultilibSet() const; + +private: + multilib_list Multilibs; +}; + +} // namespace driver +} // namespace clang + +#endif // LLVM_CLANG_DRIVER_MULTILIBBUILDER_H diff --git a/clang/lib/Driver/CMakeLists.txt b/clang/lib/Driver/CMakeLists.txt --- a/clang/lib/Driver/CMakeLists.txt +++ b/clang/lib/Driver/CMakeLists.txt @@ -22,6 +22,7 @@ DriverOptions.cpp Job.cpp Multilib.cpp + MultilibBuilder.cpp OffloadBundler.cpp OptionUtils.cpp Phases.cpp 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 @@ -25,56 +25,17 @@ using namespace driver; using namespace llvm::sys; -/// normalize Segment to "/foo/bar" or "". -static void normalizePathSegment(std::string &Segment) { - StringRef seg = Segment; - - // Prune trailing "/" or "./" - while (true) { - StringRef last = path::filename(seg); - if (last != ".") - break; - seg = path::parent_path(seg); - } - - if (seg.empty() || seg == "/") { - Segment.clear(); - return; - } - - // Add leading '/' - if (seg.front() != '/') { - Segment = "/" + seg.str(); - } else { - Segment = std::string(seg); - } -} - Multilib::Multilib(StringRef GCCSuffix, StringRef OSSuffix, - StringRef IncludeSuffix, int Priority) + StringRef IncludeSuffix, int Priority, + const flags_list &Flags) : GCCSuffix(GCCSuffix), OSSuffix(OSSuffix), IncludeSuffix(IncludeSuffix), - Priority(Priority) { - normalizePathSegment(this->GCCSuffix); - normalizePathSegment(this->OSSuffix); - normalizePathSegment(this->IncludeSuffix); -} - -Multilib &Multilib::gccSuffix(StringRef S) { - GCCSuffix = std::string(S); - normalizePathSegment(GCCSuffix); - return *this; -} - -Multilib &Multilib::osSuffix(StringRef S) { - OSSuffix = std::string(S); - normalizePathSegment(OSSuffix); - return *this; -} - -Multilib &Multilib::includeSuffix(StringRef S) { - IncludeSuffix = std::string(S); - normalizePathSegment(IncludeSuffix); - return *this; + Flags(Flags), Priority(Priority) { + assert(GCCSuffix.empty() || + (StringRef(GCCSuffix).front() == '/' && GCCSuffix.size() > 1)); + assert(OSSuffix.empty() || + (StringRef(OSSuffix).front() == '/' && OSSuffix.size() > 1)); + assert(IncludeSuffix.empty() || + (StringRef(IncludeSuffix).front() == '/' && IncludeSuffix.size() > 1)); } LLVM_DUMP_METHOD void Multilib::dump() const { @@ -82,7 +43,6 @@ } void Multilib::print(raw_ostream &OS) const { - assert(GCCSuffix.empty() || (StringRef(GCCSuffix).front() == '/')); if (GCCSuffix.empty()) OS << "."; else { @@ -95,22 +55,6 @@ } } -bool Multilib::isValid() const { - llvm::StringMap FlagSet; - for (unsigned I = 0, N = Flags.size(); I != N; ++I) { - StringRef Flag(Flags[I]); - llvm::StringMap::iterator SI = FlagSet.find(Flag.substr(1)); - - assert(StringRef(Flag).front() == '+' || StringRef(Flag).front() == '-'); - - if (SI == FlagSet.end()) - FlagSet[Flag.substr(1)] = I; - else if (Flags[I] != Flags[SI->getValue()]) - return false; - } - return true; -} - bool Multilib::operator==(const Multilib &Other) const { // Check whether the flags sets match // allowing for the match to be order invariant @@ -139,102 +83,13 @@ return OS; } -MultilibSet &MultilibSet::Maybe(const Multilib &M) { - Multilib Opposite; - // Negate any '+' flags - for (StringRef Flag : M.flags()) { - if (Flag.front() == '+') - Opposite.flags().push_back(("-" + Flag.substr(1)).str()); - } - return Either(M, Opposite); -} - -MultilibSet &MultilibSet::Either(const Multilib &M1, const Multilib &M2) { - return Either({M1, M2}); -} - -MultilibSet &MultilibSet::Either(const Multilib &M1, const Multilib &M2, - const Multilib &M3) { - return Either({M1, M2, M3}); -} - -MultilibSet &MultilibSet::Either(const Multilib &M1, const Multilib &M2, - const Multilib &M3, const Multilib &M4) { - return Either({M1, M2, M3, M4}); -} - -MultilibSet &MultilibSet::Either(const Multilib &M1, const Multilib &M2, - const Multilib &M3, const Multilib &M4, - const Multilib &M5) { - return Either({M1, M2, M3, M4, M5}); -} - -static Multilib compose(const Multilib &Base, const Multilib &New) { - SmallString<128> GCCSuffix; - llvm::sys::path::append(GCCSuffix, "/", Base.gccSuffix(), New.gccSuffix()); - SmallString<128> OSSuffix; - llvm::sys::path::append(OSSuffix, "/", Base.osSuffix(), New.osSuffix()); - SmallString<128> IncludeSuffix; - llvm::sys::path::append(IncludeSuffix, "/", Base.includeSuffix(), - New.includeSuffix()); - - Multilib Composed(GCCSuffix, OSSuffix, IncludeSuffix); - - Multilib::flags_list &Flags = Composed.flags(); - - Flags.insert(Flags.end(), Base.flags().begin(), Base.flags().end()); - Flags.insert(Flags.end(), New.flags().begin(), New.flags().end()); - - return Composed; -} - -MultilibSet &MultilibSet::Either(ArrayRef MultilibSegments) { - multilib_list Composed; - - if (Multilibs.empty()) - Multilibs.insert(Multilibs.end(), MultilibSegments.begin(), - MultilibSegments.end()); - else { - for (const auto &New : MultilibSegments) { - for (const auto &Base : *this) { - Multilib MO = compose(Base, New); - if (MO.isValid()) - Composed.push_back(MO); - } - } - - Multilibs = Composed; - } - - return *this; -} - MultilibSet &MultilibSet::FilterOut(FilterCallback F) { filterInPlace(F, Multilibs); return *this; } -MultilibSet &MultilibSet::FilterOut(const char *Regex) { - llvm::Regex R(Regex); -#ifndef NDEBUG - std::string Error; - if (!R.isValid(Error)) { - llvm::errs() << Error; - llvm_unreachable("Invalid regex!"); - } -#endif - - filterInPlace([&R](const Multilib &M) { return R.match(M.gccSuffix()); }, - Multilibs); - return *this; -} - void MultilibSet::push_back(const Multilib &M) { Multilibs.push_back(M); } -void MultilibSet::combineWith(const MultilibSet &Other) { - Multilibs.insert(Multilibs.end(), Other.begin(), Other.end()); -} - static bool isFlagEnabled(StringRef Flag) { char Indicator = Flag.front(); assert(Indicator == '+' || Indicator == '-'); diff --git a/clang/lib/Driver/MultilibBuilder.cpp b/clang/lib/Driver/MultilibBuilder.cpp new file mode 100644 --- /dev/null +++ b/clang/lib/Driver/MultilibBuilder.cpp @@ -0,0 +1,192 @@ +//===- MultilibBuilder.cpp - MultilibBuilder Implementation -===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "clang/Driver/MultilibBuilder.h" +#include "llvm/ADT/SmallString.h" +#include "llvm/ADT/StringMap.h" +#include "llvm/Support/Path.h" +#include "llvm/Support/Regex.h" +#include "llvm/Support/raw_ostream.h" + +using namespace clang; +using namespace driver; + +/// normalize Segment to "/foo/bar" or "". +static void normalizePathSegment(std::string &Segment) { + StringRef seg = Segment; + + // Prune trailing "/" or "./" + while (true) { + StringRef last = llvm::sys::path::filename(seg); + if (last != ".") + break; + seg = llvm::sys::path::parent_path(seg); + } + + if (seg.empty() || seg == "/") { + Segment.clear(); + return; + } + + // Add leading '/' + if (seg.front() != '/') { + Segment = "/" + seg.str(); + } else { + Segment = std::string(seg); + } +} + +MultilibBuilder::MultilibBuilder(StringRef GCC, StringRef OS, StringRef Include, + int Priority) + : GCCSuffix(GCC), OSSuffix(OS), IncludeSuffix(Include), Priority(Priority) { + normalizePathSegment(GCCSuffix); + normalizePathSegment(OSSuffix); + normalizePathSegment(IncludeSuffix); +} + +MultilibBuilder::MultilibBuilder(StringRef Suffix) + : MultilibBuilder(Suffix, Suffix, Suffix) {} + +MultilibBuilder &MultilibBuilder::gccSuffix(StringRef S) { + GCCSuffix = std::string(S); + normalizePathSegment(GCCSuffix); + return *this; +} + +MultilibBuilder &MultilibBuilder::osSuffix(StringRef S) { + OSSuffix = std::string(S); + normalizePathSegment(OSSuffix); + return *this; +} + +MultilibBuilder &MultilibBuilder::includeSuffix(StringRef S) { + IncludeSuffix = std::string(S); + normalizePathSegment(IncludeSuffix); + return *this; +} + +bool MultilibBuilder::isValid() const { + llvm::StringMap FlagSet; + for (unsigned I = 0, N = Flags.size(); I != N; ++I) { + StringRef Flag(Flags[I]); + llvm::StringMap::iterator SI = FlagSet.find(Flag.substr(1)); + + assert(StringRef(Flag).front() == '+' || StringRef(Flag).front() == '-'); + + if (SI == FlagSet.end()) + FlagSet[Flag.substr(1)] = I; + else if (Flags[I] != Flags[SI->getValue()]) + return false; + } + return true; +} + +Multilib MultilibBuilder::makeMultilib() const { + return Multilib(GCCSuffix, OSSuffix, IncludeSuffix, Priority, Flags); +} + +MultilibSetBuilder &MultilibSetBuilder::Maybe(const MultilibBuilder &M) { + MultilibBuilder Opposite; + // Negate any '+' flags + for (StringRef Flag : M.flags()) { + if (Flag.front() == '+') + Opposite.flags().push_back(("-" + Flag.substr(1)).str()); + } + return Either(M, Opposite); +} + +MultilibSetBuilder &MultilibSetBuilder::Either(const MultilibBuilder &M1, + const MultilibBuilder &M2) { + return Either({M1, M2}); +} + +MultilibSetBuilder &MultilibSetBuilder::Either(const MultilibBuilder &M1, + const MultilibBuilder &M2, + const MultilibBuilder &M3) { + return Either({M1, M2, M3}); +} + +MultilibSetBuilder &MultilibSetBuilder::Either(const MultilibBuilder &M1, + const MultilibBuilder &M2, + const MultilibBuilder &M3, + const MultilibBuilder &M4) { + return Either({M1, M2, M3, M4}); +} + +MultilibSetBuilder &MultilibSetBuilder::Either(const MultilibBuilder &M1, + const MultilibBuilder &M2, + const MultilibBuilder &M3, + const MultilibBuilder &M4, + const MultilibBuilder &M5) { + return Either({M1, M2, M3, M4, M5}); +} + +static MultilibBuilder compose(const MultilibBuilder &Base, + const MultilibBuilder &New) { + SmallString<128> GCCSuffix; + llvm::sys::path::append(GCCSuffix, "/", Base.gccSuffix(), New.gccSuffix()); + SmallString<128> OSSuffix; + llvm::sys::path::append(OSSuffix, "/", Base.osSuffix(), New.osSuffix()); + SmallString<128> IncludeSuffix; + llvm::sys::path::append(IncludeSuffix, "/", Base.includeSuffix(), + New.includeSuffix()); + + MultilibBuilder Composed(GCCSuffix, OSSuffix, IncludeSuffix); + + MultilibBuilder::flags_list &Flags = Composed.flags(); + + Flags.insert(Flags.end(), Base.flags().begin(), Base.flags().end()); + Flags.insert(Flags.end(), New.flags().begin(), New.flags().end()); + + return Composed; +} + +MultilibSetBuilder & +MultilibSetBuilder::Either(ArrayRef MultilibSegments) { + multilib_list Composed; + + if (Multilibs.empty()) + Multilibs.insert(Multilibs.end(), MultilibSegments.begin(), + MultilibSegments.end()); + else { + for (const auto &New : MultilibSegments) { + for (const auto &Base : Multilibs) { + MultilibBuilder MO = compose(Base, New); + if (MO.isValid()) + Composed.push_back(MO); + } + } + + Multilibs = Composed; + } + + return *this; +} + +MultilibSetBuilder &MultilibSetBuilder::FilterOut(const char *Regex) { + llvm::Regex R(Regex); +#ifndef NDEBUG + std::string Error; + if (!R.isValid(Error)) { + llvm::errs() << Error; + llvm_unreachable("Invalid regex!"); + } +#endif + llvm::erase_if(Multilibs, [&R](const MultilibBuilder &M) { + return R.match(M.gccSuffix()); + }); + return *this; +} + +MultilibSet MultilibSetBuilder::makeMultilibSet() const { + MultilibSet Result; + for (const auto &M : Multilibs) { + Result.push_back(M.makeMultilib()); + } + return Result; +} 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 @@ -16,6 +16,7 @@ #include "clang/Driver/Compilation.h" #include "clang/Driver/Driver.h" #include "clang/Driver/DriverDiagnostic.h" +#include "clang/Driver/MultilibBuilder.h" #include "clang/Driver/Options.h" #include "llvm/Option/ArgList.h" #include "llvm/Support/Path.h" @@ -28,10 +29,6 @@ using namespace clang::driver::tools; using namespace clang::driver::toolchains; -static Multilib makeMultilib(StringRef commonSuffix) { - return Multilib(commonSuffix, commonSuffix, commonSuffix); -} - static bool findRISCVMultilibs(const Driver &D, const llvm::Triple &TargetTriple, const ArgList &Args, DetectedMultilibs &Result) { @@ -40,10 +37,11 @@ StringRef Abi = tools::riscv::getRISCVABI(Args, TargetTriple); if (TargetTriple.isRISCV64()) { - Multilib Imac = makeMultilib("").flag("+march=rv64imac").flag("+mabi=lp64"); - Multilib Imafdc = makeMultilib("/rv64imafdc/lp64d") - .flag("+march=rv64imafdc") - .flag("+mabi=lp64d"); + MultilibBuilder Imac = + MultilibBuilder().flag("+march=rv64imac").flag("+mabi=lp64"); + MultilibBuilder Imafdc = MultilibBuilder("/rv64imafdc/lp64d") + .flag("+march=rv64imafdc") + .flag("+mabi=lp64d"); // Multilib reuse bool UseImafdc = @@ -54,22 +52,25 @@ addMultilibFlag(Abi == "lp64", "mabi=lp64", Flags); addMultilibFlag(Abi == "lp64d", "mabi=lp64d", Flags); - Result.Multilibs = MultilibSet().Either(Imac, Imafdc); + Result.Multilibs = + MultilibSetBuilder().Either(Imac, Imafdc).makeMultilibSet(); return Result.Multilibs.select(Flags, Result.SelectedMultilib); } if (TargetTriple.isRISCV32()) { - Multilib Imac = - makeMultilib("").flag("+march=rv32imac").flag("+mabi=ilp32"); - Multilib I = - makeMultilib("/rv32i/ilp32").flag("+march=rv32i").flag("+mabi=ilp32"); - Multilib Im = - makeMultilib("/rv32im/ilp32").flag("+march=rv32im").flag("+mabi=ilp32"); - Multilib Iac = makeMultilib("/rv32iac/ilp32") - .flag("+march=rv32iac") - .flag("+mabi=ilp32"); - Multilib Imafc = makeMultilib("/rv32imafc/ilp32f") - .flag("+march=rv32imafc") - .flag("+mabi=ilp32f"); + MultilibBuilder Imac = + MultilibBuilder().flag("+march=rv32imac").flag("+mabi=ilp32"); + MultilibBuilder I = MultilibBuilder("/rv32i/ilp32") + .flag("+march=rv32i") + .flag("+mabi=ilp32"); + MultilibBuilder Im = MultilibBuilder("/rv32im/ilp32") + .flag("+march=rv32im") + .flag("+mabi=ilp32"); + MultilibBuilder Iac = MultilibBuilder("/rv32iac/ilp32") + .flag("+march=rv32iac") + .flag("+mabi=ilp32"); + MultilibBuilder Imafc = MultilibBuilder("/rv32imafc/ilp32f") + .flag("+march=rv32imafc") + .flag("+mabi=ilp32f"); // Multilib reuse bool UseI = (Arch == "rv32i") || (Arch == "rv32ic"); // ic => i @@ -85,7 +86,8 @@ addMultilibFlag(Abi == "ilp32", "mabi=ilp32", Flags); addMultilibFlag(Abi == "ilp32f", "mabi=ilp32f", Flags); - Result.Multilibs = MultilibSet().Either(I, Im, Iac, Imac, Imafc); + Result.Multilibs = + MultilibSetBuilder().Either(I, Im, Iac, Imac, Imafc).makeMultilibSet(); return Result.Multilibs.select(Flags, Result.SelectedMultilib); } return false; 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 @@ -12,6 +12,7 @@ #include "clang/Driver/Compilation.h" #include "clang/Driver/Driver.h" #include "clang/Driver/DriverDiagnostic.h" +#include "clang/Driver/MultilibBuilder.h" #include "clang/Driver/Options.h" #include "clang/Driver/SanitizerArgs.h" #include "llvm/Option/ArgList.h" @@ -262,28 +263,35 @@ Multilibs.push_back(Multilib()); // Use the noexcept variant with -fno-exceptions to avoid the extra overhead. - Multilibs.push_back(Multilib("noexcept", {}, {}, 1) + Multilibs.push_back(MultilibBuilder("noexcept", {}, {}, 1) .flag("-fexceptions") - .flag("+fno-exceptions")); + .flag("+fno-exceptions") + .makeMultilib()); // ASan has higher priority because we always want the instrumentated version. - Multilibs.push_back(Multilib("asan", {}, {}, 2) - .flag("+fsanitize=address")); + Multilibs.push_back(MultilibBuilder("asan", {}, {}, 2) + .flag("+fsanitize=address") + .makeMultilib()); // Use the asan+noexcept variant with ASan and -fno-exceptions. - Multilibs.push_back(Multilib("asan+noexcept", {}, {}, 3) + Multilibs.push_back(MultilibBuilder("asan+noexcept", {}, {}, 3) .flag("+fsanitize=address") .flag("-fexceptions") - .flag("+fno-exceptions")); + .flag("+fno-exceptions") + .makeMultilib()); // HWASan has higher priority because we always want the instrumentated // version. - Multilibs.push_back( - Multilib("hwasan", {}, {}, 4).flag("+fsanitize=hwaddress")); + Multilibs.push_back(MultilibBuilder("hwasan", {}, {}, 4) + .flag("+fsanitize=hwaddress") + .makeMultilib()); // Use the hwasan+noexcept variant with HWASan and -fno-exceptions. - Multilibs.push_back(Multilib("hwasan+noexcept", {}, {}, 5) + Multilibs.push_back(MultilibBuilder("hwasan+noexcept", {}, {}, 5) .flag("+fsanitize=hwaddress") .flag("-fexceptions") - .flag("+fno-exceptions")); + .flag("+fno-exceptions") + .makeMultilib()); // Use Itanium C++ ABI for the compat multilib. - Multilibs.push_back(Multilib("compat", {}, {}, 6).flag("+fc++-abi=itanium")); + Multilibs.push_back(MultilibBuilder("compat", {}, {}, 6) + .flag("+fc++-abi=itanium") + .makeMultilib()); Multilibs.FilterOut([&](const Multilib &M) { std::vector RD = FilePaths(M); 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 @@ -20,6 +20,7 @@ #include "clang/Driver/Compilation.h" #include "clang/Driver/Driver.h" #include "clang/Driver/DriverDiagnostic.h" +#include "clang/Driver/MultilibBuilder.h" #include "clang/Driver/Options.h" #include "clang/Driver/Tool.h" #include "clang/Driver/ToolChain.h" @@ -1045,38 +1046,34 @@ return Arch == llvm::Triple::msp430; } -static Multilib makeMultilib(StringRef commonSuffix) { - return Multilib(commonSuffix, commonSuffix, commonSuffix); -} - static bool findMipsCsMultilibs(const Multilib::flags_list &Flags, FilterNonExistent &NonExistent, DetectedMultilibs &Result) { // Check for Code Sourcery toolchain multilibs MultilibSet CSMipsMultilibs; { - auto MArchMips16 = makeMultilib("/mips16").flag("+m32").flag("+mips16"); + auto MArchMips16 = MultilibBuilder("/mips16").flag("+m32").flag("+mips16"); auto MArchMicroMips = - makeMultilib("/micromips").flag("+m32").flag("+mmicromips"); + MultilibBuilder("/micromips").flag("+m32").flag("+mmicromips"); - auto MArchDefault = makeMultilib("").flag("-mips16").flag("-mmicromips"); + auto MArchDefault = MultilibBuilder("").flag("-mips16").flag("-mmicromips"); - auto UCLibc = makeMultilib("/uclibc").flag("+muclibc"); + auto UCLibc = MultilibBuilder("/uclibc").flag("+muclibc"); - auto SoftFloat = makeMultilib("/soft-float").flag("+msoft-float"); + auto SoftFloat = MultilibBuilder("/soft-float").flag("+msoft-float"); - auto Nan2008 = makeMultilib("/nan2008").flag("+mnan=2008"); + auto Nan2008 = MultilibBuilder("/nan2008").flag("+mnan=2008"); auto DefaultFloat = - makeMultilib("").flag("-msoft-float").flag("-mnan=2008"); + MultilibBuilder("").flag("-msoft-float").flag("-mnan=2008"); - auto BigEndian = makeMultilib("").flag("+EB").flag("-EL"); + auto BigEndian = MultilibBuilder("").flag("+EB").flag("-EL"); - auto LittleEndian = makeMultilib("/el").flag("+EL").flag("-EB"); + auto LittleEndian = MultilibBuilder("/el").flag("+EL").flag("-EB"); // Note that this one's osSuffix is "" - auto MAbi64 = makeMultilib("") + auto MAbi64 = MultilibBuilder("") .gccSuffix("/64") .includeSuffix("/64") .flag("+mabi=n64") @@ -1084,7 +1081,7 @@ .flag("-m32"); CSMipsMultilibs = - MultilibSet() + MultilibSetBuilder() .Either(MArchMips16, MArchMicroMips, MArchDefault) .Maybe(UCLibc) .Either(SoftFloat, Nan2008, DefaultFloat) @@ -1094,6 +1091,7 @@ .Maybe(MAbi64) .FilterOut("/mips16.*/64") .FilterOut("/micromips.*/64") + .makeMultilibSet() .FilterOut(NonExistent) .setIncludeDirsCallback([](const Multilib &M) { std::vector Dirs({"/include"}); @@ -1108,21 +1106,25 @@ MultilibSet DebianMipsMultilibs; { - Multilib MAbiN32 = - Multilib().gccSuffix("/n32").includeSuffix("/n32").flag("+mabi=n32"); + MultilibBuilder MAbiN32 = + MultilibBuilder().gccSuffix("/n32").includeSuffix("/n32").flag( + "+mabi=n32"); - Multilib M64 = Multilib() - .gccSuffix("/64") - .includeSuffix("/64") - .flag("+m64") - .flag("-m32") - .flag("-mabi=n32"); + MultilibBuilder M64 = MultilibBuilder() + .gccSuffix("/64") + .includeSuffix("/64") + .flag("+m64") + .flag("-m32") + .flag("-mabi=n32"); - Multilib M32 = - Multilib().gccSuffix("/32").flag("-m64").flag("+m32").flag("-mabi=n32"); + MultilibBuilder M32 = + MultilibBuilder().gccSuffix("/32").flag("-m64").flag("+m32").flag( + "-mabi=n32"); - DebianMipsMultilibs = - MultilibSet().Either(M32, M64, MAbiN32).FilterOut(NonExistent); + DebianMipsMultilibs = MultilibSetBuilder() + .Either(M32, M64, MAbiN32) + .makeMultilibSet() + .FilterOut(NonExistent); } // Sort candidates. Toolchain that best meets the directories tree goes first. @@ -1147,25 +1149,32 @@ DetectedMultilibs &Result) { MultilibSet AndroidMipsMultilibs = - MultilibSet() - .Maybe(Multilib("/mips-r2").flag("+march=mips32r2")) - .Maybe(Multilib("/mips-r6").flag("+march=mips32r6")) + MultilibSetBuilder() + .Maybe(MultilibBuilder("/mips-r2", {}, {}).flag("+march=mips32r2")) + .Maybe(MultilibBuilder("/mips-r6", {}, {}).flag("+march=mips32r6")) + .makeMultilibSet() .FilterOut(NonExistent); MultilibSet AndroidMipselMultilibs = - MultilibSet() - .Either(Multilib().flag("+march=mips32"), - Multilib("/mips-r2", "", "/mips-r2").flag("+march=mips32r2"), - Multilib("/mips-r6", "", "/mips-r6").flag("+march=mips32r6")) + MultilibSetBuilder() + .Either(MultilibBuilder().flag("+march=mips32"), + MultilibBuilder("/mips-r2", "", "/mips-r2") + .flag("+march=mips32r2"), + MultilibBuilder("/mips-r6", "", "/mips-r6") + .flag("+march=mips32r6")) + .makeMultilibSet() .FilterOut(NonExistent); MultilibSet AndroidMips64elMultilibs = - MultilibSet() - .Either( - Multilib().flag("+march=mips64r6"), - Multilib("/32/mips-r1", "", "/mips-r1").flag("+march=mips32"), - Multilib("/32/mips-r2", "", "/mips-r2").flag("+march=mips32r2"), - Multilib("/32/mips-r6", "", "/mips-r6").flag("+march=mips32r6")) + MultilibSetBuilder() + .Either(MultilibBuilder().flag("+march=mips64r6"), + MultilibBuilder("/32/mips-r1", "", "/mips-r1") + .flag("+march=mips32"), + MultilibBuilder("/32/mips-r2", "", "/mips-r2") + .flag("+march=mips32r2"), + MultilibBuilder("/32/mips-r6", "", "/mips-r6") + .flag("+march=mips32r6")) + .makeMultilibSet() .FilterOut(NonExistent); MultilibSet *MS = &AndroidMipsMultilibs; @@ -1186,18 +1195,20 @@ // Musl toolchain multilibs MultilibSet MuslMipsMultilibs; { - auto MArchMipsR2 = makeMultilib("") + auto MArchMipsR2 = MultilibBuilder("") .osSuffix("/mips-r2-hard-musl") .flag("+EB") .flag("-EL") .flag("+march=mips32r2"); - auto MArchMipselR2 = makeMultilib("/mipsel-r2-hard-musl") + auto MArchMipselR2 = MultilibBuilder("/mipsel-r2-hard-musl") .flag("-EB") .flag("+EL") .flag("+march=mips32r2"); - MuslMipsMultilibs = MultilibSet().Either(MArchMipsR2, MArchMipselR2); + MuslMipsMultilibs = MultilibSetBuilder() + .Either(MArchMipsR2, MArchMipselR2) + .makeMultilibSet(); // Specify the callback that computes the include directories. MuslMipsMultilibs.setIncludeDirsCallback([](const Multilib &M) { @@ -1218,48 +1229,49 @@ // CodeScape MTI toolchain v1.2 and early. MultilibSet MtiMipsMultilibsV1; { - auto MArchMips32 = makeMultilib("/mips32") + auto MArchMips32 = MultilibBuilder("/mips32") .flag("+m32") .flag("-m64") .flag("-mmicromips") .flag("+march=mips32"); - auto MArchMicroMips = makeMultilib("/micromips") + auto MArchMicroMips = MultilibBuilder("/micromips") .flag("+m32") .flag("-m64") .flag("+mmicromips"); - auto MArchMips64r2 = makeMultilib("/mips64r2") + auto MArchMips64r2 = MultilibBuilder("/mips64r2") .flag("-m32") .flag("+m64") .flag("+march=mips64r2"); - auto MArchMips64 = makeMultilib("/mips64").flag("-m32").flag("+m64").flag( - "-march=mips64r2"); + auto MArchMips64 = + MultilibBuilder("/mips64").flag("-m32").flag("+m64").flag( + "-march=mips64r2"); - auto MArchDefault = makeMultilib("") + auto MArchDefault = MultilibBuilder("") .flag("+m32") .flag("-m64") .flag("-mmicromips") .flag("+march=mips32r2"); - auto Mips16 = makeMultilib("/mips16").flag("+mips16"); + auto Mips16 = MultilibBuilder("/mips16").flag("+mips16"); - auto UCLibc = makeMultilib("/uclibc").flag("+muclibc"); + auto UCLibc = MultilibBuilder("/uclibc").flag("+muclibc"); auto MAbi64 = - makeMultilib("/64").flag("+mabi=n64").flag("-mabi=n32").flag("-m32"); + MultilibBuilder("/64").flag("+mabi=n64").flag("-mabi=n32").flag("-m32"); - auto BigEndian = makeMultilib("").flag("+EB").flag("-EL"); + auto BigEndian = MultilibBuilder("").flag("+EB").flag("-EL"); - auto LittleEndian = makeMultilib("/el").flag("+EL").flag("-EB"); + auto LittleEndian = MultilibBuilder("/el").flag("+EL").flag("-EB"); - auto SoftFloat = makeMultilib("/sof").flag("+msoft-float"); + auto SoftFloat = MultilibBuilder("/sof").flag("+msoft-float"); - auto Nan2008 = makeMultilib("/nan2008").flag("+mnan=2008"); + auto Nan2008 = MultilibBuilder("/nan2008").flag("+mnan=2008"); MtiMipsMultilibsV1 = - MultilibSet() + MultilibSetBuilder() .Either(MArchMips32, MArchMicroMips, MArchMips64r2, MArchMips64, MArchDefault) .Maybe(UCLibc) @@ -1276,6 +1288,7 @@ .Maybe(SoftFloat) .Maybe(Nan2008) .FilterOut(".*sof/nan2008") + .makeMultilibSet() .FilterOut(NonExistent) .setIncludeDirsCallback([](const Multilib &M) { std::vector Dirs({"/include"}); @@ -1290,80 +1303,87 @@ // CodeScape IMG toolchain starting from v1.3. MultilibSet MtiMipsMultilibsV2; { - auto BeHard = makeMultilib("/mips-r2-hard") + auto BeHard = MultilibBuilder("/mips-r2-hard") .flag("+EB") .flag("-msoft-float") .flag("-mnan=2008") .flag("-muclibc"); - auto BeSoft = makeMultilib("/mips-r2-soft") + auto BeSoft = MultilibBuilder("/mips-r2-soft") .flag("+EB") .flag("+msoft-float") .flag("-mnan=2008"); - auto ElHard = makeMultilib("/mipsel-r2-hard") + auto ElHard = MultilibBuilder("/mipsel-r2-hard") .flag("+EL") .flag("-msoft-float") .flag("-mnan=2008") .flag("-muclibc"); - auto ElSoft = makeMultilib("/mipsel-r2-soft") + auto ElSoft = MultilibBuilder("/mipsel-r2-soft") .flag("+EL") .flag("+msoft-float") .flag("-mnan=2008") .flag("-mmicromips"); - auto BeHardNan = makeMultilib("/mips-r2-hard-nan2008") + auto BeHardNan = MultilibBuilder("/mips-r2-hard-nan2008") .flag("+EB") .flag("-msoft-float") .flag("+mnan=2008") .flag("-muclibc"); - auto ElHardNan = makeMultilib("/mipsel-r2-hard-nan2008") + auto ElHardNan = MultilibBuilder("/mipsel-r2-hard-nan2008") .flag("+EL") .flag("-msoft-float") .flag("+mnan=2008") .flag("-muclibc") .flag("-mmicromips"); - auto BeHardNanUclibc = makeMultilib("/mips-r2-hard-nan2008-uclibc") + auto BeHardNanUclibc = MultilibBuilder("/mips-r2-hard-nan2008-uclibc") .flag("+EB") .flag("-msoft-float") .flag("+mnan=2008") .flag("+muclibc"); - auto ElHardNanUclibc = makeMultilib("/mipsel-r2-hard-nan2008-uclibc") + auto ElHardNanUclibc = MultilibBuilder("/mipsel-r2-hard-nan2008-uclibc") .flag("+EL") .flag("-msoft-float") .flag("+mnan=2008") .flag("+muclibc"); - auto BeHardUclibc = makeMultilib("/mips-r2-hard-uclibc") + auto BeHardUclibc = MultilibBuilder("/mips-r2-hard-uclibc") .flag("+EB") .flag("-msoft-float") .flag("-mnan=2008") .flag("+muclibc"); - auto ElHardUclibc = makeMultilib("/mipsel-r2-hard-uclibc") + auto ElHardUclibc = MultilibBuilder("/mipsel-r2-hard-uclibc") .flag("+EL") .flag("-msoft-float") .flag("-mnan=2008") .flag("+muclibc"); - auto ElMicroHardNan = makeMultilib("/micromipsel-r2-hard-nan2008") + auto ElMicroHardNan = MultilibBuilder("/micromipsel-r2-hard-nan2008") .flag("+EL") .flag("-msoft-float") .flag("+mnan=2008") .flag("+mmicromips"); - auto ElMicroSoft = makeMultilib("/micromipsel-r2-soft") + auto ElMicroSoft = MultilibBuilder("/micromipsel-r2-soft") .flag("+EL") .flag("+msoft-float") .flag("-mnan=2008") .flag("+mmicromips"); - auto O32 = - makeMultilib("/lib").osSuffix("").flag("-mabi=n32").flag("-mabi=n64"); - auto N32 = - makeMultilib("/lib32").osSuffix("").flag("+mabi=n32").flag("-mabi=n64"); - auto N64 = - makeMultilib("/lib64").osSuffix("").flag("-mabi=n32").flag("+mabi=n64"); + auto O32 = MultilibBuilder("/lib") + .osSuffix("") + .flag("-mabi=n32") + .flag("-mabi=n64"); + auto N32 = MultilibBuilder("/lib32") + .osSuffix("") + .flag("+mabi=n32") + .flag("-mabi=n64"); + auto N64 = MultilibBuilder("/lib64") + .osSuffix("") + .flag("-mabi=n32") + .flag("+mabi=n64"); MtiMipsMultilibsV2 = - MultilibSet() + MultilibSetBuilder() .Either({BeHard, BeSoft, ElHard, ElSoft, BeHardNan, ElHardNan, BeHardNanUclibc, ElHardNanUclibc, BeHardUclibc, ElHardUclibc, ElMicroHardNan, ElMicroSoft}) .Either(O32, N32, N64) + .makeMultilibSet() .FilterOut(NonExistent) .setIncludeDirsCallback([](const Multilib &M) { return std::vector({"/../../../../sysroot" + @@ -1390,18 +1410,19 @@ // CodeScape IMG toolchain v1.2 and early. MultilibSet ImgMultilibsV1; { - auto Mips64r6 = makeMultilib("/mips64r6").flag("+m64").flag("-m32"); + auto Mips64r6 = MultilibBuilder("/mips64r6").flag("+m64").flag("-m32"); - auto LittleEndian = makeMultilib("/el").flag("+EL").flag("-EB"); + auto LittleEndian = MultilibBuilder("/el").flag("+EL").flag("-EB"); auto MAbi64 = - makeMultilib("/64").flag("+mabi=n64").flag("-mabi=n32").flag("-m32"); + MultilibBuilder("/64").flag("+mabi=n64").flag("-mabi=n32").flag("-m32"); ImgMultilibsV1 = - MultilibSet() + MultilibSetBuilder() .Maybe(Mips64r6) .Maybe(MAbi64) .Maybe(LittleEndian) + .makeMultilibSet() .FilterOut(NonExistent) .setIncludeDirsCallback([](const Multilib &M) { return std::vector( @@ -1412,51 +1433,58 @@ // CodeScape IMG toolchain starting from v1.3. MultilibSet ImgMultilibsV2; { - auto BeHard = makeMultilib("/mips-r6-hard") + auto BeHard = MultilibBuilder("/mips-r6-hard") .flag("+EB") .flag("-msoft-float") .flag("-mmicromips"); - auto BeSoft = makeMultilib("/mips-r6-soft") + auto BeSoft = MultilibBuilder("/mips-r6-soft") .flag("+EB") .flag("+msoft-float") .flag("-mmicromips"); - auto ElHard = makeMultilib("/mipsel-r6-hard") + auto ElHard = MultilibBuilder("/mipsel-r6-hard") .flag("+EL") .flag("-msoft-float") .flag("-mmicromips"); - auto ElSoft = makeMultilib("/mipsel-r6-soft") + auto ElSoft = MultilibBuilder("/mipsel-r6-soft") .flag("+EL") .flag("+msoft-float") .flag("-mmicromips"); - auto BeMicroHard = makeMultilib("/micromips-r6-hard") + auto BeMicroHard = MultilibBuilder("/micromips-r6-hard") .flag("+EB") .flag("-msoft-float") .flag("+mmicromips"); - auto BeMicroSoft = makeMultilib("/micromips-r6-soft") + auto BeMicroSoft = MultilibBuilder("/micromips-r6-soft") .flag("+EB") .flag("+msoft-float") .flag("+mmicromips"); - auto ElMicroHard = makeMultilib("/micromipsel-r6-hard") + auto ElMicroHard = MultilibBuilder("/micromipsel-r6-hard") .flag("+EL") .flag("-msoft-float") .flag("+mmicromips"); - auto ElMicroSoft = makeMultilib("/micromipsel-r6-soft") + auto ElMicroSoft = MultilibBuilder("/micromipsel-r6-soft") .flag("+EL") .flag("+msoft-float") .flag("+mmicromips"); - auto O32 = - makeMultilib("/lib").osSuffix("").flag("-mabi=n32").flag("-mabi=n64"); - auto N32 = - makeMultilib("/lib32").osSuffix("").flag("+mabi=n32").flag("-mabi=n64"); - auto N64 = - makeMultilib("/lib64").osSuffix("").flag("-mabi=n32").flag("+mabi=n64"); + auto O32 = MultilibBuilder("/lib") + .osSuffix("") + .flag("-mabi=n32") + .flag("-mabi=n64"); + auto N32 = MultilibBuilder("/lib32") + .osSuffix("") + .flag("+mabi=n32") + .flag("-mabi=n64"); + auto N64 = MultilibBuilder("/lib64") + .osSuffix("") + .flag("-mabi=n32") + .flag("+mabi=n64"); ImgMultilibsV2 = - MultilibSet() + MultilibSetBuilder() .Either({BeHard, BeSoft, ElHard, ElSoft, BeMicroHard, BeMicroSoft, ElMicroHard, ElMicroSoft}) .Either(O32, N32, N64) + .makeMultilibSet() .FilterOut(NonExistent) .setIncludeDirsCallback([](const Multilib &M) { return std::vector({"/../../../../sysroot" + @@ -1556,22 +1584,19 @@ DetectedMultilibs &Result) { // Find multilibs with subdirectories like armv7-a, thumb, armv7-a/thumb. FilterNonExistent NonExistent(Path, "/crtbegin.o", D.getVFS()); - Multilib ArmV7Multilib = makeMultilib("/armv7-a") - .flag("+march=armv7-a") - .flag("-mthumb"); - Multilib ThumbMultilib = makeMultilib("/thumb") - .flag("-march=armv7-a") - .flag("+mthumb"); - Multilib ArmV7ThumbMultilib = makeMultilib("/armv7-a/thumb") - .flag("+march=armv7-a") - .flag("+mthumb"); - Multilib DefaultMultilib = makeMultilib("") - .flag("-march=armv7-a") - .flag("-mthumb"); + MultilibBuilder ArmV7Multilib = + MultilibBuilder("/armv7-a").flag("+march=armv7-a").flag("-mthumb"); + MultilibBuilder ThumbMultilib = + MultilibBuilder("/thumb").flag("-march=armv7-a").flag("+mthumb"); + MultilibBuilder ArmV7ThumbMultilib = + MultilibBuilder("/armv7-a/thumb").flag("+march=armv7-a").flag("+mthumb"); + MultilibBuilder DefaultMultilib = + MultilibBuilder("").flag("-march=armv7-a").flag("-mthumb"); MultilibSet AndroidArmMultilibs = - MultilibSet() - .Either(ThumbMultilib, ArmV7Multilib, - ArmV7ThumbMultilib, DefaultMultilib) + MultilibSetBuilder() + .Either(ThumbMultilib, ArmV7Multilib, ArmV7ThumbMultilib, + DefaultMultilib) + .makeMultilibSet() .FilterOut(NonExistent); Multilib::flags_list Flags; @@ -1597,15 +1622,17 @@ StringRef Path, const ArgList &Args, DetectedMultilibs &Result) { FilterNonExistent NonExistent(Path, "/crtbegin.o", D.getVFS()); - Multilib WithoutExceptions = makeMultilib("/430").flag("-exceptions"); - Multilib WithExceptions = makeMultilib("/430/exceptions").flag("+exceptions"); + MultilibBuilder WithoutExceptions = + MultilibBuilder("/430").flag("-exceptions"); + MultilibBuilder WithExceptions = + MultilibBuilder("/430/exceptions").flag("+exceptions"); // FIXME: when clang starts to support msp430x ISA additional logic // to select between multilib must be implemented - // Multilib MSP430xMultilib = makeMultilib("/large"); + // MultilibBuilder MSP430xMultilib = MultilibBuilder("/large"); - Result.Multilibs.push_back(WithoutExceptions); - Result.Multilibs.push_back(WithExceptions); + Result.Multilibs.push_back(WithoutExceptions.makeMultilib()); + Result.Multilibs.push_back(WithExceptions.makeMultilib()); Result.Multilibs.FilterOut(NonExistent); Multilib::flags_list Flags; @@ -1653,28 +1680,29 @@ isBigEndian = !A->getOption().matches(options::OPT_mlittle_endian); addMultilibFlag(isBigEndian, "EB", Flags); - auto HardFloat = makeMultilib("/hard-fp").flag("+hard-fp"); - auto SoftFpFloat = makeMultilib("/soft-fp").flag("+soft-fp"); - auto SoftFloat = makeMultilib("").flag("+soft"); - auto Arch801 = makeMultilib("/ck801").flag("+march=ck801"); - auto Arch802 = makeMultilib("/ck802").flag("+march=ck802"); - auto Arch803 = makeMultilib("/ck803").flag("+march=ck803"); + auto HardFloat = MultilibBuilder("/hard-fp").flag("+hard-fp"); + auto SoftFpFloat = MultilibBuilder("/soft-fp").flag("+soft-fp"); + auto SoftFloat = MultilibBuilder("").flag("+soft"); + auto Arch801 = MultilibBuilder("/ck801").flag("+march=ck801"); + auto Arch802 = MultilibBuilder("/ck802").flag("+march=ck802"); + auto Arch803 = MultilibBuilder("/ck803").flag("+march=ck803"); // CK804 use the same library as CK803 - auto Arch804 = makeMultilib("/ck803").flag("+march=ck804"); - auto Arch805 = makeMultilib("/ck805").flag("+march=ck805"); - auto Arch807 = makeMultilib("/ck807").flag("+march=ck807"); - auto Arch810 = makeMultilib("").flag("+march=ck810"); - auto Arch810v = makeMultilib("/ck810v").flag("+march=ck810v"); - auto Arch860 = makeMultilib("/ck860").flag("+march=ck860"); - auto Arch860v = makeMultilib("/ck860v").flag("+march=ck860v"); - auto BigEndian = makeMultilib("/big").flag("+EB"); + auto Arch804 = MultilibBuilder("/ck803").flag("+march=ck804"); + auto Arch805 = MultilibBuilder("/ck805").flag("+march=ck805"); + auto Arch807 = MultilibBuilder("/ck807").flag("+march=ck807"); + auto Arch810 = MultilibBuilder("").flag("+march=ck810"); + auto Arch810v = MultilibBuilder("/ck810v").flag("+march=ck810v"); + auto Arch860 = MultilibBuilder("/ck860").flag("+march=ck860"); + auto Arch860v = MultilibBuilder("/ck860v").flag("+march=ck860v"); + auto BigEndian = MultilibBuilder("/big").flag("+EB"); MultilibSet CSKYMultilibs = - MultilibSet() + MultilibSetBuilder() .Maybe(BigEndian) .Either({Arch801, Arch802, Arch803, Arch804, Arch805, Arch807, Arch810, Arch810v, Arch860, Arch860v}) .Either(HardFloat, SoftFpFloat, SoftFloat) + .makeMultilibSet() .FilterOut(NonExistent); if (CSKYMultilibs.select(Flags, Result.SelectedMultilib)) @@ -1697,17 +1725,19 @@ {"rv32imac", "ilp32"}, {"rv32imafc", "ilp32f"}, {"rv64imac", "lp64"}, {"rv64imafdc", "lp64d"}}; - std::vector Ms; + std::vector Ms; for (auto Element : RISCVMultilibSet) { // multilib path rule is ${march}/${mabi} Ms.emplace_back( - makeMultilib((Twine(Element.march) + "/" + Twine(Element.mabi)).str()) + MultilibBuilder( + (Twine(Element.march) + "/" + Twine(Element.mabi)).str()) .flag(Twine("+march=", Element.march).str()) .flag(Twine("+mabi=", Element.mabi).str())); } MultilibSet RISCVMultilibs = - MultilibSet() - .Either(ArrayRef(Ms)) + MultilibSetBuilder() + .Either(Ms) + .makeMultilibSet() .FilterOut(NonExistent) .setFilePathsCallback([](const Multilib &M) { return std::vector( @@ -1716,7 +1746,6 @@ "/../../../../riscv32-unknown-elf/lib" + M.gccSuffix()}); }); - Multilib::flags_list Flags; llvm::StringSet<> Added_ABIs; StringRef ABIName = tools::riscv::getRISCVABI(Args, TargetTriple); @@ -1742,17 +1771,22 @@ return findRISCVBareMetalMultilibs(D, TargetTriple, Path, Args, Result); FilterNonExistent NonExistent(Path, "/crtbegin.o", D.getVFS()); - Multilib Ilp32 = makeMultilib("lib32/ilp32").flag("+m32").flag("+mabi=ilp32"); - Multilib Ilp32f = - makeMultilib("lib32/ilp32f").flag("+m32").flag("+mabi=ilp32f"); - Multilib Ilp32d = - makeMultilib("lib32/ilp32d").flag("+m32").flag("+mabi=ilp32d"); - Multilib Lp64 = makeMultilib("lib64/lp64").flag("+m64").flag("+mabi=lp64"); - Multilib Lp64f = makeMultilib("lib64/lp64f").flag("+m64").flag("+mabi=lp64f"); - Multilib Lp64d = makeMultilib("lib64/lp64d").flag("+m64").flag("+mabi=lp64d"); + MultilibBuilder Ilp32 = + MultilibBuilder("lib32/ilp32").flag("+m32").flag("+mabi=ilp32"); + MultilibBuilder Ilp32f = + MultilibBuilder("lib32/ilp32f").flag("+m32").flag("+mabi=ilp32f"); + MultilibBuilder Ilp32d = + MultilibBuilder("lib32/ilp32d").flag("+m32").flag("+mabi=ilp32d"); + MultilibBuilder Lp64 = + MultilibBuilder("lib64/lp64").flag("+m64").flag("+mabi=lp64"); + MultilibBuilder Lp64f = + MultilibBuilder("lib64/lp64f").flag("+m64").flag("+mabi=lp64f"); + MultilibBuilder Lp64d = + MultilibBuilder("lib64/lp64d").flag("+m64").flag("+mabi=lp64d"); MultilibSet RISCVMultilibs = - MultilibSet() + MultilibSetBuilder() .Either({Ilp32, Ilp32f, Ilp32d, Lp64, Lp64f, Lp64d}) + .makeMultilibSet() .FilterOut(NonExistent); Multilib::flags_list Flags; @@ -1777,7 +1811,7 @@ StringRef Path, const ArgList &Args, bool NeedsBiarchSuffix, DetectedMultilibs &Result) { - Multilib Default; + MultilibBuilder DefaultBuilder; // Some versions of SUSE and Fedora on ppc64 put 32-bit libs // in what would normally be GCCInstallPath and put the 64-bit @@ -1803,24 +1837,27 @@ } } - Multilib Alt64 = Multilib() + Multilib Alt64 = MultilibBuilder() .gccSuffix(Suff64) .includeSuffix(Suff64) .flag("-m32") .flag("+m64") - .flag("-mx32"); - Multilib Alt32 = Multilib() + .flag("-mx32") + .makeMultilib(); + Multilib Alt32 = MultilibBuilder() .gccSuffix("/32") .includeSuffix("/32") .flag("+m32") .flag("-m64") - .flag("-mx32"); - Multilib Altx32 = Multilib() + .flag("-mx32") + .makeMultilib(); + Multilib Altx32 = MultilibBuilder() .gccSuffix("/x32") .includeSuffix("/x32") .flag("-m32") .flag("-m64") - .flag("+mx32"); + .flag("+mx32") + .makeMultilib(); // GCC toolchain for IAMCU doesn't have crtbegin.o, so look for libgcc.a. FilterNonExistent NonExistent( @@ -1846,14 +1883,16 @@ } if (Want == WANT32) - Default.flag("+m32").flag("-m64").flag("-mx32"); + DefaultBuilder.flag("+m32").flag("-m64").flag("-mx32"); else if (Want == WANT64) - Default.flag("-m32").flag("+m64").flag("-mx32"); + DefaultBuilder.flag("-m32").flag("+m64").flag("-mx32"); else if (Want == WANTX32) - Default.flag("-m32").flag("-m64").flag("+mx32"); + DefaultBuilder.flag("-m32").flag("-m64").flag("+mx32"); else return false; + Multilib Default = DefaultBuilder.makeMultilib(); + Result.Multilibs.push_back(Default); Result.Multilibs.push_back(Alt64); Result.Multilibs.push_back(Alt32); diff --git a/clang/unittests/Driver/CMakeLists.txt b/clang/unittests/Driver/CMakeLists.txt --- a/clang/unittests/Driver/CMakeLists.txt +++ b/clang/unittests/Driver/CMakeLists.txt @@ -11,6 +11,7 @@ DXCModeTest.cpp ToolChainTest.cpp ModuleCacheTest.cpp + MultilibBuilderTest.cpp MultilibTest.cpp SanitizerArgsTest.cpp ) diff --git a/clang/unittests/Driver/MultilibBuilderTest.cpp b/clang/unittests/Driver/MultilibBuilderTest.cpp new file mode 100644 --- /dev/null +++ b/clang/unittests/Driver/MultilibBuilderTest.cpp @@ -0,0 +1,209 @@ +//===- unittests/Driver/MultilibBuilderTest.cpp --- MultilibBuilder tests +//---------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// Unit tests for MultilibBuilder and MultilibSetBuilder +// +//===----------------------------------------------------------------------===// + +#include "clang/Driver/MultilibBuilder.h" +#include "../../lib/Driver/ToolChains/CommonArgs.h" +#include "clang/Basic/LLVM.h" +#include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/ADT/StringSwitch.h" +#include "gtest/gtest.h" + +using llvm::is_contained; +using namespace clang; +using namespace driver; + +TEST(MultilibBuilderTest, MultilibValidity) { + + ASSERT_TRUE(MultilibBuilder().isValid()) << "Empty multilib is not valid"; + + ASSERT_TRUE(MultilibBuilder().flag("+foo").isValid()) + << "Single indicative flag is not valid"; + + ASSERT_TRUE(MultilibBuilder().flag("-foo").isValid()) + << "Single contraindicative flag is not valid"; + + ASSERT_FALSE(MultilibBuilder().flag("+foo").flag("-foo").isValid()) + << "Conflicting flags should invalidate the Multilib"; + + ASSERT_TRUE(MultilibBuilder().flag("+foo").flag("+foo").isValid()) + << "Multilib should be valid even if it has the same flag " + "twice"; + + ASSERT_TRUE(MultilibBuilder().flag("+foo").flag("-foobar").isValid()) + << "Seemingly conflicting prefixes shouldn't actually conflict"; +} + +TEST(MultilibBuilderTest, Construction1) { + MultilibBuilder M("gcc64", "os64", "inc64"); + ASSERT_TRUE(M.gccSuffix() == "/gcc64"); + ASSERT_TRUE(M.osSuffix() == "/os64"); + ASSERT_TRUE(M.includeSuffix() == "/inc64"); +} + +TEST(MultilibBuilderTest, Construction3) { + MultilibBuilder M = MultilibBuilder().flag("+f1").flag("+f2").flag("-f3"); + for (const std::string &A : M.flags()) { + ASSERT_TRUE(llvm::StringSwitch(A) + .Cases("+f1", "+f2", "-f3", true) + .Default(false)); + } +} + +TEST(MultilibBuilderTest, SetConstruction1) { + // Single maybe + MultilibSet MS = MultilibSetBuilder() + .Maybe(MultilibBuilder("64").flag("+m64")) + .makeMultilibSet(); + ASSERT_TRUE(MS.size() == 2); + for (MultilibSet::const_iterator I = MS.begin(), E = MS.end(); I != E; ++I) { + if (I->gccSuffix() == "/64") + ASSERT_TRUE(*I->flags().begin() == "+m64"); + else if (I->gccSuffix() == "") + ASSERT_TRUE(*I->flags().begin() == "-m64"); + else + FAIL() << "Unrecognized gccSufix: " << I->gccSuffix(); + } +} + +TEST(MultilibBuilderTest, SetConstruction2) { + // Double maybe + MultilibSet MS = MultilibSetBuilder() + .Maybe(MultilibBuilder("sof").flag("+sof")) + .Maybe(MultilibBuilder("el").flag("+EL")) + .makeMultilibSet(); + ASSERT_TRUE(MS.size() == 4); + for (MultilibSet::const_iterator I = MS.begin(), E = MS.end(); I != E; ++I) { + ASSERT_TRUE(llvm::StringSwitch(I->gccSuffix()) + .Cases("", "/sof", "/el", "/sof/el", true) + .Default(false)) + << "Multilib " << *I << " wasn't expected"; + ASSERT_TRUE(llvm::StringSwitch(I->gccSuffix()) + .Case("", is_contained(I->flags(), "-sof")) + .Case("/sof", is_contained(I->flags(), "+sof")) + .Case("/el", is_contained(I->flags(), "-sof")) + .Case("/sof/el", is_contained(I->flags(), "+sof")) + .Default(false)) + << "Multilib " << *I << " didn't have the appropriate {+,-}sof flag"; + ASSERT_TRUE(llvm::StringSwitch(I->gccSuffix()) + .Case("", is_contained(I->flags(), "-EL")) + .Case("/sof", is_contained(I->flags(), "-EL")) + .Case("/el", is_contained(I->flags(), "+EL")) + .Case("/sof/el", is_contained(I->flags(), "+EL")) + .Default(false)) + << "Multilib " << *I << " didn't have the appropriate {+,-}EL flag"; + } +} + +TEST(MultilibBuilderTest, SetRegexFilter) { + MultilibSetBuilder MB; + MB.Maybe(MultilibBuilder("one")) + .Maybe(MultilibBuilder("two")) + .Maybe(MultilibBuilder("three")) + .makeMultilibSet(); + MultilibSet MS = MB.makeMultilibSet(); + ASSERT_EQ(MS.size(), (unsigned)2 * 2 * 2) + << "Size before filter was incorrect. Contents:\n" + << MS; + MB.FilterOut("/one/two/three"); + MS = MB.makeMultilibSet(); + ASSERT_EQ(MS.size(), (unsigned)2 * 2 * 2 - 1) + << "Size after filter was incorrect. Contents:\n" + << MS; + for (MultilibSet::const_iterator I = MS.begin(), E = MS.end(); I != E; ++I) { + ASSERT_TRUE(I->gccSuffix() != "/one/two/three") + << "The filter should have removed " << *I; + } +} + +TEST(MultilibBuilderTest, SetFilterObject) { + MultilibSet MS = MultilibSetBuilder() + .Maybe(MultilibBuilder("orange")) + .Maybe(MultilibBuilder("pear")) + .Maybe(MultilibBuilder("plum")) + .makeMultilibSet(); + ASSERT_EQ((int)MS.size(), 1 /* Default */ + 1 /* pear */ + 1 /* plum */ + + 1 /* pear/plum */ + 1 /* orange */ + + 1 /* orange/pear */ + 1 /* orange/plum */ + + 1 /* orange/pear/plum */) + << "Size before filter was incorrect. Contents:\n" + << MS; + MS.FilterOut([](const Multilib &M) { + return StringRef(M.gccSuffix()).startswith("/p"); + }); + ASSERT_EQ((int)MS.size(), 1 /* Default */ + 1 /* orange */ + + 1 /* orange/pear */ + 1 /* orange/plum */ + + 1 /* orange/pear/plum */) + << "Size after filter was incorrect. Contents:\n" + << MS; + for (MultilibSet::const_iterator I = MS.begin(), E = MS.end(); I != E; ++I) { + ASSERT_FALSE(StringRef(I->gccSuffix()).startswith("/p")) + << "The filter should have removed " << *I; + } +} + +TEST(MultilibBuilderTest, SetSelection1) { + MultilibSet MS1 = MultilibSetBuilder() + .Maybe(MultilibBuilder("64").flag("+m64")) + .makeMultilibSet(); + + Multilib::flags_list 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 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"; +} + +TEST(MultilibBuilderTest, SetSelection2) { + MultilibSet MS2 = MultilibSetBuilder() + .Maybe(MultilibBuilder("el").flag("+EL")) + .Maybe(MultilibBuilder("sf").flag("+SF")) + .makeMultilibSet(); + + for (unsigned I = 0; I < 4; ++I) { + bool IsEL = I & 0x1; + bool IsSF = I & 0x2; + Multilib::flags_list Flags; + if (IsEL) + Flags.push_back("+EL"); + else + Flags.push_back("-EL"); + + if (IsSF) + Flags.push_back("+SF"); + else + Flags.push_back("-SF"); + + Multilib Selection; + ASSERT_TRUE(MS2.select(Flags, Selection)) + << "Selection failed for " << (IsEL ? "+EL" : "-EL") << " " + << (IsSF ? "+SF" : "-SF"); + + std::string Suffix; + if (IsEL) + Suffix += "/el"; + if (IsSF) + Suffix += "/sf"; + + ASSERT_EQ(Selection.gccSuffix(), Suffix) + << "Selection picked " << Selection << " which was not expected "; + } +} 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 @@ -11,34 +11,17 @@ //===----------------------------------------------------------------------===// #include "clang/Driver/Multilib.h" +#include "../../lib/Driver/ToolChains/CommonArgs.h" #include "clang/Basic/LLVM.h" +#include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/StringRef.h" #include "llvm/ADT/StringSwitch.h" +#include "llvm/Support/SourceMgr.h" #include "gtest/gtest.h" using namespace clang::driver; using namespace clang; -TEST(MultilibTest, MultilibValidity) { - - ASSERT_TRUE(Multilib().isValid()) << "Empty multilib is not valid"; - - ASSERT_TRUE(Multilib().flag("+foo").isValid()) - << "Single indicative flag is not valid"; - - ASSERT_TRUE(Multilib().flag("-foo").isValid()) - << "Single contraindicative flag is not valid"; - - ASSERT_FALSE(Multilib().flag("+foo").flag("-foo").isValid()) - << "Conflicting flags should invalidate the Multilib"; - - ASSERT_TRUE(Multilib().flag("+foo").flag("+foo").isValid()) - << "Multilib should be valid even if it has the same flag twice"; - - ASSERT_TRUE(Multilib().flag("+foo").flag("-foobar").isValid()) - << "Seemingly conflicting prefixes shouldn't actually conflict"; -} - TEST(MultilibTest, OpEqReflexivity1) { Multilib M; ASSERT_TRUE(M == M) << "Multilib::operator==() is not reflexive"; @@ -50,40 +33,28 @@ } TEST(MultilibTest, OpEqReflexivity3) { - Multilib M1, M2; - M1.flag("+foo"); - M2.flag("+foo"); + Multilib M1({}, {}, {}, 0, {"+foo"}); + Multilib M2({}, {}, {}, 0, {"+foo"}); ASSERT_TRUE(M1 == M2) << "Multilibs with the same flag should be the same"; } TEST(MultilibTest, OpEqInequivalence1) { - Multilib M1, M2; - M1.flag("+foo"); - M2.flag("-foo"); + Multilib M1({}, {}, {}, 0, {"+foo"}); + Multilib M2({}, {}, {}, 0, {"-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)"; } TEST(MultilibTest, OpEqInequivalence2) { - Multilib M1, M2; - M2.flag("+foo"); + Multilib M1; + Multilib M2({}, {}, {}, 0, {"+foo"}); ASSERT_FALSE(M1 == M2) << "Flags make Multilibs different"; } -TEST(MultilibTest, OpEqEquivalence1) { - Multilib M1, M2; - M1.flag("+foo"); - M2.flag("+foo").flag("+foo"); - ASSERT_TRUE(M1 == M2) << "Flag duplication shouldn't affect equivalence"; - ASSERT_TRUE(M2 == M1) - << "Flag duplication shouldn't affect equivalence (commuted)"; -} - TEST(MultilibTest, OpEqEquivalence2) { - Multilib M1("64"); - Multilib M2; - M2.gccSuffix("/64"); + Multilib M1("/64"); + Multilib M2("/64"); ASSERT_TRUE(M1 == M2) << "Constructor argument must match Multilib::gccSuffix()"; ASSERT_TRUE(M2 == M1) @@ -91,9 +62,8 @@ } TEST(MultilibTest, OpEqEquivalence3) { - Multilib M1("", "32"); - Multilib M2; - M2.osSuffix("/32"); + Multilib M1("", "/32"); + Multilib M2("", "/32"); ASSERT_TRUE(M1 == M2) << "Constructor argument must match Multilib::osSuffix()"; ASSERT_TRUE(M2 == M1) @@ -101,9 +71,8 @@ } TEST(MultilibTest, OpEqEquivalence4) { - Multilib M1("", "", "16"); - Multilib M2; - M2.includeSuffix("/16"); + Multilib M1("", "", "/16"); + Multilib M2("", "", "/16"); ASSERT_TRUE(M1 == M2) << "Constructor argument must match Multilib::includeSuffix()"; ASSERT_TRUE(M2 == M1) @@ -111,31 +80,31 @@ } TEST(MultilibTest, OpEqInequivalence3) { - Multilib M1("foo"); - Multilib M2("bar"); + Multilib M1("/foo"); + Multilib M2("/bar"); ASSERT_FALSE(M1 == M2) << "Differing gccSuffixes should be different"; ASSERT_FALSE(M2 == M1) << "Differing gccSuffixes should be different (commuted)"; } TEST(MultilibTest, OpEqInequivalence4) { - Multilib M1("", "foo"); - Multilib M2("", "bar"); + Multilib M1("", "/foo"); + Multilib M2("", "/bar"); ASSERT_FALSE(M1 == M2) << "Differing osSuffixes should be different"; ASSERT_FALSE(M2 == M1) << "Differing osSuffixes should be different (commuted)"; } TEST(MultilibTest, OpEqInequivalence5) { - Multilib M1("", "", "foo"); - Multilib M2("", "", "bar"); + Multilib M1("", "", "/foo"); + Multilib M2("", "", "/bar"); ASSERT_FALSE(M1 == M2) << "Differing includeSuffixes should be different"; ASSERT_FALSE(M2 == M1) << "Differing includeSuffixes should be different (commuted)"; } TEST(MultilibTest, Construction1) { - Multilib M("gcc64", "os64", "inc64"); + Multilib M("/gcc64", "/os64", "/inc64"); ASSERT_TRUE(M.gccSuffix() == "/gcc64"); ASSERT_TRUE(M.osSuffix() == "/os64"); ASSERT_TRUE(M.includeSuffix() == "/inc64"); @@ -155,7 +124,7 @@ } TEST(MultilibTest, Construction3) { - Multilib M = Multilib().flag("+f1").flag("+f2").flag("-f3"); + Multilib M({}, {}, {}, 0, {"+f1", "+f2", "-f3"}); for (Multilib::flags_list::const_iterator I = M.flags().begin(), E = M.flags().end(); I != E; ++I) { @@ -165,208 +134,32 @@ } } -static bool hasFlag(const Multilib &M, StringRef Flag) { - for (Multilib::flags_list::const_iterator I = M.flags().begin(), - E = M.flags().end(); - I != E; ++I) { - if (*I == Flag) - return true; - else if (StringRef(*I).substr(1) == Flag.substr(1)) - return false; - } - return false; -} - -TEST(MultilibTest, SetConstruction1) { - // Single maybe - MultilibSet MS; - ASSERT_TRUE(MS.size() == 0); - MS.Maybe(Multilib("64").flag("+m64")); - ASSERT_TRUE(MS.size() == 2); - for (MultilibSet::const_iterator I = MS.begin(), E = MS.end(); I != E; ++I) { - if (I->gccSuffix() == "/64") - ASSERT_TRUE(I->flags()[0] == "+m64"); - else if (I->gccSuffix() == "") - ASSERT_TRUE(I->flags()[0] == "-m64"); - else - FAIL() << "Unrecognized gccSufix: " << I->gccSuffix(); - } -} - -TEST(MultilibTest, SetConstruction2) { - // Double maybe - MultilibSet MS; - MS.Maybe(Multilib("sof").flag("+sof")); - MS.Maybe(Multilib("el").flag("+EL")); - ASSERT_TRUE(MS.size() == 4); - for (MultilibSet::const_iterator I = MS.begin(), E = MS.end(); I != E; ++I) { - ASSERT_TRUE(I->isValid()) << "Multilb " << *I << " should be valid"; - ASSERT_TRUE(llvm::StringSwitch(I->gccSuffix()) - .Cases("", "/sof", "/el", "/sof/el", true) - .Default(false)) - << "Multilib " << *I << " wasn't expected"; - ASSERT_TRUE(llvm::StringSwitch(I->gccSuffix()) - .Case("", hasFlag(*I, "-sof")) - .Case("/sof", hasFlag(*I, "+sof")) - .Case("/el", hasFlag(*I, "-sof")) - .Case("/sof/el", hasFlag(*I, "+sof")) - .Default(false)) - << "Multilib " << *I << " didn't have the appropriate {+,-}sof flag"; - ASSERT_TRUE(llvm::StringSwitch(I->gccSuffix()) - .Case("", hasFlag(*I, "-EL")) - .Case("/sof", hasFlag(*I, "-EL")) - .Case("/el", hasFlag(*I, "+EL")) - .Case("/sof/el", hasFlag(*I, "+EL")) - .Default(false)) - << "Multilib " << *I << " didn't have the appropriate {+,-}EL flag"; - } -} - TEST(MultilibTest, SetPushback) { - MultilibSet MS; - MS.push_back(Multilib("one")); - MS.push_back(Multilib("two")); + MultilibSet MS({ + Multilib("/one"), + Multilib("/two"), + }); ASSERT_TRUE(MS.size() == 2); for (MultilibSet::const_iterator I = MS.begin(), E = MS.end(); I != E; ++I) { ASSERT_TRUE(llvm::StringSwitch(I->gccSuffix()) .Cases("/one", "/two", true) .Default(false)); } - MS.clear(); - ASSERT_TRUE(MS.size() == 0); -} - -TEST(MultilibTest, SetRegexFilter) { - MultilibSet MS; - MS.Maybe(Multilib("one")); - MS.Maybe(Multilib("two")); - MS.Maybe(Multilib("three")); - ASSERT_EQ(MS.size(), (unsigned)2 * 2 * 2) - << "Size before filter was incorrect. Contents:\n" << MS; - MS.FilterOut("/one/two/three"); - ASSERT_EQ(MS.size(), (unsigned)2 * 2 * 2 - 1) - << "Size after filter was incorrect. Contents:\n" << MS; - for (MultilibSet::const_iterator I = MS.begin(), E = MS.end(); I != E; ++I) { - ASSERT_TRUE(I->gccSuffix() != "/one/two/three") - << "The filter should have removed " << *I; - } -} - -TEST(MultilibTest, SetFilterObject) { - MultilibSet MS; - MS.Maybe(Multilib("orange")); - MS.Maybe(Multilib("pear")); - MS.Maybe(Multilib("plum")); - ASSERT_EQ((int)MS.size(), 1 /* Default */ + - 1 /* pear */ + - 1 /* plum */ + - 1 /* pear/plum */ + - 1 /* orange */ + - 1 /* orange/pear */ + - 1 /* orange/plum */ + - 1 /* orange/pear/plum */ ) - << "Size before filter was incorrect. Contents:\n" << MS; - MS.FilterOut([](const Multilib &M) { - return StringRef(M.gccSuffix()).startswith("/p"); - }); - ASSERT_EQ((int)MS.size(), 1 /* Default */ + - 1 /* orange */ + - 1 /* orange/pear */ + - 1 /* orange/plum */ + - 1 /* orange/pear/plum */ ) - << "Size after filter was incorrect. Contents:\n" << MS; - for (MultilibSet::const_iterator I = MS.begin(), E = MS.end(); I != E; ++I) { - ASSERT_FALSE(StringRef(I->gccSuffix()).startswith("/p")) - << "The filter should have removed " << *I; - } -} - -TEST(MultilibTest, SetSelection1) { - MultilibSet MS1 = MultilibSet() - .Maybe(Multilib("64").flag("+m64")); - - Multilib::flags_list FlagM64; - FlagM64.push_back("+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; - FlagNoM64.push_back("-m64"); - 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"; -} - -TEST(MultilibTest, SetSelection2) { - MultilibSet MS2 = MultilibSet() - .Maybe(Multilib("el").flag("+EL")) - .Maybe(Multilib("sf").flag("+SF")); - - for (unsigned I = 0; I < 4; ++I) { - bool IsEL = I & 0x1; - bool IsSF = I & 0x2; - Multilib::flags_list Flags; - if (IsEL) - Flags.push_back("+EL"); - else - Flags.push_back("-EL"); - - if (IsSF) - Flags.push_back("+SF"); - else - Flags.push_back("-SF"); - - Multilib Selection; - ASSERT_TRUE(MS2.select(Flags, Selection)) << "Selection failed for " - << (IsEL ? "+EL" : "-EL") << " " - << (IsSF ? "+SF" : "-SF"); - - std::string Suffix; - if (IsEL) - Suffix += "/el"; - if (IsSF) - Suffix += "/sf"; - - ASSERT_EQ(Selection.gccSuffix(), Suffix) << "Selection picked " << Selection - << " which was not expected "; - } -} - -TEST(MultilibTest, SetCombineWith) { - MultilibSet Coffee; - Coffee.push_back(Multilib("coffee")); - MultilibSet Milk; - Milk.push_back(Multilib("milk")); - MultilibSet Latte; - ASSERT_EQ(Latte.size(), (unsigned)0); - Latte.combineWith(Coffee); - ASSERT_EQ(Latte.size(), (unsigned)1); - Latte.combineWith(Milk); - ASSERT_EQ(Latte.size(), (unsigned)2); } TEST(MultilibTest, SetPriority) { - MultilibSet MS; - MS.push_back(Multilib("foo", {}, {}, 1).flag("+foo")); - MS.push_back(Multilib("bar", {}, {}, 2).flag("+bar")); - - Multilib::flags_list Flags1; - Flags1.push_back("+foo"); - Flags1.push_back("-bar"); + MultilibSet MS({ + Multilib("/foo", {}, {}, 1, {"+foo"}), + Multilib("/bar", {}, {}, 2, {"+bar"}), + }); + Multilib::flags_list 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; - Flags2.push_back("+foo"); - Flags2.push_back("+bar"); + Multilib::flags_list Flags2 = {"+foo", "+bar"}; Multilib Selection2; ASSERT_TRUE(MS.select(Flags2, Selection2)) << "Flag set was {\"+bar\"}, but selection not found";