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