LLVM 20.0.0git
InterfaceFile.cpp
Go to the documentation of this file.
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
16#include <iomanip>
17#include <sstream>
18
19using namespace llvm;
20using namespace llvm::MachO;
21
23 addEntry(Targets, Target);
24}
25
27 const Target &Target) {
28 if (InstallName.empty())
29 return;
30 auto Client = addEntry(AllowableClients, InstallName);
31 Client->addTarget(Target);
32}
33
35 const Target &Target) {
36 if (InstallName.empty())
37 return;
38 auto Lib = addEntry(ReexportedLibraries, InstallName);
39 Lib->addTarget(Target);
40}
41
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
57void 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
73 addEntry(Targets, Target);
74}
75
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
84void 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 assert((Pos == Documents.end() ||
91 (*Pos)->InstallName != Document->InstallName) &&
92 "Unexpected duplicate document added");
93 Document->Parent = this;
94 Documents.insert(Pos, Document);
95}
96
97void InterfaceFile::inlineLibrary(std::shared_ptr<InterfaceFile> Library,
98 bool Overwrite) {
99 auto AddFwk = [&](std::shared_ptr<InterfaceFile> &&Reexport) {
100 auto It = lower_bound(
101 Documents, Reexport->getInstallName(),
102 [](std::shared_ptr<InterfaceFile> &Lhs, const StringRef Rhs) {
103 return Lhs->getInstallName() < Rhs;
104 });
105
106 if (Overwrite && It != Documents.end() &&
107 Reexport->getInstallName() == (*It)->getInstallName()) {
108 std::replace(Documents.begin(), Documents.end(), *It,
109 std::move(Reexport));
110 return;
111 }
112
113 if ((It != Documents.end()) &&
114 !(Reexport->getInstallName() < (*It)->getInstallName()))
115 return;
116
117 Documents.emplace(It, std::move(Reexport));
118 };
119 for (auto Doc : Library->documents())
120 AddFwk(std::move(Doc));
121
122 Library->Documents.clear();
123 AddFwk(std::move(Library));
124}
125
128 // Verify files can be merged.
129 if (getInstallName() != O->getInstallName()) {
130 return make_error<StringError>("install names do not match",
132 }
133
134 if (getCurrentVersion() != O->getCurrentVersion()) {
135 return make_error<StringError>("current versions do not match",
137 }
138
139 if (getCompatibilityVersion() != O->getCompatibilityVersion()) {
140 return make_error<StringError>("compatibility versions do not match",
142 }
143
144 if ((getSwiftABIVersion() != 0) && (O->getSwiftABIVersion() != 0) &&
145 (getSwiftABIVersion() != O->getSwiftABIVersion())) {
146 return make_error<StringError>("swift ABI versions do not match",
148 }
149
150 if (isTwoLevelNamespace() != O->isTwoLevelNamespace()) {
151 return make_error<StringError>("two level namespace flags do not match",
153 }
154
155 if (isApplicationExtensionSafe() != O->isApplicationExtensionSafe()) {
156 return make_error<StringError>(
157 "application extension safe flags do not match",
159 }
160
161 std::unique_ptr<InterfaceFile> IF(new InterfaceFile());
162 IF->setFileType(std::max(getFileType(), O->getFileType()));
163 IF->setPath(getPath());
164 IF->setInstallName(getInstallName());
165 IF->setCurrentVersion(getCurrentVersion());
166 IF->setCompatibilityVersion(getCompatibilityVersion());
167
168 if (getSwiftABIVersion() == 0)
169 IF->setSwiftABIVersion(O->getSwiftABIVersion());
170 else
171 IF->setSwiftABIVersion(getSwiftABIVersion());
172
173 IF->setTwoLevelNamespace(isTwoLevelNamespace());
174 IF->setApplicationExtensionSafe(isApplicationExtensionSafe());
175
176 for (const auto &It : umbrellas()) {
177 if (!It.second.empty())
178 IF->addParentUmbrella(It.first, It.second);
179 }
180 for (const auto &It : O->umbrellas()) {
181 if (!It.second.empty())
182 IF->addParentUmbrella(It.first, It.second);
183 }
184 IF->addTargets(targets());
185 IF->addTargets(O->targets());
186
187 for (const auto &Lib : allowableClients())
188 for (const auto &Target : Lib.targets())
189 IF->addAllowableClient(Lib.getInstallName(), Target);
190
191 for (const auto &Lib : O->allowableClients())
192 for (const auto &Target : Lib.targets())
193 IF->addAllowableClient(Lib.getInstallName(), Target);
194
195 for (const auto &Lib : reexportedLibraries())
196 for (const auto &Target : Lib.targets())
197 IF->addReexportedLibrary(Lib.getInstallName(), Target);
198
199 for (const auto &Lib : O->reexportedLibraries())
200 for (const auto &Target : Lib.targets())
201 IF->addReexportedLibrary(Lib.getInstallName(), Target);
202
203 for (const auto &[Target, Path] : rpaths())
204 IF->addRPath(Path, Target);
205 for (const auto &[Target, Path] : O->rpaths())
206 IF->addRPath(Path, Target);
207
208 for (const auto *Sym : symbols()) {
209 IF->addSymbol(Sym->getKind(), Sym->getName(), Sym->targets(),
210 Sym->getFlags());
211 }
212
213 for (const auto *Sym : O->symbols()) {
214 IF->addSymbol(Sym->getKind(), Sym->getName(), Sym->targets(),
215 Sym->getFlags());
216 }
217
218 return std::move(IF);
219}
220
223 if (getArchitectures() == Arch)
224 return make_error<StringError>("cannot remove last architecture slice '" +
225 getArchitectureName(Arch) + "'",
227
228 if (!getArchitectures().has(Arch)) {
229 bool Found = false;
230 for (auto &Doc : Documents) {
231 if (Doc->getArchitectures().has(Arch)) {
232 Found = true;
233 break;
234 }
235 }
236
237 if (!Found)
238 return make_error<TextAPIError>(TextAPIErrorCode::NoSuchArchitecture);
239 }
240
241 std::unique_ptr<InterfaceFile> IF(new InterfaceFile());
242 IF->setFileType(getFileType());
243 IF->setPath(getPath());
244 IF->addTargets(targets(ArchitectureSet::All().clear(Arch)));
245 IF->setInstallName(getInstallName());
246 IF->setCurrentVersion(getCurrentVersion());
247 IF->setCompatibilityVersion(getCompatibilityVersion());
248 IF->setSwiftABIVersion(getSwiftABIVersion());
249 IF->setTwoLevelNamespace(isTwoLevelNamespace());
250 IF->setApplicationExtensionSafe(isApplicationExtensionSafe());
251 for (const auto &It : umbrellas())
252 if (It.first.Arch != Arch)
253 IF->addParentUmbrella(It.first, It.second);
254
255 for (const auto &Lib : allowableClients()) {
256 for (const auto &Target : Lib.targets())
257 if (Target.Arch != Arch)
258 IF->addAllowableClient(Lib.getInstallName(), Target);
259 }
260
261 for (const auto &Lib : reexportedLibraries()) {
262 for (const auto &Target : Lib.targets())
263 if (Target.Arch != Arch)
264 IF->addReexportedLibrary(Lib.getInstallName(), Target);
265 }
266
267 for (const auto *Sym : symbols()) {
268 auto Archs = Sym->getArchitectures();
269 Archs.clear(Arch);
270 if (Archs.empty())
271 continue;
272
273 IF->addSymbol(Sym->getKind(), Sym->getName(), Sym->targets(Archs),
274 Sym->getFlags());
275 }
276
277 for (auto &Doc : Documents) {
278 // Skip the inlined document if the to be removed architecture is the
279 // only one left.
280 if (Doc->getArchitectures() == Arch)
281 continue;
282
283 // If the document doesn't contain the arch, then no work is to be done
284 // and it can be copied over.
285 if (!Doc->getArchitectures().has(Arch)) {
286 auto NewDoc = Doc;
287 IF->addDocument(std::move(NewDoc));
288 continue;
289 }
290
291 auto Result = Doc->remove(Arch);
292 if (!Result)
293 return Result;
294
295 IF->addDocument(std::move(Result.get()));
296 }
297
298 return std::move(IF);
299}
300
303 if (!getArchitectures().has(Arch)) {
304 return make_error<StringError>("file doesn't have architecture '" +
305 getArchitectureName(Arch) + "'",
307 }
308
309 std::unique_ptr<InterfaceFile> IF(new InterfaceFile());
310 IF->setFileType(getFileType());
311 IF->setPath(getPath());
312 IF->addTargets(targets(Arch));
313 IF->setInstallName(getInstallName());
314 IF->setCurrentVersion(getCurrentVersion());
315 IF->setCompatibilityVersion(getCompatibilityVersion());
316 IF->setSwiftABIVersion(getSwiftABIVersion());
317 IF->setTwoLevelNamespace(isTwoLevelNamespace());
318 IF->setApplicationExtensionSafe(isApplicationExtensionSafe());
319 for (const auto &It : umbrellas())
320 if (It.first.Arch == Arch)
321 IF->addParentUmbrella(It.first, It.second);
322
323 for (const auto &It : rpaths())
324 if (It.first.Arch == Arch)
325 IF->addRPath(It.second, It.first);
326
327 for (const auto &Lib : allowableClients())
328 for (const auto &Target : Lib.targets())
329 if (Target.Arch == Arch)
330 IF->addAllowableClient(Lib.getInstallName(), Target);
331
332 for (const auto &Lib : reexportedLibraries())
333 for (const auto &Target : Lib.targets())
334 if (Target.Arch == Arch)
335 IF->addReexportedLibrary(Lib.getInstallName(), Target);
336
337 for (const auto *Sym : symbols()) {
338 if (Sym->hasArchitecture(Arch))
339 IF->addSymbol(Sym->getKind(), Sym->getName(), Sym->targets(Arch),
340 Sym->getFlags());
341 }
342
343 for (auto &Doc : Documents) {
344 // Skip documents that don't have the requested architecture.
345 if (!Doc->getArchitectures().has(Arch))
346 continue;
347
348 auto Result = Doc->extract(Arch);
349 if (!Result)
350 return Result;
351
352 IF->addDocument(std::move(Result.get()));
353 }
354
355 return std::move(IF);
356}
357
359 const Target &Targ) {
360 if (getFileType() != BA.File)
361 setFileType(BA.File);
362 if (getInstallName().empty())
370 if (getCurrentVersion().empty())
372 if (getCompatibilityVersion().empty())
374 if (getSwiftABIVersion() == 0)
376 if (getPath().empty())
377 setPath(BA.Path);
378 if (!BA.ParentUmbrella.empty())
380 for (const auto &Client : BA.AllowableClients)
381 addAllowableClient(Client, Targ);
382 for (const auto &Lib : BA.RexportedLibraries)
384}
385
386static bool isYAMLTextStub(const FileType &Kind) {
387 return (Kind >= FileType::TBD_V1) && (Kind < FileType::TBD_V5);
388}
389
391 if (Targets != O.Targets)
392 return false;
393 if (InstallName != O.InstallName)
394 return false;
395 if ((CurrentVersion != O.CurrentVersion) ||
396 (CompatibilityVersion != O.CompatibilityVersion))
397 return false;
398 if (SwiftABIVersion != O.SwiftABIVersion)
399 return false;
400 if (IsTwoLevelNamespace != O.IsTwoLevelNamespace)
401 return false;
402 if (IsAppExtensionSafe != O.IsAppExtensionSafe)
403 return false;
404 if (IsOSLibNotForSharedCache != O.IsOSLibNotForSharedCache)
405 return false;
406 if (HasSimSupport != O.HasSimSupport)
407 return false;
408 if (ParentUmbrellas != O.ParentUmbrellas)
409 return false;
410 if (AllowableClients != O.AllowableClients)
411 return false;
412 if (ReexportedLibraries != O.ReexportedLibraries)
413 return false;
414 if (*SymbolsSet != *O.SymbolsSet)
415 return false;
416 // Don't compare run search paths for older filetypes that cannot express
417 // them.
418 if (!(isYAMLTextStub(FileKind)) && !(isYAMLTextStub(O.FileKind))) {
419 if (RPaths != O.RPaths)
420 return false;
421 if (mapToPlatformVersionSet(Targets) != mapToPlatformVersionSet(O.Targets))
422 return false;
423 }
424
425 if (!std::equal(Documents.begin(), Documents.end(), O.Documents.begin(),
426 O.Documents.end(),
427 [](const std::shared_ptr<InterfaceFile> LHS,
428 const std::shared_ptr<InterfaceFile> RHS) {
429 return *LHS == *RHS;
430 }))
431 return false;
432 return true;
433}
static void clear(coro::Shape &Shape)
Definition: Coroutines.cpp:148
Symbol * Sym
Definition: ELF_riscv.cpp:479
static bool isYAMLTextStub(const FileType &Kind)
Implements the TAPI Record Collection Type.
assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())
Define TAPI specific error codes.
Value * RHS
Value * LHS
Tagged union holding either a T or a Error.
Definition: Error.h:481
static ArchitectureSet All()
ArchitectureSet clear(Architecture Arch)
bool has(Architecture Arch) const
void addTarget(const Target &Target)
Defines the interface file.
void addDocument(std::shared_ptr< InterfaceFile > &&Document)
Add a library for inlining to top level library.
StringRef getPath() const
Get the path from which this file was generated (if applicable).
void addReexportedLibrary(StringRef InstallName, const Target &Target)
Add a re-exported library.
void setPath(StringRef Path_)
Set the path from which this file was generated (if applicable).
void setFromBinaryAttrs(const RecordsSlice::BinaryAttrs &BA, const Target &Targ)
Set InterfaceFile properties from pre-gathered binary attributes, if they are not set already.
void addParentUmbrella(const Target &Target_, StringRef Parent)
Set the parent umbrella frameworks.
const_target_range targets() const
void setOSLibNotForSharedCache(bool V=true)
Specify if the library is an OS library but not shared cache eligible.
bool isOSLibNotForSharedCache() const
Check if the library is an OS library that is not shared cache eligible.
llvm::Expected< std::unique_ptr< InterfaceFile > > remove(Architecture Arch) const
Remove architecture slice from Interface.
bool isTwoLevelNamespace() const
Check if the library uses two-level namespace.
bool operator==(const InterfaceFile &O) const
The equality is determined by attributes that impact linking compatibilities.
PackedVersion getCompatibilityVersion() const
Get the compatibility version of the library.
void addTarget(const Target &Target)
Set and add target.
bool isApplicationExtensionSafe() const
Check if the library is application extension safe.
const std::vector< std::pair< Target, std::string > > & rpaths() const
Get the list of runpath search paths.
const std::vector< InterfaceFileRef > & allowableClients() const
Get the list of allowable clients.
void setInstallName(StringRef InstallName_)
Set the install name of the library.
const std::vector< std::pair< Target, std::string > > & umbrellas() const
Get the list of Parent Umbrella frameworks.
const std::vector< InterfaceFileRef > & reexportedLibraries() const
Get the list of re-exported libraries.
const_symbol_range symbols() const
void setFileType(FileType Kind)
Set the file type.
uint8_t getSwiftABIVersion() const
Get the Swift ABI version of the library.
PackedVersion getCurrentVersion() const
Get the current version of the library.
void addRPath(StringRef RPath, const Target &InputTarget)
Set the runpath search paths.
void setCompatibilityVersion(PackedVersion Version)
Set the compatibility version of the library.
ArchitectureSet getArchitectures() const
Get the architectures.
StringRef getInstallName() const
Get the install name of the library.
llvm::Expected< std::unique_ptr< InterfaceFile > > merge(const InterfaceFile *O) const
Merge Interfaces for the same library.
FileType getFileType() const
Get the file type.
void setApplicationExtensionSafe(bool V=true)
Specify if the library is application extension safe (or not).
void addAllowableClient(StringRef InstallName, const Target &Target)
Add an allowable client.
void inlineLibrary(std::shared_ptr< InterfaceFile > Library, bool Overwrite=false)
Inline reexported library into Interface.
void setSwiftABIVersion(uint8_t Version)
Set the Swift ABI version of the library.
void setCurrentVersion(PackedVersion Version)
Set the current version of the library.
llvm::Expected< std::unique_ptr< InterfaceFile > > extract(Architecture Arch) const
Extract architecture slice from Interface.
void setTwoLevelNamespace(bool V=true)
Specify if the library uses two-level namespace (or flat namespace).
SymbolFlags getFlags() const
Definition: Symbol.h:107
bool hasArchitecture(Architecture Arch) const
Definition: Symbol.h:138
const_target_range targets() const
Definition: Symbol.h:148
ArchitectureSet getArchitectures() const
Definition: Symbol.h:104
StringRef getName() const
Definition: Symbol.h:103
EncodeKind getKind() const
Definition: Symbol.h:102
Architecture Arch
Definition: Target.h:42
StringRef - Represent a constant reference to a string, i.e.
Definition: StringRef.h:50
constexpr bool empty() const
empty - Check if the string is empty.
Definition: StringRef.h:134
A range adaptor for a pair of iterators.
FileType
Defines the file type TextAPI files can represent.
Definition: FileTypes.h:15
@ TBD_V1
Text-based stub file (.tbd) version 1.0.
Definition: FileTypes.h:29
@ TBD_V5
Text-based stub file (.tbd) version 5.0.
Definition: FileTypes.h:41
StringRef getArchitectureName(Architecture Arch)
Convert an architecture slice to a string.
C::iterator addEntry(C &Container, StringRef InstallName)
Architecture
Defines the architecture slices that are supported by Text-based Stub files.
Definition: Architecture.h:27
PlatformVersionSet mapToPlatformVersionSet(ArrayRef< Target > Targets)
Definition: Target.cpp:55
This is an optimization pass for GlobalISel generic memory operations.
Definition: AddressRanges.h:18
std::error_code inconvertibleErrorCode()
The value returned by this function can be returned from convertToErrorCode for Error values where no...
Definition: Error.cpp:98
iterator_range< filter_iterator< detail::IterOfRange< RangeT >, PredicateT > > make_filter_range(RangeT &&Range, PredicateT Pred)
Convenience function that takes a range of elements and a predicate, and return a new filter_iterator...
Definition: STLExtras.h:572
auto lower_bound(R &&Range, T &&Value)
Provide wrappers to std::lower_bound which take ranges instead of having to pass begin/end explicitly...
Definition: STLExtras.h:1954
std::vector< StringRef > RexportedLibraries
Definition: RecordsSlice.h:145
std::vector< StringRef > AllowableClients
Definition: RecordsSlice.h:144
llvm::MachO::PackedVersion CompatVersion
Definition: RecordsSlice.h:153
llvm::MachO::PackedVersion CurrentVersion
Definition: RecordsSlice.h:152