Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/contrib/llvm-project/llvm/lib/TextAPI/InterfaceFile.cpp
35262 views
1
//===- InterfaceFile.cpp --------------------------------------------------===//
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
// Implements the Interface File.
10
//
11
//===----------------------------------------------------------------------===//
12
13
#include "llvm/TextAPI/InterfaceFile.h"
14
#include "llvm/TextAPI/RecordsSlice.h"
15
#include "llvm/TextAPI/TextAPIError.h"
16
#include <iomanip>
17
#include <sstream>
18
19
using namespace llvm;
20
using namespace llvm::MachO;
21
22
void InterfaceFileRef::addTarget(const Target &Target) {
23
addEntry(Targets, Target);
24
}
25
26
void InterfaceFile::addAllowableClient(StringRef InstallName,
27
const Target &Target) {
28
if (InstallName.empty())
29
return;
30
auto Client = addEntry(AllowableClients, InstallName);
31
Client->addTarget(Target);
32
}
33
34
void InterfaceFile::addReexportedLibrary(StringRef InstallName,
35
const Target &Target) {
36
if (InstallName.empty())
37
return;
38
auto Lib = addEntry(ReexportedLibraries, InstallName);
39
Lib->addTarget(Target);
40
}
41
42
void InterfaceFile::addParentUmbrella(const Target &Target_, StringRef Parent) {
43
if (Parent.empty())
44
return;
45
auto Iter = lower_bound(ParentUmbrellas, Target_,
46
[](const std::pair<Target, std::string> &LHS,
47
Target RHS) { return LHS.first < RHS; });
48
49
if ((Iter != ParentUmbrellas.end()) && !(Target_ < Iter->first)) {
50
Iter->second = std::string(Parent);
51
return;
52
}
53
54
ParentUmbrellas.emplace(Iter, Target_, std::string(Parent));
55
}
56
57
void InterfaceFile::addRPath(StringRef RPath, const Target &InputTarget) {
58
if (RPath.empty())
59
return;
60
using RPathEntryT = const std::pair<Target, std::string>;
61
RPathEntryT Entry(InputTarget, RPath);
62
auto Iter =
63
lower_bound(RPaths, Entry,
64
[](RPathEntryT &LHS, RPathEntryT &RHS) { return LHS < RHS; });
65
66
if ((Iter != RPaths.end()) && (*Iter == Entry))
67
return;
68
69
RPaths.emplace(Iter, Entry);
70
}
71
72
void InterfaceFile::addTarget(const Target &Target) {
73
addEntry(Targets, Target);
74
}
75
76
InterfaceFile::const_filtered_target_range
77
InterfaceFile::targets(ArchitectureSet Archs) const {
78
std::function<bool(const Target &)> fn = [Archs](const Target &Target_) {
79
return Archs.has(Target_.Arch);
80
};
81
return make_filter_range(Targets, fn);
82
}
83
84
void InterfaceFile::addDocument(std::shared_ptr<InterfaceFile> &&Document) {
85
auto Pos = llvm::lower_bound(Documents, Document,
86
[](const std::shared_ptr<InterfaceFile> &LHS,
87
const std::shared_ptr<InterfaceFile> &RHS) {
88
return LHS->InstallName < RHS->InstallName;
89
});
90
Document->Parent = this;
91
Documents.insert(Pos, Document);
92
}
93
94
void InterfaceFile::inlineLibrary(std::shared_ptr<InterfaceFile> Library,
95
bool Overwrite) {
96
auto AddFwk = [&](std::shared_ptr<InterfaceFile> &&Reexport) {
97
auto It = lower_bound(
98
Documents, Reexport->getInstallName(),
99
[](std::shared_ptr<InterfaceFile> &Lhs, const StringRef Rhs) {
100
return Lhs->getInstallName() < Rhs;
101
});
102
103
if (Overwrite && It != Documents.end() &&
104
Reexport->getInstallName() == (*It)->getInstallName()) {
105
std::replace(Documents.begin(), Documents.end(), *It,
106
std::move(Reexport));
107
return;
108
}
109
110
if ((It != Documents.end()) &&
111
!(Reexport->getInstallName() < (*It)->getInstallName()))
112
return;
113
114
Documents.emplace(It, std::move(Reexport));
115
};
116
for (auto Doc : Library->documents())
117
AddFwk(std::move(Doc));
118
119
Library->Documents.clear();
120
AddFwk(std::move(Library));
121
}
122
123
Expected<std::unique_ptr<InterfaceFile>>
124
InterfaceFile::merge(const InterfaceFile *O) const {
125
// Verify files can be merged.
126
if (getInstallName() != O->getInstallName()) {
127
return make_error<StringError>("install names do not match",
128
inconvertibleErrorCode());
129
}
130
131
if (getCurrentVersion() != O->getCurrentVersion()) {
132
return make_error<StringError>("current versions do not match",
133
inconvertibleErrorCode());
134
}
135
136
if (getCompatibilityVersion() != O->getCompatibilityVersion()) {
137
return make_error<StringError>("compatibility versions do not match",
138
inconvertibleErrorCode());
139
}
140
141
if ((getSwiftABIVersion() != 0) && (O->getSwiftABIVersion() != 0) &&
142
(getSwiftABIVersion() != O->getSwiftABIVersion())) {
143
return make_error<StringError>("swift ABI versions do not match",
144
inconvertibleErrorCode());
145
}
146
147
if (isTwoLevelNamespace() != O->isTwoLevelNamespace()) {
148
return make_error<StringError>("two level namespace flags do not match",
149
inconvertibleErrorCode());
150
}
151
152
if (isApplicationExtensionSafe() != O->isApplicationExtensionSafe()) {
153
return make_error<StringError>(
154
"application extension safe flags do not match",
155
inconvertibleErrorCode());
156
}
157
158
std::unique_ptr<InterfaceFile> IF(new InterfaceFile());
159
IF->setFileType(std::max(getFileType(), O->getFileType()));
160
IF->setPath(getPath());
161
IF->setInstallName(getInstallName());
162
IF->setCurrentVersion(getCurrentVersion());
163
IF->setCompatibilityVersion(getCompatibilityVersion());
164
165
if (getSwiftABIVersion() == 0)
166
IF->setSwiftABIVersion(O->getSwiftABIVersion());
167
else
168
IF->setSwiftABIVersion(getSwiftABIVersion());
169
170
IF->setTwoLevelNamespace(isTwoLevelNamespace());
171
IF->setApplicationExtensionSafe(isApplicationExtensionSafe());
172
173
for (const auto &It : umbrellas()) {
174
if (!It.second.empty())
175
IF->addParentUmbrella(It.first, It.second);
176
}
177
for (const auto &It : O->umbrellas()) {
178
if (!It.second.empty())
179
IF->addParentUmbrella(It.first, It.second);
180
}
181
IF->addTargets(targets());
182
IF->addTargets(O->targets());
183
184
for (const auto &Lib : allowableClients())
185
for (const auto &Target : Lib.targets())
186
IF->addAllowableClient(Lib.getInstallName(), Target);
187
188
for (const auto &Lib : O->allowableClients())
189
for (const auto &Target : Lib.targets())
190
IF->addAllowableClient(Lib.getInstallName(), Target);
191
192
for (const auto &Lib : reexportedLibraries())
193
for (const auto &Target : Lib.targets())
194
IF->addReexportedLibrary(Lib.getInstallName(), Target);
195
196
for (const auto &Lib : O->reexportedLibraries())
197
for (const auto &Target : Lib.targets())
198
IF->addReexportedLibrary(Lib.getInstallName(), Target);
199
200
for (const auto &[Target, Path] : rpaths())
201
IF->addRPath(Path, Target);
202
for (const auto &[Target, Path] : O->rpaths())
203
IF->addRPath(Path, Target);
204
205
for (const auto *Sym : symbols()) {
206
IF->addSymbol(Sym->getKind(), Sym->getName(), Sym->targets(),
207
Sym->getFlags());
208
}
209
210
for (const auto *Sym : O->symbols()) {
211
IF->addSymbol(Sym->getKind(), Sym->getName(), Sym->targets(),
212
Sym->getFlags());
213
}
214
215
return std::move(IF);
216
}
217
218
Expected<std::unique_ptr<InterfaceFile>>
219
InterfaceFile::remove(Architecture Arch) const {
220
if (getArchitectures() == Arch)
221
return make_error<StringError>("cannot remove last architecture slice '" +
222
getArchitectureName(Arch) + "'",
223
inconvertibleErrorCode());
224
225
if (!getArchitectures().has(Arch)) {
226
bool Found = false;
227
for (auto &Doc : Documents) {
228
if (Doc->getArchitectures().has(Arch)) {
229
Found = true;
230
break;
231
}
232
}
233
234
if (!Found)
235
return make_error<TextAPIError>(TextAPIErrorCode::NoSuchArchitecture);
236
}
237
238
std::unique_ptr<InterfaceFile> IF(new InterfaceFile());
239
IF->setFileType(getFileType());
240
IF->setPath(getPath());
241
IF->addTargets(targets(ArchitectureSet::All().clear(Arch)));
242
IF->setInstallName(getInstallName());
243
IF->setCurrentVersion(getCurrentVersion());
244
IF->setCompatibilityVersion(getCompatibilityVersion());
245
IF->setSwiftABIVersion(getSwiftABIVersion());
246
IF->setTwoLevelNamespace(isTwoLevelNamespace());
247
IF->setApplicationExtensionSafe(isApplicationExtensionSafe());
248
for (const auto &It : umbrellas())
249
if (It.first.Arch != Arch)
250
IF->addParentUmbrella(It.first, It.second);
251
252
for (const auto &Lib : allowableClients()) {
253
for (const auto &Target : Lib.targets())
254
if (Target.Arch != Arch)
255
IF->addAllowableClient(Lib.getInstallName(), Target);
256
}
257
258
for (const auto &Lib : reexportedLibraries()) {
259
for (const auto &Target : Lib.targets())
260
if (Target.Arch != Arch)
261
IF->addReexportedLibrary(Lib.getInstallName(), Target);
262
}
263
264
for (const auto *Sym : symbols()) {
265
auto Archs = Sym->getArchitectures();
266
Archs.clear(Arch);
267
if (Archs.empty())
268
continue;
269
270
IF->addSymbol(Sym->getKind(), Sym->getName(), Sym->targets(Archs),
271
Sym->getFlags());
272
}
273
274
for (auto &Doc : Documents) {
275
// Skip the inlined document if the to be removed architecture is the
276
// only one left.
277
if (Doc->getArchitectures() == Arch)
278
continue;
279
280
// If the document doesn't contain the arch, then no work is to be done
281
// and it can be copied over.
282
if (!Doc->getArchitectures().has(Arch)) {
283
auto NewDoc = Doc;
284
IF->addDocument(std::move(NewDoc));
285
continue;
286
}
287
288
auto Result = Doc->remove(Arch);
289
if (!Result)
290
return Result;
291
292
IF->addDocument(std::move(Result.get()));
293
}
294
295
return std::move(IF);
296
}
297
298
Expected<std::unique_ptr<InterfaceFile>>
299
InterfaceFile::extract(Architecture Arch) const {
300
if (!getArchitectures().has(Arch)) {
301
return make_error<StringError>("file doesn't have architecture '" +
302
getArchitectureName(Arch) + "'",
303
inconvertibleErrorCode());
304
}
305
306
std::unique_ptr<InterfaceFile> IF(new InterfaceFile());
307
IF->setFileType(getFileType());
308
IF->setPath(getPath());
309
IF->addTargets(targets(Arch));
310
IF->setInstallName(getInstallName());
311
IF->setCurrentVersion(getCurrentVersion());
312
IF->setCompatibilityVersion(getCompatibilityVersion());
313
IF->setSwiftABIVersion(getSwiftABIVersion());
314
IF->setTwoLevelNamespace(isTwoLevelNamespace());
315
IF->setApplicationExtensionSafe(isApplicationExtensionSafe());
316
for (const auto &It : umbrellas())
317
if (It.first.Arch == Arch)
318
IF->addParentUmbrella(It.first, It.second);
319
320
for (const auto &It : rpaths())
321
if (It.first.Arch == Arch)
322
IF->addRPath(It.second, It.first);
323
324
for (const auto &Lib : allowableClients())
325
for (const auto &Target : Lib.targets())
326
if (Target.Arch == Arch)
327
IF->addAllowableClient(Lib.getInstallName(), Target);
328
329
for (const auto &Lib : reexportedLibraries())
330
for (const auto &Target : Lib.targets())
331
if (Target.Arch == Arch)
332
IF->addReexportedLibrary(Lib.getInstallName(), Target);
333
334
for (const auto *Sym : symbols()) {
335
if (Sym->hasArchitecture(Arch))
336
IF->addSymbol(Sym->getKind(), Sym->getName(), Sym->targets(Arch),
337
Sym->getFlags());
338
}
339
340
for (auto &Doc : Documents) {
341
// Skip documents that don't have the requested architecture.
342
if (!Doc->getArchitectures().has(Arch))
343
continue;
344
345
auto Result = Doc->extract(Arch);
346
if (!Result)
347
return Result;
348
349
IF->addDocument(std::move(Result.get()));
350
}
351
352
return std::move(IF);
353
}
354
355
void InterfaceFile::setFromBinaryAttrs(const RecordsSlice::BinaryAttrs &BA,
356
const Target &Targ) {
357
if (getFileType() != BA.File)
358
setFileType(BA.File);
359
if (getInstallName().empty())
360
setInstallName(BA.InstallName);
361
if (BA.AppExtensionSafe && !isApplicationExtensionSafe())
362
setApplicationExtensionSafe();
363
if (BA.TwoLevelNamespace && !isTwoLevelNamespace())
364
setTwoLevelNamespace();
365
if (BA.OSLibNotForSharedCache && !isOSLibNotForSharedCache())
366
setOSLibNotForSharedCache();
367
if (getCurrentVersion().empty())
368
setCurrentVersion(BA.CurrentVersion);
369
if (getCompatibilityVersion().empty())
370
setCompatibilityVersion(BA.CompatVersion);
371
if (getSwiftABIVersion() == 0)
372
setSwiftABIVersion(BA.SwiftABI);
373
if (getPath().empty())
374
setPath(BA.Path);
375
if (!BA.ParentUmbrella.empty())
376
addParentUmbrella(Targ, BA.ParentUmbrella);
377
for (const auto &Client : BA.AllowableClients)
378
addAllowableClient(Client, Targ);
379
for (const auto &Lib : BA.RexportedLibraries)
380
addReexportedLibrary(Lib, Targ);
381
}
382
383
static bool isYAMLTextStub(const FileType &Kind) {
384
return (Kind >= FileType::TBD_V1) && (Kind < FileType::TBD_V5);
385
}
386
387
bool InterfaceFile::operator==(const InterfaceFile &O) const {
388
if (Targets != O.Targets)
389
return false;
390
if (InstallName != O.InstallName)
391
return false;
392
if ((CurrentVersion != O.CurrentVersion) ||
393
(CompatibilityVersion != O.CompatibilityVersion))
394
return false;
395
if (SwiftABIVersion != O.SwiftABIVersion)
396
return false;
397
if (IsTwoLevelNamespace != O.IsTwoLevelNamespace)
398
return false;
399
if (IsAppExtensionSafe != O.IsAppExtensionSafe)
400
return false;
401
if (IsOSLibNotForSharedCache != O.IsOSLibNotForSharedCache)
402
return false;
403
if (HasSimSupport != O.HasSimSupport)
404
return false;
405
if (ParentUmbrellas != O.ParentUmbrellas)
406
return false;
407
if (AllowableClients != O.AllowableClients)
408
return false;
409
if (ReexportedLibraries != O.ReexportedLibraries)
410
return false;
411
if (*SymbolsSet != *O.SymbolsSet)
412
return false;
413
// Don't compare run search paths for older filetypes that cannot express
414
// them.
415
if (!(isYAMLTextStub(FileKind)) && !(isYAMLTextStub(O.FileKind))) {
416
if (RPaths != O.RPaths)
417
return false;
418
if (mapToPlatformVersionSet(Targets) != mapToPlatformVersionSet(O.Targets))
419
return false;
420
}
421
422
if (!std::equal(Documents.begin(), Documents.end(), O.Documents.begin(),
423
O.Documents.end(),
424
[](const std::shared_ptr<InterfaceFile> LHS,
425
const std::shared_ptr<InterfaceFile> RHS) {
426
return *LHS == *RHS;
427
}))
428
return false;
429
return true;
430
}
431
432