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/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 auto [SI, Inserted] = FlagSet.try_emplace(Flag.substr(1), I); 77 78 assert(StringRef(Flag).front() == '-' || StringRef(Flag).front() == '!'); 79 80 if (!Inserted && Flags[I] != Flags[SI->getValue()]) 81 return false; 82 } 83 return true; 84 } 85 86 MultilibBuilder &MultilibBuilder::flag(StringRef Flag, bool Disallow) { 87 tools::addMultilibFlag(!Disallow, Flag, Flags); 88 return *this; 89 } 90 91 Multilib MultilibBuilder::makeMultilib() const { 92 return Multilib(GCCSuffix, OSSuffix, IncludeSuffix, Flags); 93 } 94 95 MultilibSetBuilder &MultilibSetBuilder::Maybe(const MultilibBuilder &M) { 96 MultilibBuilder Opposite; 97 // Negate positive flags 98 for (StringRef Flag : M.flags()) { 99 if (Flag.front() == '-') 100 Opposite.flag(Flag, /*Disallow=*/true); 101 } 102 return Either(M, Opposite); 103 } 104 105 MultilibSetBuilder &MultilibSetBuilder::Either(const MultilibBuilder &M1, 106 const MultilibBuilder &M2) { 107 return Either({M1, M2}); 108 } 109 110 MultilibSetBuilder &MultilibSetBuilder::Either(const MultilibBuilder &M1, 111 const MultilibBuilder &M2, 112 const MultilibBuilder &M3) { 113 return Either({M1, M2, M3}); 114 } 115 116 MultilibSetBuilder &MultilibSetBuilder::Either(const MultilibBuilder &M1, 117 const MultilibBuilder &M2, 118 const MultilibBuilder &M3, 119 const MultilibBuilder &M4) { 120 return Either({M1, M2, M3, M4}); 121 } 122 123 MultilibSetBuilder &MultilibSetBuilder::Either(const MultilibBuilder &M1, 124 const MultilibBuilder &M2, 125 const MultilibBuilder &M3, 126 const MultilibBuilder &M4, 127 const MultilibBuilder &M5) { 128 return Either({M1, M2, M3, M4, M5}); 129 } 130 131 static MultilibBuilder compose(const MultilibBuilder &Base, 132 const MultilibBuilder &New) { 133 SmallString<128> GCCSuffix; 134 llvm::sys::path::append(GCCSuffix, "/", Base.gccSuffix(), New.gccSuffix()); 135 SmallString<128> OSSuffix; 136 llvm::sys::path::append(OSSuffix, "/", Base.osSuffix(), New.osSuffix()); 137 SmallString<128> IncludeSuffix; 138 llvm::sys::path::append(IncludeSuffix, "/", Base.includeSuffix(), 139 New.includeSuffix()); 140 141 MultilibBuilder Composed(GCCSuffix, OSSuffix, IncludeSuffix); 142 143 MultilibBuilder::flags_list &Flags = Composed.flags(); 144 145 Flags.insert(Flags.end(), Base.flags().begin(), Base.flags().end()); 146 Flags.insert(Flags.end(), New.flags().begin(), New.flags().end()); 147 148 return Composed; 149 } 150 151 MultilibSetBuilder & 152 MultilibSetBuilder::Either(ArrayRef<MultilibBuilder> MultilibSegments) { 153 multilib_list Composed; 154 155 if (Multilibs.empty()) 156 Multilibs.insert(Multilibs.end(), MultilibSegments.begin(), 157 MultilibSegments.end()); 158 else { 159 for (const auto &New : MultilibSegments) { 160 for (const auto &Base : Multilibs) { 161 MultilibBuilder MO = compose(Base, New); 162 if (MO.isValid()) 163 Composed.push_back(MO); 164 } 165 } 166 167 Multilibs = Composed; 168 } 169 170 return *this; 171 } 172 173 MultilibSetBuilder &MultilibSetBuilder::FilterOut(const char *Regex) { 174 llvm::Regex R(Regex); 175 #ifndef NDEBUG 176 std::string Error; 177 if (!R.isValid(Error)) { 178 llvm::errs() << Error; 179 llvm_unreachable("Invalid regex!"); 180 } 181 #endif 182 llvm::erase_if(Multilibs, [&R](const MultilibBuilder &M) { 183 return R.match(M.gccSuffix()); 184 }); 185 return *this; 186 } 187 188 MultilibSet MultilibSetBuilder::makeMultilibSet() const { 189 MultilibSet Result; 190 for (const auto &M : Multilibs) { 191 Result.push_back(M.makeMultilib()); 192 } 193 return Result; 194 } 195