blob: 6d68517e83f38fb1f9f8e5a56406614db4714dfc [file] [log] [blame]
Jonathan Roelofs2cea1be2014-02-12 03:21:20 +00001//===--- Multilib.cpp - Multilib Implementation ---------------------------===//
2//
3// The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9
10#include "clang/Driver/Multilib.h"
11#include "Tools.h"
12#include "clang/Driver/Options.h"
13#include "llvm/ADT/StringMap.h"
14#include "llvm/ADT/StringRef.h"
15#include "llvm/ADT/StringSet.h"
16#include "llvm/ADT/Triple.h"
17#include "llvm/Option/Arg.h"
18#include "llvm/Option/ArgList.h"
19#include "llvm/Option/OptTable.h"
20#include "llvm/Option/Option.h"
21#include "llvm/Support/MemoryBuffer.h"
22#include "llvm/Support/Path.h"
23#include "llvm/Support/raw_ostream.h"
24#include "llvm/Support/Regex.h"
25#include "llvm/Support/YAMLParser.h"
26#include "llvm/Support/YAMLTraits.h"
27#include <algorithm>
28
29using namespace clang::driver;
30using namespace clang;
31using namespace llvm::opt;
32
33static void normalizePathSegment(std::string &Segment) {
34 StringRef SRS(Segment);
35 if (SRS.empty() || SRS == "/." || SRS == "/" || SRS == ".") {
36 SRS = "";
37 } else {
38 if (SRS.back() == '/')
39 SRS = SRS.drop_back();
40 if (SRS.front() != '/')
41 SRS = ("/" + SRS).str();
42 }
43 Segment = SRS;
44}
45
46Multilib::Multilib(StringRef GCCSuffix, StringRef OSSuffix,
47 StringRef IncludeSuffix)
48 : GCCSuffix(GCCSuffix), OSSuffix(OSSuffix), IncludeSuffix(IncludeSuffix) {
49 normalizePathSegment(this->GCCSuffix);
50 normalizePathSegment(this->OSSuffix);
51 normalizePathSegment(this->IncludeSuffix);
52}
53
54Multilib &Multilib::gccSuffix(StringRef S) {
55 GCCSuffix = S;
56 normalizePathSegment(GCCSuffix);
57 return *this;
58}
59
60Multilib &Multilib::osSuffix(StringRef S) {
61 OSSuffix = S;
62 normalizePathSegment(OSSuffix);
63 return *this;
64}
65
66Multilib &Multilib::includeSuffix(StringRef S) {
67 IncludeSuffix = S;
68 normalizePathSegment(IncludeSuffix);
69 return *this;
70}
71
72void Multilib::print(raw_ostream &OS) const {
73 assert(GCCSuffix.empty() || (StringRef(GCCSuffix).front() == '/'));
74 if (GCCSuffix.empty())
75 OS << ".";
76 else {
77 OS << StringRef(GCCSuffix).drop_front();
78 }
79 OS << ";";
80 for (flags_list::const_iterator I = Flags.begin(), E = Flags.end(); I != E;
81 ++I) {
82 if (StringRef(*I).front() == '+')
83 OS << "@" << I->substr(1);
84 }
85}
86
87bool Multilib::isValid() const {
88 llvm::StringMap<int> FlagSet;
89 for (unsigned I = 0, N = Flags.size(); I != N; ++I) {
90 StringRef Flag(Flags[I]);
91 llvm::StringMap<int>::iterator SI = FlagSet.find(Flag.substr(1));
92
93 assert(StringRef(Flag).front() == '+' || StringRef(Flag).front() == '-');
94
95 if (SI == FlagSet.end())
96 FlagSet[Flag.substr(1)] = I;
97 else if (Flags[I] != Flags[SI->getValue()])
98 return false;
99 }
100 return true;
101}
102
103bool Multilib::operator==(const Multilib &Other) const {
104 // Check whether the flags sets match
105 // allowing for the match to be order invariant
106 llvm::StringSet<> MyFlags;
107 for (flags_list::const_iterator I = Flags.begin(), E = Flags.end(); I != E;
108 ++I) {
109 MyFlags.insert(*I);
110 }
111 for (flags_list::const_iterator I = Other.Flags.begin(),
112 E = Other.Flags.end();
113 I != E; ++I) {
114 if (MyFlags.find(*I) == MyFlags.end())
115 return false;
116 }
117
118 if (osSuffix() != Other.osSuffix())
119 return false;
120
121 if (gccSuffix() != Other.gccSuffix())
122 return false;
123
124 if (includeSuffix() != Other.includeSuffix())
125 return false;
126
127 return true;
128}
129
130raw_ostream &clang::driver::operator<<(raw_ostream &OS, const Multilib &M) {
131 M.print(OS);
132 return OS;
133}
134
135MultilibSet &MultilibSet::Maybe(const Multilib &M) {
136 Multilib Opposite;
137 // Negate any '+' flags
138 for (Multilib::flags_list::const_iterator I = M.flags().begin(),
139 E = M.flags().end();
140 I != E; ++I) {
141 StringRef Flag(*I);
142 if (Flag.front() == '+')
143 Opposite.flags().push_back(("-" + Flag.substr(1)).str());
144 }
145 return Either(M, Opposite);
146}
147
148MultilibSet &MultilibSet::Either(const Multilib &M1, const Multilib &M2) {
149 std::vector<Multilib> Ms;
150 Ms.push_back(M1);
151 Ms.push_back(M2);
152 return Either(Ms);
153}
154
155MultilibSet &MultilibSet::Either(const Multilib &M1, const Multilib &M2,
156 const Multilib &M3) {
157 std::vector<Multilib> Ms;
158 Ms.push_back(M1);
159 Ms.push_back(M2);
160 Ms.push_back(M3);
161 return Either(Ms);
162}
163
164MultilibSet &MultilibSet::Either(const Multilib &M1, const Multilib &M2,
165 const Multilib &M3, const Multilib &M4) {
166 std::vector<Multilib> Ms;
167 Ms.push_back(M1);
168 Ms.push_back(M2);
169 Ms.push_back(M3);
170 Ms.push_back(M4);
171 return Either(Ms);
172}
173
174MultilibSet &MultilibSet::Either(const Multilib &M1, const Multilib &M2,
175 const Multilib &M3, const Multilib &M4,
176 const Multilib &M5) {
177 std::vector<Multilib> Ms;
178 Ms.push_back(M1);
179 Ms.push_back(M2);
180 Ms.push_back(M3);
181 Ms.push_back(M4);
182 Ms.push_back(M5);
183 return Either(Ms);
184}
185
186static Multilib compose(const Multilib &Base, const Multilib &New) {
187 SmallString<128> GCCSuffix;
188 llvm::sys::path::append(GCCSuffix, "/", Base.gccSuffix(), New.gccSuffix());
189 SmallString<128> OSSuffix;
190 llvm::sys::path::append(OSSuffix, "/", Base.osSuffix(), New.osSuffix());
191 SmallString<128> IncludeSuffix;
192 llvm::sys::path::append(IncludeSuffix, "/", Base.includeSuffix(),
193 New.includeSuffix());
194
195 Multilib Composed(GCCSuffix.str(), OSSuffix.str(), IncludeSuffix.str());
196
197 Multilib::flags_list &Flags = Composed.flags();
198
199 Flags.insert(Flags.end(), Base.flags().begin(), Base.flags().end());
200 Flags.insert(Flags.end(), New.flags().begin(), New.flags().end());
201
202 return Composed;
203}
204
205MultilibSet &
206MultilibSet::Either(const std::vector<Multilib> &MultilibSegments) {
207 multilib_list Composed;
208
209 if (Multilibs.empty())
210 Multilibs.insert(Multilibs.end(), MultilibSegments.begin(),
211 MultilibSegments.end());
212 else {
213 for (std::vector<Multilib>::const_iterator NewI = MultilibSegments.begin(),
214 NewE = MultilibSegments.end();
215 NewI != NewE; ++NewI) {
216 for (const_iterator BaseI = begin(), BaseE = end(); BaseI != BaseE;
217 ++BaseI) {
218 Multilib MO = compose(*BaseI, *NewI);
219 if (MO.isValid())
220 Composed.push_back(MO);
221 }
222 }
223
224 Multilibs = Composed;
225 }
226
227 return *this;
228}
229
230MultilibSet &MultilibSet::FilterOut(const MultilibSet::FilterCallback &F) {
231 filterInPlace(F, Multilibs);
232 return *this;
233}
234
235MultilibSet &MultilibSet::FilterOut(std::string Regex) {
236 class REFilter : public MultilibSet::FilterCallback {
237 mutable llvm::Regex R;
238
239 public:
240 REFilter(std::string Regex) : R(Regex) {}
241 bool operator()(const Multilib &M) const LLVM_OVERRIDE {
242 std::string Error;
243 if (!R.isValid(Error)) {
244 llvm::errs() << Error;
245 assert(false);
246 return false;
247 }
248 return R.match(M.gccSuffix());
249 }
250 };
251
252 REFilter REF(Regex);
253 filterInPlace(REF, Multilibs);
254 return *this;
255}
256
257void MultilibSet::push_back(const Multilib &M) { Multilibs.push_back(M); }
258
259void MultilibSet::combineWith(const MultilibSet &Other) {
260 Multilibs.insert(Multilibs.end(), Other.begin(), Other.end());
261}
262
263bool MultilibSet::select(const Multilib::flags_list &Flags, Multilib &M) const {
264 class FilterFlagsMismatch : public MultilibSet::FilterCallback {
265 llvm::StringMap<bool> FlagSet;
266
267 public:
268 FilterFlagsMismatch(const std::vector<std::string> &Flags) {
269 // Stuff all of the flags into the FlagSet such that a true mappend
270 // indicates the flag was enabled, and a false mappend indicates the
271 // flag was disabled
272 for (Multilib::flags_list::const_iterator I = Flags.begin(),
273 E = Flags.end();
274 I != E; ++I) {
275 FlagSet[StringRef(*I).substr(1)] = isFlagEnabled(*I);
276 }
277 }
278 bool operator()(const Multilib &M) const LLVM_OVERRIDE {
279 for (Multilib::flags_list::const_iterator I = M.flags().begin(),
280 E = M.flags().end();
281 I != E; ++I) {
282 StringRef Flag(*I);
283 llvm::StringMap<bool>::const_iterator SI = FlagSet.find(Flag.substr(1));
284 if (SI != FlagSet.end())
285 if ((*SI).getValue() != isFlagEnabled(Flag))
286 return true;
287 }
288 return false;
289 }
290 private:
291 bool isFlagEnabled(StringRef Flag) const {
292 char Indicator = Flag.front();
293 assert(Indicator == '+' || Indicator == '-');
294 return Indicator == '+';
295 }
296 };
297
298 FilterFlagsMismatch FlagsMismatch(Flags);
299
300 multilib_list Filtered = filterCopy(FlagsMismatch, Multilibs);
301
302 if (Filtered.size() == 0) {
303 return false;
304 } else if (Filtered.size() == 1) {
305 M = Filtered[0];
306 return true;
307 }
308
309 // TODO: pick the "best" multlib when more than one is suitable
310 assert(false);
311
312 return false;
313}
314
315void MultilibSet::print(raw_ostream &OS) const {
316 for (const_iterator I = begin(), E = end(); I != E; ++I)
317 OS << *I << "\n";
318}
319
320MultilibSet::multilib_list
321MultilibSet::filterCopy(const MultilibSet::FilterCallback &F,
322 const multilib_list &Ms) {
323 multilib_list Copy(Ms);
324 filterInPlace(F, Copy);
325 return Copy;
326}
327
328namespace {
329// Wrapper for FilterCallback to make operator() nonvirtual so it
330// can be passed by value to std::remove_if
331class FilterWrapper {
332 const MultilibSet::FilterCallback &F;
333public:
334 FilterWrapper(const MultilibSet::FilterCallback &F) : F(F) {}
335 bool operator()(const Multilib &M) const { return F(M); }
336};
337} // end anonymous namespace
338
339void MultilibSet::filterInPlace(const MultilibSet::FilterCallback &F,
340 multilib_list &Ms) {
341 Ms.erase(std::remove_if(Ms.begin(), Ms.end(), FilterWrapper(F)), Ms.end());
342}
343
344raw_ostream &clang::driver::operator<<(raw_ostream &OS, const MultilibSet &MS) {
345 MS.print(OS);
346 return OS;
347}