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 "llvm/ADT/SmallString.h" 12 #include "llvm/ADT/StringMap.h" 13 #include "llvm/ADT/StringRef.h" 14 #include "llvm/ADT/StringSet.h" 15 #include "llvm/Support/Compiler.h" 16 #include "llvm/Support/ErrorHandling.h" 17 #include "llvm/Support/Path.h" 18 #include "llvm/Support/Regex.h" 19 #include "llvm/Support/raw_ostream.h" 20 #include <algorithm> 21 #include <cassert> 22 #include <string> 23 24 using namespace clang; 25 using namespace driver; 26 using namespace llvm::sys; 27 28 Multilib::Multilib(StringRef GCCSuffix, StringRef OSSuffix, 29 StringRef IncludeSuffix, const flags_list &Flags) 30 : GCCSuffix(GCCSuffix), OSSuffix(OSSuffix), IncludeSuffix(IncludeSuffix), 31 Flags(Flags) { 32 assert(GCCSuffix.empty() || 33 (StringRef(GCCSuffix).front() == '/' && GCCSuffix.size() > 1)); 34 assert(OSSuffix.empty() || 35 (StringRef(OSSuffix).front() == '/' && OSSuffix.size() > 1)); 36 assert(IncludeSuffix.empty() || 37 (StringRef(IncludeSuffix).front() == '/' && IncludeSuffix.size() > 1)); 38 } 39 40 LLVM_DUMP_METHOD void Multilib::dump() const { 41 print(llvm::errs()); 42 } 43 44 void Multilib::print(raw_ostream &OS) const { 45 if (GCCSuffix.empty()) 46 OS << "."; 47 else { 48 OS << StringRef(GCCSuffix).drop_front(); 49 } 50 OS << ";"; 51 for (StringRef Flag : Flags) { 52 if (Flag.front() == '+') 53 OS << "@" << Flag.substr(1); 54 } 55 } 56 57 bool Multilib::operator==(const Multilib &Other) const { 58 // Check whether the flags sets match 59 // allowing for the match to be order invariant 60 llvm::StringSet<> MyFlags; 61 for (const auto &Flag : Flags) 62 MyFlags.insert(Flag); 63 64 for (const auto &Flag : Other.Flags) 65 if (!MyFlags.contains(Flag)) 66 return false; 67 68 if (osSuffix() != Other.osSuffix()) 69 return false; 70 71 if (gccSuffix() != Other.gccSuffix()) 72 return false; 73 74 if (includeSuffix() != Other.includeSuffix()) 75 return false; 76 77 return true; 78 } 79 80 raw_ostream &clang::driver::operator<<(raw_ostream &OS, const Multilib &M) { 81 M.print(OS); 82 return OS; 83 } 84 85 MultilibSet &MultilibSet::FilterOut(FilterCallback F) { 86 llvm::erase_if(Multilibs, F); 87 return *this; 88 } 89 90 void MultilibSet::push_back(const Multilib &M) { Multilibs.push_back(M); } 91 92 MultilibSet::multilib_list 93 MultilibSet::select(const Multilib::flags_list &Flags) const { 94 llvm::StringSet<> FlagSet; 95 for (const auto &Flag : Flags) 96 FlagSet.insert(Flag); 97 98 multilib_list Result; 99 llvm::copy_if(Multilibs, std::back_inserter(Result), 100 [&FlagSet](const Multilib &M) { 101 for (const std::string &F : M.flags()) 102 if (!FlagSet.contains(F)) 103 return false; 104 return true; 105 }); 106 return Result; 107 } 108 109 bool MultilibSet::select(const Multilib::flags_list &Flags, 110 Multilib &Selected) const { 111 multilib_list Result = select(Flags); 112 if (Result.empty()) 113 return false; 114 Selected = Result.back(); 115 return true; 116 } 117 118 LLVM_DUMP_METHOD void MultilibSet::dump() const { 119 print(llvm::errs()); 120 } 121 122 void MultilibSet::print(raw_ostream &OS) const { 123 for (const auto &M : *this) 124 OS << M << "\n"; 125 } 126 127 raw_ostream &clang::driver::operator<<(raw_ostream &OS, const MultilibSet &MS) { 128 MS.print(OS); 129 return OS; 130 } 131