1 //===- MultilibBuilder.cpp - MultilibBuilder 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/MultilibBuilder.h" 10 #include "llvm/ADT/SmallString.h" 11 #include "llvm/ADT/StringMap.h" 12 #include "llvm/Support/Path.h" 13 #include "llvm/Support/Regex.h" 14 #include "llvm/Support/raw_ostream.h" 15 16 using namespace clang; 17 using namespace driver; 18 19 /// normalize Segment to "/foo/bar" or "". 20 static void normalizePathSegment(std::string &Segment) { 21 StringRef seg = Segment; 22 23 // Prune trailing "/" or "./" 24 while (true) { 25 StringRef last = llvm::sys::path::filename(seg); 26 if (last != ".") 27 break; 28 seg = llvm::sys::path::parent_path(seg); 29 } 30 31 if (seg.empty() || seg == "/") { 32 Segment.clear(); 33 return; 34 } 35 36 // Add leading '/' 37 if (seg.front() != '/') { 38 Segment = "/" + seg.str(); 39 } else { 40 Segment = std::string(seg); 41 } 42 } 43 44 MultilibBuilder::MultilibBuilder(StringRef GCC, StringRef OS, StringRef Include) 45 : GCCSuffix(GCC), OSSuffix(OS), IncludeSuffix(Include) { 46 normalizePathSegment(GCCSuffix); 47 normalizePathSegment(OSSuffix); 48 normalizePathSegment(IncludeSuffix); 49 } 50 51 MultilibBuilder::MultilibBuilder(StringRef Suffix) 52 : MultilibBuilder(Suffix, Suffix, Suffix) {} 53 54 MultilibBuilder &MultilibBuilder::gccSuffix(StringRef S) { 55 GCCSuffix = std::string(S); 56 normalizePathSegment(GCCSuffix); 57 return *this; 58 } 59 60 MultilibBuilder &MultilibBuilder::osSuffix(StringRef S) { 61 OSSuffix = std::string(S); 62 normalizePathSegment(OSSuffix); 63 return *this; 64 } 65 66 MultilibBuilder &MultilibBuilder::includeSuffix(StringRef S) { 67 IncludeSuffix = std::string(S); 68 normalizePathSegment(IncludeSuffix); 69 return *this; 70 } 71 72 bool MultilibBuilder::isValid() const { 73 llvm::StringMap<int> FlagSet; 74 for (unsigned I = 0, N = Flags.size(); I != N; ++I) { 75 StringRef Flag(Flags[I]); 76 llvm::StringMap<int>::iterator SI = FlagSet.find(Flag.substr(1)); 77 78 assert(StringRef(Flag).front() == '+' || StringRef(Flag).front() == '-'); 79 80 if (SI == FlagSet.end()) 81 FlagSet[Flag.substr(1)] = I; 82 else if (Flags[I] != Flags[SI->getValue()]) 83 return false; 84 } 85 return true; 86 } 87 88 Multilib MultilibBuilder::makeMultilib() const { 89 return Multilib(GCCSuffix, OSSuffix, IncludeSuffix, Flags); 90 } 91 92 MultilibSetBuilder &MultilibSetBuilder::Maybe(const MultilibBuilder &M) { 93 MultilibBuilder Opposite; 94 // Negate any '+' flags 95 for (StringRef Flag : M.flags()) { 96 if (Flag.front() == '+') 97 Opposite.flags().push_back(("-" + Flag.substr(1)).str()); 98 } 99 return Either(M, Opposite); 100 } 101 102 MultilibSetBuilder &MultilibSetBuilder::Either(const MultilibBuilder &M1, 103 const MultilibBuilder &M2) { 104 return Either({M1, M2}); 105 } 106 107 MultilibSetBuilder &MultilibSetBuilder::Either(const MultilibBuilder &M1, 108 const MultilibBuilder &M2, 109 const MultilibBuilder &M3) { 110 return Either({M1, M2, M3}); 111 } 112 113 MultilibSetBuilder &MultilibSetBuilder::Either(const MultilibBuilder &M1, 114 const MultilibBuilder &M2, 115 const MultilibBuilder &M3, 116 const MultilibBuilder &M4) { 117 return Either({M1, M2, M3, M4}); 118 } 119 120 MultilibSetBuilder &MultilibSetBuilder::Either(const MultilibBuilder &M1, 121 const MultilibBuilder &M2, 122 const MultilibBuilder &M3, 123 const MultilibBuilder &M4, 124 const MultilibBuilder &M5) { 125 return Either({M1, M2, M3, M4, M5}); 126 } 127 128 static MultilibBuilder compose(const MultilibBuilder &Base, 129 const MultilibBuilder &New) { 130 SmallString<128> GCCSuffix; 131 llvm::sys::path::append(GCCSuffix, "/", Base.gccSuffix(), New.gccSuffix()); 132 SmallString<128> OSSuffix; 133 llvm::sys::path::append(OSSuffix, "/", Base.osSuffix(), New.osSuffix()); 134 SmallString<128> IncludeSuffix; 135 llvm::sys::path::append(IncludeSuffix, "/", Base.includeSuffix(), 136 New.includeSuffix()); 137 138 MultilibBuilder Composed(GCCSuffix, OSSuffix, IncludeSuffix); 139 140 MultilibBuilder::flags_list &Flags = Composed.flags(); 141 142 Flags.insert(Flags.end(), Base.flags().begin(), Base.flags().end()); 143 Flags.insert(Flags.end(), New.flags().begin(), New.flags().end()); 144 145 return Composed; 146 } 147 148 MultilibSetBuilder & 149 MultilibSetBuilder::Either(ArrayRef<MultilibBuilder> MultilibSegments) { 150 multilib_list Composed; 151 152 if (Multilibs.empty()) 153 Multilibs.insert(Multilibs.end(), MultilibSegments.begin(), 154 MultilibSegments.end()); 155 else { 156 for (const auto &New : MultilibSegments) { 157 for (const auto &Base : Multilibs) { 158 MultilibBuilder MO = compose(Base, New); 159 if (MO.isValid()) 160 Composed.push_back(MO); 161 } 162 } 163 164 Multilibs = Composed; 165 } 166 167 return *this; 168 } 169 170 MultilibSetBuilder &MultilibSetBuilder::FilterOut(const char *Regex) { 171 llvm::Regex R(Regex); 172 #ifndef NDEBUG 173 std::string Error; 174 if (!R.isValid(Error)) { 175 llvm::errs() << Error; 176 llvm_unreachable("Invalid regex!"); 177 } 178 #endif 179 llvm::erase_if(Multilibs, [&R](const MultilibBuilder &M) { 180 return R.match(M.gccSuffix()); 181 }); 182 return *this; 183 } 184 185 MultilibSet MultilibSetBuilder::makeMultilibSet() const { 186 MultilibSet Result; 187 for (const auto &M : Multilibs) { 188 Result.push_back(M.makeMultilib()); 189 } 190 return Result; 191 } 192