1*67e74705SXin Li //===--- Multilib.cpp - Multilib Implementation ---------------------------===//
2*67e74705SXin Li //
3*67e74705SXin Li // The LLVM Compiler Infrastructure
4*67e74705SXin Li //
5*67e74705SXin Li // This file is distributed under the University of Illinois Open Source
6*67e74705SXin Li // License. See LICENSE.TXT for details.
7*67e74705SXin Li //
8*67e74705SXin Li //===----------------------------------------------------------------------===//
9*67e74705SXin Li
10*67e74705SXin Li #include "clang/Driver/Multilib.h"
11*67e74705SXin Li #include "Tools.h"
12*67e74705SXin Li #include "clang/Driver/Options.h"
13*67e74705SXin Li #include "llvm/ADT/StringMap.h"
14*67e74705SXin Li #include "llvm/ADT/StringRef.h"
15*67e74705SXin Li #include "llvm/ADT/StringSet.h"
16*67e74705SXin Li #include "llvm/ADT/Triple.h"
17*67e74705SXin Li #include "llvm/Option/Arg.h"
18*67e74705SXin Li #include "llvm/Option/ArgList.h"
19*67e74705SXin Li #include "llvm/Option/OptTable.h"
20*67e74705SXin Li #include "llvm/Option/Option.h"
21*67e74705SXin Li #include "llvm/Support/MemoryBuffer.h"
22*67e74705SXin Li #include "llvm/Support/Path.h"
23*67e74705SXin Li #include "llvm/Support/Regex.h"
24*67e74705SXin Li #include "llvm/Support/YAMLParser.h"
25*67e74705SXin Li #include "llvm/Support/YAMLTraits.h"
26*67e74705SXin Li #include "llvm/Support/raw_ostream.h"
27*67e74705SXin Li #include <algorithm>
28*67e74705SXin Li
29*67e74705SXin Li using namespace clang::driver;
30*67e74705SXin Li using namespace clang;
31*67e74705SXin Li using namespace llvm::opt;
32*67e74705SXin Li using namespace llvm::sys;
33*67e74705SXin Li
34*67e74705SXin Li /// normalize Segment to "/foo/bar" or "".
normalizePathSegment(std::string & Segment)35*67e74705SXin Li static void normalizePathSegment(std::string &Segment) {
36*67e74705SXin Li StringRef seg = Segment;
37*67e74705SXin Li
38*67e74705SXin Li // Prune trailing "/" or "./"
39*67e74705SXin Li while (1) {
40*67e74705SXin Li StringRef last = path::filename(seg);
41*67e74705SXin Li if (last != ".")
42*67e74705SXin Li break;
43*67e74705SXin Li seg = path::parent_path(seg);
44*67e74705SXin Li }
45*67e74705SXin Li
46*67e74705SXin Li if (seg.empty() || seg == "/") {
47*67e74705SXin Li Segment = "";
48*67e74705SXin Li return;
49*67e74705SXin Li }
50*67e74705SXin Li
51*67e74705SXin Li // Add leading '/'
52*67e74705SXin Li if (seg.front() != '/') {
53*67e74705SXin Li Segment = "/" + seg.str();
54*67e74705SXin Li } else {
55*67e74705SXin Li Segment = seg;
56*67e74705SXin Li }
57*67e74705SXin Li }
58*67e74705SXin Li
Multilib(StringRef GCCSuffix,StringRef OSSuffix,StringRef IncludeSuffix)59*67e74705SXin Li Multilib::Multilib(StringRef GCCSuffix, StringRef OSSuffix,
60*67e74705SXin Li StringRef IncludeSuffix)
61*67e74705SXin Li : GCCSuffix(GCCSuffix), OSSuffix(OSSuffix), IncludeSuffix(IncludeSuffix) {
62*67e74705SXin Li normalizePathSegment(this->GCCSuffix);
63*67e74705SXin Li normalizePathSegment(this->OSSuffix);
64*67e74705SXin Li normalizePathSegment(this->IncludeSuffix);
65*67e74705SXin Li }
66*67e74705SXin Li
gccSuffix(StringRef S)67*67e74705SXin Li Multilib &Multilib::gccSuffix(StringRef S) {
68*67e74705SXin Li GCCSuffix = S;
69*67e74705SXin Li normalizePathSegment(GCCSuffix);
70*67e74705SXin Li return *this;
71*67e74705SXin Li }
72*67e74705SXin Li
osSuffix(StringRef S)73*67e74705SXin Li Multilib &Multilib::osSuffix(StringRef S) {
74*67e74705SXin Li OSSuffix = S;
75*67e74705SXin Li normalizePathSegment(OSSuffix);
76*67e74705SXin Li return *this;
77*67e74705SXin Li }
78*67e74705SXin Li
includeSuffix(StringRef S)79*67e74705SXin Li Multilib &Multilib::includeSuffix(StringRef S) {
80*67e74705SXin Li IncludeSuffix = S;
81*67e74705SXin Li normalizePathSegment(IncludeSuffix);
82*67e74705SXin Li return *this;
83*67e74705SXin Li }
84*67e74705SXin Li
print(raw_ostream & OS) const85*67e74705SXin Li void Multilib::print(raw_ostream &OS) const {
86*67e74705SXin Li assert(GCCSuffix.empty() || (StringRef(GCCSuffix).front() == '/'));
87*67e74705SXin Li if (GCCSuffix.empty())
88*67e74705SXin Li OS << ".";
89*67e74705SXin Li else {
90*67e74705SXin Li OS << StringRef(GCCSuffix).drop_front();
91*67e74705SXin Li }
92*67e74705SXin Li OS << ";";
93*67e74705SXin Li for (StringRef Flag : Flags) {
94*67e74705SXin Li if (Flag.front() == '+')
95*67e74705SXin Li OS << "@" << Flag.substr(1);
96*67e74705SXin Li }
97*67e74705SXin Li }
98*67e74705SXin Li
isValid() const99*67e74705SXin Li bool Multilib::isValid() const {
100*67e74705SXin Li llvm::StringMap<int> FlagSet;
101*67e74705SXin Li for (unsigned I = 0, N = Flags.size(); I != N; ++I) {
102*67e74705SXin Li StringRef Flag(Flags[I]);
103*67e74705SXin Li llvm::StringMap<int>::iterator SI = FlagSet.find(Flag.substr(1));
104*67e74705SXin Li
105*67e74705SXin Li assert(StringRef(Flag).front() == '+' || StringRef(Flag).front() == '-');
106*67e74705SXin Li
107*67e74705SXin Li if (SI == FlagSet.end())
108*67e74705SXin Li FlagSet[Flag.substr(1)] = I;
109*67e74705SXin Li else if (Flags[I] != Flags[SI->getValue()])
110*67e74705SXin Li return false;
111*67e74705SXin Li }
112*67e74705SXin Li return true;
113*67e74705SXin Li }
114*67e74705SXin Li
operator ==(const Multilib & Other) const115*67e74705SXin Li bool Multilib::operator==(const Multilib &Other) const {
116*67e74705SXin Li // Check whether the flags sets match
117*67e74705SXin Li // allowing for the match to be order invariant
118*67e74705SXin Li llvm::StringSet<> MyFlags;
119*67e74705SXin Li for (const auto &Flag : Flags)
120*67e74705SXin Li MyFlags.insert(Flag);
121*67e74705SXin Li
122*67e74705SXin Li for (const auto &Flag : Other.Flags)
123*67e74705SXin Li if (MyFlags.find(Flag) == MyFlags.end())
124*67e74705SXin Li return false;
125*67e74705SXin Li
126*67e74705SXin Li if (osSuffix() != Other.osSuffix())
127*67e74705SXin Li return false;
128*67e74705SXin Li
129*67e74705SXin Li if (gccSuffix() != Other.gccSuffix())
130*67e74705SXin Li return false;
131*67e74705SXin Li
132*67e74705SXin Li if (includeSuffix() != Other.includeSuffix())
133*67e74705SXin Li return false;
134*67e74705SXin Li
135*67e74705SXin Li return true;
136*67e74705SXin Li }
137*67e74705SXin Li
operator <<(raw_ostream & OS,const Multilib & M)138*67e74705SXin Li raw_ostream &clang::driver::operator<<(raw_ostream &OS, const Multilib &M) {
139*67e74705SXin Li M.print(OS);
140*67e74705SXin Li return OS;
141*67e74705SXin Li }
142*67e74705SXin Li
Maybe(const Multilib & M)143*67e74705SXin Li MultilibSet &MultilibSet::Maybe(const Multilib &M) {
144*67e74705SXin Li Multilib Opposite;
145*67e74705SXin Li // Negate any '+' flags
146*67e74705SXin Li for (StringRef Flag : M.flags()) {
147*67e74705SXin Li if (Flag.front() == '+')
148*67e74705SXin Li Opposite.flags().push_back(("-" + Flag.substr(1)).str());
149*67e74705SXin Li }
150*67e74705SXin Li return Either(M, Opposite);
151*67e74705SXin Li }
152*67e74705SXin Li
Either(const Multilib & M1,const Multilib & M2)153*67e74705SXin Li MultilibSet &MultilibSet::Either(const Multilib &M1, const Multilib &M2) {
154*67e74705SXin Li return Either({M1, M2});
155*67e74705SXin Li }
156*67e74705SXin Li
Either(const Multilib & M1,const Multilib & M2,const Multilib & M3)157*67e74705SXin Li MultilibSet &MultilibSet::Either(const Multilib &M1, const Multilib &M2,
158*67e74705SXin Li const Multilib &M3) {
159*67e74705SXin Li return Either({M1, M2, M3});
160*67e74705SXin Li }
161*67e74705SXin Li
Either(const Multilib & M1,const Multilib & M2,const Multilib & M3,const Multilib & M4)162*67e74705SXin Li MultilibSet &MultilibSet::Either(const Multilib &M1, const Multilib &M2,
163*67e74705SXin Li const Multilib &M3, const Multilib &M4) {
164*67e74705SXin Li return Either({M1, M2, M3, M4});
165*67e74705SXin Li }
166*67e74705SXin Li
Either(const Multilib & M1,const Multilib & M2,const Multilib & M3,const Multilib & M4,const Multilib & M5)167*67e74705SXin Li MultilibSet &MultilibSet::Either(const Multilib &M1, const Multilib &M2,
168*67e74705SXin Li const Multilib &M3, const Multilib &M4,
169*67e74705SXin Li const Multilib &M5) {
170*67e74705SXin Li return Either({M1, M2, M3, M4, M5});
171*67e74705SXin Li }
172*67e74705SXin Li
compose(const Multilib & Base,const Multilib & New)173*67e74705SXin Li static Multilib compose(const Multilib &Base, const Multilib &New) {
174*67e74705SXin Li SmallString<128> GCCSuffix;
175*67e74705SXin Li llvm::sys::path::append(GCCSuffix, "/", Base.gccSuffix(), New.gccSuffix());
176*67e74705SXin Li SmallString<128> OSSuffix;
177*67e74705SXin Li llvm::sys::path::append(OSSuffix, "/", Base.osSuffix(), New.osSuffix());
178*67e74705SXin Li SmallString<128> IncludeSuffix;
179*67e74705SXin Li llvm::sys::path::append(IncludeSuffix, "/", Base.includeSuffix(),
180*67e74705SXin Li New.includeSuffix());
181*67e74705SXin Li
182*67e74705SXin Li Multilib Composed(GCCSuffix, OSSuffix, IncludeSuffix);
183*67e74705SXin Li
184*67e74705SXin Li Multilib::flags_list &Flags = Composed.flags();
185*67e74705SXin Li
186*67e74705SXin Li Flags.insert(Flags.end(), Base.flags().begin(), Base.flags().end());
187*67e74705SXin Li Flags.insert(Flags.end(), New.flags().begin(), New.flags().end());
188*67e74705SXin Li
189*67e74705SXin Li return Composed;
190*67e74705SXin Li }
191*67e74705SXin Li
Either(ArrayRef<Multilib> MultilibSegments)192*67e74705SXin Li MultilibSet &MultilibSet::Either(ArrayRef<Multilib> MultilibSegments) {
193*67e74705SXin Li multilib_list Composed;
194*67e74705SXin Li
195*67e74705SXin Li if (Multilibs.empty())
196*67e74705SXin Li Multilibs.insert(Multilibs.end(), MultilibSegments.begin(),
197*67e74705SXin Li MultilibSegments.end());
198*67e74705SXin Li else {
199*67e74705SXin Li for (const Multilib &New : MultilibSegments) {
200*67e74705SXin Li for (const Multilib &Base : *this) {
201*67e74705SXin Li Multilib MO = compose(Base, New);
202*67e74705SXin Li if (MO.isValid())
203*67e74705SXin Li Composed.push_back(MO);
204*67e74705SXin Li }
205*67e74705SXin Li }
206*67e74705SXin Li
207*67e74705SXin Li Multilibs = Composed;
208*67e74705SXin Li }
209*67e74705SXin Li
210*67e74705SXin Li return *this;
211*67e74705SXin Li }
212*67e74705SXin Li
FilterOut(FilterCallback F)213*67e74705SXin Li MultilibSet &MultilibSet::FilterOut(FilterCallback F) {
214*67e74705SXin Li filterInPlace(F, Multilibs);
215*67e74705SXin Li return *this;
216*67e74705SXin Li }
217*67e74705SXin Li
FilterOut(const char * Regex)218*67e74705SXin Li MultilibSet &MultilibSet::FilterOut(const char *Regex) {
219*67e74705SXin Li llvm::Regex R(Regex);
220*67e74705SXin Li #ifndef NDEBUG
221*67e74705SXin Li std::string Error;
222*67e74705SXin Li if (!R.isValid(Error)) {
223*67e74705SXin Li llvm::errs() << Error;
224*67e74705SXin Li llvm_unreachable("Invalid regex!");
225*67e74705SXin Li }
226*67e74705SXin Li #endif
227*67e74705SXin Li
228*67e74705SXin Li filterInPlace([&R](const Multilib &M) { return R.match(M.gccSuffix()); },
229*67e74705SXin Li Multilibs);
230*67e74705SXin Li return *this;
231*67e74705SXin Li }
232*67e74705SXin Li
push_back(const Multilib & M)233*67e74705SXin Li void MultilibSet::push_back(const Multilib &M) { Multilibs.push_back(M); }
234*67e74705SXin Li
combineWith(const MultilibSet & Other)235*67e74705SXin Li void MultilibSet::combineWith(const MultilibSet &Other) {
236*67e74705SXin Li Multilibs.insert(Multilibs.end(), Other.begin(), Other.end());
237*67e74705SXin Li }
238*67e74705SXin Li
isFlagEnabled(StringRef Flag)239*67e74705SXin Li static bool isFlagEnabled(StringRef Flag) {
240*67e74705SXin Li char Indicator = Flag.front();
241*67e74705SXin Li assert(Indicator == '+' || Indicator == '-');
242*67e74705SXin Li return Indicator == '+';
243*67e74705SXin Li }
244*67e74705SXin Li
select(const Multilib::flags_list & Flags,Multilib & M) const245*67e74705SXin Li bool MultilibSet::select(const Multilib::flags_list &Flags, Multilib &M) const {
246*67e74705SXin Li llvm::StringMap<bool> FlagSet;
247*67e74705SXin Li
248*67e74705SXin Li // Stuff all of the flags into the FlagSet such that a true mappend indicates
249*67e74705SXin Li // the flag was enabled, and a false mappend indicates the flag was disabled.
250*67e74705SXin Li for (StringRef Flag : Flags)
251*67e74705SXin Li FlagSet[Flag.substr(1)] = isFlagEnabled(Flag);
252*67e74705SXin Li
253*67e74705SXin Li multilib_list Filtered = filterCopy([&FlagSet](const Multilib &M) {
254*67e74705SXin Li for (StringRef Flag : M.flags()) {
255*67e74705SXin Li llvm::StringMap<bool>::const_iterator SI = FlagSet.find(Flag.substr(1));
256*67e74705SXin Li if (SI != FlagSet.end())
257*67e74705SXin Li if (SI->getValue() != isFlagEnabled(Flag))
258*67e74705SXin Li return true;
259*67e74705SXin Li }
260*67e74705SXin Li return false;
261*67e74705SXin Li }, Multilibs);
262*67e74705SXin Li
263*67e74705SXin Li if (Filtered.size() == 0)
264*67e74705SXin Li return false;
265*67e74705SXin Li if (Filtered.size() == 1) {
266*67e74705SXin Li M = Filtered[0];
267*67e74705SXin Li return true;
268*67e74705SXin Li }
269*67e74705SXin Li
270*67e74705SXin Li // TODO: pick the "best" multlib when more than one is suitable
271*67e74705SXin Li assert(false);
272*67e74705SXin Li return false;
273*67e74705SXin Li }
274*67e74705SXin Li
print(raw_ostream & OS) const275*67e74705SXin Li void MultilibSet::print(raw_ostream &OS) const {
276*67e74705SXin Li for (const Multilib &M : *this)
277*67e74705SXin Li OS << M << "\n";
278*67e74705SXin Li }
279*67e74705SXin Li
filterCopy(FilterCallback F,const multilib_list & Ms)280*67e74705SXin Li MultilibSet::multilib_list MultilibSet::filterCopy(FilterCallback F,
281*67e74705SXin Li const multilib_list &Ms) {
282*67e74705SXin Li multilib_list Copy(Ms);
283*67e74705SXin Li filterInPlace(F, Copy);
284*67e74705SXin Li return Copy;
285*67e74705SXin Li }
286*67e74705SXin Li
filterInPlace(FilterCallback F,multilib_list & Ms)287*67e74705SXin Li void MultilibSet::filterInPlace(FilterCallback F, multilib_list &Ms) {
288*67e74705SXin Li Ms.erase(std::remove_if(Ms.begin(), Ms.end(), F), Ms.end());
289*67e74705SXin Li }
290*67e74705SXin Li
operator <<(raw_ostream & OS,const MultilibSet & MS)291*67e74705SXin Li raw_ostream &clang::driver::operator<<(raw_ostream &OS, const MultilibSet &MS) {
292*67e74705SXin Li MS.print(OS);
293*67e74705SXin Li return OS;
294*67e74705SXin Li }
295