LLVM 22.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
17using namespace llvm;
18using namespace llvm::MachO;
19
21 addEntry(Targets, Target);
22}
23
25 const Target &Target) {
26 if (InstallName.empty())
27 return;
28 auto Client = addEntry(AllowableClients, InstallName);
29 Client->addTarget(Target);
30}
31
33 const Target &Target) {
34 if (InstallName.empty())
35 return;
36 auto Lib = addEntry(ReexportedLibraries, InstallName);
37 Lib->addTarget(Target);
38}
39
41 if (Parent.empty())
42 return;
43 auto Iter = lower_bound(ParentUmbrellas, Target_,
44 [](const std::pair<Target, std::string> &LHS,
45 Target RHS) { return LHS.first < RHS; });
46
47 if ((Iter != ParentUmbrellas.end()) && !(Target_ < Iter->first)) {
48 Iter->second = std::string(Parent);
49 return;
50 }
51
52 ParentUmbrellas.emplace(Iter, Target_, std::string(Parent));
53}
54
55void InterfaceFile::addRPath(StringRef RPath, const Target &InputTarget) {
56 if (RPath.empty())
57 return;
58 using RPathEntryT = const std::pair<Target, std::string>;
59 RPathEntryT Entry(InputTarget, RPath);
60
61 if (is_contained(RPaths, Entry))
62 return;
63
64 RPaths.emplace_back(Entry);
65}
66
68 addEntry(Targets, Target);
69}
70
73 std::function<bool(const Target &)> fn = [Archs](const Target &Target_) {
74 return Archs.has(Target_.Arch);
75 };
76 return make_filter_range(Targets, fn);
77}
78
79void InterfaceFile::addDocument(std::shared_ptr<InterfaceFile> &&Document) {
80 auto Pos = llvm::lower_bound(Documents, Document,
81 [](const std::shared_ptr<InterfaceFile> &LHS,
82 const std::shared_ptr<InterfaceFile> &RHS) {
83 return LHS->InstallName < RHS->InstallName;
84 });
85 assert((Pos == Documents.end() ||
86 (*Pos)->InstallName != Document->InstallName) &&
87 "Unexpected duplicate document added");
88 Document->Parent = this;
89 Documents.insert(Pos, Document);
90}
91
92void InterfaceFile::inlineLibrary(std::shared_ptr<InterfaceFile> Library,
93 bool Overwrite) {
94 auto AddFwk = [&](std::shared_ptr<InterfaceFile> &&Reexport) {
95 auto It = lower_bound(
96 Documents, Reexport->getInstallName(),
97 [](std::shared_ptr<InterfaceFile> &Lhs, const StringRef Rhs) {
98 return Lhs->getInstallName() < Rhs;
99 });
100
101 if (Overwrite && It != Documents.end() &&
102 Reexport->getInstallName() == (*It)->getInstallName()) {
103 llvm::replace(Documents, *It, std::move(Reexport));
104 return;
105 }
106
107 if ((It != Documents.end()) &&
108 !(Reexport->getInstallName() < (*It)->getInstallName()))
109 return;
110
111 Documents.emplace(It, std::move(Reexport));
112 };
113 for (auto Doc : Library->documents())
114 AddFwk(std::move(Doc));
115
116 Library->Documents.clear();
117 AddFwk(std::move(Library));
118}
119
122 // Verify files can be merged.
123 if (getInstallName() != O->getInstallName()) {
124 return make_error<StringError>("install names do not match",
126 }
127
128 if (getCurrentVersion() != O->getCurrentVersion()) {
129 return make_error<StringError>("current versions do not match",
131 }
132
133 if (getCompatibilityVersion() != O->getCompatibilityVersion()) {
134 return make_error<StringError>("compatibility versions do not match",
136 }
137
138 if ((getSwiftABIVersion() != 0) && (O->getSwiftABIVersion() != 0) &&
139 (getSwiftABIVersion() != O->getSwiftABIVersion())) {
140 return make_error<StringError>("swift ABI versions do not match",
142 }
143
144 if (isTwoLevelNamespace() != O->isTwoLevelNamespace()) {
145 return make_error<StringError>("two level namespace flags do not match",
147 }
148
149 if (isApplicationExtensionSafe() != O->isApplicationExtensionSafe()) {
150 return make_error<StringError>(
151 "application extension safe flags do not match",
153 }
154
155 std::unique_ptr<InterfaceFile> IF(new InterfaceFile());
156 IF->setFileType(std::max(getFileType(), O->getFileType()));
157 IF->setPath(getPath());
158 IF->setInstallName(getInstallName());
159 IF->setCurrentVersion(getCurrentVersion());
160 IF->setCompatibilityVersion(getCompatibilityVersion());
161
162 if (getSwiftABIVersion() == 0)
163 IF->setSwiftABIVersion(O->getSwiftABIVersion());
164 else
165 IF->setSwiftABIVersion(getSwiftABIVersion());
166
167 IF->setTwoLevelNamespace(isTwoLevelNamespace());
168 IF->setApplicationExtensionSafe(isApplicationExtensionSafe());
169 IF->setOSLibNotForSharedCache(isOSLibNotForSharedCache());
170
171 for (const auto &It : umbrellas()) {
172 if (!It.second.empty())
173 IF->addParentUmbrella(It.first, It.second);
174 }
175 for (const auto &It : O->umbrellas()) {
176 if (!It.second.empty())
177 IF->addParentUmbrella(It.first, It.second);
178 }
179 IF->addTargets(targets());
180 IF->addTargets(O->targets());
181
182 for (const auto &Lib : allowableClients())
183 for (const auto &Target : Lib.targets())
184 IF->addAllowableClient(Lib.getInstallName(), Target);
185
186 for (const auto &Lib : O->allowableClients())
187 for (const auto &Target : Lib.targets())
188 IF->addAllowableClient(Lib.getInstallName(), Target);
189
190 for (const auto &Lib : reexportedLibraries())
191 for (const auto &Target : Lib.targets())
192 IF->addReexportedLibrary(Lib.getInstallName(), Target);
193
194 for (const auto &Lib : O->reexportedLibraries())
195 for (const auto &Target : Lib.targets())
196 IF->addReexportedLibrary(Lib.getInstallName(), Target);
197
198 for (const auto &[Target, Path] : rpaths())
199 IF->addRPath(Path, Target);
200 for (const auto &[Target, Path] : O->rpaths())
201 IF->addRPath(Path, Target);
202
203 for (const auto *Sym : symbols()) {
204 IF->addSymbol(Sym->getKind(), Sym->getName(), Sym->targets(),
205 Sym->getFlags());
206 }
207
208 for (const auto *Sym : O->symbols()) {
209 IF->addSymbol(Sym->getKind(), Sym->getName(), Sym->targets(),
210 Sym->getFlags());
211 }
212
213 return std::move(IF);
214}
215
218 if (getArchitectures() == Arch)
219 return make_error<StringError>("cannot remove last architecture slice '" +
220 getArchitectureName(Arch) + "'",
222
223 if (!getArchitectures().has(Arch)) {
224 bool Found = false;
225 for (auto &Doc : Documents) {
226 if (Doc->getArchitectures().has(Arch)) {
227 Found = true;
228 break;
229 }
230 }
231
232 if (!Found)
233 return make_error<TextAPIError>(TextAPIErrorCode::NoSuchArchitecture);
234 }
235
236 // FIXME: Figure out how to keep these attributes in sync when new ones are
237 // added.
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 IF->setOSLibNotForSharedCache(isOSLibNotForSharedCache());
249 for (const auto &It : umbrellas())
250 if (It.first.Arch != Arch)
251 IF->addParentUmbrella(It.first, It.second);
252
253 for (const auto &Lib : allowableClients()) {
254 for (const auto &Target : Lib.targets())
255 if (Target.Arch != Arch)
256 IF->addAllowableClient(Lib.getInstallName(), Target);
257 }
258
259 for (const auto &Lib : reexportedLibraries()) {
260 for (const auto &Target : Lib.targets())
261 if (Target.Arch != Arch)
262 IF->addReexportedLibrary(Lib.getInstallName(), Target);
263 }
264
265 for (const auto *Sym : symbols()) {
266 auto Archs = Sym->getArchitectures();
267 Archs.clear(Arch);
268 if (Archs.empty())
269 continue;
270
271 IF->addSymbol(Sym->getKind(), Sym->getName(), Sym->targets(Archs),
272 Sym->getFlags());
273 }
274
275 for (auto &Doc : Documents) {
276 // Skip the inlined document if the to be removed architecture is the
277 // only one left.
278 if (Doc->getArchitectures() == Arch)
279 continue;
280
281 // If the document doesn't contain the arch, then no work is to be done
282 // and it can be copied over.
283 if (!Doc->getArchitectures().has(Arch)) {
284 auto NewDoc = Doc;
285 IF->addDocument(std::move(NewDoc));
286 continue;
287 }
288
289 auto Result = Doc->remove(Arch);
290 if (!Result)
291 return Result;
292
293 IF->addDocument(std::move(Result.get()));
294 }
295
296 return std::move(IF);
297}
298
301 if (!getArchitectures().has(Arch)) {
302 return make_error<StringError>("file doesn't have architecture '" +
303 getArchitectureName(Arch) + "'",
305 }
306
307 std::unique_ptr<InterfaceFile> IF(new InterfaceFile());
308 IF->setFileType(getFileType());
309 IF->setPath(getPath());
310 IF->addTargets(targets(Arch));
311 IF->setInstallName(getInstallName());
312 IF->setCurrentVersion(getCurrentVersion());
313 IF->setCompatibilityVersion(getCompatibilityVersion());
314 IF->setSwiftABIVersion(getSwiftABIVersion());
315 IF->setTwoLevelNamespace(isTwoLevelNamespace());
316 IF->setApplicationExtensionSafe(isApplicationExtensionSafe());
317 IF->setOSLibNotForSharedCache(isOSLibNotForSharedCache());
318 for (const auto &It : umbrellas())
319 if (It.first.Arch == Arch)
320 IF->addParentUmbrella(It.first, It.second);
321
322 for (const auto &It : rpaths())
323 if (It.first.Arch == Arch)
324 IF->addRPath(It.second, It.first);
325
326 for (const auto &Lib : allowableClients())
327 for (const auto &Target : Lib.targets())
328 if (Target.Arch == Arch)
329 IF->addAllowableClient(Lib.getInstallName(), Target);
330
331 for (const auto &Lib : reexportedLibraries())
332 for (const auto &Target : Lib.targets())
333 if (Target.Arch == Arch)
334 IF->addReexportedLibrary(Lib.getInstallName(), Target);
335
336 for (const auto *Sym : symbols()) {
337 if (Sym->hasArchitecture(Arch))
338 IF->addSymbol(Sym->getKind(), Sym->getName(), Sym->targets(Arch),
339 Sym->getFlags());
340 }
341
342 for (auto &Doc : Documents) {
343 // Skip documents that don't have the requested architecture.
344 if (!Doc->getArchitectures().has(Arch))
345 continue;
346
347 auto Result = Doc->extract(Arch);
348 if (!Result)
349 return Result;
350
351 IF->addDocument(std::move(Result.get()));
352 }
353
354 return std::move(IF);
355}
356
358 const Target &Targ) {
359 if (getFileType() != BA.File)
360 setFileType(BA.File);
361 if (getInstallName().empty())
369 if (getCurrentVersion().empty())
371 if (getCompatibilityVersion().empty())
373 if (getSwiftABIVersion() == 0)
375 if (getPath().empty())
376 setPath(BA.Path);
377 if (!BA.ParentUmbrella.empty())
379 for (const auto &Client : BA.AllowableClients)
380 addAllowableClient(Client, Targ);
381 for (const auto &Lib : BA.RexportedLibraries)
383}
384
385static bool isYAMLTextStub(const FileType &Kind) {
386 return (Kind >= FileType::TBD_V1) && (Kind < FileType::TBD_V5);
387}
388
390 if (Targets != O.Targets)
391 return false;
392 if (InstallName != O.InstallName)
393 return false;
394 if ((CurrentVersion != O.CurrentVersion) ||
395 (CompatibilityVersion != O.CompatibilityVersion))
396 return false;
397 if (SwiftABIVersion != O.SwiftABIVersion)
398 return false;
399 if (IsTwoLevelNamespace != O.IsTwoLevelNamespace)
400 return false;
401 if (IsAppExtensionSafe != O.IsAppExtensionSafe)
402 return false;
403 if (IsOSLibNotForSharedCache != O.IsOSLibNotForSharedCache)
404 return false;
405 if (HasSimSupport != O.HasSimSupport)
406 return false;
407 if (ParentUmbrellas != O.ParentUmbrellas)
408 return false;
409 if (AllowableClients != O.AllowableClients)
410 return false;
411 if (ReexportedLibraries != O.ReexportedLibraries)
412 return false;
413 if (*SymbolsSet != *O.SymbolsSet)
414 return false;
415 // Don't compare run search paths for older filetypes that cannot express
416 // them.
417 if (!(isYAMLTextStub(FileKind)) && !(isYAMLTextStub(O.FileKind))) {
418 if (RPaths != O.RPaths)
419 return false;
420 if (mapToPlatformVersionSet(Targets) != mapToPlatformVersionSet(O.Targets))
421 return false;
422 }
423
424 if (!std::equal(Documents.begin(), Documents.end(), O.Documents.begin(),
425 O.Documents.end(),
426 [](const std::shared_ptr<InterfaceFile> LHS,
427 const std::shared_ptr<InterfaceFile> RHS) {
428 return *LHS == *RHS;
429 }))
430 return false;
431 return true;
432}
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
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:485
static ArchitectureSet All()
ArchitectureSet clear(Architecture Arch)
bool has(Architecture Arch) const
LLVM_ABI void addTarget(const Target &Target)
Defines the interface file.
LLVM_ABI 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).
LLVM_ABI 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).
LLVM_ABI void setFromBinaryAttrs(const RecordsSlice::BinaryAttrs &BA, const Target &Targ)
Set InterfaceFile properties from pre-gathered binary attributes, if they are not set already.
LLVM_ABI 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_ABI 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.
LLVM_ABI 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.
LLVM_ABI 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.
LLVM_ABI 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_ABI 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).
LLVM_ABI void addAllowableClient(StringRef InstallName, const Target &Target)
Add an allowable client.
LLVM_ABI 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_ABI 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:108
bool hasArchitecture(Architecture Arch) const
Definition: Symbol.h:139
const_target_range targets() const
Definition: Symbol.h:149
ArchitectureSet getArchitectures() const
Definition: Symbol.h:105
StringRef getName() const
Definition: Symbol.h:104
EncodeKind getKind() const
Definition: Symbol.h:103
Architecture Arch
Definition: Target.h:43
StringRef - Represent a constant reference to a string, i.e.
Definition: StringRef.h:55
constexpr bool empty() const
empty - Check if the string is empty.
Definition: StringRef.h:151
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
LLVM_ABI 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:28
LLVM_ABI PlatformVersionSet mapToPlatformVersionSet(ArrayRef< Target > Targets)
Definition: Target.cpp:55
This is an optimization pass for GlobalISel generic memory operations.
Definition: AddressRanges.h:18
LLVM_ABI 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: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:2013
void replace(R &&Range, const T &OldValue, const T &NewValue)
Provide wrappers to std::replace which take ranges instead of having to pass begin/end explicitly.
Definition: STLExtras.h:1879
bool is_contained(R &&Range, const E &Element)
Returns true if Element is found in Range.
Definition: STLExtras.h:1916
std::vector< StringRef > RexportedLibraries
Definition: RecordsSlice.h:150
std::vector< StringRef > AllowableClients
Definition: RecordsSlice.h:149
llvm::MachO::PackedVersion CompatVersion
Definition: RecordsSlice.h:158
llvm::MachO::PackedVersion CurrentVersion
Definition: RecordsSlice.h:157