1 //===- Multilib.h -----------------------------------------------*- C++ -*-===// 2 // 3 // The LLVM Compiler Infrastructure 4 // 5 // This file is distributed under the University of Illinois Open Source 6 // License. See LICENSE.TXT for details. 7 // 8 //===----------------------------------------------------------------------===// 9 10 #ifndef LLVM_CLANG_DRIVER_MULTILIB_H 11 #define LLVM_CLANG_DRIVER_MULTILIB_H 12 13 #include "clang/Basic/LLVM.h" 14 #include "llvm/ADT/ArrayRef.h" 15 #include "llvm/ADT/STLExtras.h" 16 #include "llvm/ADT/StringRef.h" 17 #include "llvm/Support/Compiler.h" 18 #include <cassert> 19 #include <functional> 20 #include <string> 21 #include <utility> 22 #include <vector> 23 24 namespace clang { 25 namespace driver { 26 27 /// This corresponds to a single GCC Multilib, or a segment of one controlled 28 /// by a command line flag 29 class Multilib { 30 public: 31 using flags_list = std::vector<std::string>; 32 33 private: 34 std::string GCCSuffix; 35 std::string OSSuffix; 36 std::string IncludeSuffix; 37 flags_list Flags; 38 39 public: 40 Multilib(StringRef GCCSuffix = {}, StringRef OSSuffix = {}, 41 StringRef IncludeSuffix = {}); 42 43 /// Get the detected GCC installation path suffix for the multi-arch 44 /// target variant. Always starts with a '/', unless empty gccSuffix()45 const std::string &gccSuffix() const { 46 assert(GCCSuffix.empty() || 47 (StringRef(GCCSuffix).front() == '/' && GCCSuffix.size() > 1)); 48 return GCCSuffix; 49 } 50 51 /// Set the GCC installation path suffix. 52 Multilib &gccSuffix(StringRef S); 53 54 /// Get the detected os path suffix for the multi-arch 55 /// target variant. Always starts with a '/', unless empty osSuffix()56 const std::string &osSuffix() const { 57 assert(OSSuffix.empty() || 58 (StringRef(OSSuffix).front() == '/' && OSSuffix.size() > 1)); 59 return OSSuffix; 60 } 61 62 /// Set the os path suffix. 63 Multilib &osSuffix(StringRef S); 64 65 /// Get the include directory suffix. Always starts with a '/', unless 66 /// empty includeSuffix()67 const std::string &includeSuffix() const { 68 assert(IncludeSuffix.empty() || 69 (StringRef(IncludeSuffix).front() == '/' && IncludeSuffix.size() > 1)); 70 return IncludeSuffix; 71 } 72 73 /// Set the include directory suffix 74 Multilib &includeSuffix(StringRef S); 75 76 /// Get the flags that indicate or contraindicate this multilib's use 77 /// All elements begin with either '+' or '-' flags()78 const flags_list &flags() const { return Flags; } flags()79 flags_list &flags() { return Flags; } 80 81 /// Add a flag to the flags list 82 /// \p Flag must be a flag accepted by the driver with its leading '-' removed, 83 /// and replaced with either: 84 /// '-' which contraindicates using this multilib with that flag 85 /// or: 86 /// '+' which promotes using this multilib in the presence of that flag 87 /// otherwise '-print-multi-lib' will not emit them correctly. flag(StringRef F)88 Multilib &flag(StringRef F) { 89 assert(F.front() == '+' || F.front() == '-'); 90 Flags.push_back(F); 91 return *this; 92 } 93 94 LLVM_DUMP_METHOD void dump() const; 95 /// print summary of the Multilib 96 void print(raw_ostream &OS) const; 97 98 /// Check whether any of the 'against' flags contradict the 'for' flags. 99 bool isValid() const; 100 101 /// Check whether the default is selected isDefault()102 bool isDefault() const 103 { return GCCSuffix.empty() && OSSuffix.empty() && IncludeSuffix.empty(); } 104 105 bool operator==(const Multilib &Other) const; 106 }; 107 108 raw_ostream &operator<<(raw_ostream &OS, const Multilib &M); 109 110 class MultilibSet { 111 public: 112 using multilib_list = std::vector<Multilib>; 113 using iterator = multilib_list::iterator; 114 using const_iterator = multilib_list::const_iterator; 115 using IncludeDirsFunc = 116 std::function<std::vector<std::string>(const Multilib &M)>; 117 using FilterCallback = llvm::function_ref<bool(const Multilib &)>; 118 119 private: 120 multilib_list Multilibs; 121 IncludeDirsFunc IncludeCallback; 122 IncludeDirsFunc FilePathsCallback; 123 124 public: 125 MultilibSet() = default; 126 127 /// Add an optional Multilib segment 128 MultilibSet &Maybe(const Multilib &M); 129 130 /// Add a set of mutually incompatible Multilib segments 131 MultilibSet &Either(const Multilib &M1, const Multilib &M2); 132 MultilibSet &Either(const Multilib &M1, const Multilib &M2, 133 const Multilib &M3); 134 MultilibSet &Either(const Multilib &M1, const Multilib &M2, 135 const Multilib &M3, const Multilib &M4); 136 MultilibSet &Either(const Multilib &M1, const Multilib &M2, 137 const Multilib &M3, const Multilib &M4, 138 const Multilib &M5); 139 MultilibSet &Either(ArrayRef<Multilib> Ms); 140 141 /// Filter out some subset of the Multilibs using a user defined callback 142 MultilibSet &FilterOut(FilterCallback F); 143 144 /// Filter out those Multilibs whose gccSuffix matches the given expression 145 MultilibSet &FilterOut(const char *Regex); 146 147 /// Add a completed Multilib to the set 148 void push_back(const Multilib &M); 149 150 /// Union this set of multilibs with another 151 void combineWith(const MultilibSet &MS); 152 153 /// Remove all of the multilibs from the set clear()154 void clear() { Multilibs.clear(); } 155 begin()156 iterator begin() { return Multilibs.begin(); } begin()157 const_iterator begin() const { return Multilibs.begin(); } 158 end()159 iterator end() { return Multilibs.end(); } end()160 const_iterator end() const { return Multilibs.end(); } 161 162 /// Pick the best multilib in the set, \returns false if none are compatible 163 bool select(const Multilib::flags_list &Flags, Multilib &M) const; 164 size()165 unsigned size() const { return Multilibs.size(); } 166 167 LLVM_DUMP_METHOD void dump() const; 168 void print(raw_ostream &OS) const; 169 setIncludeDirsCallback(IncludeDirsFunc F)170 MultilibSet &setIncludeDirsCallback(IncludeDirsFunc F) { 171 IncludeCallback = std::move(F); 172 return *this; 173 } 174 includeDirsCallback()175 const IncludeDirsFunc &includeDirsCallback() const { return IncludeCallback; } 176 setFilePathsCallback(IncludeDirsFunc F)177 MultilibSet &setFilePathsCallback(IncludeDirsFunc F) { 178 FilePathsCallback = std::move(F); 179 return *this; 180 } 181 filePathsCallback()182 const IncludeDirsFunc &filePathsCallback() const { return FilePathsCallback; } 183 184 private: 185 /// Apply the filter to Multilibs and return the subset that remains 186 static multilib_list filterCopy(FilterCallback F, const multilib_list &Ms); 187 188 /// Apply the filter to the multilib_list, removing those that don't match 189 static void filterInPlace(FilterCallback F, multilib_list &Ms); 190 }; 191 192 raw_ostream &operator<<(raw_ostream &OS, const MultilibSet &MS); 193 194 } // namespace driver 195 } // namespace clang 196 197 #endif // LLVM_CLANG_DRIVER_MULTILIB_H 198