12#include "llvm/ADT/DenseSet.h"
13#include "llvm/ADT/StringRef.h"
14#include "llvm/Support/Compiler.h"
15#include "llvm/Support/ErrorHandling.h"
16#include "llvm/Support/Regex.h"
17#include "llvm/Support/VersionTuple.h"
18#include "llvm/Support/YAMLParser.h"
19#include "llvm/Support/YAMLTraits.h"
20#include "llvm/Support/raw_ostream.h"
26using namespace driver;
27using namespace llvm::sys;
30 StringRef IncludeSuffix,
const flags_list &Flags,
31 StringRef ExclusiveGroup, std::optional<StringRef> Error)
32 : GCCSuffix(GCCSuffix), OSSuffix(OSSuffix), IncludeSuffix(IncludeSuffix),
33 Flags(Flags), ExclusiveGroup(ExclusiveGroup), Error(Error) {
34 assert(GCCSuffix.empty() ||
35 (StringRef(GCCSuffix).front() ==
'/' && GCCSuffix.size() > 1));
36 assert(OSSuffix.empty() ||
37 (StringRef(OSSuffix).front() ==
'/' && OSSuffix.size() > 1));
38 assert(IncludeSuffix.empty() ||
39 (StringRef(IncludeSuffix).front() ==
'/' && IncludeSuffix.size() > 1));
47 if (GCCSuffix.empty())
50 OS << StringRef(GCCSuffix).drop_front();
53 for (StringRef Flag : Flags) {
54 if (Flag.front() ==
'-')
55 OS <<
"@" << Flag.substr(1);
62 llvm::StringSet<> MyFlags;
63 for (
const auto &Flag : Flags)
66 for (
const auto &Flag :
Other.Flags)
67 if (!MyFlags.contains(Flag))
88 llvm::erase_if(Multilibs, F);
98 bool AnyErrors =
false;
101 llvm::DenseSet<StringRef> ExclusiveGroupsSelected;
102 for (
const Multilib &M : llvm::reverse(Multilibs)) {
104 if (!llvm::all_of(M.flags(), [&FlagSet](
const std::string &F) {
105 return FlagSet.contains(F);
109 const std::string &group = M.exclusiveGroup();
110 if (!group.empty()) {
117 auto [It, Inserted] = ExclusiveGroupsSelected.insert(group);
129 Selected.push_back(M);
134 std::reverse(Selected.begin(), Selected.end());
136 return !AnyErrors && !Selected.empty();
142 for (
const auto &F : InFlags)
145 std::string RegexString(M.Match);
148 if (!StringRef(M.Match).starts_with(
"^"))
149 RegexString.insert(RegexString.begin(),
'^');
150 if (!StringRef(M.Match).ends_with(
"$"))
151 RegexString.push_back(
'$');
153 const llvm::Regex Regex(RegexString);
154 assert(Regex.isValid());
155 if (llvm::any_of(InFlags,
156 [&Regex](StringRef F) {
return Regex.match(F); })) {
157 Result.insert(M.Flags.begin(), M.Flags.end());
166static const VersionTuple MultilibVersionCurrent(1, 0);
168struct MultilibSerialization {
171 std::vector<std::string> Flags;
175enum class MultilibGroupType {
197struct MultilibGroupSerialization {
199 MultilibGroupType
Type;
202struct MultilibSetSerialization {
203 llvm::VersionTuple MultilibVersion;
204 std::vector<MultilibGroupSerialization> Groups;
205 std::vector<MultilibSerialization> Multilibs;
206 std::vector<MultilibSet::FlagMatcher> FlagMatchers;
211template <>
struct llvm::yaml::MappingTraits<MultilibSerialization> {
212 static void mapping(llvm::yaml::IO &io, MultilibSerialization &
V) {
213 io.mapOptional(
"Dir",
V.Dir);
214 io.mapOptional(
"Error",
V.Error);
215 io.mapRequired(
"Flags",
V.Flags);
216 io.mapOptional(
"Group",
V.Group);
218 static std::string
validate(IO &io, MultilibSerialization &
V) {
219 if (
V.Dir.empty() &&
V.Error.empty())
220 return "one of the 'Dir' and 'Error' keys must be specified";
221 if (!
V.Dir.empty() && !
V.Error.empty())
222 return "the 'Dir' and 'Error' keys may not both be specified";
223 if (StringRef(
V.Dir).starts_with(
"/"))
224 return "paths must be relative but \"" +
V.Dir +
"\" starts with \"/\"";
225 return std::string{};
229template <>
struct llvm::yaml::ScalarEnumerationTraits<MultilibGroupType> {
231 io.enumCase(Val,
"Exclusive", MultilibGroupType::Exclusive);
235template <>
struct llvm::yaml::MappingTraits<MultilibGroupSerialization> {
236 static void mapping(llvm::yaml::IO &io, MultilibGroupSerialization &
V) {
237 io.mapRequired(
"Name",
V.Name);
238 io.mapRequired(
"Type",
V.Type);
242template <>
struct llvm::yaml::MappingTraits<
MultilibSet::FlagMatcher> {
244 io.mapRequired(
"Match", M.
Match);
245 io.mapRequired(
"Flags", M.
Flags);
248 llvm::Regex Regex(M.
Match);
249 std::string RegexError;
250 if (!Regex.isValid(RegexError))
253 return "value required for 'Flags'";
254 return std::string{};
258template <>
struct llvm::yaml::MappingTraits<MultilibSetSerialization> {
259 static void mapping(llvm::yaml::IO &io, MultilibSetSerialization &M) {
260 io.mapRequired(
"MultilibVersion", M.MultilibVersion);
261 io.mapRequired(
"Variants", M.Multilibs);
262 io.mapOptional(
"Groups", M.Groups);
263 io.mapOptional(
"Mappings", M.FlagMatchers);
265 static std::string
validate(IO &io, MultilibSetSerialization &M) {
266 if (M.MultilibVersion.empty())
267 return "missing required key 'MultilibVersion'";
268 if (M.MultilibVersion.getMajor() != MultilibVersionCurrent.getMajor())
269 return "multilib version " + M.MultilibVersion.getAsString() +
271 if (M.MultilibVersion.getMinor() > MultilibVersionCurrent.getMinor())
272 return "multilib version " + M.MultilibVersion.getAsString() +
274 for (
const MultilibSerialization &Lib : M.Multilibs) {
275 if (!Lib.Group.empty()) {
277 for (
const MultilibGroupSerialization &Group : M.Groups)
278 if (Group.Name == Lib.Group) {
283 return "multilib \"" + Lib.Dir +
284 "\" specifies undefined group name \"" + Lib.Group +
"\"";
287 return std::string{};
291LLVM_YAML_IS_SEQUENCE_VECTOR(MultilibSerialization)
292LLVM_YAML_IS_SEQUENCE_VECTOR(MultilibGroupSerialization)
295llvm::ErrorOr<MultilibSet>
297 llvm::SourceMgr::DiagHandlerTy DiagHandler,
298 void *DiagHandlerCtxt) {
299 MultilibSetSerialization MS;
300 llvm::yaml::Input YamlInput(Input,
nullptr, DiagHandler, DiagHandlerCtxt);
302 if (YamlInput.error())
303 return YamlInput.error();
306 Multilibs.reserve(MS.Multilibs.size());
307 for (
const auto &M : MS.Multilibs) {
308 if (!M.Error.empty()) {
309 Multilibs.emplace_back(
"",
"",
"", M.Flags, M.Group, M.Error);
318 Multilibs.emplace_back(Dir, Dir, Dir, M.Flags, M.Group);
322 return MultilibSet(std::move(Multilibs), std::move(MS.FlagMatchers));
330 for (
const auto &M : *
this)
Forward-declares and imports various common LLVM datatypes that clang wants to use unqualified.
The base class of the type hierarchy.
Driver - Encapsulate logic for constructing compilation processes from a set of gcc-driver-like comma...
See also MultilibSetBuilder for combining multilibs into a set.
LLVM_DUMP_METHOD void dump() const
llvm::function_ref< bool(const Multilib &)> FilterCallback
static llvm::ErrorOr< MultilibSet > parseYaml(llvm::MemoryBufferRef, llvm::SourceMgr::DiagHandlerTy=nullptr, void *DiagHandlerCtxt=nullptr)
void print(raw_ostream &OS) const
MultilibSet & FilterOut(FilterCallback F)
Filter out some subset of the Multilibs using a user defined callback.
std::vector< Multilib > multilib_list
llvm::StringSet expandFlags(const Multilib::flags_list &) const
Get the given flags plus flags found by matching them against the FlagMatchers and choosing the Flags...
void push_back(const Multilib &M)
Add a completed Multilib to the set.
bool select(const Driver &D, const Multilib::flags_list &Flags, llvm::SmallVectorImpl< Multilib > &) const
Select compatible variants,.
This corresponds to a single GCC Multilib, or a segment of one controlled by a command line flag.
const std::string & gccSuffix() const
Get the detected GCC installation path suffix for the multi-arch target variant.
const std::string & osSuffix() const
Get the detected os path suffix for the multi-arch target variant.
std::vector< std::string > flags_list
Multilib(StringRef GCCSuffix={}, StringRef OSSuffix={}, StringRef IncludeSuffix={}, const flags_list &Flags=flags_list(), StringRef ExclusiveGroup={}, std::optional< StringRef > Error=std::nullopt)
GCCSuffix, OSSuffix & IncludeSuffix will be appended directly to the sysroot string so they must eith...
const std::string & includeSuffix() const
Get the include directory suffix.
LLVM_DUMP_METHOD void dump() const
void print(raw_ostream &OS) const
print summary of the Multilib
bool operator==(const Multilib &Other) const
raw_ostream & operator<<(raw_ostream &OS, const Multilib &M)
The JSON file list parser is used to communicate input to InstallAPI.
@ Result
The result type of a method or function.
@ Other
Other implicit parameter.
Uses regular expressions to simplify flags used for multilib selection.
std::vector< std::string > Flags
static void mapping(llvm::yaml::IO &io, MultilibGroupSerialization &V)
static void mapping(llvm::yaml::IO &io, MultilibSerialization &V)
static std::string validate(IO &io, MultilibSerialization &V)
static void mapping(llvm::yaml::IO &io, MultilibSetSerialization &M)
static std::string validate(IO &io, MultilibSetSerialization &M)
static std::string validate(IO &io, MultilibSet::FlagMatcher &M)
static void mapping(llvm::yaml::IO &io, MultilibSet::FlagMatcher &M)
static void enumeration(IO &io, MultilibGroupType &Val)