clang API Documentation
00001 //===--- Multilib.cpp - Multilib Implementation ---------------------------===// 00002 // 00003 // The LLVM Compiler Infrastructure 00004 // 00005 // This file is distributed under the University of Illinois Open Source 00006 // License. See LICENSE.TXT for details. 00007 // 00008 //===----------------------------------------------------------------------===// 00009 00010 #include "clang/Driver/Multilib.h" 00011 #include "Tools.h" 00012 #include "clang/Driver/Options.h" 00013 #include "llvm/ADT/StringMap.h" 00014 #include "llvm/ADT/StringRef.h" 00015 #include "llvm/ADT/StringSet.h" 00016 #include "llvm/ADT/Triple.h" 00017 #include "llvm/Option/Arg.h" 00018 #include "llvm/Option/ArgList.h" 00019 #include "llvm/Option/OptTable.h" 00020 #include "llvm/Option/Option.h" 00021 #include "llvm/Support/MemoryBuffer.h" 00022 #include "llvm/Support/Path.h" 00023 #include "llvm/Support/Regex.h" 00024 #include "llvm/Support/YAMLParser.h" 00025 #include "llvm/Support/YAMLTraits.h" 00026 #include "llvm/Support/raw_ostream.h" 00027 #include <algorithm> 00028 00029 using namespace clang::driver; 00030 using namespace clang; 00031 using namespace llvm::opt; 00032 using namespace llvm::sys; 00033 00034 /// normalize Segment to "/foo/bar" or "". 00035 static void normalizePathSegment(std::string &Segment) { 00036 StringRef seg = Segment; 00037 00038 // Prune trailing "/" or "./" 00039 while (1) { 00040 StringRef last = path::filename(seg); 00041 if (last != ".") 00042 break; 00043 seg = path::parent_path(seg); 00044 } 00045 00046 if (seg.empty() || seg == "/") { 00047 Segment = ""; 00048 return; 00049 } 00050 00051 // Add leading '/' 00052 if (seg.front() != '/') { 00053 Segment = "/" + seg.str(); 00054 } else { 00055 Segment = seg; 00056 } 00057 } 00058 00059 Multilib::Multilib(StringRef GCCSuffix, StringRef OSSuffix, 00060 StringRef IncludeSuffix) 00061 : GCCSuffix(GCCSuffix), OSSuffix(OSSuffix), IncludeSuffix(IncludeSuffix) { 00062 normalizePathSegment(this->GCCSuffix); 00063 normalizePathSegment(this->OSSuffix); 00064 normalizePathSegment(this->IncludeSuffix); 00065 } 00066 00067 Multilib &Multilib::gccSuffix(StringRef S) { 00068 GCCSuffix = S; 00069 normalizePathSegment(GCCSuffix); 00070 return *this; 00071 } 00072 00073 Multilib &Multilib::osSuffix(StringRef S) { 00074 OSSuffix = S; 00075 normalizePathSegment(OSSuffix); 00076 return *this; 00077 } 00078 00079 Multilib &Multilib::includeSuffix(StringRef S) { 00080 IncludeSuffix = S; 00081 normalizePathSegment(IncludeSuffix); 00082 return *this; 00083 } 00084 00085 void Multilib::print(raw_ostream &OS) const { 00086 assert(GCCSuffix.empty() || (StringRef(GCCSuffix).front() == '/')); 00087 if (GCCSuffix.empty()) 00088 OS << "."; 00089 else { 00090 OS << StringRef(GCCSuffix).drop_front(); 00091 } 00092 OS << ";"; 00093 for (StringRef Flag : Flags) { 00094 if (Flag.front() == '+') 00095 OS << "@" << Flag.substr(1); 00096 } 00097 } 00098 00099 bool Multilib::isValid() const { 00100 llvm::StringMap<int> FlagSet; 00101 for (unsigned I = 0, N = Flags.size(); I != N; ++I) { 00102 StringRef Flag(Flags[I]); 00103 llvm::StringMap<int>::iterator SI = FlagSet.find(Flag.substr(1)); 00104 00105 assert(StringRef(Flag).front() == '+' || StringRef(Flag).front() == '-'); 00106 00107 if (SI == FlagSet.end()) 00108 FlagSet[Flag.substr(1)] = I; 00109 else if (Flags[I] != Flags[SI->getValue()]) 00110 return false; 00111 } 00112 return true; 00113 } 00114 00115 bool Multilib::operator==(const Multilib &Other) const { 00116 // Check whether the flags sets match 00117 // allowing for the match to be order invariant 00118 llvm::StringSet<> MyFlags; 00119 for (const auto &Flag : Flags) 00120 MyFlags.insert(Flag); 00121 00122 for (const auto &Flag : Other.Flags) 00123 if (MyFlags.find(Flag) == MyFlags.end()) 00124 return false; 00125 00126 if (osSuffix() != Other.osSuffix()) 00127 return false; 00128 00129 if (gccSuffix() != Other.gccSuffix()) 00130 return false; 00131 00132 if (includeSuffix() != Other.includeSuffix()) 00133 return false; 00134 00135 return true; 00136 } 00137 00138 raw_ostream &clang::driver::operator<<(raw_ostream &OS, const Multilib &M) { 00139 M.print(OS); 00140 return OS; 00141 } 00142 00143 MultilibSet &MultilibSet::Maybe(const Multilib &M) { 00144 Multilib Opposite; 00145 // Negate any '+' flags 00146 for (StringRef Flag : M.flags()) { 00147 if (Flag.front() == '+') 00148 Opposite.flags().push_back(("-" + Flag.substr(1)).str()); 00149 } 00150 return Either(M, Opposite); 00151 } 00152 00153 MultilibSet &MultilibSet::Either(const Multilib &M1, const Multilib &M2) { 00154 std::vector<Multilib> Ms; 00155 Ms.push_back(M1); 00156 Ms.push_back(M2); 00157 return Either(Ms); 00158 } 00159 00160 MultilibSet &MultilibSet::Either(const Multilib &M1, const Multilib &M2, 00161 const Multilib &M3) { 00162 std::vector<Multilib> Ms; 00163 Ms.push_back(M1); 00164 Ms.push_back(M2); 00165 Ms.push_back(M3); 00166 return Either(Ms); 00167 } 00168 00169 MultilibSet &MultilibSet::Either(const Multilib &M1, const Multilib &M2, 00170 const Multilib &M3, const Multilib &M4) { 00171 std::vector<Multilib> Ms; 00172 Ms.push_back(M1); 00173 Ms.push_back(M2); 00174 Ms.push_back(M3); 00175 Ms.push_back(M4); 00176 return Either(Ms); 00177 } 00178 00179 MultilibSet &MultilibSet::Either(const Multilib &M1, const Multilib &M2, 00180 const Multilib &M3, const Multilib &M4, 00181 const Multilib &M5) { 00182 std::vector<Multilib> Ms; 00183 Ms.push_back(M1); 00184 Ms.push_back(M2); 00185 Ms.push_back(M3); 00186 Ms.push_back(M4); 00187 Ms.push_back(M5); 00188 return Either(Ms); 00189 } 00190 00191 static Multilib compose(const Multilib &Base, const Multilib &New) { 00192 SmallString<128> GCCSuffix; 00193 llvm::sys::path::append(GCCSuffix, "/", Base.gccSuffix(), New.gccSuffix()); 00194 SmallString<128> OSSuffix; 00195 llvm::sys::path::append(OSSuffix, "/", Base.osSuffix(), New.osSuffix()); 00196 SmallString<128> IncludeSuffix; 00197 llvm::sys::path::append(IncludeSuffix, "/", Base.includeSuffix(), 00198 New.includeSuffix()); 00199 00200 Multilib Composed(GCCSuffix.str(), OSSuffix.str(), IncludeSuffix.str()); 00201 00202 Multilib::flags_list &Flags = Composed.flags(); 00203 00204 Flags.insert(Flags.end(), Base.flags().begin(), Base.flags().end()); 00205 Flags.insert(Flags.end(), New.flags().begin(), New.flags().end()); 00206 00207 return Composed; 00208 } 00209 00210 MultilibSet & 00211 MultilibSet::Either(const std::vector<Multilib> &MultilibSegments) { 00212 multilib_list Composed; 00213 00214 if (Multilibs.empty()) 00215 Multilibs.insert(Multilibs.end(), MultilibSegments.begin(), 00216 MultilibSegments.end()); 00217 else { 00218 for (const Multilib &New : MultilibSegments) { 00219 for (const Multilib &Base : *this) { 00220 Multilib MO = compose(Base, New); 00221 if (MO.isValid()) 00222 Composed.push_back(MO); 00223 } 00224 } 00225 00226 Multilibs = Composed; 00227 } 00228 00229 return *this; 00230 } 00231 00232 MultilibSet &MultilibSet::FilterOut(const MultilibSet::FilterCallback &F) { 00233 filterInPlace(F, Multilibs); 00234 return *this; 00235 } 00236 00237 MultilibSet &MultilibSet::FilterOut(std::string Regex) { 00238 class REFilter : public MultilibSet::FilterCallback { 00239 mutable llvm::Regex R; 00240 00241 public: 00242 REFilter(std::string Regex) : R(Regex) {} 00243 bool operator()(const Multilib &M) const override { 00244 std::string Error; 00245 if (!R.isValid(Error)) { 00246 llvm::errs() << Error; 00247 assert(false); 00248 return false; 00249 } 00250 return R.match(M.gccSuffix()); 00251 } 00252 }; 00253 00254 REFilter REF(Regex); 00255 filterInPlace(REF, Multilibs); 00256 return *this; 00257 } 00258 00259 void MultilibSet::push_back(const Multilib &M) { Multilibs.push_back(M); } 00260 00261 void MultilibSet::combineWith(const MultilibSet &Other) { 00262 Multilibs.insert(Multilibs.end(), Other.begin(), Other.end()); 00263 } 00264 00265 bool MultilibSet::select(const Multilib::flags_list &Flags, Multilib &M) const { 00266 class FilterFlagsMismatch : public MultilibSet::FilterCallback { 00267 llvm::StringMap<bool> FlagSet; 00268 00269 public: 00270 FilterFlagsMismatch(const std::vector<std::string> &Flags) { 00271 // Stuff all of the flags into the FlagSet such that a true mappend 00272 // indicates the flag was enabled, and a false mappend indicates the 00273 // flag was disabled 00274 for (StringRef Flag : Flags) 00275 FlagSet[Flag.substr(1)] = isFlagEnabled(Flag); 00276 } 00277 bool operator()(const Multilib &M) const override { 00278 for (StringRef Flag : M.flags()) { 00279 llvm::StringMap<bool>::const_iterator SI = FlagSet.find(Flag.substr(1)); 00280 if (SI != FlagSet.end()) 00281 if (SI->getValue() != isFlagEnabled(Flag)) 00282 return true; 00283 } 00284 return false; 00285 } 00286 private: 00287 bool isFlagEnabled(StringRef Flag) const { 00288 char Indicator = Flag.front(); 00289 assert(Indicator == '+' || Indicator == '-'); 00290 return Indicator == '+'; 00291 } 00292 }; 00293 00294 FilterFlagsMismatch FlagsMismatch(Flags); 00295 00296 multilib_list Filtered = filterCopy(FlagsMismatch, Multilibs); 00297 00298 if (Filtered.size() == 0) { 00299 return false; 00300 } else if (Filtered.size() == 1) { 00301 M = Filtered[0]; 00302 return true; 00303 } 00304 00305 // TODO: pick the "best" multlib when more than one is suitable 00306 assert(false); 00307 00308 return false; 00309 } 00310 00311 void MultilibSet::print(raw_ostream &OS) const { 00312 for (const Multilib &M : *this) 00313 OS << M << "\n"; 00314 } 00315 00316 MultilibSet::multilib_list 00317 MultilibSet::filterCopy(const MultilibSet::FilterCallback &F, 00318 const multilib_list &Ms) { 00319 multilib_list Copy(Ms); 00320 filterInPlace(F, Copy); 00321 return Copy; 00322 } 00323 00324 void MultilibSet::filterInPlace(const MultilibSet::FilterCallback &F, 00325 multilib_list &Ms) { 00326 Ms.erase(std::remove_if(Ms.begin(), Ms.end(), 00327 [&F](const Multilib &M) { return F(M); }), 00328 Ms.end()); 00329 } 00330 00331 raw_ostream &clang::driver::operator<<(raw_ostream &OS, const MultilibSet &MS) { 00332 MS.print(OS); 00333 return OS; 00334 }