1 //===- Multilib.cpp - Multilib Implementation -----------------------------===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 9 #include "clang/Driver/Multilib.h" 10 #include "clang/Basic/LLVM.h" 11 #include "clang/Driver/Driver.h" 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 <algorithm> 23 #include <cassert> 24 #include <string> 25 26 using namespace clang; 27 using namespace driver; 28 using namespace llvm::sys; 29 30 Multilib::Multilib(StringRef GCCSuffix, StringRef OSSuffix, 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)); 41 } 42 43 LLVM_DUMP_METHOD void Multilib::dump() const { 44 print(llvm::errs()); 45 } 46 47 void Multilib::print(raw_ostream &OS) const { 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 60 bool Multilib::operator==(const Multilib &Other) const { 61 // Check whether the flags sets match 62 // allowing for the match to be order invariant 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 71 if (osSuffix() != Other.osSuffix()) 72 return false; 73 74 if (gccSuffix() != Other.gccSuffix()) 75 return false; 76 77 if (includeSuffix() != Other.includeSuffix()) 78 return false; 79 80 return true; 81 } 82 83 raw_ostream &clang::driver::operator<<(raw_ostream &OS, const Multilib &M) { 84 M.print(OS); 85 return OS; 86 } 87 88 MultilibSet &MultilibSet::FilterOut(FilterCallback F) { 89 llvm::erase_if(Multilibs, F); 90 return *this; 91 } 92 93 void MultilibSet::push_back(const Multilib &M) { Multilibs.push_back(M); } 94 95 static void DiagnoseUnclaimedMultilibCustomFlags( 96 const Driver &D, const SmallVector<StringRef> &UnclaimedCustomFlagValues, 97 const SmallVector<custom_flag::Declaration> &CustomFlagDecls) { 98 struct EditDistanceInfo { 99 StringRef FlagValue; 100 unsigned EditDistance; 101 }; 102 const unsigned MaxEditDistance = 5; 103 104 for (StringRef Unclaimed : UnclaimedCustomFlagValues) { 105 std::optional<EditDistanceInfo> 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, /*AllowReplacements=*/true, 111 /*MaxEditDistance=*/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) 120 << (custom_flag::Prefix + Unclaimed).str(); 121 else 122 D.Diag(clang::diag::err_drv_unsupported_opt_with_suggestion) 123 << (custom_flag::Prefix + Unclaimed).str() 124 << (custom_flag::Prefix + BestCandidate->FlagValue).str(); 125 } 126 } 127 128 namespace clang::driver::custom_flag { 129 // Map implemented using linear searches as the expected size is too small for 130 // the overhead of a search tree or a hash table. 131 class ValueNameToDetailMap { 132 SmallVector<std::pair<StringRef, const ValueDetail *>> Mapping; 133 134 public: 135 template <typename It> 136 ValueNameToDetailMap(It FlagDeclsBegin, It FlagDeclsEnd) { 137 for (auto DeclIt = FlagDeclsBegin; DeclIt != FlagDeclsEnd; ++DeclIt) { 138 const Declaration &Decl = *DeclIt; 139 for (const auto &Value : Decl.ValueList) 140 Mapping.emplace_back(Value.Name, &Value); 141 } 142 } 143 144 const ValueDetail *get(StringRef Key) const { 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 } // namespace clang::driver::custom_flag 151 152 std::pair<Multilib::flags_list, SmallVector<StringRef>> 153 MultilibSet::processCustomFlags(const Driver &D, 154 const Multilib::flags_list &Flags) const { 155 Multilib::flags_list Result; 156 SmallVector<StringRef> MacroDefines; 157 158 // Custom flag values detected in the flags list 159 SmallVector<const custom_flag::ValueDetail *> ClaimedCustomFlagValues; 160 161 // Arguments to -fmultilib-flag=<arg> that don't correspond to any valid 162 // custom flag value. An error will be printed out for each of these. 163 SmallVector<StringRef> UnclaimedCustomFlagValueStrs; 164 165 const auto ValueNameToValueDetail = custom_flag::ValueNameToDetailMap( 166 CustomFlagDecls.begin(), CustomFlagDecls.end()); 167 168 for (StringRef Flag : Flags) { 169 if (!Flag.starts_with(custom_flag::Prefix)) { 170 Result.push_back(Flag.str()); 171 continue; 172 } 173 174 StringRef CustomFlagValueStr = Flag.substr(custom_flag::Prefix.size()); 175 const custom_flag::ValueDetail *Detail = 176 ValueNameToValueDetail.get(CustomFlagValueStr); 177 if (Detail) 178 ClaimedCustomFlagValues.push_back(Detail); 179 else 180 UnclaimedCustomFlagValueStrs.push_back(CustomFlagValueStr); 181 } 182 183 // Set of custom flag declarations for which a value was passed in the flags 184 // list. This is used to, firstly, detect multiple values for the same flag 185 // declaration (in this case, the last one wins), and secondly, to detect 186 // which declarations had no value passed in (in this case, the default value 187 // is selected). 188 llvm::SmallPtrSet<custom_flag::Declaration *, 32> TriggeredCustomFlagDecls; 189 190 // Detect multiple values for the same flag declaration. Last one wins. 191 for (auto *CustomFlagValue : llvm::reverse(ClaimedCustomFlagValues)) { 192 if (!TriggeredCustomFlagDecls.insert(CustomFlagValue->Decl).second) 193 continue; 194 Result.push_back(std::string(custom_flag::Prefix) + CustomFlagValue->Name); 195 if (CustomFlagValue->MacroDefines) 196 MacroDefines.append(CustomFlagValue->MacroDefines->begin(), 197 CustomFlagValue->MacroDefines->end()); 198 } 199 200 // Detect flag declarations with no value passed in. Select default value. 201 for (const auto &Decl : CustomFlagDecls) { 202 if (TriggeredCustomFlagDecls.contains(&Decl)) 203 continue; 204 const custom_flag::ValueDetail &CustomFlagValue = 205 Decl.ValueList[*Decl.DefaultValueIdx]; 206 Result.push_back(std::string(custom_flag::Prefix) + CustomFlagValue.Name); 207 if (CustomFlagValue.MacroDefines) 208 MacroDefines.append(CustomFlagValue.MacroDefines->begin(), 209 CustomFlagValue.MacroDefines->end()); 210 } 211 212 DiagnoseUnclaimedMultilibCustomFlags(D, UnclaimedCustomFlagValueStrs, 213 CustomFlagDecls); 214 215 return {Result, MacroDefines}; 216 } 217 218 bool MultilibSet::select( 219 const Driver &D, const Multilib::flags_list &Flags, 220 llvm::SmallVectorImpl<Multilib> &Selected, 221 llvm::SmallVector<StringRef> *CustomFlagMacroDefines) const { 222 auto [FlagsWithCustom, CFMacroDefines] = processCustomFlags(D, Flags); 223 llvm::StringSet<> FlagSet(expandFlags(FlagsWithCustom)); 224 Selected.clear(); 225 bool AnyErrors = false; 226 227 // Determining the list of macro defines depends only on the custom flags 228 // passed in. The library variants actually selected are not relevant in 229 // this. Therefore this assignment can take place before the selection 230 // happens. 231 if (CustomFlagMacroDefines) 232 *CustomFlagMacroDefines = std::move(CFMacroDefines); 233 234 // Decide which multilibs we're going to select at all. 235 llvm::DenseSet<StringRef> ExclusiveGroupsSelected; 236 for (const Multilib &M : llvm::reverse(Multilibs)) { 237 // If this multilib doesn't match all our flags, don't select it. 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 // If this multilib has the same ExclusiveGroup as one we've already 246 // selected, skip it. We're iterating in reverse order, so the group 247 // member we've selected already is preferred. 248 // 249 // Otherwise, add the group name to the set of groups we've already 250 // selected a member of. 251 auto [It, Inserted] = ExclusiveGroupsSelected.insert(group); 252 if (!Inserted) 253 continue; 254 } 255 256 // If this multilib is actually a placeholder containing an error message 257 // written by the multilib.yaml author, then set a flag that will cause a 258 // failure return. Our caller will display the error message. 259 if (M.isError()) 260 AnyErrors = true; 261 262 // Select this multilib. 263 Selected.push_back(M); 264 } 265 266 // We iterated in reverse order, so now put Selected back the right way 267 // round. 268 std::reverse(Selected.begin(), Selected.end()); 269 270 return !AnyErrors && !Selected.empty(); 271 } 272 273 llvm::StringSet<> 274 MultilibSet::expandFlags(const Multilib::flags_list &InFlags) const { 275 llvm::StringSet<> Result; 276 for (const auto &F : InFlags) 277 Result.insert(F); 278 for (const FlagMatcher &M : FlagMatchers) { 279 std::string RegexString(M.Match); 280 281 // Make the regular expression match the whole string. 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 } 294 return Result; 295 } 296 297 namespace { 298 299 // When updating this also update MULTILIB_VERSION in MultilibTest.cpp 300 static const VersionTuple MultilibVersionCurrent(1, 0); 301 302 struct MultilibSerialization { 303 std::string Dir; // if this record successfully selects a library dir 304 std::string Error; // if this record reports a fatal error message 305 std::vector<std::string> Flags; 306 std::string Group; 307 }; 308 309 enum class MultilibGroupType { 310 /* 311 * The only group type currently supported is 'Exclusive', which indicates a 312 * group of multilibs of which at most one may be selected. 313 */ 314 Exclusive, 315 316 /* 317 * Future possibility: a second group type indicating a set of library 318 * directories that are mutually _dependent_ rather than mutually exclusive: 319 * if you include one you must include them all. 320 * 321 * It might also be useful to allow groups to be members of other groups, so 322 * that a mutually exclusive group could contain a mutually dependent set of 323 * library directories, or vice versa. 324 * 325 * These additional features would need changes in the implementation, but 326 * the YAML schema is set up so they can be added without requiring changes 327 * in existing users' multilib.yaml files. 328 */ 329 }; 330 331 struct MultilibGroupSerialization { 332 std::string Name; 333 MultilibGroupType Type; 334 }; 335 336 struct MultilibSetSerialization { 337 llvm::VersionTuple MultilibVersion; 338 SmallVector<MultilibGroupSerialization> Groups; 339 SmallVector<MultilibSerialization> Multilibs; 340 SmallVector<MultilibSet::FlagMatcher> FlagMatchers; 341 SmallVector<custom_flag::Declaration> CustomFlagDeclarations; 342 }; 343 344 } // end anonymous namespace 345 346 LLVM_YAML_IS_SEQUENCE_VECTOR(MultilibSerialization) 347 LLVM_YAML_IS_SEQUENCE_VECTOR(MultilibGroupSerialization) 348 LLVM_YAML_IS_SEQUENCE_VECTOR(MultilibSet::FlagMatcher) 349 LLVM_YAML_IS_SEQUENCE_VECTOR(custom_flag::ValueDetail) 350 LLVM_YAML_IS_SEQUENCE_VECTOR(custom_flag::Declaration) 351 352 template <> struct llvm::yaml::MappingTraits<MultilibSerialization> { 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 (!V.Dir.empty() && !V.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 370 template <> struct llvm::yaml::ScalarEnumerationTraits<MultilibGroupType> { 371 static void enumeration(IO &io, MultilibGroupType &Val) { 372 io.enumCase(Val, "Exclusive", MultilibGroupType::Exclusive); 373 } 374 }; 375 376 template <> struct llvm::yaml::MappingTraits<MultilibGroupSerialization> { 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 383 template <> struct llvm::yaml::MappingTraits<MultilibSet::FlagMatcher> { 384 static void mapping(llvm::yaml::IO &io, MultilibSet::FlagMatcher &M) { 385 io.mapRequired("Match", M.Match); 386 io.mapRequired("Flags", M.Flags); 387 } 388 static std::string validate(IO &io, MultilibSet::FlagMatcher &M) { 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 399 template <> 400 struct llvm::yaml::MappingContextTraits<custom_flag::ValueDetail, 401 llvm::SmallSet<std::string, 32>> { 402 static void mapping(llvm::yaml::IO &io, custom_flag::ValueDetail &V, 403 llvm::SmallSet<std::string, 32> &) { 404 io.mapRequired("Name", V.Name); 405 io.mapOptional("MacroDefines", V.MacroDefines); 406 } 407 static std::string validate(IO &io, custom_flag::ValueDetail &V, 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 417 template <> 418 struct llvm::yaml::MappingContextTraits<custom_flag::Declaration, 419 llvm::SmallSet<std::string, 32>> { 420 static void mapping(llvm::yaml::IO &io, custom_flag::Declaration &V, 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)) { 428 Value.Decl = &V; 429 if (Value.Name == DefaultValueName) { 430 assert(!V.DefaultValueIdx); 431 V.DefaultValueIdx = Idx; 432 } 433 } 434 } 435 static std::string validate(IO &io, custom_flag::Declaration &V, 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 (!V.DefaultValueIdx) 442 return "custom flag must have a default value"; 443 return {}; 444 } 445 }; 446 447 template <> struct llvm::yaml::MappingTraits<MultilibSetSerialization> { 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) { 470 Found = true; 471 break; 472 } 473 if (!Found) 474 return "multilib \"" + Lib.Dir + 475 "\" specifies undefined group name \"" + Lib.Group + "\""; 476 } 477 } 478 return std::string{}; 479 } 480 }; 481 482 llvm::ErrorOr<MultilibSet> 483 MultilibSet::parseYaml(llvm::MemoryBufferRef Input, 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 492 multilib_list Multilibs; 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 // We transfer M.Group straight into the ExclusiveGroup parameter for the 502 // Multilib constructor. If we later support more than one type of group, 503 // we'll have to look up the group name in MS.Groups, check its type, and 504 // decide what to do here. 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 513 LLVM_DUMP_METHOD void MultilibSet::dump() const { 514 print(llvm::errs()); 515 } 516 517 void MultilibSet::print(raw_ostream &OS) const { 518 for (const auto &M : *this) 519 OS << M << "\n"; 520 } 521 522 raw_ostream &clang::driver::operator<<(raw_ostream &OS, const MultilibSet &MS) { 523 MS.print(OS); 524 return OS; 525 } 526 527 namespace clang::driver::custom_flag { 528 Declaration::Declaration(const Declaration &Other) 529 : Name(Other.Name), ValueList(Other.ValueList), 530 DefaultValueIdx(Other.DefaultValueIdx) { 531 for (ValueDetail &Detail : ValueList) 532 Detail.Decl = this; 533 } 534 535 Declaration::Declaration(Declaration &&Other) 536 : Name(std::move(Other.Name)), ValueList(std::move(Other.ValueList)), 537 DefaultValueIdx(std::move(Other.DefaultValueIdx)) { 538 for (ValueDetail &Detail : ValueList) 539 Detail.Decl = this; 540 } 541 542 Declaration &Declaration::operator=(const Declaration &Other) { 543 if (this == &Other) 544 return *this; 545 Name = Other.Name; 546 ValueList = Other.ValueList; 547 DefaultValueIdx = Other.DefaultValueIdx; 548 for (ValueDetail &Detail : ValueList) 549 Detail.Decl = this; 550 return *this; 551 } 552 553 Declaration &Declaration::operator=(Declaration &&Other) { 554 if (this == &Other) 555 return *this; 556 Name = std::move(Other.Name); 557 ValueList = std::move(Other.ValueList); 558 DefaultValueIdx = std::move(Other.DefaultValueIdx); 559 for (ValueDetail &Detail : ValueList) 560 Detail.Decl = this; 561 return *this; 562 } 563 } // namespace clang::driver::custom_flag 564