Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/contrib/llvm-project/clang/lib/Driver/Multilib.cpp
35233 views
1
//===- Multilib.cpp - Multilib 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/Multilib.h"
10
#include "clang/Basic/LLVM.h"
11
#include "clang/Basic/Version.h"
12
#include "llvm/ADT/DenseSet.h"
13
#include "llvm/ADT/SmallString.h"
14
#include "llvm/ADT/StringRef.h"
15
#include "llvm/Support/Compiler.h"
16
#include "llvm/Support/Error.h"
17
#include "llvm/Support/ErrorHandling.h"
18
#include "llvm/Support/Path.h"
19
#include "llvm/Support/Regex.h"
20
#include "llvm/Support/VersionTuple.h"
21
#include "llvm/Support/YAMLParser.h"
22
#include "llvm/Support/YAMLTraits.h"
23
#include "llvm/Support/raw_ostream.h"
24
#include <algorithm>
25
#include <cassert>
26
#include <string>
27
28
using namespace clang;
29
using namespace driver;
30
using namespace llvm::sys;
31
32
Multilib::Multilib(StringRef GCCSuffix, StringRef OSSuffix,
33
StringRef IncludeSuffix, const flags_list &Flags,
34
StringRef ExclusiveGroup)
35
: GCCSuffix(GCCSuffix), OSSuffix(OSSuffix), IncludeSuffix(IncludeSuffix),
36
Flags(Flags), ExclusiveGroup(ExclusiveGroup) {
37
assert(GCCSuffix.empty() ||
38
(StringRef(GCCSuffix).front() == '/' && GCCSuffix.size() > 1));
39
assert(OSSuffix.empty() ||
40
(StringRef(OSSuffix).front() == '/' && OSSuffix.size() > 1));
41
assert(IncludeSuffix.empty() ||
42
(StringRef(IncludeSuffix).front() == '/' && IncludeSuffix.size() > 1));
43
}
44
45
LLVM_DUMP_METHOD void Multilib::dump() const {
46
print(llvm::errs());
47
}
48
49
void Multilib::print(raw_ostream &OS) const {
50
if (GCCSuffix.empty())
51
OS << ".";
52
else {
53
OS << StringRef(GCCSuffix).drop_front();
54
}
55
OS << ";";
56
for (StringRef Flag : Flags) {
57
if (Flag.front() == '-')
58
OS << "@" << Flag.substr(1);
59
}
60
}
61
62
bool Multilib::operator==(const Multilib &Other) const {
63
// Check whether the flags sets match
64
// allowing for the match to be order invariant
65
llvm::StringSet<> MyFlags;
66
for (const auto &Flag : Flags)
67
MyFlags.insert(Flag);
68
69
for (const auto &Flag : Other.Flags)
70
if (!MyFlags.contains(Flag))
71
return false;
72
73
if (osSuffix() != Other.osSuffix())
74
return false;
75
76
if (gccSuffix() != Other.gccSuffix())
77
return false;
78
79
if (includeSuffix() != Other.includeSuffix())
80
return false;
81
82
return true;
83
}
84
85
raw_ostream &clang::driver::operator<<(raw_ostream &OS, const Multilib &M) {
86
M.print(OS);
87
return OS;
88
}
89
90
MultilibSet &MultilibSet::FilterOut(FilterCallback F) {
91
llvm::erase_if(Multilibs, F);
92
return *this;
93
}
94
95
void MultilibSet::push_back(const Multilib &M) { Multilibs.push_back(M); }
96
97
bool MultilibSet::select(const Multilib::flags_list &Flags,
98
llvm::SmallVectorImpl<Multilib> &Selected) const {
99
llvm::StringSet<> FlagSet(expandFlags(Flags));
100
Selected.clear();
101
102
// Decide which multilibs we're going to select at all.
103
llvm::DenseSet<StringRef> ExclusiveGroupsSelected;
104
for (const Multilib &M : llvm::reverse(Multilibs)) {
105
// If this multilib doesn't match all our flags, don't select it.
106
if (!llvm::all_of(M.flags(), [&FlagSet](const std::string &F) {
107
return FlagSet.contains(F);
108
}))
109
continue;
110
111
const std::string &group = M.exclusiveGroup();
112
if (!group.empty()) {
113
// If this multilib has the same ExclusiveGroup as one we've already
114
// selected, skip it. We're iterating in reverse order, so the group
115
// member we've selected already is preferred.
116
//
117
// Otherwise, add the group name to the set of groups we've already
118
// selected a member of.
119
auto [It, Inserted] = ExclusiveGroupsSelected.insert(group);
120
if (!Inserted)
121
continue;
122
}
123
124
// Select this multilib.
125
Selected.push_back(M);
126
}
127
128
// We iterated in reverse order, so now put Selected back the right way
129
// round.
130
std::reverse(Selected.begin(), Selected.end());
131
132
return !Selected.empty();
133
}
134
135
llvm::StringSet<>
136
MultilibSet::expandFlags(const Multilib::flags_list &InFlags) const {
137
llvm::StringSet<> Result;
138
for (const auto &F : InFlags)
139
Result.insert(F);
140
for (const FlagMatcher &M : FlagMatchers) {
141
std::string RegexString(M.Match);
142
143
// Make the regular expression match the whole string.
144
if (!StringRef(M.Match).starts_with("^"))
145
RegexString.insert(RegexString.begin(), '^');
146
if (!StringRef(M.Match).ends_with("$"))
147
RegexString.push_back('$');
148
149
const llvm::Regex Regex(RegexString);
150
assert(Regex.isValid());
151
if (llvm::any_of(InFlags,
152
[&Regex](StringRef F) { return Regex.match(F); })) {
153
Result.insert(M.Flags.begin(), M.Flags.end());
154
}
155
}
156
return Result;
157
}
158
159
namespace {
160
161
// When updating this also update MULTILIB_VERSION in MultilibTest.cpp
162
static const VersionTuple MultilibVersionCurrent(1, 0);
163
164
struct MultilibSerialization {
165
std::string Dir;
166
std::vector<std::string> Flags;
167
std::string Group;
168
};
169
170
enum class MultilibGroupType {
171
/*
172
* The only group type currently supported is 'Exclusive', which indicates a
173
* group of multilibs of which at most one may be selected.
174
*/
175
Exclusive,
176
177
/*
178
* Future possibility: a second group type indicating a set of library
179
* directories that are mutually _dependent_ rather than mutually exclusive:
180
* if you include one you must include them all.
181
*
182
* It might also be useful to allow groups to be members of other groups, so
183
* that a mutually exclusive group could contain a mutually dependent set of
184
* library directories, or vice versa.
185
*
186
* These additional features would need changes in the implementation, but
187
* the YAML schema is set up so they can be added without requiring changes
188
* in existing users' multilib.yaml files.
189
*/
190
};
191
192
struct MultilibGroupSerialization {
193
std::string Name;
194
MultilibGroupType Type;
195
};
196
197
struct MultilibSetSerialization {
198
llvm::VersionTuple MultilibVersion;
199
std::vector<MultilibGroupSerialization> Groups;
200
std::vector<MultilibSerialization> Multilibs;
201
std::vector<MultilibSet::FlagMatcher> FlagMatchers;
202
};
203
204
} // end anonymous namespace
205
206
template <> struct llvm::yaml::MappingTraits<MultilibSerialization> {
207
static void mapping(llvm::yaml::IO &io, MultilibSerialization &V) {
208
io.mapRequired("Dir", V.Dir);
209
io.mapRequired("Flags", V.Flags);
210
io.mapOptional("Group", V.Group);
211
}
212
static std::string validate(IO &io, MultilibSerialization &V) {
213
if (StringRef(V.Dir).starts_with("/"))
214
return "paths must be relative but \"" + V.Dir + "\" starts with \"/\"";
215
return std::string{};
216
}
217
};
218
219
template <> struct llvm::yaml::ScalarEnumerationTraits<MultilibGroupType> {
220
static void enumeration(IO &io, MultilibGroupType &Val) {
221
io.enumCase(Val, "Exclusive", MultilibGroupType::Exclusive);
222
}
223
};
224
225
template <> struct llvm::yaml::MappingTraits<MultilibGroupSerialization> {
226
static void mapping(llvm::yaml::IO &io, MultilibGroupSerialization &V) {
227
io.mapRequired("Name", V.Name);
228
io.mapRequired("Type", V.Type);
229
}
230
};
231
232
template <> struct llvm::yaml::MappingTraits<MultilibSet::FlagMatcher> {
233
static void mapping(llvm::yaml::IO &io, MultilibSet::FlagMatcher &M) {
234
io.mapRequired("Match", M.Match);
235
io.mapRequired("Flags", M.Flags);
236
}
237
static std::string validate(IO &io, MultilibSet::FlagMatcher &M) {
238
llvm::Regex Regex(M.Match);
239
std::string RegexError;
240
if (!Regex.isValid(RegexError))
241
return RegexError;
242
if (M.Flags.empty())
243
return "value required for 'Flags'";
244
return std::string{};
245
}
246
};
247
248
template <> struct llvm::yaml::MappingTraits<MultilibSetSerialization> {
249
static void mapping(llvm::yaml::IO &io, MultilibSetSerialization &M) {
250
io.mapRequired("MultilibVersion", M.MultilibVersion);
251
io.mapRequired("Variants", M.Multilibs);
252
io.mapOptional("Groups", M.Groups);
253
io.mapOptional("Mappings", M.FlagMatchers);
254
}
255
static std::string validate(IO &io, MultilibSetSerialization &M) {
256
if (M.MultilibVersion.empty())
257
return "missing required key 'MultilibVersion'";
258
if (M.MultilibVersion.getMajor() != MultilibVersionCurrent.getMajor())
259
return "multilib version " + M.MultilibVersion.getAsString() +
260
" is unsupported";
261
if (M.MultilibVersion.getMinor() > MultilibVersionCurrent.getMinor())
262
return "multilib version " + M.MultilibVersion.getAsString() +
263
" is unsupported";
264
for (const MultilibSerialization &Lib : M.Multilibs) {
265
if (!Lib.Group.empty()) {
266
bool Found = false;
267
for (const MultilibGroupSerialization &Group : M.Groups)
268
if (Group.Name == Lib.Group) {
269
Found = true;
270
break;
271
}
272
if (!Found)
273
return "multilib \"" + Lib.Dir +
274
"\" specifies undefined group name \"" + Lib.Group + "\"";
275
}
276
}
277
return std::string{};
278
}
279
};
280
281
LLVM_YAML_IS_SEQUENCE_VECTOR(MultilibSerialization)
282
LLVM_YAML_IS_SEQUENCE_VECTOR(MultilibGroupSerialization)
283
LLVM_YAML_IS_SEQUENCE_VECTOR(MultilibSet::FlagMatcher)
284
285
llvm::ErrorOr<MultilibSet>
286
MultilibSet::parseYaml(llvm::MemoryBufferRef Input,
287
llvm::SourceMgr::DiagHandlerTy DiagHandler,
288
void *DiagHandlerCtxt) {
289
MultilibSetSerialization MS;
290
llvm::yaml::Input YamlInput(Input, nullptr, DiagHandler, DiagHandlerCtxt);
291
YamlInput >> MS;
292
if (YamlInput.error())
293
return YamlInput.error();
294
295
multilib_list Multilibs;
296
Multilibs.reserve(MS.Multilibs.size());
297
for (const auto &M : MS.Multilibs) {
298
std::string Dir;
299
if (M.Dir != ".")
300
Dir = "/" + M.Dir;
301
// We transfer M.Group straight into the ExclusiveGroup parameter for the
302
// Multilib constructor. If we later support more than one type of group,
303
// we'll have to look up the group name in MS.Groups, check its type, and
304
// decide what to do here.
305
Multilibs.emplace_back(Dir, Dir, Dir, M.Flags, M.Group);
306
}
307
308
return MultilibSet(std::move(Multilibs), std::move(MS.FlagMatchers));
309
}
310
311
LLVM_DUMP_METHOD void MultilibSet::dump() const {
312
print(llvm::errs());
313
}
314
315
void MultilibSet::print(raw_ostream &OS) const {
316
for (const auto &M : *this)
317
OS << M << "\n";
318
}
319
320
raw_ostream &clang::driver::operator<<(raw_ostream &OS, const MultilibSet &MS) {
321
MS.print(OS);
322
return OS;
323
}
324
325