1 //===- InterfaceFile.cpp --------------------------------------------------===//
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
7 //===----------------------------------------------------------------------===//
9 // Implements the Interface File.
11 //===----------------------------------------------------------------------===//
13 #include "llvm/TextAPI/InterfaceFile.h"
14 #include "llvm/TextAPI/TextAPIError.h"
19 using namespace llvm::MachO
;
21 void InterfaceFileRef::addTarget(const Target
&Target
) {
22 addEntry(Targets
, Target
);
25 void InterfaceFile::addAllowableClient(StringRef InstallName
,
26 const Target
&Target
) {
27 auto Client
= addEntry(AllowableClients
, InstallName
);
28 Client
->addTarget(Target
);
31 void InterfaceFile::addReexportedLibrary(StringRef InstallName
,
32 const Target
&Target
) {
33 auto Lib
= addEntry(ReexportedLibraries
, InstallName
);
34 Lib
->addTarget(Target
);
37 void InterfaceFile::addParentUmbrella(const Target
&Target_
, StringRef Parent
) {
38 auto Iter
= lower_bound(ParentUmbrellas
, Target_
,
39 [](const std::pair
<Target
, std::string
> &LHS
,
40 Target RHS
) { return LHS
.first
< RHS
; });
42 if ((Iter
!= ParentUmbrellas
.end()) && !(Target_
< Iter
->first
)) {
43 Iter
->second
= std::string(Parent
);
47 ParentUmbrellas
.emplace(Iter
, Target_
, std::string(Parent
));
50 void InterfaceFile::addRPath(const Target
&InputTarget
, StringRef RPath
) {
51 using RPathEntryT
= const std::pair
<Target
, std::string
>;
52 RPathEntryT
Entry(InputTarget
, RPath
);
54 lower_bound(RPaths
, Entry
,
55 [](RPathEntryT
&LHS
, RPathEntryT
&RHS
) { return LHS
< RHS
; });
57 if ((Iter
!= RPaths
.end()) && (*Iter
== Entry
))
60 RPaths
.emplace(Iter
, Entry
);
63 void InterfaceFile::addTarget(const Target
&Target
) {
64 addEntry(Targets
, Target
);
67 InterfaceFile::const_filtered_target_range
68 InterfaceFile::targets(ArchitectureSet Archs
) const {
69 std::function
<bool(const Target
&)> fn
= [Archs
](const Target
&Target_
) {
70 return Archs
.has(Target_
.Arch
);
72 return make_filter_range(Targets
, fn
);
75 void 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
;
81 Document
->Parent
= this;
82 Documents
.insert(Pos
, Document
);
85 void InterfaceFile::inlineLibrary(std::shared_ptr
<InterfaceFile
> Library
,
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
;
94 if (Overwrite
&& It
!= Documents
.end() &&
95 Reexport
->getInstallName() == (*It
)->getInstallName()) {
96 std::replace(Documents
.begin(), Documents
.end(), *It
,
101 if ((It
!= Documents
.end()) &&
102 !(Reexport
->getInstallName() < (*It
)->getInstallName()))
105 Documents
.emplace(It
, std::move(Reexport
));
107 for (auto Doc
: Library
->documents())
108 AddFwk(std::move(Doc
));
110 Library
->Documents
.clear();
111 AddFwk(std::move(Library
));
114 Expected
<std::unique_ptr
<InterfaceFile
>>
115 InterfaceFile::merge(const InterfaceFile
*O
) const {
116 // Verify files can be merged.
117 if (getInstallName() != O
->getInstallName()) {
118 return make_error
<StringError
>("install names do not match",
119 inconvertibleErrorCode());
122 if (getCurrentVersion() != O
->getCurrentVersion()) {
123 return make_error
<StringError
>("current versions do not match",
124 inconvertibleErrorCode());
127 if (getCompatibilityVersion() != O
->getCompatibilityVersion()) {
128 return make_error
<StringError
>("compatibility versions do not match",
129 inconvertibleErrorCode());
132 if ((getSwiftABIVersion() != 0) && (O
->getSwiftABIVersion() != 0) &&
133 (getSwiftABIVersion() != O
->getSwiftABIVersion())) {
134 return make_error
<StringError
>("swift ABI versions do not match",
135 inconvertibleErrorCode());
138 if (isTwoLevelNamespace() != O
->isTwoLevelNamespace()) {
139 return make_error
<StringError
>("two level namespace flags do not match",
140 inconvertibleErrorCode());
143 if (isApplicationExtensionSafe() != O
->isApplicationExtensionSafe()) {
144 return make_error
<StringError
>(
145 "application extension safe flags do not match",
146 inconvertibleErrorCode());
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());
156 if (getSwiftABIVersion() == 0)
157 IF
->setSwiftABIVersion(O
->getSwiftABIVersion());
159 IF
->setSwiftABIVersion(getSwiftABIVersion());
161 IF
->setTwoLevelNamespace(isTwoLevelNamespace());
162 IF
->setApplicationExtensionSafe(isApplicationExtensionSafe());
164 for (const auto &It
: umbrellas()) {
165 if (!It
.second
.empty())
166 IF
->addParentUmbrella(It
.first
, It
.second
);
168 for (const auto &It
: O
->umbrellas()) {
169 if (!It
.second
.empty())
170 IF
->addParentUmbrella(It
.first
, It
.second
);
172 IF
->addTargets(targets());
173 IF
->addTargets(O
->targets());
175 for (const auto &Lib
: allowableClients())
176 for (const auto &Target
: Lib
.targets())
177 IF
->addAllowableClient(Lib
.getInstallName(), Target
);
179 for (const auto &Lib
: O
->allowableClients())
180 for (const auto &Target
: Lib
.targets())
181 IF
->addAllowableClient(Lib
.getInstallName(), Target
);
183 for (const auto &Lib
: reexportedLibraries())
184 for (const auto &Target
: Lib
.targets())
185 IF
->addReexportedLibrary(Lib
.getInstallName(), Target
);
187 for (const auto &Lib
: O
->reexportedLibraries())
188 for (const auto &Target
: Lib
.targets())
189 IF
->addReexportedLibrary(Lib
.getInstallName(), Target
);
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
);
196 for (const auto *Sym
: symbols()) {
197 IF
->addSymbol(Sym
->getKind(), Sym
->getName(), Sym
->targets(),
201 for (const auto *Sym
: O
->symbols()) {
202 IF
->addSymbol(Sym
->getKind(), Sym
->getName(), Sym
->targets(),
206 return std::move(IF
);
209 Expected
<std::unique_ptr
<InterfaceFile
>>
210 InterfaceFile::remove(Architecture Arch
) const {
211 if (getArchitectures() == Arch
)
212 return make_error
<StringError
>("cannot remove last architecture slice '" +
213 getArchitectureName(Arch
) + "'",
214 inconvertibleErrorCode());
216 if (!getArchitectures().has(Arch
)) {
218 for (auto &Doc
: Documents
) {
219 if (Doc
->getArchitectures().has(Arch
)) {
226 return make_error
<TextAPIError
>(TextAPIErrorCode::NoSuchArchitecture
);
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
);
243 for (const auto &Lib
: allowableClients()) {
244 for (const auto &Target
: Lib
.targets())
245 if (Target
.Arch
!= Arch
)
246 IF
->addAllowableClient(Lib
.getInstallName(), Target
);
249 for (const auto &Lib
: reexportedLibraries()) {
250 for (const auto &Target
: Lib
.targets())
251 if (Target
.Arch
!= Arch
)
252 IF
->addReexportedLibrary(Lib
.getInstallName(), Target
);
255 for (const auto *Sym
: symbols()) {
256 auto Archs
= Sym
->getArchitectures();
261 IF
->addSymbol(Sym
->getKind(), Sym
->getName(), Sym
->targets(Archs
),
265 for (auto &Doc
: Documents
) {
266 // Skip the inlined document if the to be removed architecture is the
268 if (Doc
->getArchitectures() == Arch
)
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
)) {
275 IF
->addDocument(std::move(NewDoc
));
279 auto Result
= Doc
->remove(Arch
);
283 IF
->addDocument(std::move(Result
.get()));
286 return std::move(IF
);
289 Expected
<std::unique_ptr
<InterfaceFile
>>
290 InterfaceFile::extract(Architecture Arch
) const {
291 if (!getArchitectures().has(Arch
)) {
292 return make_error
<StringError
>("file doesn't have architecture '" +
293 getArchitectureName(Arch
) + "'",
294 inconvertibleErrorCode());
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
);
311 for (const auto &It
: rpaths())
312 if (It
.first
.Arch
== Arch
)
313 IF
->addRPath(It
.first
, It
.second
);
315 for (const auto &Lib
: allowableClients())
316 for (const auto &Target
: Lib
.targets())
317 if (Target
.Arch
== Arch
)
318 IF
->addAllowableClient(Lib
.getInstallName(), Target
);
320 for (const auto &Lib
: reexportedLibraries())
321 for (const auto &Target
: Lib
.targets())
322 if (Target
.Arch
== Arch
)
323 IF
->addReexportedLibrary(Lib
.getInstallName(), Target
);
325 for (const auto *Sym
: symbols()) {
326 if (Sym
->hasArchitecture(Arch
))
327 IF
->addSymbol(Sym
->getKind(), Sym
->getName(), Sym
->targets(Arch
),
331 for (auto &Doc
: Documents
) {
332 // Skip documents that don't have the requested architecture.
333 if (!Doc
->getArchitectures().has(Arch
))
336 auto Result
= Doc
->extract(Arch
);
340 IF
->addDocument(std::move(Result
.get()));
343 return std::move(IF
);
346 static bool isYAMLTextStub(const FileType
&Kind
) {
347 return (Kind
>= FileType::TBD_V1
) && (Kind
< FileType::TBD_V5
);
350 bool InterfaceFile::operator==(const InterfaceFile
&O
) const {
351 if (Targets
!= O
.Targets
)
353 if (InstallName
!= O
.InstallName
)
355 if ((CurrentVersion
!= O
.CurrentVersion
) ||
356 (CompatibilityVersion
!= O
.CompatibilityVersion
))
358 if (SwiftABIVersion
!= O
.SwiftABIVersion
)
360 if (IsTwoLevelNamespace
!= O
.IsTwoLevelNamespace
)
362 if (IsAppExtensionSafe
!= O
.IsAppExtensionSafe
)
364 if (HasSimSupport
!= O
.HasSimSupport
)
366 if (ParentUmbrellas
!= O
.ParentUmbrellas
)
368 if (AllowableClients
!= O
.AllowableClients
)
370 if (ReexportedLibraries
!= O
.ReexportedLibraries
)
372 if (*SymbolsSet
!= *O
.SymbolsSet
)
374 // Don't compare run search paths for older filetypes that cannot express
376 if (!(isYAMLTextStub(FileKind
)) && !(isYAMLTextStub(O
.FileKind
))) {
377 if (RPaths
!= O
.RPaths
)
379 if (mapToPlatformVersionSet(Targets
) != mapToPlatformVersionSet(O
.Targets
))
383 if (!std::equal(Documents
.begin(), Documents
.end(), O
.Documents
.begin(),
385 [](const std::shared_ptr
<InterfaceFile
> LHS
,
386 const std::shared_ptr
<InterfaceFile
> RHS
) {