xref: /llvm-project/clang/lib/Driver/MultilibBuilder.cpp (revision 4d6a5fc702e568b0456c4d8f9e2307eb6d81e955)
1850dab0fSMichael Platings //===- MultilibBuilder.cpp - MultilibBuilder Implementation -===//
2850dab0fSMichael Platings //
3850dab0fSMichael Platings // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4850dab0fSMichael Platings // See https://llvm.org/LICENSE.txt for license information.
5850dab0fSMichael Platings // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6850dab0fSMichael Platings //
7850dab0fSMichael Platings //===----------------------------------------------------------------------===//
8850dab0fSMichael Platings 
9850dab0fSMichael Platings #include "clang/Driver/MultilibBuilder.h"
1047b431d6SMichael Platings #include "ToolChains/CommonArgs.h"
11850dab0fSMichael Platings #include "llvm/ADT/StringMap.h"
12850dab0fSMichael Platings #include "llvm/Support/Path.h"
13850dab0fSMichael Platings #include "llvm/Support/Regex.h"
14850dab0fSMichael Platings #include "llvm/Support/raw_ostream.h"
15850dab0fSMichael Platings 
16850dab0fSMichael Platings using namespace clang;
17850dab0fSMichael Platings using namespace driver;
18850dab0fSMichael Platings 
19850dab0fSMichael Platings /// normalize Segment to "/foo/bar" or "".
20850dab0fSMichael Platings static void normalizePathSegment(std::string &Segment) {
21850dab0fSMichael Platings   StringRef seg = Segment;
22850dab0fSMichael Platings 
23850dab0fSMichael Platings   // Prune trailing "/" or "./"
24850dab0fSMichael Platings   while (true) {
25850dab0fSMichael Platings     StringRef last = llvm::sys::path::filename(seg);
26850dab0fSMichael Platings     if (last != ".")
27850dab0fSMichael Platings       break;
28850dab0fSMichael Platings     seg = llvm::sys::path::parent_path(seg);
29850dab0fSMichael Platings   }
30850dab0fSMichael Platings 
31850dab0fSMichael Platings   if (seg.empty() || seg == "/") {
32850dab0fSMichael Platings     Segment.clear();
33850dab0fSMichael Platings     return;
34850dab0fSMichael Platings   }
35850dab0fSMichael Platings 
36850dab0fSMichael Platings   // Add leading '/'
37850dab0fSMichael Platings   if (seg.front() != '/') {
38850dab0fSMichael Platings     Segment = "/" + seg.str();
39850dab0fSMichael Platings   } else {
40850dab0fSMichael Platings     Segment = std::string(seg);
41850dab0fSMichael Platings   }
42850dab0fSMichael Platings }
43850dab0fSMichael Platings 
44d30bc9e9SMichael Platings MultilibBuilder::MultilibBuilder(StringRef GCC, StringRef OS, StringRef Include)
45d30bc9e9SMichael Platings     : GCCSuffix(GCC), OSSuffix(OS), IncludeSuffix(Include) {
46850dab0fSMichael Platings   normalizePathSegment(GCCSuffix);
47850dab0fSMichael Platings   normalizePathSegment(OSSuffix);
48850dab0fSMichael Platings   normalizePathSegment(IncludeSuffix);
49850dab0fSMichael Platings }
50850dab0fSMichael Platings 
51850dab0fSMichael Platings MultilibBuilder::MultilibBuilder(StringRef Suffix)
52850dab0fSMichael Platings     : MultilibBuilder(Suffix, Suffix, Suffix) {}
53850dab0fSMichael Platings 
54850dab0fSMichael Platings MultilibBuilder &MultilibBuilder::gccSuffix(StringRef S) {
55850dab0fSMichael Platings   GCCSuffix = std::string(S);
56850dab0fSMichael Platings   normalizePathSegment(GCCSuffix);
57850dab0fSMichael Platings   return *this;
58850dab0fSMichael Platings }
59850dab0fSMichael Platings 
60850dab0fSMichael Platings MultilibBuilder &MultilibBuilder::osSuffix(StringRef S) {
61850dab0fSMichael Platings   OSSuffix = std::string(S);
62850dab0fSMichael Platings   normalizePathSegment(OSSuffix);
63850dab0fSMichael Platings   return *this;
64850dab0fSMichael Platings }
65850dab0fSMichael Platings 
66850dab0fSMichael Platings MultilibBuilder &MultilibBuilder::includeSuffix(StringRef S) {
67850dab0fSMichael Platings   IncludeSuffix = std::string(S);
68850dab0fSMichael Platings   normalizePathSegment(IncludeSuffix);
69850dab0fSMichael Platings   return *this;
70850dab0fSMichael Platings }
71850dab0fSMichael Platings 
72850dab0fSMichael Platings bool MultilibBuilder::isValid() const {
73850dab0fSMichael Platings   llvm::StringMap<int> FlagSet;
74850dab0fSMichael Platings   for (unsigned I = 0, N = Flags.size(); I != N; ++I) {
75850dab0fSMichael Platings     StringRef Flag(Flags[I]);
76*dec641e4SKazu Hirata     auto [SI, Inserted] = FlagSet.try_emplace(Flag.substr(1), I);
77850dab0fSMichael Platings 
78ce8fa36eSMichael Platings     assert(StringRef(Flag).front() == '-' || StringRef(Flag).front() == '!');
79850dab0fSMichael Platings 
80*dec641e4SKazu Hirata     if (!Inserted && Flags[I] != Flags[SI->getValue()])
81850dab0fSMichael Platings       return false;
82850dab0fSMichael Platings   }
83850dab0fSMichael Platings   return true;
84850dab0fSMichael Platings }
85850dab0fSMichael Platings 
86b4507dcaSMichael Platings MultilibBuilder &MultilibBuilder::flag(StringRef Flag, bool Disallow) {
87b4507dcaSMichael Platings   tools::addMultilibFlag(!Disallow, Flag, Flags);
8847b431d6SMichael Platings   return *this;
8947b431d6SMichael Platings }
9047b431d6SMichael Platings 
91850dab0fSMichael Platings Multilib MultilibBuilder::makeMultilib() const {
92d30bc9e9SMichael Platings   return Multilib(GCCSuffix, OSSuffix, IncludeSuffix, Flags);
93850dab0fSMichael Platings }
94850dab0fSMichael Platings 
95850dab0fSMichael Platings MultilibSetBuilder &MultilibSetBuilder::Maybe(const MultilibBuilder &M) {
96850dab0fSMichael Platings   MultilibBuilder Opposite;
97ce8fa36eSMichael Platings   // Negate positive flags
98850dab0fSMichael Platings   for (StringRef Flag : M.flags()) {
99ce8fa36eSMichael Platings     if (Flag.front() == '-')
100b4507dcaSMichael Platings       Opposite.flag(Flag, /*Disallow=*/true);
101850dab0fSMichael Platings   }
102850dab0fSMichael Platings   return Either(M, Opposite);
103850dab0fSMichael Platings }
104850dab0fSMichael Platings 
105850dab0fSMichael Platings MultilibSetBuilder &MultilibSetBuilder::Either(const MultilibBuilder &M1,
106850dab0fSMichael Platings                                                const MultilibBuilder &M2) {
107850dab0fSMichael Platings   return Either({M1, M2});
108850dab0fSMichael Platings }
109850dab0fSMichael Platings 
110850dab0fSMichael Platings MultilibSetBuilder &MultilibSetBuilder::Either(const MultilibBuilder &M1,
111850dab0fSMichael Platings                                                const MultilibBuilder &M2,
112850dab0fSMichael Platings                                                const MultilibBuilder &M3) {
113850dab0fSMichael Platings   return Either({M1, M2, M3});
114850dab0fSMichael Platings }
115850dab0fSMichael Platings 
116850dab0fSMichael Platings MultilibSetBuilder &MultilibSetBuilder::Either(const MultilibBuilder &M1,
117850dab0fSMichael Platings                                                const MultilibBuilder &M2,
118850dab0fSMichael Platings                                                const MultilibBuilder &M3,
119850dab0fSMichael Platings                                                const MultilibBuilder &M4) {
120850dab0fSMichael Platings   return Either({M1, M2, M3, M4});
121850dab0fSMichael Platings }
122850dab0fSMichael Platings 
123850dab0fSMichael Platings MultilibSetBuilder &MultilibSetBuilder::Either(const MultilibBuilder &M1,
124850dab0fSMichael Platings                                                const MultilibBuilder &M2,
125850dab0fSMichael Platings                                                const MultilibBuilder &M3,
126850dab0fSMichael Platings                                                const MultilibBuilder &M4,
127850dab0fSMichael Platings                                                const MultilibBuilder &M5) {
128850dab0fSMichael Platings   return Either({M1, M2, M3, M4, M5});
129850dab0fSMichael Platings }
130850dab0fSMichael Platings 
131850dab0fSMichael Platings static MultilibBuilder compose(const MultilibBuilder &Base,
132850dab0fSMichael Platings                                const MultilibBuilder &New) {
133850dab0fSMichael Platings   SmallString<128> GCCSuffix;
134850dab0fSMichael Platings   llvm::sys::path::append(GCCSuffix, "/", Base.gccSuffix(), New.gccSuffix());
135850dab0fSMichael Platings   SmallString<128> OSSuffix;
136850dab0fSMichael Platings   llvm::sys::path::append(OSSuffix, "/", Base.osSuffix(), New.osSuffix());
137850dab0fSMichael Platings   SmallString<128> IncludeSuffix;
138850dab0fSMichael Platings   llvm::sys::path::append(IncludeSuffix, "/", Base.includeSuffix(),
139850dab0fSMichael Platings                           New.includeSuffix());
140850dab0fSMichael Platings 
141850dab0fSMichael Platings   MultilibBuilder Composed(GCCSuffix, OSSuffix, IncludeSuffix);
142850dab0fSMichael Platings 
143850dab0fSMichael Platings   MultilibBuilder::flags_list &Flags = Composed.flags();
144850dab0fSMichael Platings 
145850dab0fSMichael Platings   Flags.insert(Flags.end(), Base.flags().begin(), Base.flags().end());
146850dab0fSMichael Platings   Flags.insert(Flags.end(), New.flags().begin(), New.flags().end());
147850dab0fSMichael Platings 
148850dab0fSMichael Platings   return Composed;
149850dab0fSMichael Platings }
150850dab0fSMichael Platings 
151850dab0fSMichael Platings MultilibSetBuilder &
152850dab0fSMichael Platings MultilibSetBuilder::Either(ArrayRef<MultilibBuilder> MultilibSegments) {
153850dab0fSMichael Platings   multilib_list Composed;
154850dab0fSMichael Platings 
155850dab0fSMichael Platings   if (Multilibs.empty())
156850dab0fSMichael Platings     Multilibs.insert(Multilibs.end(), MultilibSegments.begin(),
157850dab0fSMichael Platings                      MultilibSegments.end());
158850dab0fSMichael Platings   else {
159850dab0fSMichael Platings     for (const auto &New : MultilibSegments) {
160850dab0fSMichael Platings       for (const auto &Base : Multilibs) {
161850dab0fSMichael Platings         MultilibBuilder MO = compose(Base, New);
162850dab0fSMichael Platings         if (MO.isValid())
163850dab0fSMichael Platings           Composed.push_back(MO);
164850dab0fSMichael Platings       }
165850dab0fSMichael Platings     }
166850dab0fSMichael Platings 
167850dab0fSMichael Platings     Multilibs = Composed;
168850dab0fSMichael Platings   }
169850dab0fSMichael Platings 
170850dab0fSMichael Platings   return *this;
171850dab0fSMichael Platings }
172850dab0fSMichael Platings 
173850dab0fSMichael Platings MultilibSetBuilder &MultilibSetBuilder::FilterOut(const char *Regex) {
174850dab0fSMichael Platings   llvm::Regex R(Regex);
175850dab0fSMichael Platings #ifndef NDEBUG
176850dab0fSMichael Platings   std::string Error;
177850dab0fSMichael Platings   if (!R.isValid(Error)) {
178850dab0fSMichael Platings     llvm::errs() << Error;
179850dab0fSMichael Platings     llvm_unreachable("Invalid regex!");
180850dab0fSMichael Platings   }
181850dab0fSMichael Platings #endif
182850dab0fSMichael Platings   llvm::erase_if(Multilibs, [&R](const MultilibBuilder &M) {
183850dab0fSMichael Platings     return R.match(M.gccSuffix());
184850dab0fSMichael Platings   });
185850dab0fSMichael Platings   return *this;
186850dab0fSMichael Platings }
187850dab0fSMichael Platings 
188850dab0fSMichael Platings MultilibSet MultilibSetBuilder::makeMultilibSet() const {
189850dab0fSMichael Platings   MultilibSet Result;
190850dab0fSMichael Platings   for (const auto &M : Multilibs) {
191850dab0fSMichael Platings     Result.push_back(M.makeMultilib());
192850dab0fSMichael Platings   }
193850dab0fSMichael Platings   return Result;
194850dab0fSMichael Platings }
195