[clang] 850dab0 - [NFC] Class for building MultilibSet
Michael Platings via cfe-commits
cfe-commits at lists.llvm.org
Wed Feb 22 01:28:39 PST 2023
Author: Michael Platings
Date: 2023-02-22T09:24:48Z
New Revision: 850dab0f2537bb31103578fc35caef2f1ad98f04
URL: https://github.com/llvm/llvm-project/commit/850dab0f2537bb31103578fc35caef2f1ad98f04
DIFF: https://github.com/llvm/llvm-project/commit/850dab0f2537bb31103578fc35caef2f1ad98f04.diff
LOG: [NFC] Class for building MultilibSet
The functionality in MultilibSet for creating it is tied to its current
implementation. Putting that code in a separate class is an enabler for
changing the MultilibSet implementation.
Differential Revision: https://reviews.llvm.org/D142893
Added:
clang/include/clang/Driver/MultilibBuilder.h
clang/lib/Driver/MultilibBuilder.cpp
clang/unittests/Driver/MultilibBuilderTest.cpp
Modified:
clang/include/clang/Driver/Multilib.h
clang/lib/Driver/CMakeLists.txt
clang/lib/Driver/Multilib.cpp
clang/lib/Driver/ToolChains/BareMetal.cpp
clang/lib/Driver/ToolChains/Fuchsia.cpp
clang/lib/Driver/ToolChains/Gnu.cpp
clang/unittests/Driver/CMakeLists.txt
clang/unittests/Driver/MultilibTest.cpp
Removed:
################################################################################
diff --git a/clang/include/clang/Driver/Multilib.h b/clang/include/clang/Driver/Multilib.h
index cf2dbf6ff58a6..feb12f3638d34 100644
--- a/clang/include/clang/Driver/Multilib.h
+++ b/clang/include/clang/Driver/Multilib.h
@@ -24,7 +24,9 @@ namespace clang {
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<std::string>;
@@ -37,71 +39,37 @@ class Multilib {
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 @@ class Multilib {
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<Multilib>;
- using iterator = multilib_list::iterator;
using const_iterator = multilib_list::const_iterator;
using IncludeDirsFunc =
std::function<std::vector<std::string>(const Multilib &M)>;
@@ -127,40 +95,17 @@ class MultilibSet {
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<Multilib> 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
index 0000000000000..cf84c456152b1
--- /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<std::string>;
+
+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<MultilibBuilder>;
+
+ 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<MultilibBuilder> 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
index ba56a9323400c..e0bf3efc44c20 100644
--- a/clang/lib/Driver/CMakeLists.txt
+++ b/clang/lib/Driver/CMakeLists.txt
@@ -22,6 +22,7 @@ add_clang_library(clangDriver
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
index ec619874ad607..1f8db753e8233 100644
--- a/clang/lib/Driver/Multilib.cpp
+++ b/clang/lib/Driver/Multilib.cpp
@@ -25,56 +25,17 @@ using namespace clang;
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 @@ LLVM_DUMP_METHOD void Multilib::dump() const {
}
void Multilib::print(raw_ostream &OS) const {
- assert(GCCSuffix.empty() || (StringRef(GCCSuffix).front() == '/'));
if (GCCSuffix.empty())
OS << ".";
else {
@@ -95,22 +55,6 @@ void Multilib::print(raw_ostream &OS) const {
}
}
-bool Multilib::isValid() const {
- llvm::StringMap<int> FlagSet;
- for (unsigned I = 0, N = Flags.size(); I != N; ++I) {
- StringRef Flag(Flags[I]);
- llvm::StringMap<int>::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 @@ raw_ostream &clang::driver::operator<<(raw_ostream &OS, const Multilib &M) {
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<Multilib> 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
index 0000000000000..83ebc31d8eb99
--- /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<int> FlagSet;
+ for (unsigned I = 0, N = Flags.size(); I != N; ++I) {
+ StringRef Flag(Flags[I]);
+ llvm::StringMap<int>::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<MultilibBuilder> 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
index ac9c7036ad6ef..3175b15a48ca7 100644
--- 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;
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 @@ static bool findRISCVMultilibs(const Driver &D,
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 @@ static bool findRISCVMultilibs(const Driver &D,
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 @@ static bool findRISCVMultilibs(const Driver &D,
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
index 36bd93a4913c6..3a3f7043a795f 100644
--- 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 @@ Fuchsia::Fuchsia(const Driver &D, const llvm::Triple &Triple,
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<std::string> RD = FilePaths(M);
diff --git a/clang/lib/Driver/ToolChains/Gnu.cpp b/clang/lib/Driver/ToolChains/Gnu.cpp
index c8006f3d8412c..3a69a2967462e 100644
--- 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 @@ static bool isMSP430(llvm::Triple::ArchType Arch) {
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 @@ static bool findMipsCsMultilibs(const Multilib::flags_list &Flags,
.flag("-m32");
CSMipsMultilibs =
- MultilibSet()
+ MultilibSetBuilder()
.Either(MArchMips16, MArchMicroMips, MArchDefault)
.Maybe(UCLibc)
.Either(SoftFloat, Nan2008, DefaultFloat)
@@ -1094,6 +1091,7 @@ static bool findMipsCsMultilibs(const Multilib::flags_list &Flags,
.Maybe(MAbi64)
.FilterOut("/mips16.*/64")
.FilterOut("/micromips.*/64")
+ .makeMultilibSet()
.FilterOut(NonExistent)
.setIncludeDirsCallback([](const Multilib &M) {
std::vector<std::string> Dirs({"/include"});
@@ -1108,21 +1106,25 @@ static bool findMipsCsMultilibs(const Multilib::flags_list &Flags,
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 @@ static bool findMipsAndroidMultilibs(llvm::vfs::FileSystem &VFS, StringRef Path,
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 @@ static bool findMipsMuslMultilibs(const Multilib::flags_list &Flags,
// 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 @@ static bool findMipsMtiMultilibs(const Multilib::flags_list &Flags,
// 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 @@ static bool findMipsMtiMultilibs(const Multilib::flags_list &Flags,
.Maybe(SoftFloat)
.Maybe(Nan2008)
.FilterOut(".*sof/nan2008")
+ .makeMultilibSet()
.FilterOut(NonExistent)
.setIncludeDirsCallback([](const Multilib &M) {
std::vector<std::string> Dirs({"/include"});
@@ -1290,80 +1303,87 @@ static bool findMipsMtiMultilibs(const Multilib::flags_list &Flags,
// 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<std::string>({"/../../../../sysroot" +
@@ -1390,18 +1410,19 @@ static bool findMipsImgMultilibs(const Multilib::flags_list &Flags,
// 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<std::string>(
@@ -1412,51 +1433,58 @@ static bool findMipsImgMultilibs(const Multilib::flags_list &Flags,
// 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<std::string>({"/../../../../sysroot" +
@@ -1556,22 +1584,19 @@ static void findAndroidArmMultilibs(const Driver &D,
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 @@ static bool findMSP430Multilibs(const Driver &D,
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 @@ static void findCSKYMultilibs(const Driver &D, const llvm::Triple &TargetTriple,
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 @@ static void findRISCVBareMetalMultilibs(const Driver &D,
{"rv32imac", "ilp32"}, {"rv32imafc", "ilp32f"}, {"rv64imac", "lp64"},
{"rv64imafdc", "lp64d"}};
- std::vector<Multilib> Ms;
+ std::vector<MultilibBuilder> 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<Multilib>(Ms))
+ MultilibSetBuilder()
+ .Either(Ms)
+ .makeMultilibSet()
.FilterOut(NonExistent)
.setFilePathsCallback([](const Multilib &M) {
return std::vector<std::string>(
@@ -1716,7 +1746,6 @@ static void findRISCVBareMetalMultilibs(const Driver &D,
"/../../../../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 @@ static void findRISCVMultilibs(const Driver &D,
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 @@ static bool findBiarchMultilibs(const Driver &D,
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 @@ static bool findBiarchMultilibs(const Driver &D,
}
}
- 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 @@ static bool findBiarchMultilibs(const Driver &D,
}
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
index 1de0151cc41ce..e37c158d7137a 100644
--- a/clang/unittests/Driver/CMakeLists.txt
+++ b/clang/unittests/Driver/CMakeLists.txt
@@ -11,6 +11,7 @@ add_clang_unittest(ClangDriverTests
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
index 0000000000000..45ef4992d3f78
--- /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<bool>(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<bool>(I->gccSuffix())
+ .Cases("", "/sof", "/el", "/sof/el", true)
+ .Default(false))
+ << "Multilib " << *I << " wasn't expected";
+ ASSERT_TRUE(llvm::StringSwitch<bool>(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<bool>(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
index 0731c81d9f554..2e729a5051734 100644
--- 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, OpEqReflexivity2) {
}
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
diff erent";
}
-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, OpEqEquivalence2) {
}
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, OpEqEquivalence3) {
}
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, OpEqEquivalence4) {
}
TEST(MultilibTest, OpEqInequivalence3) {
- Multilib M1("foo");
- Multilib M2("bar");
+ Multilib M1("/foo");
+ Multilib M2("/bar");
ASSERT_FALSE(M1 == M2) << "Differing gccSuffixes should be
diff erent";
ASSERT_FALSE(M2 == M1)
<< "Differing gccSuffixes should be
diff erent (commuted)";
}
TEST(MultilibTest, OpEqInequivalence4) {
- Multilib M1("", "foo");
- Multilib M2("", "bar");
+ Multilib M1("", "/foo");
+ Multilib M2("", "/bar");
ASSERT_FALSE(M1 == M2) << "Differing osSuffixes should be
diff erent";
ASSERT_FALSE(M2 == M1)
<< "Differing osSuffixes should be
diff erent (commuted)";
}
TEST(MultilibTest, OpEqInequivalence5) {
- Multilib M1("", "", "foo");
- Multilib M2("", "", "bar");
+ Multilib M1("", "", "/foo");
+ Multilib M2("", "", "/bar");
ASSERT_FALSE(M1 == M2) << "Differing includeSuffixes should be
diff erent";
ASSERT_FALSE(M2 == M1)
<< "Differing includeSuffixes should be
diff erent (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, Construction2) {
}
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 @@ TEST(MultilibTest, Construction3) {
}
}
-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<bool>(I->gccSuffix())
- .Cases("", "/sof", "/el", "/sof/el", true)
- .Default(false))
- << "Multilib " << *I << " wasn't expected";
- ASSERT_TRUE(llvm::StringSwitch<bool>(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<bool>(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<bool>(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";
More information about the cfe-commits
mailing list