12#include "llvm/ADT/DenseSet.h"
13#include "llvm/ADT/SmallSet.h"
14#include "llvm/ADT/StringRef.h"
15#include "llvm/Support/Compiler.h"
16#include "llvm/Support/ErrorHandling.h"
17#include "llvm/Support/Regex.h"
18#include "llvm/Support/VersionTuple.h"
19#include "llvm/Support/YAMLParser.h"
20#include "llvm/Support/YAMLTraits.h"
21#include "llvm/Support/raw_ostream.h"
27using namespace driver;
28using namespace llvm::sys;
31 StringRef IncludeSuffix,
const flags_list &Flags,
32 StringRef ExclusiveGroup, std::optional<StringRef> Error)
33 : GCCSuffix(GCCSuffix), OSSuffix(OSSuffix), IncludeSuffix(IncludeSuffix),
34 Flags(Flags), ExclusiveGroup(ExclusiveGroup), Error(Error) {
35 assert(GCCSuffix.empty() ||
36 (StringRef(GCCSuffix).front() ==
'/' && GCCSuffix.size() > 1));
37 assert(OSSuffix.empty() ||
38 (StringRef(OSSuffix).front() ==
'/' && OSSuffix.size() > 1));
39 assert(IncludeSuffix.empty() ||
40 (StringRef(IncludeSuffix).front() ==
'/' && IncludeSuffix.size() > 1));
48 if (GCCSuffix.empty())
51 OS << StringRef(GCCSuffix).drop_front();
54 for (StringRef Flag : Flags) {
55 if (Flag.front() ==
'-')
56 OS <<
"@" << Flag.substr(1);
63 llvm::StringSet<> MyFlags(llvm::from_range, Flags);
65 for (
const auto &Flag :
Other.Flags)
66 if (!MyFlags.contains(Flag))
87 llvm::erase_if(Multilibs, F);
96 struct EditDistanceInfo {
98 unsigned EditDistance;
100 const unsigned MaxEditDistance = 5;
102 for (StringRef Unclaimed : UnclaimedCustomFlagValues) {
103 std::optional<EditDistanceInfo> BestCandidate;
104 for (
const auto &
Decl : CustomFlagDecls) {
105 for (
const auto &
Value :
Decl.ValueList) {
106 const std::string &FlagValueName =
Value.Name;
107 unsigned EditDistance =
108 Unclaimed.edit_distance(FlagValueName,
true,
110 if (!BestCandidate || (EditDistance <= MaxEditDistance &&
111 EditDistance < BestCandidate->EditDistance)) {
112 BestCandidate = {FlagValueName, EditDistance};
117 D.Diag(clang::diag::err_drv_unsupported_opt)
120 D.Diag(clang::diag::err_drv_unsupported_opt_with_suggestion)
133 template <
typename It>
135 for (
auto DeclIt = FlagDeclsBegin; DeclIt != FlagDeclsEnd; ++DeclIt) {
143 auto Iter = llvm::find_if(
144 Mapping, [&](
const auto &Pair) {
return Pair.first == Key; });
145 return Iter != Mapping.end() ?
Iter->second :
nullptr;
150std::pair<Multilib::flags_list, SmallVector<StringRef>>
164 CustomFlagDecls.begin(), CustomFlagDecls.end());
166 for (StringRef Flag : Flags) {
168 Result.push_back(Flag.str());
174 ValueNameToValueDetail.get(CustomFlagValueStr);
176 ClaimedCustomFlagValues.push_back(Detail);
178 UnclaimedCustomFlagValueStrs.push_back(CustomFlagValueStr);
189 for (
auto *CustomFlagValue : llvm::reverse(ClaimedCustomFlagValues)) {
190 if (!TriggeredCustomFlagDecls.insert(CustomFlagValue->Decl).second)
193 if (CustomFlagValue->MacroDefines)
194 MacroDefines.append(CustomFlagValue->MacroDefines->begin(),
195 CustomFlagValue->MacroDefines->end());
199 for (
const auto &
Decl : CustomFlagDecls) {
200 if (TriggeredCustomFlagDecls.contains(&
Decl))
203 Decl.ValueList[*
Decl.DefaultValueIdx];
206 MacroDefines.append(CustomFlagValue.
MacroDefines->begin(),
213 return {
Result, MacroDefines};
221 llvm::StringSet<> FlagSet(
expandFlags(FlagsWithCustom));
223 bool AnyErrors =
false;
229 if (CustomFlagMacroDefines)
230 *CustomFlagMacroDefines = std::move(CFMacroDefines);
233 llvm::DenseSet<StringRef> ExclusiveGroupsSelected;
234 for (
const Multilib &M : llvm::reverse(Multilibs)) {
236 if (!llvm::all_of(M.flags(), [&FlagSet](
const std::string &F) {
237 return FlagSet.contains(F);
241 const std::string &group = M.exclusiveGroup();
242 if (!group.empty()) {
249 auto [It, Inserted] = ExclusiveGroupsSelected.insert(group);
261 Selected.push_back(M);
266 std::reverse(Selected.begin(), Selected.end());
268 return !AnyErrors && !Selected.empty();
273 llvm::StringSet<>
Result(llvm::from_range, InFlags);
275 std::string RegexString(M.Match);
278 if (!StringRef(M.Match).starts_with(
"^"))
279 RegexString.insert(RegexString.begin(),
'^');
280 if (!StringRef(M.Match).ends_with(
"$"))
281 RegexString.push_back(
'$');
283 const llvm::Regex Regex(RegexString);
284 assert(Regex.isValid());
285 if (llvm::any_of(InFlags,
286 [&Regex](StringRef F) {
return Regex.match(F); })) {
287 Result.insert_range(M.Flags);
296static const VersionTuple MultilibVersionCurrent(1, 0);
298struct MultilibSerialization {
301 std::vector<std::string> Flags;
305enum class MultilibGroupType {
327struct MultilibGroupSerialization {
329 MultilibGroupType
Type;
332struct MultilibSetSerialization {
333 llvm::VersionTuple MultilibVersion;
342LLVM_YAML_IS_SEQUENCE_VECTOR(MultilibSerialization)
343LLVM_YAML_IS_SEQUENCE_VECTOR(MultilibGroupSerialization)
348template <> struct
llvm::yaml::MappingTraits<MultilibSerialization> {
349 static void mapping(llvm::yaml::IO &io, MultilibSerialization &
V) {
350 io.mapOptional(
"Dir",
V.Dir);
351 io.mapOptional(
"Error",
V.Error);
352 io.mapRequired(
"Flags",
V.Flags);
353 io.mapOptional(
"Group",
V.Group);
355 static std::string
validate(IO &io, MultilibSerialization &
V) {
356 if (
V.Dir.empty() &&
V.Error.empty())
357 return "one of the 'Dir' and 'Error' keys must be specified";
358 if (!
V.Dir.empty() && !
V.Error.empty())
359 return "the 'Dir' and 'Error' keys may not both be specified";
360 if (StringRef(
V.Dir).starts_with(
"/"))
361 return "paths must be relative but \"" +
V.Dir +
"\" starts with \"/\"";
362 return std::string{};
366template <>
struct llvm::yaml::ScalarEnumerationTraits<MultilibGroupType> {
368 io.enumCase(Val,
"Exclusive", MultilibGroupType::Exclusive);
372template <>
struct llvm::yaml::MappingTraits<MultilibGroupSerialization> {
373 static void mapping(llvm::yaml::IO &io, MultilibGroupSerialization &
V) {
374 io.mapRequired(
"Name",
V.Name);
375 io.mapRequired(
"Type",
V.Type);
379template <>
struct llvm::yaml::MappingTraits<
MultilibSet::FlagMatcher> {
381 io.mapRequired(
"Match", M.
Match);
382 io.mapRequired(
"Flags", M.
Flags);
385 llvm::Regex Regex(M.
Match);
386 std::string RegexError;
387 if (!Regex.isValid(RegexError))
390 return "value required for 'Flags'";
391 return std::string{};
396struct llvm::yaml::MappingContextTraits<custom_flag::ValueDetail,
397 llvm::SmallSet<std::string, 32>> {
399 llvm::SmallSet<std::string, 32> &) {
400 io.mapRequired(
"Name",
V.Name);
401 io.mapOptional(
"MacroDefines",
V.MacroDefines);
404 llvm::SmallSet<std::string, 32> &NameSet) {
406 return "custom flag value requires a name";
407 if (!NameSet.insert(
V.Name).second)
408 return "duplicate custom flag value name: \"" +
V.Name +
"\"";
415 llvm::SmallSet<std::string, 32>> {
417 llvm::SmallSet<std::string, 32> &NameSet) {
418 io.mapRequired(
"Name",
V.Name);
419 io.mapRequired(
"Values",
V.ValueList, NameSet);
420 std::string DefaultValueName;
421 io.mapRequired(
"Default", DefaultValueName);
423 for (
auto [Idx,
Value] : llvm::enumerate(
V.ValueList)) {
425 if (
Value.Name == DefaultValueName) {
426 assert(!
V.DefaultValueIdx);
427 V.DefaultValueIdx = Idx;
432 llvm::SmallSet<std::string, 32> &) {
434 return "custom flag requires a name";
435 if (
V.ValueList.empty())
436 return "custom flag must have at least one value";
437 if (!
V.DefaultValueIdx)
438 return "custom flag must have a default value";
443template <>
struct llvm::yaml::MappingTraits<MultilibSetSerialization> {
444 static void mapping(llvm::yaml::IO &io, MultilibSetSerialization &M) {
445 io.mapRequired(
"MultilibVersion", M.MultilibVersion);
446 io.mapRequired(
"Variants", M.Multilibs);
447 io.mapOptional(
"Groups", M.Groups);
448 llvm::SmallSet<std::string, 32> NameSet;
449 io.mapOptionalWithContext(
"Flags", M.CustomFlagDeclarations, NameSet);
450 io.mapOptional(
"Mappings", M.FlagMatchers);
452 static std::string
validate(IO &io, MultilibSetSerialization &M) {
453 if (M.MultilibVersion.empty())
454 return "missing required key 'MultilibVersion'";
455 if (M.MultilibVersion.getMajor() != MultilibVersionCurrent.getMajor())
456 return "multilib version " + M.MultilibVersion.getAsString() +
458 if (M.MultilibVersion.getMinor() > MultilibVersionCurrent.getMinor())
459 return "multilib version " + M.MultilibVersion.getAsString() +
461 for (
const MultilibSerialization &Lib : M.Multilibs) {
462 if (!Lib.Group.empty()) {
464 for (
const MultilibGroupSerialization &Group : M.Groups)
465 if (Group.Name == Lib.Group) {
470 return "multilib \"" + Lib.Dir +
471 "\" specifies undefined group name \"" + Lib.Group +
"\"";
474 return std::string{};
478llvm::ErrorOr<MultilibSet>
480 llvm::SourceMgr::DiagHandlerTy DiagHandler,
481 void *DiagHandlerCtxt) {
482 MultilibSetSerialization MS;
483 llvm::yaml::Input YamlInput(Input,
nullptr, DiagHandler, DiagHandlerCtxt);
485 if (YamlInput.error())
486 return YamlInput.error();
489 Multilibs.reserve(MS.Multilibs.size());
490 for (
const auto &M : MS.Multilibs) {
491 if (!M.Error.empty()) {
492 Multilibs.emplace_back(
"",
"",
"", M.Flags, M.Group, M.Error);
501 Multilibs.emplace_back(Dir, Dir, Dir, M.Flags, M.Group);
505 return MultilibSet(std::move(Multilibs), std::move(MS.FlagMatchers),
506 std::move(MS.CustomFlagDeclarations));
514 for (
const auto &M : *
this)
526 DefaultValueIdx(
Other.DefaultValueIdx) {
533 DefaultValueIdx(
std::move(
Other.DefaultValueIdx)) {
Forward-declares and imports various common LLVM datatypes that clang wants to use unqualified.
static void DiagnoseUnclaimedMultilibCustomFlags(const Driver &D, const SmallVector< StringRef > &UnclaimedCustomFlagValues, const SmallVector< custom_flag::Declaration > &CustomFlagDecls)
Decl - This represents one declaration (or definition), e.g.
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.
bool select(const Driver &D, const Multilib::flags_list &Flags, llvm::SmallVectorImpl< Multilib > &, llvm::SmallVector< StringRef > *=nullptr) const
Select compatible variants,.
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.
std::pair< Multilib::flags_list, SmallVector< StringRef > > processCustomFlags(const Driver &D, const Multilib::flags_list &Flags) const
Process custom flags from Flags and returns an expanded flags list and a list of macro defines.
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
ValueNameToDetailMap(It FlagDeclsBegin, It FlagDeclsEnd)
const ValueDetail * get(StringRef Key) const
static constexpr StringRef Prefix
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.
Diagnostic wrappers for TextAPI types for error reporting.
Uses regular expressions to simplify flags used for multilib selection.
std::vector< std::string > Flags
Declaration & operator=(const Declaration &)
std::optional< size_t > DefaultValueIdx
std::optional< SmallVector< std::string > > MacroDefines
static std::string validate(IO &io, custom_flag::Declaration &V, llvm::SmallSet< std::string, 32 > &)
static void mapping(llvm::yaml::IO &io, custom_flag::Declaration &V, llvm::SmallSet< std::string, 32 > &NameSet)
static void mapping(llvm::yaml::IO &io, custom_flag::ValueDetail &V, llvm::SmallSet< std::string, 32 > &)
static std::string validate(IO &io, custom_flag::ValueDetail &V, llvm::SmallSet< std::string, 32 > &NameSet)
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)