LLVM 18.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
15#include <iomanip>
16#include <sstream>
17
18using namespace llvm;
19using namespace llvm::MachO;
20
22 addEntry(Targets, Target);
23}
24
26 const Target &Target) {
27 auto Client = addEntry(AllowableClients, InstallName);
28 Client->addTarget(Target);
29}
30
32 const Target &Target) {
33 auto Lib = addEntry(ReexportedLibraries, InstallName);
34 Lib->addTarget(Target);
35}
36
38 auto Iter = lower_bound(ParentUmbrellas, Target_,
39 [](const std::pair<Target, std::string> &LHS,
40 Target RHS) { return LHS.first < RHS; });
41
42 if ((Iter != ParentUmbrellas.end()) && !(Target_ < Iter->first)) {
43 Iter->second = std::string(Parent);
44 return;
45 }
46
47 ParentUmbrellas.emplace(Iter, Target_, std::string(Parent));
48}
49
50void InterfaceFile::addRPath(const Target &InputTarget, StringRef RPath) {
51 using RPathEntryT = const std::pair<Target, std::string>;
52 RPathEntryT Entry(InputTarget, RPath);
53 auto Iter =
54 lower_bound(RPaths, Entry,
55 [](RPathEntryT &LHS, RPathEntryT &RHS) { return LHS < RHS; });
56
57 if ((Iter != RPaths.end()) && (*Iter == Entry))
58 return;
59
60 RPaths.emplace(Iter, Entry);
61}
62
64 addEntry(Targets, Target);
65}
66
69 std::function<bool(const Target &)> fn = [Archs](const Target &Target_) {
70 return Archs.has(Target_.Arch);
71 };
72 return make_filter_range(Targets, fn);
73}
74
75void InterfaceFile::addDocument(std::shared_ptr<InterfaceFile> &&Document) {
76 auto Pos = llvm::lower_bound(Documents, Document,
77 [](const std::shared_ptr<InterfaceFile> &LHS,
78 const std::shared_ptr<InterfaceFile> &RHS) {
79 return LHS->InstallName < RHS->InstallName;
80 });
81 Document->Parent = this;
82 Documents.insert(Pos, Document);
83}
84
85void InterfaceFile::inlineLibrary(std::shared_ptr<InterfaceFile> Library,
86 bool Overwrite) {
87 auto AddFwk = [&](std::shared_ptr<InterfaceFile> &&Reexport) {
88 auto It = lower_bound(
89 Documents, Reexport->getInstallName(),
90 [](std::shared_ptr<InterfaceFile> &Lhs, const StringRef Rhs) {
91 return Lhs->getInstallName() < Rhs;
92 });
93
94 if (Overwrite && It != Documents.end() &&
95 Reexport->getInstallName() == (*It)->getInstallName()) {
96 std::replace(Documents.begin(), Documents.end(), *It,
97 std::move(Reexport));
98 return;
99 }
100
101 if ((It != Documents.end()) &&
102 !(Reexport->getInstallName() < (*It)->getInstallName()))
103 return;
104
105 Documents.emplace(It, std::move(Reexport));
106 };
107 for (auto Doc : Library->documents())
108 AddFwk(std::move(Doc));
109
110 Library->Documents.clear();
111 AddFwk(std::move(Library));
112}
113
116 // Verify files can be merged.
117 if (getInstallName() != O->getInstallName()) {
118 return make_error<StringError>("install names do not match",
120 }
121
122 if (getCurrentVersion() != O->getCurrentVersion()) {
123 return make_error<StringError>("current versions do not match",
125 }
126
127 if (getCompatibilityVersion() != O->getCompatibilityVersion()) {
128 return make_error<StringError>("compatibility versions do not match",
130 }
131
132 if ((getSwiftABIVersion() != 0) && (O->getSwiftABIVersion() != 0) &&
133 (getSwiftABIVersion() != O->getSwiftABIVersion())) {
134 return make_error<StringError>("swift ABI versions do not match",
136 }
137
138 if (isTwoLevelNamespace() != O->isTwoLevelNamespace()) {
139 return make_error<StringError>("two level namespace flags do not match",
141 }
142
143 if (isApplicationExtensionSafe() != O->isApplicationExtensionSafe()) {
144 return make_error<StringError>(
145 "application extension safe flags do not match",
147 }
148
149 std::unique_ptr<InterfaceFile> IF(new InterfaceFile());
150 IF->setFileType(std::max(getFileType(), O->getFileType()));
151 IF->setPath(getPath());
152 IF->setInstallName(getInstallName());
153 IF->setCurrentVersion(getCurrentVersion());
154 IF->setCompatibilityVersion(getCompatibilityVersion());
155
156 if (getSwiftABIVersion() == 0)
157 IF->setSwiftABIVersion(O->getSwiftABIVersion());
158 else
159 IF->setSwiftABIVersion(getSwiftABIVersion());
160
161 IF->setTwoLevelNamespace(isTwoLevelNamespace());
162 IF->setApplicationExtensionSafe(isApplicationExtensionSafe());
163
164 for (const auto &It : umbrellas()) {
165 if (!It.second.empty())
166 IF->addParentUmbrella(It.first, It.second);
167 }
168 for (const auto &It : O->umbrellas()) {
169 if (!It.second.empty())
170 IF->addParentUmbrella(It.first, It.second);
171 }
172 IF->addTargets(targets());
173 IF->addTargets(O->targets());
174
175 for (const auto &Lib : allowableClients())
176 for (const auto &Target : Lib.targets())
177 IF->addAllowableClient(Lib.getInstallName(), Target);
178
179 for (const auto &Lib : O->allowableClients())
180 for (const auto &Target : Lib.targets())
181 IF->addAllowableClient(Lib.getInstallName(), Target);
182
183 for (const auto &Lib : reexportedLibraries())
184 for (const auto &Target : Lib.targets())
185 IF->addReexportedLibrary(Lib.getInstallName(), Target);
186
187 for (const auto &Lib : O->reexportedLibraries())
188 for (const auto &Target : Lib.targets())
189 IF->addReexportedLibrary(Lib.getInstallName(), Target);
190
191 for (const auto &[Target, Path] : rpaths())
192 IF->addRPath(Target, Path);
193 for (const auto &[Target, Path] : O->rpaths())
194 IF->addRPath(Target, Path);
195
196 for (const auto *Sym : symbols()) {
197 IF->addSymbol(Sym->getKind(), Sym->getName(), Sym->targets(),
198 Sym->getFlags());
199 }
200
201 for (const auto *Sym : O->symbols()) {
202 IF->addSymbol(Sym->getKind(), Sym->getName(), Sym->targets(),
203 Sym->getFlags());
204 }
205
206 return std::move(IF);
207}
208
211 if (getArchitectures() == Arch)
212 return make_error<StringError>("cannot remove last architecture slice '" +
213 getArchitectureName(Arch) + "'",
215
216 if (!getArchitectures().has(Arch)) {
217 bool Found = false;
218 for (auto &Doc : Documents) {
219 if (Doc->getArchitectures().has(Arch)) {
220 Found = true;
221 break;
222 }
223 }
224
225 if (!Found)
226 return make_error<TextAPIError>(TextAPIErrorCode::NoSuchArchitecture);
227 }
228
229 std::unique_ptr<InterfaceFile> IF(new InterfaceFile());
230 IF->setFileType(getFileType());
231 IF->setPath(getPath());
232 IF->addTargets(targets(ArchitectureSet::All().clear(Arch)));
233 IF->setInstallName(getInstallName());
234 IF->setCurrentVersion(getCurrentVersion());
235 IF->setCompatibilityVersion(getCompatibilityVersion());
236 IF->setSwiftABIVersion(getSwiftABIVersion());
237 IF->setTwoLevelNamespace(isTwoLevelNamespace());
238 IF->setApplicationExtensionSafe(isApplicationExtensionSafe());
239 for (const auto &It : umbrellas())
240 if (It.first.Arch != Arch)
241 IF->addParentUmbrella(It.first, It.second);
242
243 for (const auto &Lib : allowableClients()) {
244 for (const auto &Target : Lib.targets())
245 if (Target.Arch != Arch)
246 IF->addAllowableClient(Lib.getInstallName(), Target);
247 }
248
249 for (const auto &Lib : reexportedLibraries()) {
250 for (const auto &Target : Lib.targets())
251 if (Target.Arch != Arch)
252 IF->addReexportedLibrary(Lib.getInstallName(), Target);
253 }
254
255 for (const auto *Sym : symbols()) {
256 auto Archs = Sym->getArchitectures();
257 Archs.clear(Arch);
258 if (Archs.empty())
259 continue;
260
261 IF->addSymbol(Sym->getKind(), Sym->getName(), Sym->targets(Archs),
262 Sym->getFlags());
263 }
264
265 for (auto &Doc : Documents) {
266 // Skip the inlined document if the to be removed architecture is the
267 // only one left.
268 if (Doc->getArchitectures() == Arch)
269 continue;
270
271 // If the document doesn't contain the arch, then no work is to be done
272 // and it can be copied over.
273 if (!Doc->getArchitectures().has(Arch)) {
274 auto NewDoc = Doc;
275 IF->addDocument(std::move(NewDoc));
276 continue;
277 }
278
279 auto Result = Doc->remove(Arch);
280 if (!Result)
281 return Result;
282
283 IF->addDocument(std::move(Result.get()));
284 }
285
286 return std::move(IF);
287}
288
291 if (!getArchitectures().has(Arch)) {
292 return make_error<StringError>("file doesn't have architecture '" +
293 getArchitectureName(Arch) + "'",
295 }
296
297 std::unique_ptr<InterfaceFile> IF(new InterfaceFile());
298 IF->setFileType(getFileType());
299 IF->setPath(getPath());
300 IF->addTargets(targets(Arch));
301 IF->setInstallName(getInstallName());
302 IF->setCurrentVersion(getCurrentVersion());
303 IF->setCompatibilityVersion(getCompatibilityVersion());
304 IF->setSwiftABIVersion(getSwiftABIVersion());
305 IF->setTwoLevelNamespace(isTwoLevelNamespace());
306 IF->setApplicationExtensionSafe(isApplicationExtensionSafe());
307 for (const auto &It : umbrellas())
308 if (It.first.Arch == Arch)
309 IF->addParentUmbrella(It.first, It.second);
310
311 for (const auto &It : rpaths())
312 if (It.first.Arch == Arch)
313 IF->addRPath(It.first, It.second);
314
315 for (const auto &Lib : allowableClients())
316 for (const auto &Target : Lib.targets())
317 if (Target.Arch == Arch)
318 IF->addAllowableClient(Lib.getInstallName(), Target);
319
320 for (const auto &Lib : reexportedLibraries())
321 for (const auto &Target : Lib.targets())
322 if (Target.Arch == Arch)
323 IF->addReexportedLibrary(Lib.getInstallName(), Target);
324
325 for (const auto *Sym : symbols()) {
326 if (Sym->hasArchitecture(Arch))
327 IF->addSymbol(Sym->getKind(), Sym->getName(), Sym->targets(Arch),
328 Sym->getFlags());
329 }
330
331 for (auto &Doc : Documents) {
332 // Skip documents that don't have the requested architecture.
333 if (!Doc->getArchitectures().has(Arch))
334 continue;
335
336 auto Result = Doc->extract(Arch);
337 if (!Result)
338 return Result;
339
340 IF->addDocument(std::move(Result.get()));
341 }
342
343 return std::move(IF);
344}
345
346static bool isYAMLTextStub(const FileType &Kind) {
347 return (Kind >= FileType::TBD_V1) && (Kind < FileType::TBD_V5);
348}
349
351 if (Targets != O.Targets)
352 return false;
353 if (InstallName != O.InstallName)
354 return false;
355 if ((CurrentVersion != O.CurrentVersion) ||
356 (CompatibilityVersion != O.CompatibilityVersion))
357 return false;
358 if (SwiftABIVersion != O.SwiftABIVersion)
359 return false;
360 if (IsTwoLevelNamespace != O.IsTwoLevelNamespace)
361 return false;
362 if (IsAppExtensionSafe != O.IsAppExtensionSafe)
363 return false;
364 if (IsOSLibNotForSharedCache != O.IsOSLibNotForSharedCache)
365 return false;
366 if (HasSimSupport != O.HasSimSupport)
367 return false;
368 if (ParentUmbrellas != O.ParentUmbrellas)
369 return false;
370 if (AllowableClients != O.AllowableClients)
371 return false;
372 if (ReexportedLibraries != O.ReexportedLibraries)
373 return false;
374 if (*SymbolsSet != *O.SymbolsSet)
375 return false;
376 // Don't compare run search paths for older filetypes that cannot express
377 // them.
378 if (!(isYAMLTextStub(FileKind)) && !(isYAMLTextStub(O.FileKind))) {
379 if (RPaths != O.RPaths)
380 return false;
381 if (mapToPlatformVersionSet(Targets) != mapToPlatformVersionSet(O.Targets))
382 return false;
383 }
384
385 if (!std::equal(Documents.begin(), Documents.end(), O.Documents.begin(),
386 O.Documents.end(),
387 [](const std::shared_ptr<InterfaceFile> LHS,
388 const std::shared_ptr<InterfaceFile> RHS) {
389 return *LHS == *RHS;
390 }))
391 return false;
392 return true;
393}
static void clear(coro::Shape &Shape)
Definition: Coroutines.cpp:145
Symbol * Sym
Definition: ELF_riscv.cpp:477
static bool isYAMLTextStub(const FileType &Kind)
Define TAPI specific error codes.
Value * RHS
Value * LHS
Tagged union holding either a T or a Error.
Definition: Error.h:474
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 addParentUmbrella(const Target &Target_, StringRef Parent)
Set the parent umbrella frameworks.
const_target_range targets() const
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.
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
uint8_t getSwiftABIVersion() const
Get the Swift ABI version of the library.
PackedVersion getCurrentVersion() const
Get the current 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 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 addRPath(const Target &InputTarget, StringRef RPath)
Set the runpath search paths.
llvm::Expected< std::unique_ptr< InterfaceFile > > extract(Architecture Arch) const
Extract architecture slice from Interface.
SymbolFlags getFlags() const
Definition: Symbol.h:93
bool hasArchitecture(Architecture Arch) const
Definition: Symbol.h:124
const_target_range targets() const
Definition: Symbol.h:134
SymbolKind getKind() const
Definition: Symbol.h:88
ArchitectureSet getArchitectures() const
Definition: Symbol.h:90
StringRef getName() const
Definition: Symbol.h:89
Architecture Arch
Definition: Target.h:42
StringRef - Represent a constant reference to a string, i.e.
Definition: StringRef.h:50
A range adaptor for a pair of iterators.
FileType
Defines the file type this file represents.
Definition: InterfaceFile.h:53
@ TBD_V1
Text-based stub file (.tbd) version 1.0.
Definition: InterfaceFile.h:67
@ TBD_V5
Text-based stub file (.tbd) version 5.0.
Definition: InterfaceFile.h:79
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:90
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:581
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:1945