1 //===- Multilib.h -----------------------------------------------*- C++ -*-===// 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 #ifndef LLVM_CLANG_DRIVER_MULTILIB_H 10 #define LLVM_CLANG_DRIVER_MULTILIB_H 11 12 #include "clang/Basic/LLVM.h" 13 #include "llvm/ADT/ArrayRef.h" 14 #include "llvm/ADT/STLExtras.h" 15 #include "llvm/ADT/StringRef.h" 16 #include "llvm/Support/Compiler.h" 17 #include <cassert> 18 #include <functional> 19 #include <string> 20 #include <utility> 21 #include <vector> 22 23 namespace clang { 24 namespace driver { 25 26 /// This corresponds to a single GCC Multilib, or a segment of one controlled 27 /// by a command line flag 28 class Multilib { 29 public: 30 using flags_list = std::vector<std::string>; 31 32 private: 33 std::string GCCSuffix; 34 std::string OSSuffix; 35 std::string IncludeSuffix; 36 flags_list Flags; 37 int Priority; 38 39 public: 40 Multilib(StringRef GCCSuffix = {}, StringRef OSSuffix = {}, 41 StringRef IncludeSuffix = {}, int Priority = 0); 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 /// Returns the multilib priority. When more than one multilib matches flags, 82 /// the one with the highest priority is selected, with 0 being the default. priority()83 int priority() const { return Priority; } 84 85 /// Add a flag to the flags list 86 /// \p Flag must be a flag accepted by the driver with its leading '-' removed, 87 /// and replaced with either: 88 /// '-' which contraindicates using this multilib with that flag 89 /// or: 90 /// '+' which promotes using this multilib in the presence of that flag 91 /// otherwise '-print-multi-lib' will not emit them correctly. flag(StringRef F)92 Multilib &flag(StringRef F) { 93 assert(F.front() == '+' || F.front() == '-'); 94 Flags.push_back(std::string(F)); 95 return *this; 96 } 97 98 LLVM_DUMP_METHOD void dump() const; 99 /// print summary of the Multilib 100 void print(raw_ostream &OS) const; 101 102 /// Check whether any of the 'against' flags contradict the 'for' flags. 103 bool isValid() const; 104 105 /// Check whether the default is selected isDefault()106 bool isDefault() const 107 { return GCCSuffix.empty() && OSSuffix.empty() && IncludeSuffix.empty(); } 108 109 bool operator==(const Multilib &Other) const; 110 }; 111 112 raw_ostream &operator<<(raw_ostream &OS, const Multilib &M); 113 114 class MultilibSet { 115 public: 116 using multilib_list = std::vector<Multilib>; 117 using iterator = multilib_list::iterator; 118 using const_iterator = multilib_list::const_iterator; 119 using IncludeDirsFunc = 120 std::function<std::vector<std::string>(const Multilib &M)>; 121 using FilterCallback = llvm::function_ref<bool(const Multilib &)>; 122 123 private: 124 multilib_list Multilibs; 125 IncludeDirsFunc IncludeCallback; 126 IncludeDirsFunc FilePathsCallback; 127 128 public: 129 MultilibSet() = default; 130 131 /// Add an optional Multilib segment 132 MultilibSet &Maybe(const Multilib &M); 133 134 /// Add a set of mutually incompatible Multilib segments 135 MultilibSet &Either(const Multilib &M1, const Multilib &M2); 136 MultilibSet &Either(const Multilib &M1, const Multilib &M2, 137 const Multilib &M3); 138 MultilibSet &Either(const Multilib &M1, const Multilib &M2, 139 const Multilib &M3, const Multilib &M4); 140 MultilibSet &Either(const Multilib &M1, const Multilib &M2, 141 const Multilib &M3, const Multilib &M4, 142 const Multilib &M5); 143 MultilibSet &Either(ArrayRef<Multilib> Ms); 144 145 /// Filter out some subset of the Multilibs using a user defined callback 146 MultilibSet &FilterOut(FilterCallback F); 147 148 /// Filter out those Multilibs whose gccSuffix matches the given expression 149 MultilibSet &FilterOut(const char *Regex); 150 151 /// Add a completed Multilib to the set 152 void push_back(const Multilib &M); 153 154 /// Union this set of multilibs with another 155 void combineWith(const MultilibSet &MS); 156 157 /// Remove all of the multilibs from the set clear()158 void clear() { Multilibs.clear(); } 159 begin()160 iterator begin() { return Multilibs.begin(); } begin()161 const_iterator begin() const { return Multilibs.begin(); } 162 end()163 iterator end() { return Multilibs.end(); } end()164 const_iterator end() const { return Multilibs.end(); } 165 166 /// Pick the best multilib in the set, \returns false if none are compatible 167 bool select(const Multilib::flags_list &Flags, Multilib &M) const; 168 size()169 unsigned size() const { return Multilibs.size(); } 170 171 LLVM_DUMP_METHOD void dump() const; 172 void print(raw_ostream &OS) const; 173 setIncludeDirsCallback(IncludeDirsFunc F)174 MultilibSet &setIncludeDirsCallback(IncludeDirsFunc F) { 175 IncludeCallback = std::move(F); 176 return *this; 177 } 178 includeDirsCallback()179 const IncludeDirsFunc &includeDirsCallback() const { return IncludeCallback; } 180 setFilePathsCallback(IncludeDirsFunc F)181 MultilibSet &setFilePathsCallback(IncludeDirsFunc F) { 182 FilePathsCallback = std::move(F); 183 return *this; 184 } 185 filePathsCallback()186 const IncludeDirsFunc &filePathsCallback() const { return FilePathsCallback; } 187 188 private: 189 /// Apply the filter to Multilibs and return the subset that remains 190 static multilib_list filterCopy(FilterCallback F, const multilib_list &Ms); 191 192 /// Apply the filter to the multilib_list, removing those that don't match 193 static void filterInPlace(FilterCallback F, multilib_list &Ms); 194 }; 195 196 raw_ostream &operator<<(raw_ostream &OS, const MultilibSet &MS); 197 198 } // namespace driver 199 } // namespace clang 200 201 #endif // LLVM_CLANG_DRIVER_MULTILIB_H 202