clang 20.0.0git
MultilibBuilder.cpp
Go to the documentation of this file.
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
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
16using namespace clang;
17using namespace driver;
18
19/// normalize Segment to "/foo/bar" or "".
20static 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
44MultilibBuilder::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
52 : MultilibBuilder(Suffix, Suffix, Suffix) {}
53
55 GCCSuffix = std::string(S);
56 normalizePathSegment(GCCSuffix);
57 return *this;
58}
59
61 OSSuffix = std::string(S);
62 normalizePathSegment(OSSuffix);
63 return *this;
64}
65
67 IncludeSuffix = std::string(S);
68 normalizePathSegment(IncludeSuffix);
69 return *this;
70}
71
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
86MultilibBuilder &MultilibBuilder::flag(StringRef Flag, bool Disallow) {
87 tools::addMultilibFlag(!Disallow, Flag, Flags);
88 return *this;
89}
90
92 return Multilib(GCCSuffix, OSSuffix, IncludeSuffix, Flags);
93}
94
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
106 const MultilibBuilder &M2) {
107 return Either({M1, M2});
108}
109
111 const MultilibBuilder &M2,
112 const MultilibBuilder &M3) {
113 return Either({M1, M2, M3});
114}
115
117 const MultilibBuilder &M2,
118 const MultilibBuilder &M3,
119 const MultilibBuilder &M4) {
120 return Either({M1, M2, M3, M4});
121}
122
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
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 Flags.insert(Flags.end(), Base.flags().begin(), Base.flags().end());
146 Flags.insert(Flags.end(), New.flags().begin(), New.flags().end());
147
148 return Composed;
149}
150
153 multilib_list Composed;
154
155 if (Multilibs.empty())
156 Multilibs.insert(Multilibs.end(), MultilibSegments.begin(),
157 MultilibSegments.end());
158 else {
159 for (const auto &New : MultilibSegments) {
160 for (const auto &Base : Multilibs) {
161 MultilibBuilder MO = compose(Base, New);
162 if (MO.isValid())
163 Composed.push_back(MO);
164 }
165 }
166
167 Multilibs = Composed;
168 }
169
170 return *this;
171}
172
174 llvm::Regex R(Regex);
175#ifndef NDEBUG
176 std::string Error;
177 if (!R.isValid(Error)) {
178 llvm::errs() << Error;
179 llvm_unreachable("Invalid regex!");
180 }
181#endif
182 llvm::erase_if(Multilibs, [&R](const MultilibBuilder &M) {
183 return R.match(M.gccSuffix());
184 });
185 return *this;
186}
187
190 for (const auto &M : Multilibs) {
191 Result.push_back(M.makeMultilib());
192 }
193 return Result;
194}
static MultilibBuilder compose(const MultilibBuilder &Base, const MultilibBuilder &New)
static void normalizePathSegment(std::string &Segment)
normalize Segment to "/foo/bar" or "".
This corresponds to a single GCC multilib, or a segment of one controlled by a command line flag.
bool isValid() const
Check whether any of the 'against' flags contradict the 'for' flags.
MultilibBuilder & flag(StringRef Flag, bool Disallow=false)
Add a flag to the flags list Flag must be a flag accepted by the driver.
const std::string & gccSuffix() const
Get the detected GCC installation path suffix for the multi-arch target variant.
const std::string & includeSuffix() const
Get the include directory suffix.
const std::string & osSuffix() const
Get the detected os path suffix for the multi-arch target variant.
std::vector< std::string > flags_list
const flags_list & flags() const
Get the flags that indicate or contraindicate this multilib's use All elements begin with either '-' ...
MultilibBuilder(StringRef GCCSuffix, StringRef OSSuffix, StringRef IncludeSuffix)
This class can be used to create a MultilibSet, and contains helper functions to add combinations of ...
MultilibSetBuilder & Maybe(const MultilibBuilder &M)
Add an optional Multilib segment.
MultilibSetBuilder & FilterOut(const char *Regex)
Filter out those Multilibs whose gccSuffix matches the given expression.
MultilibSetBuilder & Either(const MultilibBuilder &M1, const MultilibBuilder &M2)
Add a set of mutually incompatible Multilib segments.
std::vector< MultilibBuilder > multilib_list
See also MultilibSetBuilder for combining multilibs into a set.
Definition: Multilib.h:105
This corresponds to a single GCC Multilib, or a segment of one controlled by a command line flag.
Definition: Multilib.h:35
void addMultilibFlag(bool Enabled, const StringRef Flag, Multilib::flags_list &Flags)
Flag must be a flag accepted by the driver.
The JSON file list parser is used to communicate input to InstallAPI.
@ Result
The result type of a method or function.