michaelplatings updated this revision to Diff 503900.
michaelplatings added a comment.
flags -> tags
Repository:
rG LLVM Github Monorepo
CHANGES SINCE LAST ACTION
https://reviews.llvm.org/D142932/new/
https://reviews.llvm.org/D142932
Files:
clang/include/clang/Driver/Multilib.h
clang/lib/Driver/Multilib.cpp
clang/unittests/Driver/MultilibTest.cpp
Index: clang/unittests/Driver/MultilibTest.cpp
===================================================================
--- clang/unittests/Driver/MultilibTest.cpp
+++ clang/unittests/Driver/MultilibTest.cpp
@@ -13,6 +13,7 @@
#include "clang/Driver/Multilib.h"
#include "../../lib/Driver/ToolChains/CommonArgs.h"
#include "clang/Basic/LLVM.h"
+#include "clang/Basic/Version.h"
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/ADT/StringSwitch.h"
@@ -187,3 +188,407 @@
EXPECT_EQ("/a", Selection[0].gccSuffix());
EXPECT_EQ("/b", Selection[1].gccSuffix());
}
+
+static void diagnosticCallback(const llvm::SMDiagnostic &D, void *Out) {
+ *reinterpret_cast<std::string *>(Out) = D.getMessage();
+}
+
+static bool parse(MultilibSet &MS, std::string &Diagnostic, const char *Data) {
+ return MS.parse(llvm::MemoryBufferRef(Data, "TEST"), diagnosticCallback,
+ &Diagnostic);
+}
+
+static bool parse(MultilibSet &MS, std::string &Diagnostic,
+ const std::string &Data) {
+ return MS.parse(llvm::MemoryBufferRef(Data, "TEST"), diagnosticCallback,
+ &Diagnostic);
+}
+
+static bool parse(MultilibSet &MS, const char *Data) {
+ return MS.parse(llvm::MemoryBufferRef(Data, "TEST"));
+}
+
+#define _STRINGIFY(x) #x
+#define STRINGIFY(x) _STRINGIFY(x)
+// Avoid using MULTILIB_CLANG_VERSION in case it has extra non-numeric parts.
+#define MULTILIB_CLANG_VERSION \
+ STRINGIFY(CLANG_VERSION_MAJOR) \
+ "." STRINGIFY(CLANG_VERSION_MINOR) "." STRINGIFY(CLANG_VERSION_PATCHLEVEL)
+#define YAML_PREAMBLE "ClangMinimumVersion: " MULTILIB_CLANG_VERSION "\n"
+
+TEST(MultilibTest, ParseInvalid) {
+ std::string Diagnostic;
+
+ MultilibSet MS;
+
+ EXPECT_FALSE(parse(MS, Diagnostic, R"(
+Variants: []
+)"));
+ EXPECT_TRUE(StringRef(Diagnostic)
+ .contains("missing required key 'ClangMinimumVersion'"))
+ << Diagnostic;
+
+ // Require all 3 major.minor.patch version components
+ EXPECT_FALSE(parse(MS, Diagnostic, R"(
+ClangMinimumVersion: )" STRINGIFY(CLANG_VERSION_MAJOR) R"(.0
+Variants: []
+)"));
+ EXPECT_TRUE(StringRef(Diagnostic)
+ .contains("not a valid version string. Expected "
+ "MAJOR.MINOR.PATCHLEVEL but got \"" STRINGIFY(
+ CLANG_VERSION_MAJOR) ".0\""))
+ << Diagnostic;
+
+ EXPECT_FALSE(parse(MS, Diagnostic, R"(
+ClangMinimumVersion: )" MULTILIB_CLANG_VERSION R"(a
+Variants: []
+)"));
+ EXPECT_TRUE(
+ StringRef(Diagnostic)
+ .contains("not a valid version string. Expected "
+ "MAJOR.MINOR.PATCHLEVEL where all components are decimal "
+ "integers but got \"" MULTILIB_CLANG_VERSION "a\""))
+ << Diagnostic;
+
+ // Reject configurations that require a later clang version
+ EXPECT_FALSE(parse(MS, Diagnostic,
+ R"(
+ClangMinimumVersion: )" + std::to_string(CLANG_VERSION_MAJOR + 1) +
+ R"(.0.0
+Variants: []
+)"));
+ EXPECT_TRUE(StringRef(Diagnostic)
+ .contains("clang version " MULTILIB_CLANG_VERSION
+ " is less than ClangMinimumVersion: " +
+ std::to_string(CLANG_VERSION_MAJOR + 1) + ".0.0"))
+ << Diagnostic;
+
+ // but accept configurations that only need an earlier clang version
+ EXPECT_TRUE(parse(MS, Diagnostic, R"(
+ClangMinimumVersion: 16.0.0
+Variants: []
+)")) << Diagnostic;
+
+ EXPECT_FALSE(parse(MS, Diagnostic, YAML_PREAMBLE));
+ EXPECT_TRUE(StringRef(Diagnostic).contains("missing required key 'Variants'"))
+ << Diagnostic;
+
+ EXPECT_FALSE(parse(MS, Diagnostic, YAML_PREAMBLE R"(
+Variants:
+- Dir: /abc
+ Tags: []
+ PrintOptions: []
+)"));
+ EXPECT_TRUE(StringRef(Diagnostic).contains("paths must be relative"))
+ << Diagnostic;
+
+ EXPECT_FALSE(parse(MS, Diagnostic, YAML_PREAMBLE R"(
+Variants:
+- Tags: []
+ PrintOptions: []
+)"));
+ EXPECT_TRUE(StringRef(Diagnostic).contains("missing required key 'Dir'"))
+ << Diagnostic;
+
+ EXPECT_FALSE(parse(MS, Diagnostic, YAML_PREAMBLE R"(
+Variants:
+- Dir: .
+ PrintOptions: []
+)"));
+ EXPECT_TRUE(StringRef(Diagnostic).contains("missing required key 'Tags'"))
+ << Diagnostic;
+
+ EXPECT_FALSE(parse(MS, Diagnostic, YAML_PREAMBLE R"(
+Variants:
+- Dir: .
+ Tags: []
+)"));
+ EXPECT_TRUE(
+ StringRef(Diagnostic).contains("missing required key 'PrintOptions'"))
+ << Diagnostic;
+
+ EXPECT_FALSE(parse(MS, Diagnostic, YAML_PREAMBLE R"(
+Variants: []
+TagMap:
+- Regex: abc
+)"));
+ EXPECT_TRUE(StringRef(Diagnostic)
+ .contains("value required for 'MatchTags' or 'NoMatchTags'"))
+ << Diagnostic;
+
+ EXPECT_FALSE(parse(MS, Diagnostic, YAML_PREAMBLE R"(
+Variants: []
+TagMap:
+- Dir: .
+ Regex: '('
+ PrintOptions: []
+)"));
+ EXPECT_TRUE(StringRef(Diagnostic).contains("parentheses not balanced"))
+ << Diagnostic;
+}
+
+TEST(MultilibTest, Parse) {
+ MultilibSet MS;
+ EXPECT_TRUE(parse(MS, YAML_PREAMBLE R"(
+Variants:
+- Dir: .
+ Tags: []
+ PrintOptions: []
+)"));
+ EXPECT_EQ(1U, MS.size());
+ EXPECT_EQ("", MS.begin()->gccSuffix());
+
+ EXPECT_TRUE(parse(MS, YAML_PREAMBLE R"(
+Variants:
+- Dir: abc
+ Tags: []
+ PrintOptions: []
+)"));
+ EXPECT_EQ(1U, MS.size());
+ EXPECT_EQ("/abc", MS.begin()->gccSuffix());
+
+ EXPECT_TRUE(parse(MS, YAML_PREAMBLE R"(
+Variants:
+- Dir: pqr
+ Tags: []
+ PrintOptions: [-mfloat-abi=soft]
+)"));
+ EXPECT_EQ(1U, MS.size());
+ EXPECT_EQ("/pqr", MS.begin()->gccSuffix());
+ EXPECT_EQ(std::vector<std::string>({"-mfloat-abi=soft"}),
+ MS.begin()->getPrintOptions());
+
+ EXPECT_TRUE(parse(MS, YAML_PREAMBLE R"(
+Variants:
+- Dir: pqr
+ Tags: []
+ PrintOptions: [-mfloat-abi=soft, -fno-exceptions]
+)"));
+ EXPECT_EQ(1U, MS.size());
+ EXPECT_EQ(std::vector<std::string>({"-mfloat-abi=soft", "-fno-exceptions"}),
+ MS.begin()->getPrintOptions());
+
+ EXPECT_TRUE(parse(MS, YAML_PREAMBLE R"(
+Variants:
+- Dir: a
+ Tags: []
+ PrintOptions: []
+- Dir: b
+ Tags: []
+ PrintOptions: []
+)"));
+ EXPECT_EQ(2U, MS.size());
+}
+
+TEST(MultilibTest, SelectSoft) {
+ MultilibSet MS;
+ Multilib Selected;
+ ASSERT_TRUE(parse(MS, YAML_PREAMBLE R"(
+Variants:
+- Dir: s
+ Tags: [softabi]
+ PrintOptions: []
+TagMap:
+- Regex: mfloat-abi=soft
+ MatchTags: [softabi]
+- Regex: mfloat-abi=softfp
+ MatchTags: [softabi]
+)"));
+ EXPECT_TRUE(MS.select({"mfloat-abi=soft"}, Selected));
+ EXPECT_TRUE(MS.select({"mfloat-abi=softfp"}, Selected));
+ EXPECT_FALSE(MS.select({"mfloat-abi=hard"}, Selected));
+}
+
+TEST(MultilibTest, SelectSoftFP) {
+ MultilibSet MS;
+ Multilib Selected;
+ ASSERT_TRUE(parse(MS, YAML_PREAMBLE R"(
+Variants:
+- Dir: f
+ Tags: [mfloat-abi=softfp]
+ PrintOptions: []
+)"));
+ EXPECT_FALSE(MS.select({"mfloat-abi=soft"}, Selected));
+ EXPECT_TRUE(MS.select({"mfloat-abi=softfp"}, Selected));
+ EXPECT_FALSE(MS.select({"mfloat-abi=hard"}, Selected));
+}
+
+TEST(MultilibTest, SelectHard) {
+ // If hard float is all that's available then select that only if compiling
+ // with hard float.
+ MultilibSet MS;
+ Multilib Selected;
+ ASSERT_TRUE(parse(MS, YAML_PREAMBLE R"(
+Variants:
+- Dir: h
+ Tags: [mfloat-abi=hard]
+ PrintOptions: []
+)"));
+ EXPECT_FALSE(MS.select({"mfloat-abi=soft"}, Selected));
+ EXPECT_FALSE(MS.select({"mfloat-abi=softfp"}, Selected));
+ EXPECT_TRUE(MS.select({"mfloat-abi=hard"}, Selected));
+}
+
+TEST(MultilibTest, SelectFloatABI) {
+ MultilibSet MS;
+ Multilib Selected;
+ ASSERT_TRUE(parse(MS, YAML_PREAMBLE R"(
+Variants:
+- Dir: s
+ Tags: [softabi]
+ PrintOptions: []
+- Dir: f
+ Tags: [softabi, hasfp]
+ PrintOptions: []
+- Dir: h
+ Tags: [hardabi, hasfp]
+ PrintOptions: []
+TagMap:
+- Regex: mfloat-abi=(soft|softfp)
+ MatchTags: [softabi]
+- Regex: mfloat-abi=hard
+ MatchTags: [hardabi]
+- Regex: mfloat-abi=soft
+ NoMatchTags: [hasfp]
+)"));
+ MS.select({"mfloat-abi=soft"}, Selected);
+ EXPECT_EQ("/s", Selected.gccSuffix());
+ MS.select({"mfloat-abi=softfp"}, Selected);
+ EXPECT_EQ("/f", Selected.gccSuffix());
+ MS.select({"mfloat-abi=hard"}, Selected);
+ EXPECT_EQ("/h", Selected.gccSuffix());
+}
+
+TEST(MultilibTest, SelectFloatABIReversed) {
+ // If soft is specified after softfp then softfp will never be
+ // selected because soft is compatible with softfp and last wins.
+ MultilibSet MS;
+ Multilib Selected;
+ ASSERT_TRUE(parse(MS, YAML_PREAMBLE R"(
+Variants:
+- Dir: h
+ Tags: [hardabi, hasfp]
+ PrintOptions: []
+- Dir: f
+ Tags: [softabi, hasfp]
+ PrintOptions: []
+- Dir: s
+ Tags: [softabi]
+ PrintOptions: []
+TagMap:
+- Regex: mfloat-abi=(soft|softfp)
+ MatchTags: [softabi]
+- Regex: mfloat-abi=hard
+ MatchTags: [hardabi]
+- Regex: mfloat-abi=soft
+ NoMatchTags: [hasfp]
+)"));
+ MS.select({"mfloat-abi=soft"}, Selected);
+ EXPECT_EQ("/s", Selected.gccSuffix());
+ MS.select({"mfloat-abi=softfp"}, Selected);
+ EXPECT_EQ("/s", Selected.gccSuffix());
+ MS.select({"mfloat-abi=hard"}, Selected);
+ EXPECT_EQ("/h", Selected.gccSuffix());
+}
+
+TEST(MultilibTest, SelectMClass) {
+ const char *MultilibSpec = YAML_PREAMBLE R"(
+Variants:
+- Dir: thumb/v6-m/nofp
+ Tags: [target=thumbv6m-none-eabi]
+ PrintOptions: [--target=thumbv6m-none-eabi, -mfloat-abi=soft]
+
+- Dir: thumb/v7-m/nofp
+ Tags: [target=thumbv7m-none-eabi]
+ PrintOptions: [--target=thumbv7m-none-eabi, -mfloat-abi=soft]
+
+- Dir: thumb/v7e-m/nofp
+ Tags: [target=thumbv7em-none-eabi]
+ PrintOptions: [--target=thumbv7em-none-eabi, -mfloat-abi=soft, -mfpu=none]
+
+- Dir: thumb/v8-m.main/nofp
+ Tags: [target=thumbv8m.main-none-eabi]
+ PrintOptions: [--target=arm-none-eabi, -mfloat-abi=soft, -march=armv8m.main+nofp]
+
+- Dir: thumb/v8.1-m.main/nofp/nomve
+ Tags: [target=thumbv8.1m.main-none-eabi]
+ PrintOptions: [--target=arm-none-eabi, -mfloat-abi=soft, -march=armv8.1m.main+nofp+nomve]
+
+- Dir: thumb/v7e-m/fpv4_sp_d16
+ Tags: [target=thumbv7em-none-eabihf, mfpu=fpv4-sp-d16]
+ PrintOptions: [--target=thumbv7em-none-eabihf, -mfpu=fpv4-sp-d16]
+
+- Dir: thumb/v7e-m/fpv5_d16
+ Tags: [target=thumbv7em-none-eabihf, mfpu=fpv5-d16]
+ PrintOptions: [--target=thumbv7em-none-eabihf, -mfpu=fpv5-d16]
+
+- Dir: thumb/v8-m.main/fp
+ Tags: [target=thumbv8m.main-none-eabihf]
+ PrintOptions: [--target=thumbv8m.main-none-eabihf]
+
+- Dir: thumb/v8.1-m.main/fp
+ Tags: [target=thumbv8.1m.main-none-eabihf]
+ PrintOptions: [--target=thumbv8.1m.main-none-eabihf]
+
+- Dir: thumb/v8.1-m.main/nofp/mve
+ Tags: [target=thumbv8.1m.main-none-eabihf, march=+mve]
+ PrintOptions: [--target=arm-none-eabihf, -march=armv8.1m.main+nofp+mve]
+
+TagMap:
+- Regex: target=thumbv8(\.[0-9]+)?m\.base-none-eabi
+ MatchTags: [target=thumbv6m-none-eabi]
+- Regex: thumbv8\.[1-9]m\.main-none-eabi
+ MatchTags: [target=thumbv8.1m.main-none-eabi]
+- Regex: thumbv8\.[1-9]m\.main-none-eabihf
+ MatchTags: [target=thumbv8.1m.main-none-eabihf]
+)";
+
+ MultilibSet MS;
+ Multilib Selected;
+ ASSERT_TRUE(parse(MS, MultilibSpec));
+
+ EXPECT_TRUE(
+ MS.select({"target=thumbv6m-none-eabi", "mfloat-abi=soft"}, Selected));
+ EXPECT_EQ("/thumb/v6-m/nofp", Selected.gccSuffix());
+
+ EXPECT_TRUE(
+ MS.select({"target=thumbv7m-none-eabi", "mfloat-abi=soft"}, Selected));
+ EXPECT_EQ("/thumb/v7-m/nofp", Selected.gccSuffix());
+
+ EXPECT_TRUE(
+ MS.select({"target=thumbv7em-none-eabi", "mfloat-abi=soft", "mfpu=none"},
+ Selected));
+ EXPECT_EQ("/thumb/v7e-m/nofp", Selected.gccSuffix());
+
+ EXPECT_TRUE(MS.select({"target=thumbv8m.main-none-eabi", "mfloat-abi=soft"},
+ Selected));
+ EXPECT_EQ("/thumb/v8-m.main/nofp", Selected.gccSuffix());
+
+ EXPECT_TRUE(MS.select(
+ {"target=thumbv8.1m.main-none-eabi", "mfloat-abi=soft", "mfpu=none"},
+ Selected));
+ EXPECT_EQ("/thumb/v8.1-m.main/nofp/nomve", Selected.gccSuffix());
+
+ EXPECT_TRUE(MS.select(
+ {"target=thumbv7em-none-eabihf", "mfloat-abi=hard", "mfpu=fpv4-sp-d16"},
+ Selected));
+ EXPECT_EQ("/thumb/v7e-m/fpv4_sp_d16", Selected.gccSuffix());
+
+ EXPECT_TRUE(MS.select(
+ {"target=thumbv7em-none-eabihf", "mfloat-abi=hard", "mfpu=fpv5-d16"},
+ Selected));
+ EXPECT_EQ("/thumb/v7e-m/fpv5_d16", Selected.gccSuffix());
+
+ EXPECT_TRUE(MS.select({"target=thumbv8m.main-none-eabihf", "mfloat-abi=hard"},
+ Selected));
+ EXPECT_EQ("/thumb/v8-m.main/fp", Selected.gccSuffix());
+
+ EXPECT_TRUE(MS.select(
+ {"target=thumbv8.1m.main-none-eabihf", "mfloat-abi=hard"}, Selected));
+ EXPECT_EQ("/thumb/v8.1-m.main/fp", Selected.gccSuffix());
+
+ EXPECT_TRUE(MS.select({"target=thumbv8.1m.main-none-eabihf",
+ "mfloat-abi=hard", "mfpu=none", "march=+mve"},
+ Selected));
+ EXPECT_EQ("/thumb/v8.1-m.main/nofp/mve", Selected.gccSuffix());
+}
Index: clang/lib/Driver/Multilib.cpp
===================================================================
--- clang/lib/Driver/Multilib.cpp
+++ clang/lib/Driver/Multilib.cpp
@@ -8,6 +8,7 @@
#include "clang/Driver/Multilib.h"
#include "clang/Basic/LLVM.h"
+#include "clang/Basic/Version.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/StringMap.h"
#include "llvm/ADT/StringRef.h"
@@ -16,10 +17,10 @@
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/Path.h"
#include "llvm/Support/Regex.h"
+#include "llvm/Support/YAMLParser.h"
+#include "llvm/Support/YAMLTraits.h"
#include "llvm/Support/raw_ostream.h"
-#include <algorithm>
#include <cassert>
-#include <string>
using namespace clang;
using namespace driver;
@@ -80,12 +81,12 @@
void MultilibSet::push_back(const Multilib &M) { Multilibs.push_back(M); }
-MultilibSet::multilib_list
-MultilibSet::select(const Multilib::tag_set &Tags) const {
+std::vector<Multilib> MultilibSet::select(const Multilib::tag_set &Tags) const {
+ Multilib::tag_set AllTags(expandTags(Tags));
multilib_list Result;
llvm::copy_if(Multilibs, std::back_inserter(Result),
- [&Tags](const Multilib &M) {
- return std::includes(Tags.begin(), Tags.end(),
+ [&AllTags](const Multilib &M) {
+ return std::includes(AllTags.begin(), AllTags.end(),
M.tags().begin(), M.tags().end());
});
return Result;
@@ -100,6 +101,143 @@
return true;
}
+Multilib::tag_set
+MultilibSet::expandTags(const Multilib::tag_set &InTags) const {
+ Multilib::tag_set Result(InTags);
+ for (const TagMatcher &M : TagMatchers) {
+ std::string RegexString(M.Regex);
+
+ // Make the regular expression match the whole string.
+ if (!StringRef(M.Regex).starts_with("^"))
+ RegexString.insert(RegexString.begin(), '^');
+ if (!StringRef(M.Regex).ends_with("$"))
+ RegexString.push_back('$');
+
+ const llvm::Regex Regex(RegexString);
+ assert(Regex.isValid());
+ if (llvm::find_if(InTags, [&Regex](StringRef F) {
+ return Regex.match(F);
+ }) != InTags.end()) {
+ Result.insert(M.MatchTags.begin(), M.MatchTags.end());
+ } else {
+ Result.insert(M.NoMatchTags.begin(), M.NoMatchTags.end());
+ }
+ }
+ return Result;
+}
+
+namespace {
+
+struct MultilibSerialization {
+ std::string Dir;
+ std::vector<std::string> Tags, PrintOptions;
+};
+
+struct MultilibSetSerialization {
+ std::string ClangMinimumVersion;
+ std::vector<MultilibSerialization> Multilibs;
+ std::vector<MultilibSet::TagMatcher> TagMatchers;
+};
+
+} // end anonymous namespace
+
+template <> struct llvm::yaml::MappingTraits<MultilibSerialization> {
+ static void mapping(llvm::yaml::IO &io, MultilibSerialization &V) {
+ io.mapRequired("Dir", V.Dir);
+ io.mapRequired("Tags", V.Tags);
+ io.mapRequired("PrintOptions", V.PrintOptions);
+ }
+ static std::string validate(IO &io, MultilibSerialization &V) {
+ if (StringRef(V.Dir).starts_with("/"))
+ return "paths must be relative. \"" + V.Dir + "\" starts with \"/\"\n";
+ return std::string{};
+ }
+};
+
+template <> struct llvm::yaml::MappingTraits<MultilibSet::TagMatcher> {
+ static void mapping(llvm::yaml::IO &io, MultilibSet::TagMatcher &M) {
+ io.mapRequired("Regex", M.Regex);
+ io.mapOptional("MatchTags", M.MatchTags);
+ io.mapOptional("NoMatchTags", M.NoMatchTags);
+ }
+ static std::string validate(IO &io, MultilibSet::TagMatcher &M) {
+ llvm::Regex Regex(M.Regex);
+ std::string RegexError;
+ if (!Regex.isValid(RegexError))
+ return RegexError;
+ if (M.MatchTags.empty() && M.NoMatchTags.empty())
+ return "value required for 'MatchTags' or 'NoMatchTags'";
+ return std::string{};
+ }
+};
+
+template <> struct llvm::yaml::MappingTraits<MultilibSetSerialization> {
+ static void mapping(llvm::yaml::IO &io, MultilibSetSerialization &M) {
+ io.mapRequired("ClangMinimumVersion", M.ClangMinimumVersion);
+ io.mapRequired("Variants", M.Multilibs);
+ io.mapOptional("TagMap", M.TagMatchers);
+ }
+ static std::string validate(IO &io, MultilibSetSerialization &M) {
+ if (M.ClangMinimumVersion.empty())
+ return "missing required key 'ClangMinimumVersion'. Expected "
+ "MAJOR.MINOR.PATCHLEVEL";
+
+ SmallVector<int, 3> ClangMinimumVersion,
+ ClangVersion = {CLANG_VERSION_MAJOR, CLANG_VERSION_MINOR,
+ CLANG_VERSION_PATCHLEVEL};
+
+ SmallVector<StringRef, 3> MinVerStrings;
+ StringRef(M.ClangMinimumVersion).split(MinVerStrings, '.');
+
+ if (MinVerStrings.size() != 3)
+ return "not a valid version string. Expected MAJOR.MINOR.PATCHLEVEL but "
+ "got \"" +
+ M.ClangMinimumVersion + "\"";
+
+ for (StringRef S : MinVerStrings) {
+ int V;
+ if (S.getAsInteger(10, V))
+ return "not a valid version string. Expected MAJOR.MINOR.PATCHLEVEL "
+ "where all components are decimal integers but got \"" +
+ M.ClangMinimumVersion + "\"";
+ ClangMinimumVersion.push_back(V);
+ }
+
+ if (ClangVersion < ClangMinimumVersion) {
+ return "clang version " CLANG_VERSION_STRING
+ " is less than ClangMinimumVersion: " +
+ M.ClangMinimumVersion;
+ }
+ return std::string{};
+ }
+};
+
+LLVM_YAML_IS_SEQUENCE_VECTOR(MultilibSerialization)
+LLVM_YAML_IS_SEQUENCE_VECTOR(MultilibSet::TagMatcher)
+
+bool MultilibSet::parse(llvm::MemoryBufferRef Input,
+ llvm::SourceMgr::DiagHandlerTy DiagHandler,
+ void *DiagHandlerCtxt) {
+ MultilibSetSerialization MS;
+ llvm::yaml::Input YamlInput(Input, nullptr, DiagHandler, DiagHandlerCtxt);
+ YamlInput >> MS;
+ if (YamlInput.error())
+ return false;
+
+ Multilibs.clear();
+ Multilibs.reserve(MS.Multilibs.size());
+ for (const auto &M : MS.Multilibs) {
+ std::string Dir;
+ if (M.Dir != ".")
+ Dir = "/" + M.Dir;
+ Multilibs.emplace_back(Dir, Dir, Dir,
+ Multilib::tag_set(M.Tags.begin(), M.Tags.end()),
+ M.PrintOptions);
+ }
+ TagMatchers = std::move(MS.TagMatchers);
+ return true;
+}
+
LLVM_DUMP_METHOD void MultilibSet::dump() const {
print(llvm::errs());
}
Index: clang/include/clang/Driver/Multilib.h
===================================================================
--- clang/include/clang/Driver/Multilib.h
+++ clang/include/clang/Driver/Multilib.h
@@ -14,6 +14,7 @@
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/Support/Compiler.h"
+#include "llvm/Support/SourceMgr.h"
#include <cassert>
#include <functional>
#include <set>
@@ -60,9 +61,10 @@
const std::string &includeSuffix() const { return IncludeSuffix; }
/// Get the set of tags that indicate this multilib's use.
- /// Tags are arbitrary strings although typically they will look similar to
- /// command line options. A multilib is considered compatible if its tags are
- /// a subset of the tags derived from the Clang command line options.
+ /// Tags are arbitrary strings, some of which are derived from command-line
+ /// options and look similar to them, and others can be defined by a
+ /// particular multilib.yaml. A multilib is considered compatible if its tags
+ /// are a subset of the tags derived from the Clang command line options.
const tag_set &tags() const { return Tags; }
/// Returns the options that should be used for clang -print-multi-lib
@@ -90,8 +92,19 @@
std::function<std::vector<std::string>(const Multilib &M)>;
using FilterCallback = llvm::function_ref<bool(const Multilib &)>;
+ /// Uses regular expressions to simplify tags used for multilib selection.
+ /// For example, we may wish to simplify armv8, armv8.1, armv8.2 etc. to
+ /// simply "v8". It's also possible to negate matches. For example, it may be
+ /// appropriate to infer that if mfpu=none *doesn't* match then an FPU is
+ /// available. NoMatchTags can be used for this purpose.
+ struct TagMatcher {
+ std::string Regex;
+ std::vector<std::string> MatchTags, NoMatchTags;
+ };
+
private:
multilib_list Multilibs;
+ std::vector<TagMatcher> TagMatchers;
IncludeDirsFunc IncludeCallback;
IncludeDirsFunc FilePathsCallback;
@@ -118,6 +131,15 @@
unsigned size() const { return Multilibs.size(); }
+ /// Get the given tags plus tags found by matching them against the
+ /// TagMatchers and choosing the MatchTags or NoMatchTags of each
+ /// accordingly. The select method calls this method so in most cases it's not
+ /// necessary to call it directly.
+ Multilib::tag_set expandTags(const Multilib::tag_set &) const;
+
+ bool parse(llvm::MemoryBufferRef, llvm::SourceMgr::DiagHandlerTy = nullptr,
+ void *DiagHandlerCtxt = nullptr);
+
LLVM_DUMP_METHOD void dump() const;
void print(raw_ostream &OS) const;
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits