clang: lib/Driver/Multilib.cpp Source File (original) (raw)
1
2
3
4
5
6
7
8
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"
22#include
23#include
24#include
25
26using namespace clang;
27using namespace driver;
28using namespace llvm::sys;
29
31 StringRef IncludeSuffix, const flags_list &Flags,
32 StringRef ExclusiveGroup, std::optional 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));
41}
42
44 print(llvm::errs());
45}
46
48 if (GCCSuffix.empty())
49 OS << ".";
50 else {
51 OS << StringRef(GCCSuffix).drop_front();
52 }
53 OS << ";";
54 for (StringRef Flag : Flags) {
55 if (Flag.front() == '-')
56 OS << "@" << Flag.substr(1);
57 }
58}
59
61
62
63 llvm::StringSet<> MyFlags;
64 for (const auto &Flag : Flags)
65 MyFlags.insert(Flag);
66
67 for (const auto &Flag : Other.Flags)
68 if (!MyFlags.contains(Flag))
69 return false;
70
72 return false;
73
75 return false;
76
78 return false;
79
80 return true;
81}
82
85 return OS;
86}
87
89 llvm::erase_if(Multilibs, F);
90 return *this;
91}
92
94
98 struct EditDistanceInfo {
99 StringRef FlagValue;
100 unsigned EditDistance;
101 };
102 const unsigned MaxEditDistance = 5;
103
104 for (StringRef Unclaimed : UnclaimedCustomFlagValues) {
105 std::optional BestCandidate;
106 for (const auto &Decl : CustomFlagDecls) {
107 for (const auto &Value : Decl.ValueList) {
108 const std::string &FlagValueName = Value.Name;
109 unsigned EditDistance =
110 Unclaimed.edit_distance(FlagValueName, true,
111 MaxEditDistance);
112 if (!BestCandidate || (EditDistance <= MaxEditDistance &&
113 EditDistance < BestCandidate->EditDistance)) {
114 BestCandidate = {FlagValueName, EditDistance};
115 }
116 }
117 }
118 if (!BestCandidate)
119 D.Diag(clang::diag::err_drv_unsupported_opt)
121 else
122 D.Diag(clang::diag::err_drv_unsupported_opt_with_suggestion)
125 }
126}
127
129
130
133
134public:
135 template
137 for (auto DeclIt = FlagDeclsBegin; DeclIt != FlagDeclsEnd; ++DeclIt) {
139 for (const auto &Value : Decl.ValueList)
140 Mapping.emplace_back(Value.Name, &Value);
141 }
142 }
143
145 auto Iter = llvm::find_if(
146 Mapping, [&](const auto &Pair) { return Pair.first == Key; });
147 return Iter != Mapping.end() ? Iter->second : nullptr;
148 }
149};
150}
151
152std::pair<Multilib::flags_list, SmallVector>
157
158
160
161
162
164
166 CustomFlagDecls.begin(), CustomFlagDecls.end());
167
168 for (StringRef Flag : Flags) {
170 Result.push_back(Flag.str());
171 continue;
172 }
173
176 ValueNameToValueDetail.get(CustomFlagValueStr);
177 if (Detail)
178 ClaimedCustomFlagValues.push_back(Detail);
179 else
180 UnclaimedCustomFlagValueStrs.push_back(CustomFlagValueStr);
181 }
182
183
184
185
186
187
189
190
191 for (auto *CustomFlagValue : llvm::reverse(ClaimedCustomFlagValues)) {
192 if (!TriggeredCustomFlagDecls.insert(CustomFlagValue->Decl).second)
193 continue;
195 if (CustomFlagValue->MacroDefines)
196 MacroDefines.append(CustomFlagValue->MacroDefines->begin(),
197 CustomFlagValue->MacroDefines->end());
198 }
199
200
201 for (const auto &Decl : CustomFlagDecls) {
202 if (TriggeredCustomFlagDecls.contains(&Decl))
203 continue;
205 Decl.ValueList[*Decl.DefaultValueIdx];
208 MacroDefines.append(CustomFlagValue.MacroDefines->begin(),
210 }
211
213 CustomFlagDecls);
214
215 return {Result, MacroDefines};
216}
217
223 llvm::StringSet<> FlagSet(expandFlags(FlagsWithCustom));
224 Selected.clear();
225 bool AnyErrors = false;
226
227
228
229
230
231 if (CustomFlagMacroDefines)
232 *CustomFlagMacroDefines = std::move(CFMacroDefines);
233
234
235 llvm::DenseSet ExclusiveGroupsSelected;
236 for (const Multilib &M : llvm::reverse(Multilibs)) {
237
238 if (!llvm::all_of(M.flags(), [&FlagSet](const std::string &F) {
239 return FlagSet.contains(F);
240 }))
241 continue;
242
243 const std::string &group = M.exclusiveGroup();
244 if (!group.empty()) {
245
246
247
248
249
250
251 auto [It, Inserted] = ExclusiveGroupsSelected.insert(group);
252 if (!Inserted)
253 continue;
254 }
255
256
257
258
259 if (M.isError())
260 AnyErrors = true;
261
262
263 Selected.push_back(M);
264 }
265
266
267
268 std::reverse(Selected.begin(), Selected.end());
269
270 return !AnyErrors && !Selected.empty();
271}
272
273llvm::StringSet<>
275 llvm::StringSet<> Result;
276 for (const auto &F : InFlags)
278 for (const FlagMatcher &M : FlagMatchers) {
279 std::string RegexString(M.Match);
280
281
282 if (!StringRef(M.Match).starts_with("^"))
283 RegexString.insert(RegexString.begin(), '^');
284 if (!StringRef(M.Match).ends_with("$"))
285 RegexString.push_back('$');
286
287 const llvm::Regex Regex(RegexString);
288 assert(Regex.isValid());
289 if (llvm::any_of(InFlags,
290 [&Regex](StringRef F) { return Regex.match(F); })) {
291 Result.insert(M.Flags.begin(), M.Flags.end());
292 }
293 }
295}
296
297namespace {
298
299
300static const VersionTuple MultilibVersionCurrent(1, 0);
301
302struct MultilibSerialization {
303 std::string Dir;
304 std::string Error;
305 std::vectorstd::string Flags;
306 std::string Group;
307};
308
309enum class MultilibGroupType {
310
311
312
313
314 Exclusive,
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329};
330
331struct MultilibGroupSerialization {
332 std::string Name;
333 MultilibGroupType Type;
334};
335
336struct MultilibSetSerialization {
337 llvm::VersionTuple MultilibVersion;
342};
343
344}
345
346LLVM_YAML_IS_SEQUENCE_VECTOR(MultilibSerialization)
347LLVM_YAML_IS_SEQUENCE_VECTOR(MultilibGroupSerialization)
351
352template <> struct llvm::yaml::MappingTraits {
353 static void mapping(llvm::yaml::IO &io, MultilibSerialization &V) {
354 io.mapOptional("Dir", V.Dir);
355 io.mapOptional("Error", V.Error);
356 io.mapRequired("Flags", V.Flags);
357 io.mapOptional("Group", V.Group);
358 }
359 static std::string validate(IO &io, MultilibSerialization &V) {
360 if (V.Dir.empty() && V.Error.empty())
361 return "one of the 'Dir' and 'Error' keys must be specified";
362 if (.Dir.empty() &&
.Error.empty())
363 return "the 'Dir' and 'Error' keys may not both be specified";
364 if (StringRef(V.Dir).starts_with("/"))
365 return "paths must be relative but \"" + V.Dir + "\" starts with \"/\"";
366 return std::string{};
367 }
368};
369
370template <> struct llvm::yaml::ScalarEnumerationTraits {
371 static void enumeration(IO &io, MultilibGroupType &Val) {
372 io.enumCase(Val, "Exclusive", MultilibGroupType::Exclusive);
373 }
374};
375
376template <> struct llvm::yaml::MappingTraits {
377 static void mapping(llvm::yaml::IO &io, MultilibGroupSerialization &V) {
378 io.mapRequired("Name", V.Name);
379 io.mapRequired("Type", V.Type);
380 }
381};
382
383template <> struct llvm::yaml::MappingTraits<MultilibSet::FlagMatcher> {
385 io.mapRequired("Match", M.Match);
386 io.mapRequired("Flags", M.Flags);
387 }
389 llvm::Regex Regex(M.Match);
390 std::string RegexError;
391 if (!Regex.isValid(RegexError))
392 return RegexError;
393 if (M.Flags.empty())
394 return "value required for 'Flags'";
395 return std::string{};
396 }
397};
398
399template <>
400struct llvm::yaml::MappingContextTraits<custom_flag::ValueDetail,
401 llvm::SmallSet<std::string, 32>> {
403 llvm::SmallSet<std::string, 32> &) {
404 io.mapRequired("Name", V.Name);
405 io.mapOptional("MacroDefines", V.MacroDefines);
406 }
408 llvm::SmallSet<std::string, 32> &NameSet) {
409 if (V.Name.empty())
410 return "custom flag value requires a name";
411 if (!NameSet.insert(V.Name).second)
412 return "duplicate custom flag value name: \"" + V.Name + "\"";
413 return {};
414 }
415};
416
417template <>
418struct llvm::yaml::MappingContextTraits<custom_flag::Declaration,
419 llvm::SmallSet<std::string, 32>> {
421 llvm::SmallSet<std::string, 32> &NameSet) {
422 io.mapRequired("Name", V.Name);
423 io.mapRequired("Values", V.ValueList, NameSet);
424 std::string DefaultValueName;
425 io.mapRequired("Default", DefaultValueName);
426
427 for (auto [Idx, Value] : llvm::enumerate(V.ValueList)) {
429 if (Value.Name == DefaultValueName) {
430 assert(.DefaultValueIdx);
431 V.DefaultValueIdx = Idx;
432 }
433 }
434 }
436 llvm::SmallSet<std::string, 32> &) {
437 if (V.Name.empty())
438 return "custom flag requires a name";
439 if (V.ValueList.empty())
440 return "custom flag must have at least one value";
441 if (.DefaultValueIdx)
442 return "custom flag must have a default value";
443 return {};
444 }
445};
446
447template <> struct llvm::yaml::MappingTraits {
448 static void mapping(llvm::yaml::IO &io, MultilibSetSerialization &M) {
449 io.mapRequired("MultilibVersion", M.MultilibVersion);
450 io.mapRequired("Variants", M.Multilibs);
451 io.mapOptional("Groups", M.Groups);
452 llvm::SmallSet<std::string, 32> NameSet;
453 io.mapOptionalWithContext("Flags", M.CustomFlagDeclarations, NameSet);
454 io.mapOptional("Mappings", M.FlagMatchers);
455 }
456 static std::string validate(IO &io, MultilibSetSerialization &M) {
457 if (M.MultilibVersion.empty())
458 return "missing required key 'MultilibVersion'";
459 if (M.MultilibVersion.getMajor() != MultilibVersionCurrent.getMajor())
460 return "multilib version " + M.MultilibVersion.getAsString() +
461 " is unsupported";
462 if (M.MultilibVersion.getMinor() > MultilibVersionCurrent.getMinor())
463 return "multilib version " + M.MultilibVersion.getAsString() +
464 " is unsupported";
465 for (const MultilibSerialization &Lib : M.Multilibs) {
466 if (!Lib.Group.empty()) {
467 bool Found = false;
468 for (const MultilibGroupSerialization &Group : M.Groups)
469 if (Group.Name == Lib.Group) {
471 break;
472 }
474 return "multilib \"" + Lib.Dir +
475 "\" specifies undefined group name \"" + Lib.Group + "\"";
476 }
477 }
478 return std::string{};
479 }
480};
481
482llvm::ErrorOr
484 llvm::SourceMgr::DiagHandlerTy DiagHandler,
485 void *DiagHandlerCtxt) {
486 MultilibSetSerialization MS;
487 llvm::yaml::Input YamlInput(Input, nullptr, DiagHandler, DiagHandlerCtxt);
488 YamlInput >> MS;
489 if (YamlInput.error())
490 return YamlInput.error();
491
493 Multilibs.reserve(MS.Multilibs.size());
494 for (const auto &M : MS.Multilibs) {
495 if (!M.Error.empty()) {
496 Multilibs.emplace_back("", "", "", M.Flags, M.Group, M.Error);
497 } else {
498 std::string Dir;
499 if (M.Dir != ".")
500 Dir = "/" + M.Dir;
501
502
503
504
505 Multilibs.emplace_back(Dir, Dir, Dir, M.Flags, M.Group);
506 }
507 }
508
509 return MultilibSet(std::move(Multilibs), std::move(MS.FlagMatchers),
510 std::move(MS.CustomFlagDeclarations));
511}
512
514 print(llvm::errs());
515}
516
518 for (const auto &M : *this)
519 OS << M << "\n";
520}
521
524 return OS;
525}
526
530 DefaultValueIdx(Other.DefaultValueIdx) {
532 Detail.Decl = this;
533}
534
537 DefaultValueIdx(std::move(Other.DefaultValueIdx)) {
539 Detail.Decl = this;
540}
541
543 if (this == &Other)
544 return *this;
549 Detail.Decl = this;
550 return *this;
551}
552
554 if (this == &Other)
555 return *this;
560 Detail.Decl = this;
561 return *this;
562}
563}
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)