LLVM 19.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(const Target &InputTarget, StringRef RPath) {
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 Document->Parent = this;
91 Documents.insert(Pos, Document);
92}
93
94void 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
125 // Verify files can be merged.
126 if (getInstallName() != O->getInstallName()) {
127 return make_error<StringError>("install names do not match",
129 }
130
131 if (getCurrentVersion() != O->getCurrentVersion()) {
132 return make_error<StringError>("current versions do not match",
134 }
135
136 if (getCompatibilityVersion() != O->getCompatibilityVersion()) {
137 return make_error<StringError>("compatibility versions do not match",
139 }
140
141 if ((getSwiftABIVersion() != 0) && (O->getSwiftABIVersion() != 0) &&
142 (getSwiftABIVersion() != O->getSwiftABIVersion())) {
143 return make_error<StringError>("swift ABI versions do not match",
145 }
146
147 if (isTwoLevelNamespace() != O->isTwoLevelNamespace()) {
148 return make_error<StringError>("two level namespace flags do not match",
150 }
151
152 if (isApplicationExtensionSafe() != O->isApplicationExtensionSafe()) {
153 return make_error<StringError>(
154 "application extension safe flags do not match",
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(Target, Path);
202 for (const auto &[Target, Path] : O->rpaths())
203 IF->addRPath(Target, Path);
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
220 if (getArchitectures() == Arch)
221 return make_error<StringError>("cannot remove last architecture slice '" +
222 getArchitectureName(Arch) + "'",
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
300 if (!getArchitectures().has(Arch)) {
301 return make_error<StringError>("file doesn't have architecture '" +
302 getArchitectureName(Arch) + "'",
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.first, It.second);
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
356 const Target &Targ) {
357 if (getFileType() != BA.File)
358 setFileType(BA.File);
359 if (getInstallName().empty())
367 if (getCurrentVersion().empty())
369 if (getCompatibilityVersion().empty())
371 if (getSwiftABIVersion() == 0)
373 if (getPath().empty())
374 setPath(BA.Path);
375 if (!BA.ParentUmbrella.empty())
377 for (const auto &Client : BA.AllowableClients)
378 addAllowableClient(Client, Targ);
379 for (const auto &Lib : BA.RexportedLibraries)
381}
382
383static bool isYAMLTextStub(const FileType &Kind) {
384 return (Kind >= FileType::TBD_V1) && (Kind < FileType::TBD_V5);
385}
386
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}
static void clear(coro::Shape &Shape)
Definition: Coroutines.cpp:145
Symbol * Sym
Definition: ELF_riscv.cpp:479
static bool isYAMLTextStub(const FileType &Kind)
Implements the TAPI Record Collection Type.
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 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 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 addRPath(const Target &InputTarget, StringRef RPath)
Set the runpath search paths.
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: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:1950
std::vector< StringRef > RexportedLibraries
Definition: RecordsSlice.h:141
std::vector< StringRef > AllowableClients
Definition: RecordsSlice.h:140
llvm::MachO::PackedVersion CompatVersion
Definition: RecordsSlice.h:149
llvm::MachO::PackedVersion CurrentVersion
Definition: RecordsSlice.h:148