[llvm] 16c1f43 - [TextAPI] Add functionality to manipulate over InterfaceFiles
Cyndy Ishida via llvm-commits
llvm-commits at lists.llvm.org
Tue Jul 25 09:24:50 PDT 2023
Author: Cyndy Ishida
Date: 2023-07-25T09:23:57-07:00
New Revision: 16c1f43642e40dbc0d59fcf68ed1682dbf4d87bd
URL: https://github.com/llvm/llvm-project/commit/16c1f43642e40dbc0d59fcf68ed1682dbf4d87bd
DIFF: https://github.com/llvm/llvm-project/commit/16c1f43642e40dbc0d59fcf68ed1682dbf4d87bd.diff
LOG: [TextAPI] Add functionality to manipulate over InterfaceFiles
InterfaceFile is the in-memory representation for tbd files. Add APIs to
merge, extract, remove, and inline reexported libraries.
Reviewed By: zixuw
Differential Revision: https://reviews.llvm.org/D153398
Added:
llvm/include/llvm/TextAPI/TextAPIError.h
llvm/lib/TextAPI/TextAPIError.cpp
Modified:
llvm/include/llvm/TextAPI/ArchitectureSet.h
llvm/include/llvm/TextAPI/InterfaceFile.h
llvm/include/llvm/TextAPI/Symbol.h
llvm/lib/TextAPI/CMakeLists.txt
llvm/lib/TextAPI/InterfaceFile.cpp
llvm/unittests/TextAPI/TextStubV5Tests.cpp
Removed:
################################################################################
diff --git a/llvm/include/llvm/TextAPI/ArchitectureSet.h b/llvm/include/llvm/TextAPI/ArchitectureSet.h
index f17cb74c91839b..2cce9dbf0d80c3 100644
--- a/llvm/include/llvm/TextAPI/ArchitectureSet.h
+++ b/llvm/include/llvm/TextAPI/ArchitectureSet.h
@@ -40,13 +40,18 @@ class ArchitectureSet {
ArchitectureSet(Architecture Arch) : ArchitectureSet() { set(Arch); }
ArchitectureSet(const std::vector<Architecture> &Archs);
+ static ArchitectureSet All() { return ArchitectureSet(EndIndexVal); }
+
void set(Architecture Arch) {
if (Arch == AK_unknown)
return;
ArchSet |= 1U << static_cast<int>(Arch);
}
- void clear(Architecture Arch) { ArchSet &= ~(1U << static_cast<int>(Arch)); }
+ ArchitectureSet clear(Architecture Arch) {
+ ArchSet &= ~(1U << static_cast<int>(Arch));
+ return ArchSet;
+ }
bool has(Architecture Arch) const {
return ArchSet & (1U << static_cast<int>(Arch));
diff --git a/llvm/include/llvm/TextAPI/InterfaceFile.h b/llvm/include/llvm/TextAPI/InterfaceFile.h
index 2f89605d24baec..7966ec8e70cdff 100644
--- a/llvm/include/llvm/TextAPI/InterfaceFile.h
+++ b/llvm/include/llvm/TextAPI/InterfaceFile.h
@@ -372,6 +372,37 @@ class InterfaceFile {
return SymbolsSet->undefineds();
};
+ /// Extract architecture slice from Interface.
+ ///
+ /// \param Arch architecture to extract from.
+ /// \return New InterfaceFile with extracted architecture slice.
+ llvm::Expected<std::unique_ptr<InterfaceFile>>
+ extract(Architecture Arch) const;
+
+ /// Remove architecture slice from Interface.
+ ///
+ /// \param Arch architecture to remove.
+ /// \return New Interface File with removed architecture slice.
+ llvm::Expected<std::unique_ptr<InterfaceFile>>
+ remove(Architecture Arch) const;
+
+ /// Merge Interfaces for the same library. The following library attributes
+ /// must match.
+ /// * Install name, Current & Compatibility version,
+ /// * Two-level namespace enablement, and App extension enablement.
+ ///
+ /// \param O The Interface to merge.
+ /// \return New Interface File that was merged.
+ llvm::Expected<std::unique_ptr<InterfaceFile>>
+ merge(const InterfaceFile *O) const;
+
+ /// Inline reexported library into Interface.
+ ///
+ /// \param Library Interface of reexported library.
+ /// \param Overwrite Whether to overwrite preexisting inlined library.
+ void inlineLibrary(std::shared_ptr<InterfaceFile> Library,
+ bool Overwrite = false);
+
/// The equality is determined by attributes that impact linking
/// compatibilities. Path, & FileKind are irrelevant since these by
/// itself should not impact linking.
diff --git a/llvm/include/llvm/TextAPI/Symbol.h b/llvm/include/llvm/TextAPI/Symbol.h
index a20fcc785b4097..63c21c50e9c39c 100644
--- a/llvm/include/llvm/TextAPI/Symbol.h
+++ b/llvm/include/llvm/TextAPI/Symbol.h
@@ -121,6 +121,10 @@ class Symbol {
return (Flags & SymbolFlags::Text) == SymbolFlags::Text;
}
+ bool hasArchitecture(Architecture Arch) const {
+ return mapToArchitectureSet(Targets).contains(Arch);
+ }
+
using const_target_iterator = TargetList::const_iterator;
using const_target_range = llvm::iterator_range<const_target_iterator>;
const_target_range targets() const { return {Targets}; }
diff --git a/llvm/include/llvm/TextAPI/TextAPIError.h b/llvm/include/llvm/TextAPI/TextAPIError.h
new file mode 100644
index 00000000000000..566890db4b89a8
--- /dev/null
+++ b/llvm/include/llvm/TextAPI/TextAPIError.h
@@ -0,0 +1,38 @@
+//===- llvm/TextAPI/TextAPIError.h - TAPI Error -----------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// \brief Define TAPI specific error codes.
+///
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_TEXTAPI_TEXTAPIERROR_H
+#define LLVM_TEXTAPI_TEXTAPIERROR_H
+
+#include "llvm/Support/Error.h"
+
+namespace llvm::MachO {
+enum class TextAPIErrorCode {
+ NoSuchArchitecture,
+ EmptyResults,
+ GenericFrontendError,
+};
+
+class TextAPIError : public llvm::ErrorInfo<TextAPIError> {
+public:
+ static char ID;
+ TextAPIErrorCode EC;
+
+ TextAPIError(TextAPIErrorCode EC) : EC(EC) {}
+
+ void log(raw_ostream &OS) const override;
+ std::error_code convertToErrorCode() const override;
+};
+
+} // namespace llvm::MachO
+#endif // LLVM_TEXTAPI_TEXTAPIERROR_H
diff --git a/llvm/lib/TextAPI/CMakeLists.txt b/llvm/lib/TextAPI/CMakeLists.txt
index 647a04f5da7881..4088757afb900e 100644
--- a/llvm/lib/TextAPI/CMakeLists.txt
+++ b/llvm/lib/TextAPI/CMakeLists.txt
@@ -8,6 +8,7 @@ add_llvm_component_library(LLVMTextAPI
Symbol.cpp
SymbolSet.cpp
Target.cpp
+ TextAPIError.cpp
TextStub.cpp
TextStubCommon.cpp
diff --git a/llvm/lib/TextAPI/InterfaceFile.cpp b/llvm/lib/TextAPI/InterfaceFile.cpp
index b7f967aa754e78..b9ea02d8e097e3 100644
--- a/llvm/lib/TextAPI/InterfaceFile.cpp
+++ b/llvm/lib/TextAPI/InterfaceFile.cpp
@@ -11,6 +11,7 @@
//===----------------------------------------------------------------------===//
#include "llvm/TextAPI/InterfaceFile.h"
+#include "llvm/TextAPI/TextAPIError.h"
#include <iomanip>
#include <sstream>
@@ -81,6 +82,267 @@ void InterfaceFile::addDocument(std::shared_ptr<InterfaceFile> &&Document) {
Documents.insert(Pos, Document);
}
+void InterfaceFile::inlineLibrary(std::shared_ptr<InterfaceFile> Library,
+ bool Overwrite) {
+ auto AddFwk = [&](std::shared_ptr<InterfaceFile> &&Reexport) {
+ auto It = lower_bound(
+ Documents, Reexport->getInstallName(),
+ [](std::shared_ptr<InterfaceFile> &Lhs, const StringRef Rhs) {
+ return Lhs->getInstallName() < Rhs;
+ });
+
+ if (Overwrite && It != Documents.end() &&
+ Reexport->getInstallName() == (*It)->getInstallName()) {
+ std::replace(Documents.begin(), Documents.end(), *It,
+ std::move(Reexport));
+ return;
+ }
+
+ if ((It != Documents.end()) &&
+ !(Reexport->getInstallName() < (*It)->getInstallName()))
+ return;
+
+ Documents.emplace(It, std::move(Reexport));
+ };
+ for (auto Doc : Library->documents())
+ AddFwk(std::move(Doc));
+
+ Library->Documents.clear();
+ AddFwk(std::move(Library));
+}
+
+Expected<std::unique_ptr<InterfaceFile>>
+InterfaceFile::merge(const InterfaceFile *O) const {
+ // Verify files can be merged.
+ if (getInstallName() != O->getInstallName()) {
+ return make_error<StringError>("install names do not match",
+ inconvertibleErrorCode());
+ }
+
+ if (getCurrentVersion() != O->getCurrentVersion()) {
+ return make_error<StringError>("current versions do not match",
+ inconvertibleErrorCode());
+ }
+
+ if (getCompatibilityVersion() != O->getCompatibilityVersion()) {
+ return make_error<StringError>("compatibility versions do not match",
+ inconvertibleErrorCode());
+ }
+
+ if ((getSwiftABIVersion() != 0) && (O->getSwiftABIVersion() != 0) &&
+ (getSwiftABIVersion() != O->getSwiftABIVersion())) {
+ return make_error<StringError>("swift ABI versions do not match",
+ inconvertibleErrorCode());
+ }
+
+ if (isTwoLevelNamespace() != O->isTwoLevelNamespace()) {
+ return make_error<StringError>("two level namespace flags do not match",
+ inconvertibleErrorCode());
+ }
+
+ if (isApplicationExtensionSafe() != O->isApplicationExtensionSafe()) {
+ return make_error<StringError>(
+ "application extension safe flags do not match",
+ inconvertibleErrorCode());
+ }
+
+ std::unique_ptr<InterfaceFile> IF(new InterfaceFile());
+ IF->setFileType(std::max(getFileType(), O->getFileType()));
+ IF->setPath(getPath());
+ IF->setInstallName(getInstallName());
+ IF->setCurrentVersion(getCurrentVersion());
+ IF->setCompatibilityVersion(getCompatibilityVersion());
+
+ if (getSwiftABIVersion() == 0)
+ IF->setSwiftABIVersion(O->getSwiftABIVersion());
+ else
+ IF->setSwiftABIVersion(getSwiftABIVersion());
+
+ IF->setTwoLevelNamespace(isTwoLevelNamespace());
+ IF->setApplicationExtensionSafe(isApplicationExtensionSafe());
+
+ for (const auto &It : umbrellas()) {
+ if (!It.second.empty())
+ IF->addParentUmbrella(It.first, It.second);
+ }
+ for (const auto &It : O->umbrellas()) {
+ if (!It.second.empty())
+ IF->addParentUmbrella(It.first, It.second);
+ }
+ IF->addTargets(targets());
+ IF->addTargets(O->targets());
+
+ for (const auto &Lib : allowableClients())
+ for (const auto &Target : Lib.targets())
+ IF->addAllowableClient(Lib.getInstallName(), Target);
+
+ for (const auto &Lib : O->allowableClients())
+ for (const auto &Target : Lib.targets())
+ IF->addAllowableClient(Lib.getInstallName(), Target);
+
+ for (const auto &Lib : reexportedLibraries())
+ for (const auto &Target : Lib.targets())
+ IF->addReexportedLibrary(Lib.getInstallName(), Target);
+
+ for (const auto &Lib : O->reexportedLibraries())
+ for (const auto &Target : Lib.targets())
+ IF->addReexportedLibrary(Lib.getInstallName(), Target);
+
+ for (const auto &[Target, Path] : rpaths())
+ IF->addRPath(Target, Path);
+ for (const auto &[Target, Path] : O->rpaths())
+ IF->addRPath(Target, Path);
+
+ for (const auto *Sym : symbols()) {
+ IF->addSymbol(Sym->getKind(), Sym->getName(), Sym->targets(),
+ Sym->getFlags());
+ }
+
+ for (const auto *Sym : O->symbols()) {
+ IF->addSymbol(Sym->getKind(), Sym->getName(), Sym->targets(),
+ Sym->getFlags());
+ }
+
+ return std::move(IF);
+}
+
+Expected<std::unique_ptr<InterfaceFile>>
+InterfaceFile::remove(Architecture Arch) const {
+ if (getArchitectures() == Arch)
+ return make_error<StringError>("cannot remove last architecture slice '" +
+ getArchitectureName(Arch) + "'",
+ inconvertibleErrorCode());
+
+ if (!getArchitectures().has(Arch)) {
+ bool Found = false;
+ for (auto &Doc : Documents) {
+ if (Doc->getArchitectures().has(Arch)) {
+ Found = true;
+ break;
+ }
+ }
+
+ if (!Found)
+ return make_error<TextAPIError>(TextAPIErrorCode::NoSuchArchitecture);
+ }
+
+ std::unique_ptr<InterfaceFile> IF(new InterfaceFile());
+ IF->setFileType(getFileType());
+ IF->setPath(getPath());
+ IF->addTargets(targets(ArchitectureSet::All().clear(Arch)));
+ IF->setInstallName(getInstallName());
+ IF->setCurrentVersion(getCurrentVersion());
+ IF->setCompatibilityVersion(getCompatibilityVersion());
+ IF->setSwiftABIVersion(getSwiftABIVersion());
+ IF->setTwoLevelNamespace(isTwoLevelNamespace());
+ IF->setApplicationExtensionSafe(isApplicationExtensionSafe());
+ for (const auto &It : umbrellas())
+ if (It.first.Arch != Arch)
+ IF->addParentUmbrella(It.first, It.second);
+
+ for (const auto &Lib : allowableClients()) {
+ for (const auto &Target : Lib.targets())
+ if (Target.Arch != Arch)
+ IF->addAllowableClient(Lib.getInstallName(), Target);
+ }
+
+ for (const auto &Lib : reexportedLibraries()) {
+ for (const auto &Target : Lib.targets())
+ if (Target.Arch != Arch)
+ IF->addReexportedLibrary(Lib.getInstallName(), Target);
+ }
+
+ for (const auto *Sym : symbols()) {
+ auto Archs = Sym->getArchitectures();
+ Archs.clear(Arch);
+ if (Archs.empty())
+ continue;
+
+ IF->addSymbol(Sym->getKind(), Sym->getName(), Sym->targets(Archs),
+ Sym->getFlags());
+ }
+
+ for (auto &Doc : Documents) {
+ // Skip the inlined document if the to be removed architecture is the
+ // only one left.
+ if (Doc->getArchitectures() == Arch)
+ continue;
+
+ // If the document doesn't contain the arch, then no work is to be done
+ // and it can be copied over.
+ if (!Doc->getArchitectures().has(Arch)) {
+ auto NewDoc = Doc;
+ IF->addDocument(std::move(NewDoc));
+ continue;
+ }
+
+ auto Result = Doc->remove(Arch);
+ if (!Result)
+ return Result;
+
+ IF->addDocument(std::move(Result.get()));
+ }
+
+ return std::move(IF);
+}
+
+Expected<std::unique_ptr<InterfaceFile>>
+InterfaceFile::extract(Architecture Arch) const {
+ if (!getArchitectures().has(Arch)) {
+ return make_error<StringError>("file doesn't have architecture '" +
+ getArchitectureName(Arch) + "'",
+ inconvertibleErrorCode());
+ }
+
+ std::unique_ptr<InterfaceFile> IF(new InterfaceFile());
+ IF->setFileType(getFileType());
+ IF->setPath(getPath());
+ IF->addTargets(targets(Arch));
+ IF->setInstallName(getInstallName());
+ IF->setCurrentVersion(getCurrentVersion());
+ IF->setCompatibilityVersion(getCompatibilityVersion());
+ IF->setSwiftABIVersion(getSwiftABIVersion());
+ IF->setTwoLevelNamespace(isTwoLevelNamespace());
+ IF->setApplicationExtensionSafe(isApplicationExtensionSafe());
+ for (const auto &It : umbrellas())
+ if (It.first.Arch == Arch)
+ IF->addParentUmbrella(It.first, It.second);
+
+ for (const auto &It : rpaths())
+ if (It.first.Arch == Arch)
+ IF->addRPath(It.first, It.second);
+
+ for (const auto &Lib : allowableClients())
+ for (const auto &Target : Lib.targets())
+ if (Target.Arch == Arch)
+ IF->addAllowableClient(Lib.getInstallName(), Target);
+
+ for (const auto &Lib : reexportedLibraries())
+ for (const auto &Target : Lib.targets())
+ if (Target.Arch == Arch)
+ IF->addReexportedLibrary(Lib.getInstallName(), Target);
+
+ for (const auto *Sym : symbols()) {
+ if (Sym->hasArchitecture(Arch))
+ IF->addSymbol(Sym->getKind(), Sym->getName(), Sym->targets(Arch),
+ Sym->getFlags());
+ }
+
+ for (auto &Doc : Documents) {
+ // Skip documents that don't have the requested architecture.
+ if (!Doc->getArchitectures().has(Arch))
+ continue;
+
+ auto Result = Doc->extract(Arch);
+ if (!Result)
+ return Result;
+
+ IF->addDocument(std::move(Result.get()));
+ }
+
+ return std::move(IF);
+}
+
static bool isYAMLTextStub(const FileType &Kind) {
return (Kind >= FileType::TBD_V1) && (Kind < FileType::TBD_V5);
}
diff --git a/llvm/lib/TextAPI/TextAPIError.cpp b/llvm/lib/TextAPI/TextAPIError.cpp
new file mode 100644
index 00000000000000..07eae7ab4100bc
--- /dev/null
+++ b/llvm/lib/TextAPI/TextAPIError.cpp
@@ -0,0 +1,33 @@
+//===- TextAPIError.cpp - Tapi Error ----------------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// \brief Implements TAPI Error.
+///
+//===----------------------------------------------------------------------===//
+
+#include "llvm/TextAPI/TextAPIError.h"
+
+using namespace llvm;
+using namespace llvm::MachO;
+
+char TextAPIError::ID = 0;
+
+void TextAPIError::log(raw_ostream &OS) const {
+ switch (EC) {
+ case TextAPIErrorCode::NoSuchArchitecture:
+ OS << "no such architecture\n";
+ return;
+ default:
+ llvm_unreachable("unhandled TextAPIErrorCode");
+ }
+}
+
+std::error_code TextAPIError::convertToErrorCode() const {
+ llvm_unreachable("convertToErrorCode is not supported.");
+}
diff --git a/llvm/unittests/TextAPI/TextStubV5Tests.cpp b/llvm/unittests/TextAPI/TextStubV5Tests.cpp
index 782b32444ae33b..1ccbfe2b1a27f6 100644
--- a/llvm/unittests/TextAPI/TextStubV5Tests.cpp
+++ b/llvm/unittests/TextAPI/TextStubV5Tests.cpp
@@ -1104,4 +1104,1145 @@ TEST(TBDv5, InvalidSymbols) {
EXPECT_EQ("invalid exported_symbols section\n", ErrorMessage);
}
+TEST(TBDv5, MergeIF) {
+ static const char TBDv5FileA[] = R"({
+"tapi_tbd_version": 5,
+"main_library": {
+ "target_info": [
+ {
+ "target": "x86_64-macos",
+ "min_deployment": "10.14"
+ },
+ {
+ "target": "arm64-macos",
+ "min_deployment": "10.14"
+ },
+ {
+ "target": "arm64-maccatalyst",
+ "min_deployment": "12.1"
+ }
+ ],
+ "flags": [
+ {
+ "targets": [
+ "x86_64-macos"
+ ],
+ "attributes": [
+ "flat_namespace"
+ ]
+ }
+ ],
+ "install_names": [
+ {
+ "name": "/S/L/F/Foo.framework/Foo"
+ }
+ ],
+ "current_versions": [
+ {
+ "version": "1.2"
+ }
+ ],
+ "compatibility_versions": [
+ { "version": "1.1" }
+ ],
+ "rpaths": [
+ {
+ "targets": [
+ "x86_64-macos"
+ ],
+ "paths": [
+ "@executable_path/.../Frameworks"
+ ]
+ }
+ ],
+ "parent_umbrellas": [
+ {
+ "umbrella": "System"
+ }
+ ],
+ "allowable_clients": [
+ {
+ "clients": [
+ "ClientA",
+ "ClientB"
+ ]
+ }
+ ],
+ "reexported_libraries": [
+ {
+ "names": [
+ "/u/l/l/libfoo.dylib",
+ "/u/l/l/libbar.dylib"
+ ]
+ }
+ ],
+ "exported_symbols": [
+ {
+ "targets": [
+ "x86_64-macos",
+ "arm64-macos"
+ ],
+ "data": {
+ "global": [
+ "_global"
+ ],
+ "objc_class": [
+ "ClassA"
+ ],
+ "weak": [],
+ "thread_local": []
+ },
+ "text": {
+ "global": [
+ "_func"
+ ],
+ "weak": [],
+ "thread_local": []
+ }
+ },
+ {
+ "targets": [
+ "x86_64-macos"
+ ],
+ "data": {
+ "global": [
+ "_globalVar"
+ ],
+ "objc_class": [
+ "ClassA",
+ "ClassB",
+ "ClassData"
+ ],
+ "objc_eh_type": [
+ "ClassA",
+ "ClassB"
+ ],
+ "objc_ivar": [
+ "ClassA.ivar1",
+ "ClassA.ivar2",
+ "ClassC.ivar1"
+ ]
+ },
+ "text": {
+ "global": [
+ "_funcFoo"
+ ]
+ }
+ }
+ ],
+ "reexported_symbols": [
+ {
+ "targets": [
+ "x86_64-macos",
+ "arm64-macos"
+ ],
+ "data": {
+ "global": [
+ "_globalRe"
+ ],
+ "objc_class": [
+ "ClassRexport"
+ ]
+ },
+ "text": {
+ "global": [
+ "_funcA"
+ ]
+ }
+ }
+ ],
+ "undefined_symbols": [
+ {
+ "targets": [
+ "x86_64-macos"
+ ],
+ "data": {
+ "global": [
+ "_globalBind"
+ ],
+ "weak": [
+ "referenced_sym"
+ ]
+ }
+ }
+ ]
+},
+"libraries": []
+})";
+
+ static const char TBDv5FileB[] = R"({
+"tapi_tbd_version": 5,
+"main_library": {
+ "target_info": [
+ {
+ "target": "x86_64-macos",
+ "min_deployment": "10.14"
+ },
+ {
+ "target": "arm64-macos",
+ "min_deployment": "10.14"
+ },
+ {
+ "target": "arm64-maccatalyst",
+ "min_deployment": "12.1"
+ }
+ ],
+ "flags": [
+ {
+ "targets": [
+ "x86_64-macos"
+ ],
+ "attributes": [
+ "flat_namespace"
+ ]
+ }
+ ],
+ "install_names": [
+ {
+ "name": "/S/L/F/Foo.framework/Foo"
+ }
+ ],
+ "current_versions": [
+ {
+ "version": "1.2"
+ }
+ ],
+ "compatibility_versions": [
+ { "version": "1.1" }
+ ],
+ "exported_symbols": [
+ {
+ "targets": [
+ "x86_64-macos",
+ "arm64-macos"
+ ],
+ "data": {
+ "global": [
+ "_globalZ"
+ ],
+ "objc_class": [
+ "ClassZ"
+ ],
+ "weak": [],
+ "thread_local": []
+ },
+ "text": {
+ "global": [
+ "_funcZ"
+ ],
+ "weak": [],
+ "thread_local": []
+ }
+ },
+ {
+ "targets": [
+ "x86_64-macos"
+ ],
+ "data": {
+ "global": [
+ "_globalVarZ"
+ ],
+ "objc_class": [
+ "ClassZ",
+ "ClassF"
+ ],
+ "objc_eh_type": [
+ "ClassZ",
+ "ClassF"
+ ],
+ "objc_ivar": [
+ "ClassZ.ivar1",
+ "ClassZ.ivar2",
+ "ClassF.ivar1"
+ ]
+ },
+ "text": {
+ "global": [
+ "_funcFooZ"
+ ]
+ }
+ }
+ ]
+},
+"libraries": []
+})";
+
+ Expected<TBDFile> ResultA =
+ TextAPIReader::get(MemoryBufferRef(TBDv5FileA, "Test.tbd"));
+ EXPECT_TRUE(!!ResultA);
+ TBDFile FileA = std::move(ResultA.get());
+
+ Expected<TBDFile> ResultB =
+ TextAPIReader::get(MemoryBufferRef(TBDv5FileB, "Test.tbd"));
+ EXPECT_TRUE(!!ResultB);
+ TBDFile FileB = std::move(ResultB.get());
+
+ Expected<TBDFile> MergedResult = FileA->merge(FileB.get());
+ EXPECT_TRUE(!!MergedResult);
+ TBDFile MergedFile = std::move(MergedResult.get());
+
+ EXPECT_EQ(FileType::TBD_V5, MergedFile->getFileType());
+ EXPECT_EQ(std::string("/S/L/F/Foo.framework/Foo"),
+ MergedFile->getInstallName());
+ TargetList AllTargets = {
+ Target(AK_x86_64, PLATFORM_MACOS, VersionTuple(10, 14)),
+ Target(AK_arm64, PLATFORM_MACOS, VersionTuple(11, 0, 0)),
+ Target(AK_arm64, PLATFORM_MACCATALYST, VersionTuple(14, 0)),
+ };
+ EXPECT_EQ(mapToPlatformSet(AllTargets), MergedFile->getPlatforms());
+ EXPECT_EQ(mapToArchitectureSet(AllTargets), MergedFile->getArchitectures());
+ EXPECT_EQ(PackedVersion(1, 2, 0), MergedFile->getCurrentVersion());
+ EXPECT_EQ(PackedVersion(1, 1, 0), MergedFile->getCompatibilityVersion());
+ EXPECT_TRUE(MergedFile->isApplicationExtensionSafe());
+ EXPECT_FALSE(MergedFile->isTwoLevelNamespace());
+ EXPECT_EQ(0U, MergedFile->documents().size());
+ InterfaceFileRef ClientA("ClientA", AllTargets);
+ InterfaceFileRef ClientB("ClientB", AllTargets);
+ EXPECT_EQ(2U, MergedFile->allowableClients().size());
+ EXPECT_EQ(ClientA, MergedFile->allowableClients().at(0));
+ EXPECT_EQ(ClientB, MergedFile->allowableClients().at(1));
+
+ InterfaceFileRef ReexportA("/u/l/l/libbar.dylib", AllTargets);
+ InterfaceFileRef ReexportB("/u/l/l/libfoo.dylib", AllTargets);
+ EXPECT_EQ(2U, MergedFile->reexportedLibraries().size());
+ EXPECT_EQ(ReexportA, MergedFile->reexportedLibraries().at(0));
+ EXPECT_EQ(ReexportB, MergedFile->reexportedLibraries().at(1));
+
+ TargetToAttr RPaths = {
+ {Target(AK_x86_64, PLATFORM_MACOS), "@executable_path/.../Frameworks"},
+ };
+ EXPECT_EQ(RPaths, MergedFile->rpaths());
+
+ TargetToAttr Umbrellas = {{Target(AK_x86_64, PLATFORM_MACOS), "System"},
+ {Target(AK_arm64, PLATFORM_MACOS), "System"},
+ {Target(AK_arm64, PLATFORM_MACCATALYST), "System"}};
+ EXPECT_EQ(Umbrellas, MergedFile->umbrellas());
+
+ ExportedSymbolSeq Exports, Reexports, Undefineds;
+ for (const auto *Sym : MergedFile->symbols()) {
+ TargetList SymTargets{Sym->targets().begin(), Sym->targets().end()};
+ ExportedSymbol Temp =
+ ExportedSymbol{Sym->getKind(),
+ std::string(Sym->getName()),
+ Sym->isWeakDefined() || Sym->isWeakReferenced(),
+ Sym->isThreadLocalValue(),
+ Sym->isData(),
+ SymTargets};
+ if (Sym->isUndefined())
+ Undefineds.emplace_back(std::move(Temp));
+ else
+ Sym->isReexported() ? Reexports.emplace_back(std::move(Temp))
+ : Exports.emplace_back(std::move(Temp));
+ }
+ llvm::sort(Exports);
+ llvm::sort(Reexports);
+ llvm::sort(Undefineds);
+
+ TargetList MacOSTargets = {Target(AK_x86_64, PLATFORM_MACOS),
+ Target(AK_arm64, PLATFORM_MACOS)};
+
+ std::vector<ExportedSymbol> ExpectedExportedSymbols = {
+ {SymbolKind::GlobalSymbol, "_func", false, false, false, MacOSTargets},
+ {SymbolKind::GlobalSymbol,
+ "_funcFoo",
+ false,
+ false,
+ false,
+ {Target(AK_x86_64, PLATFORM_MACOS)}},
+ {SymbolKind::GlobalSymbol,
+ "_funcFooZ",
+ false,
+ false,
+ false,
+ {Target(AK_x86_64, PLATFORM_MACOS)}},
+ {SymbolKind::GlobalSymbol, "_funcZ", false, false, false, MacOSTargets},
+ {SymbolKind::GlobalSymbol, "_global", false, false, true, MacOSTargets},
+ {SymbolKind::GlobalSymbol,
+ "_globalVar",
+ false,
+ false,
+ true,
+ {Target(AK_x86_64, PLATFORM_MACOS)}},
+ {SymbolKind::GlobalSymbol,
+ "_globalVarZ",
+ false,
+ false,
+ true,
+ {Target(AK_x86_64, PLATFORM_MACOS)}},
+ {SymbolKind::GlobalSymbol, "_globalZ", false, false, true, MacOSTargets},
+ {SymbolKind::ObjectiveCClass,
+ "ClassA",
+ false,
+ false,
+ true,
+ {Target(AK_x86_64, PLATFORM_MACOS)}},
+ {SymbolKind::ObjectiveCClass,
+ "ClassB",
+ false,
+ false,
+ true,
+ {Target(AK_x86_64, PLATFORM_MACOS)}},
+ {SymbolKind::ObjectiveCClass,
+ "ClassData",
+ false,
+ false,
+ true,
+ {Target(AK_x86_64, PLATFORM_MACOS)}},
+ {SymbolKind::ObjectiveCClass,
+ "ClassF",
+ false,
+ false,
+ true,
+ {Target(AK_x86_64, PLATFORM_MACOS)}},
+ {SymbolKind::ObjectiveCClass,
+ "ClassZ",
+ false,
+ false,
+ true,
+ {Target(AK_x86_64, PLATFORM_MACOS)}},
+ {SymbolKind::ObjectiveCClassEHType,
+ "ClassA",
+ false,
+ false,
+ true,
+ {Target(AK_x86_64, PLATFORM_MACOS)}},
+ {SymbolKind::ObjectiveCClassEHType,
+ "ClassB",
+ false,
+ false,
+ true,
+ {Target(AK_x86_64, PLATFORM_MACOS)}},
+ {SymbolKind::ObjectiveCClassEHType,
+ "ClassF",
+ false,
+ false,
+ true,
+ {Target(AK_x86_64, PLATFORM_MACOS)}},
+ {SymbolKind::ObjectiveCClassEHType,
+ "ClassZ",
+ false,
+ false,
+ true,
+ {Target(AK_x86_64, PLATFORM_MACOS)}},
+ {SymbolKind::ObjectiveCInstanceVariable,
+ "ClassA.ivar1",
+ false,
+ false,
+ true,
+ {Target(AK_x86_64, PLATFORM_MACOS)}},
+ {SymbolKind::ObjectiveCInstanceVariable,
+ "ClassA.ivar2",
+ false,
+ false,
+ true,
+ {Target(AK_x86_64, PLATFORM_MACOS)}},
+ {SymbolKind::ObjectiveCInstanceVariable,
+ "ClassC.ivar1",
+ false,
+ false,
+ true,
+ {Target(AK_x86_64, PLATFORM_MACOS)}},
+ {SymbolKind::ObjectiveCInstanceVariable,
+ "ClassF.ivar1",
+ false,
+ false,
+ true,
+ {Target(AK_x86_64, PLATFORM_MACOS)}},
+ {SymbolKind::ObjectiveCInstanceVariable,
+ "ClassZ.ivar1",
+ false,
+ false,
+ true,
+ {Target(AK_x86_64, PLATFORM_MACOS)}},
+ {SymbolKind::ObjectiveCInstanceVariable,
+ "ClassZ.ivar2",
+ false,
+ false,
+ true,
+ {Target(AK_x86_64, PLATFORM_MACOS)}},
+ };
+
+ std::vector<ExportedSymbol> ExpectedReexportedSymbols = {
+ {SymbolKind::GlobalSymbol, "_funcA", false, false, false, MacOSTargets},
+ {SymbolKind::GlobalSymbol, "_globalRe", false, false, true, MacOSTargets},
+ {SymbolKind::ObjectiveCClass, "ClassRexport", false, false, true,
+ MacOSTargets},
+ };
+
+ std::vector<ExportedSymbol> ExpectedUndefinedSymbols = {
+ {SymbolKind::GlobalSymbol,
+ "_globalBind",
+ false,
+ false,
+ true,
+ {Target(AK_x86_64, PLATFORM_MACOS)}},
+ {SymbolKind::GlobalSymbol,
+ "referenced_sym",
+ true,
+ false,
+ true,
+ {Target(AK_x86_64, PLATFORM_MACOS)}},
+ };
+
+ EXPECT_EQ(ExpectedExportedSymbols.size(), Exports.size());
+ EXPECT_EQ(ExpectedReexportedSymbols.size(), Reexports.size());
+ EXPECT_EQ(ExpectedUndefinedSymbols.size(), Undefineds.size());
+ EXPECT_TRUE(std::equal(Exports.begin(), Exports.end(),
+ std::begin(ExpectedExportedSymbols)));
+ EXPECT_TRUE(std::equal(Reexports.begin(), Reexports.end(),
+ std::begin(ExpectedReexportedSymbols)));
+ EXPECT_TRUE(std::equal(Undefineds.begin(), Undefineds.end(),
+ std::begin(ExpectedUndefinedSymbols)));
+}
+
+TEST(TBDv5, ExtractIF) {
+ static const char TBDv5File[] = R"({
+"tapi_tbd_version": 5,
+"main_library": {
+ "target_info": [
+ {
+ "target": "x86_64-macos",
+ "min_deployment": "10.14"
+ },
+ {
+ "target": "arm64-macos",
+ "min_deployment": "10.14"
+ },
+ {
+ "target": "arm64-maccatalyst",
+ "min_deployment": "12.1"
+ }
+ ],
+ "flags": [
+ {
+ "targets": [
+ "x86_64-macos"
+ ],
+ "attributes": [
+ "flat_namespace"
+ ]
+ }
+ ],
+ "install_names": [
+ {
+ "name": "/S/L/F/Foo.framework/Foo"
+ }
+ ],
+ "current_versions": [
+ {
+ "version": "1.2"
+ }
+ ],
+ "compatibility_versions": [
+ { "version": "1.1" }
+ ],
+ "rpaths": [
+ {
+ "targets": [
+ "x86_64-macos"
+ ],
+ "paths": [
+ "@executable_path/.../Frameworks"
+ ]
+ }
+ ],
+ "parent_umbrellas": [
+ {
+ "umbrella": "System"
+ }
+ ],
+ "allowable_clients": [
+ {
+ "clients": [
+ "ClientA",
+ "ClientB"
+ ]
+ }
+ ],
+ "reexported_libraries": [
+ {
+ "names": [
+ "/u/l/l/libfoo.dylib",
+ "/u/l/l/libbar.dylib"
+ ]
+ }
+ ],
+ "exported_symbols": [
+ {
+ "targets": [
+ "x86_64-macos",
+ "arm64-macos"
+ ],
+ "data": {
+ "global": [
+ "_global"
+ ],
+ "objc_class": [
+ "ClassA"
+ ],
+ "weak": [],
+ "thread_local": []
+ },
+ "text": {
+ "global": [
+ "_func"
+ ],
+ "weak": [],
+ "thread_local": []
+ }
+ },
+ {
+ "targets": [
+ "x86_64-macos"
+ ],
+ "data": {
+ "global": [
+ "_globalVar"
+ ],
+ "objc_class": [
+ "ClassA",
+ "ClassB",
+ "ClassData"
+ ],
+ "objc_eh_type": [
+ "ClassA",
+ "ClassB"
+ ],
+ "objc_ivar": [
+ "ClassA.ivar1",
+ "ClassA.ivar2",
+ "ClassC.ivar1"
+ ]
+ },
+ "text": {
+ "global": [
+ "_funcFoo"
+ ]
+ }
+ }
+ ],
+ "reexported_symbols": [
+ {
+ "targets": [
+ "x86_64-macos",
+ "arm64-macos"
+ ],
+ "data": {
+ "global": [
+ "_globalRe"
+ ],
+ "objc_class": [
+ "ClassRexport"
+ ]
+ },
+ "text": {
+ "global": [
+ "_funcA"
+ ]
+ }
+ }
+ ],
+ "undefined_symbols": [
+ {
+ "targets": [
+ "x86_64-macos"
+ ],
+ "data": {
+ "global": [
+ "_globalBind"
+ ],
+ "weak": [
+ "referenced_sym"
+ ]
+ }
+ }
+ ]
+},
+"libraries": []
+})";
+
+ Expected<TBDFile> Result =
+ TextAPIReader::get(MemoryBufferRef(TBDv5File, "Test.tbd"));
+ EXPECT_TRUE(!!Result);
+ TBDFile File = std::move(Result.get());
+
+ Expected<TBDFile> ExtractedResult = File->extract(AK_arm64);
+ EXPECT_TRUE(!!ExtractedResult);
+ TBDFile ExtractedFile = std::move(ExtractedResult.get());
+
+ EXPECT_EQ(FileType::TBD_V5, ExtractedFile->getFileType());
+ EXPECT_EQ(std::string("/S/L/F/Foo.framework/Foo"),
+ ExtractedFile->getInstallName());
+
+ TargetList AllTargets = {
+ Target(AK_arm64, PLATFORM_MACOS, VersionTuple(11, 0, 0)),
+ Target(AK_arm64, PLATFORM_MACCATALYST, VersionTuple(14, 0)),
+ };
+ EXPECT_EQ(mapToPlatformSet(AllTargets), ExtractedFile->getPlatforms());
+ EXPECT_EQ(mapToArchitectureSet(AllTargets),
+ ExtractedFile->getArchitectures());
+
+ EXPECT_EQ(PackedVersion(1, 2, 0), ExtractedFile->getCurrentVersion());
+ EXPECT_EQ(PackedVersion(1, 1, 0), ExtractedFile->getCompatibilityVersion());
+ EXPECT_TRUE(ExtractedFile->isApplicationExtensionSafe());
+ EXPECT_FALSE(ExtractedFile->isTwoLevelNamespace());
+ EXPECT_EQ(0U, ExtractedFile->documents().size());
+
+ InterfaceFileRef ClientA("ClientA", AllTargets);
+ InterfaceFileRef ClientB("ClientB", AllTargets);
+ EXPECT_EQ(2U, ExtractedFile->allowableClients().size());
+ EXPECT_EQ(ClientA, ExtractedFile->allowableClients().at(0));
+ EXPECT_EQ(ClientB, ExtractedFile->allowableClients().at(1));
+
+ InterfaceFileRef ReexportA("/u/l/l/libbar.dylib", AllTargets);
+ InterfaceFileRef ReexportB("/u/l/l/libfoo.dylib", AllTargets);
+ EXPECT_EQ(2U, ExtractedFile->reexportedLibraries().size());
+ EXPECT_EQ(ReexportA, ExtractedFile->reexportedLibraries().at(0));
+ EXPECT_EQ(ReexportB, ExtractedFile->reexportedLibraries().at(1));
+
+ EXPECT_EQ(0u, ExtractedFile->rpaths().size());
+
+ TargetToAttr Umbrellas = {{Target(AK_arm64, PLATFORM_MACOS), "System"},
+ {Target(AK_arm64, PLATFORM_MACCATALYST), "System"}};
+ EXPECT_EQ(Umbrellas, ExtractedFile->umbrellas());
+
+ ExportedSymbolSeq Exports, Reexports, Undefineds;
+ for (const auto *Sym : ExtractedFile->symbols()) {
+ TargetList SymTargets{Sym->targets().begin(), Sym->targets().end()};
+ ExportedSymbol Temp =
+ ExportedSymbol{Sym->getKind(),
+ std::string(Sym->getName()),
+ Sym->isWeakDefined() || Sym->isWeakReferenced(),
+ Sym->isThreadLocalValue(),
+ Sym->isData(),
+ SymTargets};
+ if (Sym->isUndefined())
+ Undefineds.emplace_back(std::move(Temp));
+ else
+ Sym->isReexported() ? Reexports.emplace_back(std::move(Temp))
+ : Exports.emplace_back(std::move(Temp));
+ }
+ llvm::sort(Exports);
+ llvm::sort(Reexports);
+ llvm::sort(Undefineds);
+
+ TargetList MacOSTargets = {Target(AK_arm64, PLATFORM_MACOS)};
+
+ std::vector<ExportedSymbol> ExpectedExportedSymbols = {
+ {SymbolKind::GlobalSymbol, "_func", false, false, false, MacOSTargets},
+ {SymbolKind::GlobalSymbol, "_global", false, false, true, MacOSTargets},
+ {SymbolKind::ObjectiveCClass, "ClassA", false, false, true, MacOSTargets},
+ };
+ std::vector<ExportedSymbol> ExpectedReexportedSymbols = {
+ {SymbolKind::GlobalSymbol, "_funcA", false, false, false, MacOSTargets},
+ {SymbolKind::GlobalSymbol, "_globalRe", false, false, true, MacOSTargets},
+ {SymbolKind::ObjectiveCClass, "ClassRexport", false, false, true,
+ MacOSTargets},
+ };
+
+ EXPECT_EQ(ExpectedExportedSymbols.size(), Exports.size());
+ EXPECT_EQ(ExpectedReexportedSymbols.size(), Reexports.size());
+ EXPECT_EQ(0U, Undefineds.size());
+ EXPECT_TRUE(std::equal(Exports.begin(), Exports.end(),
+ std::begin(ExpectedExportedSymbols)));
+ EXPECT_TRUE(std::equal(Reexports.begin(), Reexports.end(),
+ std::begin(ExpectedReexportedSymbols)));
+}
+
+TEST(TBDv5, RemoveIF) {
+ static const char TBDv5File[] = R"({
+"tapi_tbd_version": 5,
+"main_library": {
+ "target_info": [
+ {
+ "target": "x86_64-macos",
+ "min_deployment": "10.14"
+ },
+ {
+ "target": "arm64-macos",
+ "min_deployment": "10.14"
+ },
+ {
+ "target": "arm64-maccatalyst",
+ "min_deployment": "12.1"
+ }
+ ],
+ "flags": [
+ {
+ "targets": [
+ "x86_64-macos"
+ ],
+ "attributes": [
+ "flat_namespace"
+ ]
+ }
+ ],
+ "install_names": [
+ {
+ "name": "/S/L/F/Foo.framework/Foo"
+ }
+ ],
+ "current_versions": [
+ {
+ "version": "1.2"
+ }
+ ],
+ "compatibility_versions": [
+ { "version": "1.1" }
+ ],
+ "rpaths": [
+ {
+ "targets": [
+ "x86_64-macos"
+ ],
+ "paths": [
+ "@executable_path/.../Frameworks"
+ ]
+ }
+ ],
+ "parent_umbrellas": [
+ {
+ "umbrella": "System"
+ }
+ ],
+ "allowable_clients": [
+ {
+ "clients": [
+ "ClientA",
+ "ClientB"
+ ]
+ }
+ ],
+ "reexported_libraries": [
+ {
+ "names": [
+ "/u/l/l/libfoo.dylib",
+ "/u/l/l/libbar.dylib"
+ ]
+ }
+ ],
+ "exported_symbols": [
+ {
+ "targets": [
+ "x86_64-macos",
+ "arm64-macos"
+ ],
+ "data": {
+ "global": [
+ "_global"
+ ],
+ "objc_class": [
+ "ClassA"
+ ],
+ "weak": [],
+ "thread_local": []
+ },
+ "text": {
+ "global": [
+ "_func"
+ ],
+ "weak": [],
+ "thread_local": []
+ }
+ },
+ {
+ "targets": [
+ "x86_64-macos"
+ ],
+ "data": {
+ "global": [
+ "_globalVar"
+ ],
+ "objc_class": [
+ "ClassA",
+ "ClassB",
+ "ClassData"
+ ],
+ "objc_eh_type": [
+ "ClassA",
+ "ClassB"
+ ],
+ "objc_ivar": [
+ "ClassA.ivar1",
+ "ClassA.ivar2",
+ "ClassC.ivar1"
+ ]
+ },
+ "text": {
+ "global": [
+ "_funcFoo"
+ ]
+ }
+ }
+ ],
+ "reexported_symbols": [
+ {
+ "targets": [
+ "x86_64-macos",
+ "arm64-macos"
+ ],
+ "data": {
+ "global": [
+ "_globalRe"
+ ],
+ "objc_class": [
+ "ClassRexport"
+ ]
+ },
+ "text": {
+ "global": [
+ "_funcA"
+ ]
+ }
+ }
+ ],
+ "undefined_symbols": [
+ {
+ "targets": [
+ "x86_64-macos"
+ ],
+ "data": {
+ "global": [
+ "_globalBind"
+ ],
+ "weak": [
+ "referenced_sym"
+ ]
+ }
+ }
+ ]
+},
+"libraries": []
+})";
+
+ Expected<TBDFile> Result =
+ TextAPIReader::get(MemoryBufferRef(TBDv5File, "Test.tbd"));
+ EXPECT_TRUE(!!Result);
+ TBDFile File = std::move(Result.get());
+
+ Expected<TBDFile> RemovedResult = File->remove(AK_x86_64);
+ EXPECT_TRUE(!!RemovedResult);
+ TBDFile RemovedFile = std::move(RemovedResult.get());
+
+ EXPECT_EQ(FileType::TBD_V5, RemovedFile->getFileType());
+ EXPECT_EQ(std::string("/S/L/F/Foo.framework/Foo"),
+ RemovedFile->getInstallName());
+
+ TargetList AllTargets = {
+ Target(AK_arm64, PLATFORM_MACOS, VersionTuple(11, 0, 0)),
+ Target(AK_arm64, PLATFORM_MACCATALYST, VersionTuple(14, 0)),
+ };
+ EXPECT_EQ(mapToPlatformSet(AllTargets), RemovedFile->getPlatforms());
+ EXPECT_EQ(mapToArchitectureSet(AllTargets), RemovedFile->getArchitectures());
+
+ EXPECT_EQ(PackedVersion(1, 2, 0), RemovedFile->getCurrentVersion());
+ EXPECT_EQ(PackedVersion(1, 1, 0), RemovedFile->getCompatibilityVersion());
+ EXPECT_TRUE(RemovedFile->isApplicationExtensionSafe());
+ EXPECT_FALSE(RemovedFile->isTwoLevelNamespace());
+ EXPECT_EQ(0U, RemovedFile->documents().size());
+
+ InterfaceFileRef ClientA("ClientA", AllTargets);
+ InterfaceFileRef ClientB("ClientB", AllTargets);
+ EXPECT_EQ(2U, RemovedFile->allowableClients().size());
+ EXPECT_EQ(ClientA, RemovedFile->allowableClients().at(0));
+ EXPECT_EQ(ClientB, RemovedFile->allowableClients().at(1));
+
+ InterfaceFileRef ReexportA("/u/l/l/libbar.dylib", AllTargets);
+ InterfaceFileRef ReexportB("/u/l/l/libfoo.dylib", AllTargets);
+ EXPECT_EQ(2U, RemovedFile->reexportedLibraries().size());
+ EXPECT_EQ(ReexportA, RemovedFile->reexportedLibraries().at(0));
+ EXPECT_EQ(ReexportB, RemovedFile->reexportedLibraries().at(1));
+
+ EXPECT_EQ(0u, RemovedFile->rpaths().size());
+
+ TargetToAttr Umbrellas = {{Target(AK_arm64, PLATFORM_MACOS), "System"},
+ {Target(AK_arm64, PLATFORM_MACCATALYST), "System"}};
+ EXPECT_EQ(Umbrellas, RemovedFile->umbrellas());
+
+ ExportedSymbolSeq Exports, Reexports, Undefineds;
+ for (const auto *Sym : RemovedFile->symbols()) {
+ TargetList SymTargets{Sym->targets().begin(), Sym->targets().end()};
+ ExportedSymbol Temp =
+ ExportedSymbol{Sym->getKind(),
+ std::string(Sym->getName()),
+ Sym->isWeakDefined() || Sym->isWeakReferenced(),
+ Sym->isThreadLocalValue(),
+ Sym->isData(),
+ SymTargets};
+ if (Sym->isUndefined())
+ Undefineds.emplace_back(std::move(Temp));
+ else
+ Sym->isReexported() ? Reexports.emplace_back(std::move(Temp))
+ : Exports.emplace_back(std::move(Temp));
+ }
+ llvm::sort(Exports);
+ llvm::sort(Reexports);
+ llvm::sort(Undefineds);
+
+ TargetList MacOSTargets = {Target(AK_arm64, PLATFORM_MACOS)};
+
+ std::vector<ExportedSymbol> ExpectedExportedSymbols = {
+ {SymbolKind::GlobalSymbol, "_func", false, false, false, MacOSTargets},
+ {SymbolKind::GlobalSymbol, "_global", false, false, true, MacOSTargets},
+ {SymbolKind::ObjectiveCClass, "ClassA", false, false, true, MacOSTargets},
+ };
+ std::vector<ExportedSymbol> ExpectedReexportedSymbols = {
+ {SymbolKind::GlobalSymbol, "_funcA", false, false, false, MacOSTargets},
+ {SymbolKind::GlobalSymbol, "_globalRe", false, false, true, MacOSTargets},
+ {SymbolKind::ObjectiveCClass, "ClassRexport", false, false, true,
+ MacOSTargets},
+ };
+
+ EXPECT_EQ(ExpectedExportedSymbols.size(), Exports.size());
+ EXPECT_EQ(ExpectedReexportedSymbols.size(), Reexports.size());
+ EXPECT_EQ(0U, Undefineds.size());
+ EXPECT_TRUE(std::equal(Exports.begin(), Exports.end(),
+ std::begin(ExpectedExportedSymbols)));
+ EXPECT_TRUE(std::equal(Reexports.begin(), Reexports.end(),
+ std::begin(ExpectedReexportedSymbols)));
+}
+
+TEST(TBDv5, InlineIF) {
+ static const char UmbrellaFile[] = R"({
+"tapi_tbd_version": 5,
+"main_library": {
+ "target_info": [
+ {
+ "target": "x86_64-macos",
+ "min_deployment": "10.14"
+ },
+ {
+ "target": "arm64-macos",
+ "min_deployment": "10.14"
+ }
+ ],
+ "install_names": [
+ {
+ "name": "/S/L/F/Foo.framework/Foo"
+ }
+ ],
+ "current_versions": [
+ {
+ "version": "1.2"
+ }
+ ],
+ "reexported_libraries": [
+ {
+ "names": [
+ "/u/l/l/libfoo.dylib",
+ "/u/l/l/libbar.dylib"
+ ]
+ }
+ ]
+}})";
+
+ static const char ReexportFile[] = R"({
+"tapi_tbd_version": 5,
+"main_library": {
+ "target_info": [
+ {
+ "target": "x86_64-macos",
+ "min_deployment": "10.14"
+ },
+ {
+ "target": "arm64-macos",
+ "min_deployment": "10.14"
+ }
+ ],
+ "install_names": [
+ {
+ "name" : "/u/l/l/libfoo.dylib"
+ }
+ ],
+ "current_versions": [
+ {
+ "version": "1"
+ }
+ ],
+ "rpaths": [
+ {
+ "targets": [
+ "x86_64-macos"
+ ],
+ "paths": [
+ "@executable_path/.../Frameworks"
+ ]
+ }
+ ],
+ "exported_symbols": [
+ {
+ "targets": [
+ "x86_64-macos",
+ "arm64-macos"
+ ],
+ "data": {
+ "global": [
+ "_global"
+ ],
+ "objc_class": [
+ "ClassA"
+ ],
+ "weak": [],
+ "thread_local": []
+ }
+ }
+ ]}})";
+
+ Expected<TBDFile> UmbrellaResult =
+ TextAPIReader::get(MemoryBufferRef(UmbrellaFile, "Test.tbd"));
+ EXPECT_TRUE(!!UmbrellaResult);
+ TBDFile Umbrella = std::move(UmbrellaResult.get());
+
+ Expected<TBDFile> ReexportResult =
+ TextAPIReader::get(MemoryBufferRef(ReexportFile, "Test.tbd"));
+ EXPECT_TRUE(!!ReexportResult);
+ TBDReexportFile Reexport = std::move(ReexportResult.get());
+ Umbrella->inlineLibrary(Reexport);
+
+ EXPECT_EQ(FileType::TBD_V5, Umbrella->getFileType());
+ EXPECT_EQ(std::string("/S/L/F/Foo.framework/Foo"),
+ Umbrella->getInstallName());
+
+ TargetList AllTargets = {
+ Target(AK_x86_64, PLATFORM_MACOS, VersionTuple(10, 14)),
+ Target(AK_arm64, PLATFORM_MACOS, VersionTuple(11, 0, 0)),
+ };
+ EXPECT_EQ(mapToPlatformSet(AllTargets), Umbrella->getPlatforms());
+ EXPECT_EQ(mapToArchitectureSet(AllTargets), Umbrella->getArchitectures());
+
+ EXPECT_EQ(PackedVersion(1, 2, 0), Umbrella->getCurrentVersion());
+ EXPECT_EQ(PackedVersion(1, 0, 0), Umbrella->getCompatibilityVersion());
+ InterfaceFileRef ReexportA("/u/l/l/libbar.dylib", AllTargets);
+ InterfaceFileRef ReexportB("/u/l/l/libfoo.dylib", AllTargets);
+ EXPECT_EQ(2U, Umbrella->reexportedLibraries().size());
+ EXPECT_EQ(ReexportA, Umbrella->reexportedLibraries().at(0));
+ EXPECT_EQ(ReexportB, Umbrella->reexportedLibraries().at(1));
+ EXPECT_EQ(1U, Umbrella->documents().size());
+
+ TBDReexportFile Document = Umbrella->documents().front();
+ EXPECT_EQ(std::string("/u/l/l/libfoo.dylib"), Document->getInstallName());
+ EXPECT_EQ(0U, Document->getSwiftABIVersion());
+ EXPECT_TRUE(Document->isTwoLevelNamespace());
+ EXPECT_TRUE(Document->isApplicationExtensionSafe());
+ EXPECT_EQ(PackedVersion(1, 0, 0), Document->getCurrentVersion());
+ EXPECT_EQ(PackedVersion(1, 0, 0), Document->getCompatibilityVersion());
+
+ ExportedSymbolSeq Exports;
+ for (const auto *Sym : Document->symbols()) {
+ TargetList SymTargets{Sym->targets().begin(), Sym->targets().end()};
+ Exports.emplace_back(
+ ExportedSymbol{Sym->getKind(), std::string(Sym->getName()),
+ Sym->isWeakDefined() || Sym->isWeakReferenced(),
+ Sym->isThreadLocalValue(), Sym->isData(), SymTargets});
+ }
+ llvm::sort(Exports);
+
+ ExportedSymbolSeq ExpectedExports = {
+ {SymbolKind::GlobalSymbol, "_global", false, false, true, AllTargets},
+ {SymbolKind::ObjectiveCClass, "ClassA", false, false, true, AllTargets},
+ };
+ EXPECT_EQ(ExpectedExports.size(), Exports.size());
+ EXPECT_TRUE(
+ std::equal(Exports.begin(), Exports.end(), std::begin(ExpectedExports)));
+}
} // end namespace TBDv5
More information about the llvm-commits
mailing list