xref: /freebsd/contrib/llvm-project/clang/lib/Driver/MultilibBuilder.cpp (revision 06c3fb2749bda94cb5201f81ffdb8fa6c3161b2e)
1*06c3fb27SDimitry Andric //===- MultilibBuilder.cpp - MultilibBuilder Implementation -===//
2*06c3fb27SDimitry Andric //
3*06c3fb27SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4*06c3fb27SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
5*06c3fb27SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6*06c3fb27SDimitry Andric //
7*06c3fb27SDimitry Andric //===----------------------------------------------------------------------===//
8*06c3fb27SDimitry Andric 
9*06c3fb27SDimitry Andric #include "clang/Driver/MultilibBuilder.h"
10*06c3fb27SDimitry Andric #include "ToolChains/CommonArgs.h"
11*06c3fb27SDimitry Andric #include "llvm/ADT/SmallString.h"
12*06c3fb27SDimitry Andric #include "llvm/ADT/StringMap.h"
13*06c3fb27SDimitry Andric #include "llvm/Support/Path.h"
14*06c3fb27SDimitry Andric #include "llvm/Support/Regex.h"
15*06c3fb27SDimitry Andric #include "llvm/Support/raw_ostream.h"
16*06c3fb27SDimitry Andric 
17*06c3fb27SDimitry Andric using namespace clang;
18*06c3fb27SDimitry Andric using namespace driver;
19*06c3fb27SDimitry Andric 
20*06c3fb27SDimitry Andric /// normalize Segment to "/foo/bar" or "".
normalizePathSegment(std::string & Segment)21*06c3fb27SDimitry Andric static void normalizePathSegment(std::string &Segment) {
22*06c3fb27SDimitry Andric   StringRef seg = Segment;
23*06c3fb27SDimitry Andric 
24*06c3fb27SDimitry Andric   // Prune trailing "/" or "./"
25*06c3fb27SDimitry Andric   while (true) {
26*06c3fb27SDimitry Andric     StringRef last = llvm::sys::path::filename(seg);
27*06c3fb27SDimitry Andric     if (last != ".")
28*06c3fb27SDimitry Andric       break;
29*06c3fb27SDimitry Andric     seg = llvm::sys::path::parent_path(seg);
30*06c3fb27SDimitry Andric   }
31*06c3fb27SDimitry Andric 
32*06c3fb27SDimitry Andric   if (seg.empty() || seg == "/") {
33*06c3fb27SDimitry Andric     Segment.clear();
34*06c3fb27SDimitry Andric     return;
35*06c3fb27SDimitry Andric   }
36*06c3fb27SDimitry Andric 
37*06c3fb27SDimitry Andric   // Add leading '/'
38*06c3fb27SDimitry Andric   if (seg.front() != '/') {
39*06c3fb27SDimitry Andric     Segment = "/" + seg.str();
40*06c3fb27SDimitry Andric   } else {
41*06c3fb27SDimitry Andric     Segment = std::string(seg);
42*06c3fb27SDimitry Andric   }
43*06c3fb27SDimitry Andric }
44*06c3fb27SDimitry Andric 
MultilibBuilder(StringRef GCC,StringRef OS,StringRef Include)45*06c3fb27SDimitry Andric MultilibBuilder::MultilibBuilder(StringRef GCC, StringRef OS, StringRef Include)
46*06c3fb27SDimitry Andric     : GCCSuffix(GCC), OSSuffix(OS), IncludeSuffix(Include) {
47*06c3fb27SDimitry Andric   normalizePathSegment(GCCSuffix);
48*06c3fb27SDimitry Andric   normalizePathSegment(OSSuffix);
49*06c3fb27SDimitry Andric   normalizePathSegment(IncludeSuffix);
50*06c3fb27SDimitry Andric }
51*06c3fb27SDimitry Andric 
MultilibBuilder(StringRef Suffix)52*06c3fb27SDimitry Andric MultilibBuilder::MultilibBuilder(StringRef Suffix)
53*06c3fb27SDimitry Andric     : MultilibBuilder(Suffix, Suffix, Suffix) {}
54*06c3fb27SDimitry Andric 
gccSuffix(StringRef S)55*06c3fb27SDimitry Andric MultilibBuilder &MultilibBuilder::gccSuffix(StringRef S) {
56*06c3fb27SDimitry Andric   GCCSuffix = std::string(S);
57*06c3fb27SDimitry Andric   normalizePathSegment(GCCSuffix);
58*06c3fb27SDimitry Andric   return *this;
59*06c3fb27SDimitry Andric }
60*06c3fb27SDimitry Andric 
osSuffix(StringRef S)61*06c3fb27SDimitry Andric MultilibBuilder &MultilibBuilder::osSuffix(StringRef S) {
62*06c3fb27SDimitry Andric   OSSuffix = std::string(S);
63*06c3fb27SDimitry Andric   normalizePathSegment(OSSuffix);
64*06c3fb27SDimitry Andric   return *this;
65*06c3fb27SDimitry Andric }
66*06c3fb27SDimitry Andric 
includeSuffix(StringRef S)67*06c3fb27SDimitry Andric MultilibBuilder &MultilibBuilder::includeSuffix(StringRef S) {
68*06c3fb27SDimitry Andric   IncludeSuffix = std::string(S);
69*06c3fb27SDimitry Andric   normalizePathSegment(IncludeSuffix);
70*06c3fb27SDimitry Andric   return *this;
71*06c3fb27SDimitry Andric }
72*06c3fb27SDimitry Andric 
isValid() const73*06c3fb27SDimitry Andric bool MultilibBuilder::isValid() const {
74*06c3fb27SDimitry Andric   llvm::StringMap<int> FlagSet;
75*06c3fb27SDimitry Andric   for (unsigned I = 0, N = Flags.size(); I != N; ++I) {
76*06c3fb27SDimitry Andric     StringRef Flag(Flags[I]);
77*06c3fb27SDimitry Andric     llvm::StringMap<int>::iterator SI = FlagSet.find(Flag.substr(1));
78*06c3fb27SDimitry Andric 
79*06c3fb27SDimitry Andric     assert(StringRef(Flag).front() == '-' || StringRef(Flag).front() == '!');
80*06c3fb27SDimitry Andric 
81*06c3fb27SDimitry Andric     if (SI == FlagSet.end())
82*06c3fb27SDimitry Andric       FlagSet[Flag.substr(1)] = I;
83*06c3fb27SDimitry Andric     else if (Flags[I] != Flags[SI->getValue()])
84*06c3fb27SDimitry Andric       return false;
85*06c3fb27SDimitry Andric   }
86*06c3fb27SDimitry Andric   return true;
87*06c3fb27SDimitry Andric }
88*06c3fb27SDimitry Andric 
flag(StringRef Flag,bool Disallow)89*06c3fb27SDimitry Andric MultilibBuilder &MultilibBuilder::flag(StringRef Flag, bool Disallow) {
90*06c3fb27SDimitry Andric   tools::addMultilibFlag(!Disallow, Flag, Flags);
91*06c3fb27SDimitry Andric   return *this;
92*06c3fb27SDimitry Andric }
93*06c3fb27SDimitry Andric 
makeMultilib() const94*06c3fb27SDimitry Andric Multilib MultilibBuilder::makeMultilib() const {
95*06c3fb27SDimitry Andric   return Multilib(GCCSuffix, OSSuffix, IncludeSuffix, Flags);
96*06c3fb27SDimitry Andric }
97*06c3fb27SDimitry Andric 
Maybe(const MultilibBuilder & M)98*06c3fb27SDimitry Andric MultilibSetBuilder &MultilibSetBuilder::Maybe(const MultilibBuilder &M) {
99*06c3fb27SDimitry Andric   MultilibBuilder Opposite;
100*06c3fb27SDimitry Andric   // Negate positive flags
101*06c3fb27SDimitry Andric   for (StringRef Flag : M.flags()) {
102*06c3fb27SDimitry Andric     if (Flag.front() == '-')
103*06c3fb27SDimitry Andric       Opposite.flag(Flag, /*Disallow=*/true);
104*06c3fb27SDimitry Andric   }
105*06c3fb27SDimitry Andric   return Either(M, Opposite);
106*06c3fb27SDimitry Andric }
107*06c3fb27SDimitry Andric 
Either(const MultilibBuilder & M1,const MultilibBuilder & M2)108*06c3fb27SDimitry Andric MultilibSetBuilder &MultilibSetBuilder::Either(const MultilibBuilder &M1,
109*06c3fb27SDimitry Andric                                                const MultilibBuilder &M2) {
110*06c3fb27SDimitry Andric   return Either({M1, M2});
111*06c3fb27SDimitry Andric }
112*06c3fb27SDimitry Andric 
Either(const MultilibBuilder & M1,const MultilibBuilder & M2,const MultilibBuilder & M3)113*06c3fb27SDimitry Andric MultilibSetBuilder &MultilibSetBuilder::Either(const MultilibBuilder &M1,
114*06c3fb27SDimitry Andric                                                const MultilibBuilder &M2,
115*06c3fb27SDimitry Andric                                                const MultilibBuilder &M3) {
116*06c3fb27SDimitry Andric   return Either({M1, M2, M3});
117*06c3fb27SDimitry Andric }
118*06c3fb27SDimitry Andric 
Either(const MultilibBuilder & M1,const MultilibBuilder & M2,const MultilibBuilder & M3,const MultilibBuilder & M4)119*06c3fb27SDimitry Andric MultilibSetBuilder &MultilibSetBuilder::Either(const MultilibBuilder &M1,
120*06c3fb27SDimitry Andric                                                const MultilibBuilder &M2,
121*06c3fb27SDimitry Andric                                                const MultilibBuilder &M3,
122*06c3fb27SDimitry Andric                                                const MultilibBuilder &M4) {
123*06c3fb27SDimitry Andric   return Either({M1, M2, M3, M4});
124*06c3fb27SDimitry Andric }
125*06c3fb27SDimitry Andric 
Either(const MultilibBuilder & M1,const MultilibBuilder & M2,const MultilibBuilder & M3,const MultilibBuilder & M4,const MultilibBuilder & M5)126*06c3fb27SDimitry Andric MultilibSetBuilder &MultilibSetBuilder::Either(const MultilibBuilder &M1,
127*06c3fb27SDimitry Andric                                                const MultilibBuilder &M2,
128*06c3fb27SDimitry Andric                                                const MultilibBuilder &M3,
129*06c3fb27SDimitry Andric                                                const MultilibBuilder &M4,
130*06c3fb27SDimitry Andric                                                const MultilibBuilder &M5) {
131*06c3fb27SDimitry Andric   return Either({M1, M2, M3, M4, M5});
132*06c3fb27SDimitry Andric }
133*06c3fb27SDimitry Andric 
compose(const MultilibBuilder & Base,const MultilibBuilder & New)134*06c3fb27SDimitry Andric static MultilibBuilder compose(const MultilibBuilder &Base,
135*06c3fb27SDimitry Andric                                const MultilibBuilder &New) {
136*06c3fb27SDimitry Andric   SmallString<128> GCCSuffix;
137*06c3fb27SDimitry Andric   llvm::sys::path::append(GCCSuffix, "/", Base.gccSuffix(), New.gccSuffix());
138*06c3fb27SDimitry Andric   SmallString<128> OSSuffix;
139*06c3fb27SDimitry Andric   llvm::sys::path::append(OSSuffix, "/", Base.osSuffix(), New.osSuffix());
140*06c3fb27SDimitry Andric   SmallString<128> IncludeSuffix;
141*06c3fb27SDimitry Andric   llvm::sys::path::append(IncludeSuffix, "/", Base.includeSuffix(),
142*06c3fb27SDimitry Andric                           New.includeSuffix());
143*06c3fb27SDimitry Andric 
144*06c3fb27SDimitry Andric   MultilibBuilder Composed(GCCSuffix, OSSuffix, IncludeSuffix);
145*06c3fb27SDimitry Andric 
146*06c3fb27SDimitry Andric   MultilibBuilder::flags_list &Flags = Composed.flags();
147*06c3fb27SDimitry Andric 
148*06c3fb27SDimitry Andric   Flags.insert(Flags.end(), Base.flags().begin(), Base.flags().end());
149*06c3fb27SDimitry Andric   Flags.insert(Flags.end(), New.flags().begin(), New.flags().end());
150*06c3fb27SDimitry Andric 
151*06c3fb27SDimitry Andric   return Composed;
152*06c3fb27SDimitry Andric }
153*06c3fb27SDimitry Andric 
154*06c3fb27SDimitry Andric MultilibSetBuilder &
Either(ArrayRef<MultilibBuilder> MultilibSegments)155*06c3fb27SDimitry Andric MultilibSetBuilder::Either(ArrayRef<MultilibBuilder> MultilibSegments) {
156*06c3fb27SDimitry Andric   multilib_list Composed;
157*06c3fb27SDimitry Andric 
158*06c3fb27SDimitry Andric   if (Multilibs.empty())
159*06c3fb27SDimitry Andric     Multilibs.insert(Multilibs.end(), MultilibSegments.begin(),
160*06c3fb27SDimitry Andric                      MultilibSegments.end());
161*06c3fb27SDimitry Andric   else {
162*06c3fb27SDimitry Andric     for (const auto &New : MultilibSegments) {
163*06c3fb27SDimitry Andric       for (const auto &Base : Multilibs) {
164*06c3fb27SDimitry Andric         MultilibBuilder MO = compose(Base, New);
165*06c3fb27SDimitry Andric         if (MO.isValid())
166*06c3fb27SDimitry Andric           Composed.push_back(MO);
167*06c3fb27SDimitry Andric       }
168*06c3fb27SDimitry Andric     }
169*06c3fb27SDimitry Andric 
170*06c3fb27SDimitry Andric     Multilibs = Composed;
171*06c3fb27SDimitry Andric   }
172*06c3fb27SDimitry Andric 
173*06c3fb27SDimitry Andric   return *this;
174*06c3fb27SDimitry Andric }
175*06c3fb27SDimitry Andric 
FilterOut(const char * Regex)176*06c3fb27SDimitry Andric MultilibSetBuilder &MultilibSetBuilder::FilterOut(const char *Regex) {
177*06c3fb27SDimitry Andric   llvm::Regex R(Regex);
178*06c3fb27SDimitry Andric #ifndef NDEBUG
179*06c3fb27SDimitry Andric   std::string Error;
180*06c3fb27SDimitry Andric   if (!R.isValid(Error)) {
181*06c3fb27SDimitry Andric     llvm::errs() << Error;
182*06c3fb27SDimitry Andric     llvm_unreachable("Invalid regex!");
183*06c3fb27SDimitry Andric   }
184*06c3fb27SDimitry Andric #endif
185*06c3fb27SDimitry Andric   llvm::erase_if(Multilibs, [&R](const MultilibBuilder &M) {
186*06c3fb27SDimitry Andric     return R.match(M.gccSuffix());
187*06c3fb27SDimitry Andric   });
188*06c3fb27SDimitry Andric   return *this;
189*06c3fb27SDimitry Andric }
190*06c3fb27SDimitry Andric 
makeMultilibSet() const191*06c3fb27SDimitry Andric MultilibSet MultilibSetBuilder::makeMultilibSet() const {
192*06c3fb27SDimitry Andric   MultilibSet Result;
193*06c3fb27SDimitry Andric   for (const auto &M : Multilibs) {
194*06c3fb27SDimitry Andric     Result.push_back(M.makeMultilib());
195*06c3fb27SDimitry Andric   }
196*06c3fb27SDimitry Andric   return Result;
197*06c3fb27SDimitry Andric }
198