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/ADT/StringSet.h" 17 #include "llvm/Support/Compiler.h" 18 #include "llvm/Support/SourceMgr.h" 19 #include <cassert> 20 #include <functional> 21 #include <optional> 22 #include <string> 23 #include <utility> 24 #include <vector> 25 26 namespace clang { 27 namespace driver { 28 29 class Driver; 30 31 /// This corresponds to a single GCC Multilib, or a segment of one controlled 32 /// by a command line flag. 33 /// See also MultilibBuilder for building a multilib by mutating it 34 /// incrementally. 35 class Multilib { 36 public: 37 using flags_list = std::vector<std::string>; 38 39 private: 40 std::string GCCSuffix; 41 std::string OSSuffix; 42 std::string IncludeSuffix; 43 flags_list Flags; 44 45 // Optionally, a multilib can be assigned a string tag indicating that it's 46 // part of a group of mutually exclusive possibilities. If two or more 47 // multilibs have the same non-empty value of ExclusiveGroup, then only the 48 // last matching one of them will be selected. 49 // 50 // Setting this to the empty string is a special case, indicating that the 51 // directory is not mutually exclusive with anything else. 52 std::string ExclusiveGroup; 53 54 // Some Multilib objects don't actually represent library directories you can 55 // select. Instead, they represent failures of multilib selection, of the 56 // form 'Sorry, we don't have any library compatible with these constraints'. 57 std::optional<std::string> Error; 58 59 public: 60 /// GCCSuffix, OSSuffix & IncludeSuffix will be appended directly to the 61 /// sysroot string so they must either be empty or begin with a '/' character. 62 /// This is enforced with an assert in the constructor. 63 Multilib(StringRef GCCSuffix = {}, StringRef OSSuffix = {}, 64 StringRef IncludeSuffix = {}, const flags_list &Flags = flags_list(), 65 StringRef ExclusiveGroup = {}, 66 std::optional<StringRef> Error = std::nullopt); 67 68 /// Get the detected GCC installation path suffix for the multi-arch 69 /// target variant. Always starts with a '/', unless empty 70 const std::string &gccSuffix() const { return GCCSuffix; } 71 72 /// Get the detected os path suffix for the multi-arch 73 /// target variant. Always starts with a '/', unless empty 74 const std::string &osSuffix() const { return OSSuffix; } 75 76 /// Get the include directory suffix. Always starts with a '/', unless 77 /// empty 78 const std::string &includeSuffix() const { return IncludeSuffix; } 79 80 /// Get the flags that indicate or contraindicate this multilib's use 81 /// All elements begin with either '-' or '!' 82 const flags_list &flags() const { return Flags; } 83 84 /// Get the exclusive group label. 85 const std::string &exclusiveGroup() const { return ExclusiveGroup; } 86 87 LLVM_DUMP_METHOD void dump() const; 88 /// print summary of the Multilib 89 void print(raw_ostream &OS) const; 90 91 /// Check whether the default is selected 92 bool isDefault() const 93 { return GCCSuffix.empty() && OSSuffix.empty() && IncludeSuffix.empty(); } 94 95 bool operator==(const Multilib &Other) const; 96 97 bool isError() const { return Error.has_value(); } 98 99 const std::string &getErrorMessage() const { return Error.value(); } 100 }; 101 102 raw_ostream &operator<<(raw_ostream &OS, const Multilib &M); 103 104 namespace custom_flag { 105 struct Declaration; 106 107 struct ValueDetail { 108 std::string Name; 109 std::optional<SmallVector<std::string>> MacroDefines; 110 Declaration *Decl; 111 }; 112 113 struct Declaration { 114 std::string Name; 115 SmallVector<ValueDetail> ValueList; 116 std::optional<size_t> DefaultValueIdx; 117 118 Declaration() = default; 119 Declaration(const Declaration &); 120 Declaration(Declaration &&); 121 Declaration &operator=(const Declaration &); 122 Declaration &operator=(Declaration &&); 123 }; 124 125 static constexpr StringRef Prefix = "-fmultilib-flag="; 126 } // namespace custom_flag 127 128 /// See also MultilibSetBuilder for combining multilibs into a set. 129 class MultilibSet { 130 public: 131 using multilib_list = std::vector<Multilib>; 132 using const_iterator = multilib_list::const_iterator; 133 using IncludeDirsFunc = 134 std::function<std::vector<std::string>(const Multilib &M)>; 135 using FilterCallback = llvm::function_ref<bool(const Multilib &)>; 136 137 /// Uses regular expressions to simplify flags used for multilib selection. 138 /// For example, we may wish both -mfloat-abi=soft and -mfloat-abi=softfp to 139 /// be treated as -mfloat-abi=soft. 140 struct FlagMatcher { 141 std::string Match; 142 std::vector<std::string> Flags; 143 }; 144 145 private: 146 multilib_list Multilibs; 147 SmallVector<FlagMatcher> FlagMatchers; 148 SmallVector<custom_flag::Declaration> CustomFlagDecls; 149 IncludeDirsFunc IncludeCallback; 150 IncludeDirsFunc FilePathsCallback; 151 152 public: 153 MultilibSet() = default; 154 MultilibSet(multilib_list &&Multilibs, 155 SmallVector<FlagMatcher> &&FlagMatchers = {}, 156 SmallVector<custom_flag::Declaration> &&CustomFlagDecls = {}) 157 : Multilibs(std::move(Multilibs)), FlagMatchers(std::move(FlagMatchers)), 158 CustomFlagDecls(std::move(CustomFlagDecls)) {} 159 160 const multilib_list &getMultilibs() { return Multilibs; } 161 162 /// Filter out some subset of the Multilibs using a user defined callback 163 MultilibSet &FilterOut(FilterCallback F); 164 165 /// Add a completed Multilib to the set 166 void push_back(const Multilib &M); 167 168 const_iterator begin() const { return Multilibs.begin(); } 169 const_iterator end() const { return Multilibs.end(); } 170 171 /// Process custom flags from \p Flags and returns an expanded flags list and 172 /// a list of macro defines. 173 /// Returns a pair where: 174 /// - first: the new flags list including custom flags after processing. 175 /// - second: the extra macro defines to be fed to the driver. 176 std::pair<Multilib::flags_list, SmallVector<StringRef>> 177 processCustomFlags(const Driver &D, const Multilib::flags_list &Flags) const; 178 179 /// Select compatible variants, \returns false if none are compatible 180 bool select(const Driver &D, const Multilib::flags_list &Flags, 181 llvm::SmallVectorImpl<Multilib> &, 182 llvm::SmallVector<StringRef> * = nullptr) const; 183 184 unsigned size() const { return Multilibs.size(); } 185 186 /// Get the given flags plus flags found by matching them against the 187 /// FlagMatchers and choosing the Flags of each accordingly. The select method 188 /// calls this method so in most cases it's not necessary to call it directly. 189 llvm::StringSet<> expandFlags(const Multilib::flags_list &) const; 190 191 LLVM_DUMP_METHOD void dump() const; 192 void print(raw_ostream &OS) const; 193 194 MultilibSet &setIncludeDirsCallback(IncludeDirsFunc F) { 195 IncludeCallback = std::move(F); 196 return *this; 197 } 198 199 const IncludeDirsFunc &includeDirsCallback() const { return IncludeCallback; } 200 201 MultilibSet &setFilePathsCallback(IncludeDirsFunc F) { 202 FilePathsCallback = std::move(F); 203 return *this; 204 } 205 206 const IncludeDirsFunc &filePathsCallback() const { return FilePathsCallback; } 207 208 static llvm::ErrorOr<MultilibSet> 209 parseYaml(llvm::MemoryBufferRef, llvm::SourceMgr::DiagHandlerTy = nullptr, 210 void *DiagHandlerCtxt = nullptr); 211 }; 212 213 raw_ostream &operator<<(raw_ostream &OS, const MultilibSet &MS); 214 215 } // namespace driver 216 } // namespace clang 217 218 #endif // LLVM_CLANG_DRIVER_MULTILIB_H 219