1 //===--- Multilib.cpp - Multilib Implementation ---------------------------===//
3 // The LLVM Compiler Infrastructure
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
8 //===----------------------------------------------------------------------===//
10 #include "clang/Driver/Multilib.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/Regex.h"
24 #include "llvm/Support/YAMLParser.h"
25 #include "llvm/Support/YAMLTraits.h"
26 #include "llvm/Support/raw_ostream.h"
29 using namespace clang::driver
;
30 using namespace clang
;
31 using namespace llvm::opt
;
32 using namespace llvm::sys
;
34 /// normalize Segment to "/foo/bar" or "".
35 static void normalizePathSegment(std::string
&Segment
) {
36 StringRef seg
= Segment
;
38 // Prune trailing "/" or "./"
40 StringRef last
= path::filename(seg
);
43 seg
= path::parent_path(seg
);
46 if (seg
.empty() || seg
== "/") {
52 if (seg
.front() != '/') {
53 Segment
= "/" + seg
.str();
59 Multilib::Multilib(StringRef GCCSuffix
, StringRef OSSuffix
,
60 StringRef IncludeSuffix
)
61 : GCCSuffix(GCCSuffix
), OSSuffix(OSSuffix
), IncludeSuffix(IncludeSuffix
) {
62 normalizePathSegment(this->GCCSuffix
);
63 normalizePathSegment(this->OSSuffix
);
64 normalizePathSegment(this->IncludeSuffix
);
67 Multilib
&Multilib::gccSuffix(StringRef S
) {
69 normalizePathSegment(GCCSuffix
);
73 Multilib
&Multilib::osSuffix(StringRef S
) {
75 normalizePathSegment(OSSuffix
);
79 Multilib
&Multilib::includeSuffix(StringRef S
) {
81 normalizePathSegment(IncludeSuffix
);
85 void Multilib::print(raw_ostream
&OS
) const {
86 assert(GCCSuffix
.empty() || (StringRef(GCCSuffix
).front() == '/'));
87 if (GCCSuffix
.empty())
90 OS
<< StringRef(GCCSuffix
).drop_front();
93 for (StringRef Flag
: Flags
) {
94 if (Flag
.front() == '+')
95 OS
<< "@" << Flag
.substr(1);
99 bool Multilib::isValid() const {
100 llvm::StringMap
<int> FlagSet
;
101 for (unsigned I
= 0, N
= Flags
.size(); I
!= N
; ++I
) {
102 StringRef
Flag(Flags
[I
]);
103 llvm::StringMap
<int>::iterator SI
= FlagSet
.find(Flag
.substr(1));
105 assert(StringRef(Flag
).front() == '+' || StringRef(Flag
).front() == '-');
107 if (SI
== FlagSet
.end())
108 FlagSet
[Flag
.substr(1)] = I
;
109 else if (Flags
[I
] != Flags
[SI
->getValue()])
115 bool Multilib::operator==(const Multilib
&Other
) const {
116 // Check whether the flags sets match
117 // allowing for the match to be order invariant
118 llvm::StringSet
<> MyFlags
;
119 for (const auto &Flag
: Flags
)
120 MyFlags
.insert(Flag
);
122 for (const auto &Flag
: Other
.Flags
)
123 if (MyFlags
.find(Flag
) == MyFlags
.end())
126 if (osSuffix() != Other
.osSuffix())
129 if (gccSuffix() != Other
.gccSuffix())
132 if (includeSuffix() != Other
.includeSuffix())
138 raw_ostream
&clang::driver::operator<<(raw_ostream
&OS
, const Multilib
&M
) {
143 MultilibSet
&MultilibSet::Maybe(const Multilib
&M
) {
145 // Negate any '+' flags
146 for (StringRef Flag
: M
.flags()) {
147 if (Flag
.front() == '+')
148 Opposite
.flags().push_back(("-" + Flag
.substr(1)).str());
150 return Either(M
, Opposite
);
153 MultilibSet
&MultilibSet::Either(const Multilib
&M1
, const Multilib
&M2
) {
154 std::vector
<Multilib
> Ms
;
160 MultilibSet
&MultilibSet::Either(const Multilib
&M1
, const Multilib
&M2
,
161 const Multilib
&M3
) {
162 std::vector
<Multilib
> Ms
;
169 MultilibSet
&MultilibSet::Either(const Multilib
&M1
, const Multilib
&M2
,
170 const Multilib
&M3
, const Multilib
&M4
) {
171 std::vector
<Multilib
> Ms
;
179 MultilibSet
&MultilibSet::Either(const Multilib
&M1
, const Multilib
&M2
,
180 const Multilib
&M3
, const Multilib
&M4
,
181 const Multilib
&M5
) {
182 std::vector
<Multilib
> Ms
;
191 static Multilib
compose(const Multilib
&Base
, const Multilib
&New
) {
192 SmallString
<128> GCCSuffix
;
193 llvm::sys::path::append(GCCSuffix
, "/", Base
.gccSuffix(), New
.gccSuffix());
194 SmallString
<128> OSSuffix
;
195 llvm::sys::path::append(OSSuffix
, "/", Base
.osSuffix(), New
.osSuffix());
196 SmallString
<128> IncludeSuffix
;
197 llvm::sys::path::append(IncludeSuffix
, "/", Base
.includeSuffix(),
198 New
.includeSuffix());
200 Multilib
Composed(GCCSuffix
.str(), OSSuffix
.str(), IncludeSuffix
.str());
202 Multilib::flags_list
&Flags
= Composed
.flags();
204 Flags
.insert(Flags
.end(), Base
.flags().begin(), Base
.flags().end());
205 Flags
.insert(Flags
.end(), New
.flags().begin(), New
.flags().end());
211 MultilibSet::Either(const std::vector
<Multilib
> &MultilibSegments
) {
212 multilib_list Composed
;
214 if (Multilibs
.empty())
215 Multilibs
.insert(Multilibs
.end(), MultilibSegments
.begin(),
216 MultilibSegments
.end());
218 for (const Multilib
&New
: MultilibSegments
) {
219 for (const Multilib
&Base
: *this) {
220 Multilib MO
= compose(Base
, New
);
222 Composed
.push_back(MO
);
226 Multilibs
= Composed
;
232 MultilibSet
&MultilibSet::FilterOut(const MultilibSet::FilterCallback
&F
) {
233 filterInPlace(F
, Multilibs
);
237 MultilibSet
&MultilibSet::FilterOut(std::string Regex
) {
238 class REFilter
: public MultilibSet::FilterCallback
{
239 mutable llvm::Regex R
;
242 REFilter(std::string Regex
) : R(Regex
) {}
243 bool operator()(const Multilib
&M
) const override
{
245 if (!R
.isValid(Error
)) {
246 llvm::errs() << Error
;
250 return R
.match(M
.gccSuffix());
255 filterInPlace(REF
, Multilibs
);
259 void MultilibSet::push_back(const Multilib
&M
) { Multilibs
.push_back(M
); }
261 void MultilibSet::combineWith(const MultilibSet
&Other
) {
262 Multilibs
.insert(Multilibs
.end(), Other
.begin(), Other
.end());
265 bool MultilibSet::select(const Multilib::flags_list
&Flags
, Multilib
&M
) const {
266 class FilterFlagsMismatch
: public MultilibSet::FilterCallback
{
267 llvm::StringMap
<bool> FlagSet
;
270 FilterFlagsMismatch(const std::vector
<std::string
> &Flags
) {
271 // Stuff all of the flags into the FlagSet such that a true mappend
272 // indicates the flag was enabled, and a false mappend indicates the
274 for (StringRef Flag
: Flags
)
275 FlagSet
[Flag
.substr(1)] = isFlagEnabled(Flag
);
277 bool operator()(const Multilib
&M
) const override
{
278 for (StringRef Flag
: M
.flags()) {
279 llvm::StringMap
<bool>::const_iterator SI
= FlagSet
.find(Flag
.substr(1));
280 if (SI
!= FlagSet
.end())
281 if (SI
->getValue() != isFlagEnabled(Flag
))
287 bool isFlagEnabled(StringRef Flag
) const {
288 char Indicator
= Flag
.front();
289 assert(Indicator
== '+' || Indicator
== '-');
290 return Indicator
== '+';
294 FilterFlagsMismatch
FlagsMismatch(Flags
);
296 multilib_list Filtered
= filterCopy(FlagsMismatch
, Multilibs
);
298 if (Filtered
.size() == 0) {
300 } else if (Filtered
.size() == 1) {
305 // TODO: pick the "best" multlib when more than one is suitable
311 void MultilibSet::print(raw_ostream
&OS
) const {
312 for (const Multilib
&M
: *this)
316 MultilibSet::multilib_list
317 MultilibSet::filterCopy(const MultilibSet::FilterCallback
&F
,
318 const multilib_list
&Ms
) {
319 multilib_list
Copy(Ms
);
320 filterInPlace(F
, Copy
);
324 void MultilibSet::filterInPlace(const MultilibSet::FilterCallback
&F
,
326 Ms
.erase(std::remove_if(Ms
.begin(), Ms
.end(),
327 [&F
](const Multilib
&M
) { return F(M
); }),
331 raw_ostream
&clang::driver::operator<<(raw_ostream
&OS
, const MultilibSet
&MS
) {