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 "clang/Driver/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 "".
normalizePathSegment(std::string & Segment)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
MultilibBuilder(StringRef GCC,StringRef OS,StringRef Include)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
MultilibBuilder(StringRef Suffix)51 MultilibBuilder::MultilibBuilder(StringRef Suffix)
52 : MultilibBuilder(Suffix, Suffix, Suffix) {}
53
gccSuffix(StringRef S)54 MultilibBuilder &MultilibBuilder::gccSuffix(StringRef S) {
55 GCCSuffix = std::string(S);
56 normalizePathSegment(GCCSuffix);
57 return *this;
58 }
59
osSuffix(StringRef S)60 MultilibBuilder &MultilibBuilder::osSuffix(StringRef S) {
61 OSSuffix = std::string(S);
62 normalizePathSegment(OSSuffix);
63 return *this;
64 }
65
includeSuffix(StringRef S)66 MultilibBuilder &MultilibBuilder::includeSuffix(StringRef S) {
67 IncludeSuffix = std::string(S);
68 normalizePathSegment(IncludeSuffix);
69 return *this;
70 }
71
isValid() const72 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
flag(StringRef Flag,bool Disallow)86 MultilibBuilder &MultilibBuilder::flag(StringRef Flag, bool Disallow) {
87 tools::addMultilibFlag(!Disallow, Flag, Flags);
88 return *this;
89 }
90
makeMultilib() const91 Multilib MultilibBuilder::makeMultilib() const {
92 return Multilib(GCCSuffix, OSSuffix, IncludeSuffix, Flags);
93 }
94
Maybe(const MultilibBuilder & M)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
Either(const MultilibBuilder & M1,const MultilibBuilder & M2)105 MultilibSetBuilder &MultilibSetBuilder::Either(const MultilibBuilder &M1,
106 const MultilibBuilder &M2) {
107 return Either({M1, M2});
108 }
109
Either(const MultilibBuilder & M1,const MultilibBuilder & M2,const MultilibBuilder & M3)110 MultilibSetBuilder &MultilibSetBuilder::Either(const MultilibBuilder &M1,
111 const MultilibBuilder &M2,
112 const MultilibBuilder &M3) {
113 return Either({M1, M2, M3});
114 }
115
Either(const MultilibBuilder & M1,const MultilibBuilder & M2,const MultilibBuilder & M3,const MultilibBuilder & M4)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
Either(const MultilibBuilder & M1,const MultilibBuilder & M2,const MultilibBuilder & M3,const MultilibBuilder & M4,const MultilibBuilder & M5)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
compose(const MultilibBuilder & Base,const MultilibBuilder & New)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 llvm::append_range(Flags, Base.flags());
146 llvm::append_range(Flags, New.flags());
147
148 return Composed;
149 }
150
151 MultilibSetBuilder &
Either(ArrayRef<MultilibBuilder> MultilibSegments)152 MultilibSetBuilder::Either(ArrayRef<MultilibBuilder> MultilibSegments) {
153 multilib_list Composed;
154
155 if (Multilibs.empty())
156 llvm::append_range(Multilibs, MultilibSegments);
157 else {
158 for (const auto &New : MultilibSegments) {
159 for (const auto &Base : Multilibs) {
160 MultilibBuilder MO = compose(Base, New);
161 if (MO.isValid())
162 Composed.push_back(MO);
163 }
164 }
165
166 Multilibs = Composed;
167 }
168
169 return *this;
170 }
171
FilterOut(const char * Regex)172 MultilibSetBuilder &MultilibSetBuilder::FilterOut(const char *Regex) {
173 llvm::Regex R(Regex);
174 #ifndef NDEBUG
175 std::string Error;
176 if (!R.isValid(Error)) {
177 llvm::errs() << Error;
178 llvm_unreachable("Invalid regex!");
179 }
180 #endif
181 llvm::erase_if(Multilibs, [&R](const MultilibBuilder &M) {
182 return R.match(M.gccSuffix());
183 });
184 return *this;
185 }
186
makeMultilibSet() const187 MultilibSet MultilibSetBuilder::makeMultilibSet() const {
188 MultilibSet Result;
189 for (const auto &M : Multilibs) {
190 Result.push_back(M.makeMultilib());
191 }
192 return Result;
193 }
194