diff --git a/llvm/include/llvm/TextAPI/MachO/InterfaceFile.h b/llvm/include/llvm/TextAPI/MachO/InterfaceFile.h --- a/llvm/include/llvm/TextAPI/MachO/InterfaceFile.h +++ b/llvm/include/llvm/TextAPI/MachO/InterfaceFile.h @@ -274,6 +274,11 @@ /// \param Target_ The target applicable to Parent /// \param Parent The name of Parent void addParentUmbrella(const Target &Target_, StringRef Parent); + + /// Get the list of Parent Umbrella frameworks. + /// + /// \return Returns a list of target information and install name of parent + /// umbrellas. const std::vector> &umbrellas() const { return ParentUmbrellas; } @@ -328,6 +333,20 @@ return UUIDs; } + /// Add a library for inlining to top level library. + /// + ///\param Document The library to inline with top level library. + void addDocument(std::shared_ptr &&Document) { + Documents.emplace_back(std::move(Document)); + } + + /// Get the list of inlined libraries. + /// + /// \return Returns a list of the inlined frameworks. + const std::vector> &documents() const { + return Documents; + } + /// Add a symbol to the symbols list or extend an existing one. void addSymbol(SymbolKind Kind, StringRef Name, const TargetList &Targets, SymbolFlags Flags = SymbolFlags::None); @@ -403,6 +422,7 @@ std::vector> ParentUmbrellas; std::vector AllowableClients; std::vector ReexportedLibraries; + std::vector> Documents; std::vector> UUIDs; SymbolMapType Symbols; }; diff --git a/llvm/lib/TextAPI/MachO/TextStub.cpp b/llvm/lib/TextAPI/MachO/TextStub.cpp --- a/llvm/lib/TextAPI/MachO/TextStub.cpp +++ b/llvm/lib/TextAPI/MachO/TextStub.cpp @@ -1118,6 +1118,10 @@ auto File = std::unique_ptr( const_cast(Files.front())); + for (auto Iter = std::next(Files.begin()); Iter != Files.end(); ++Iter) + File->addDocument( + std::shared_ptr(const_cast(*Iter))); + if (YAMLIn.error()) return make_error(Ctx.ErrorMessage, YAMLIn.error()); @@ -1133,6 +1137,9 @@ std::vector Files; Files.emplace_back(&File); + for (auto Document : File.documents()) + Files.emplace_back(Document.get()); + // Stream out yaml. YAMLOut << Files; diff --git a/llvm/unittests/TextAPI/TextStubV3Tests.cpp b/llvm/unittests/TextAPI/TextStubV3Tests.cpp --- a/llvm/unittests/TextAPI/TextStubV3Tests.cpp +++ b/llvm/unittests/TextAPI/TextStubV3Tests.cpp @@ -117,6 +117,127 @@ std::equal(Exports.begin(), Exports.end(), std::begin(TBDv3Symbols))); } +TEST(TBDv3, ReadMultipleDocuments) { + static const char TBDv3Inlines[] = + "--- !tapi-tbd-v3\n" + "archs: [ armv7, arm64 ]\n" + "uuids: [ 'armv7: 00000000-0000-0000-0000-000000000000',\n" + " 'arm64: 11111111-1111-1111-1111-111111111111']\n" + "platform: ios\n" + "install-name: Test.dylib\n" + "current-version: 2.3.4\n" + "compatibility-version: 1.0\n" + "swift-abi-version: 1.1\n" + "parent-umbrella: Umbrella.dylib\n" + "exports:\n" + " - archs: [ armv7, arm64 ]\n" + " allowable-clients: [ clientA ]\n" + " re-exports: [ /usr/lib/libfoo.dylib,\n" + " TestInline.dylib ]\n" + " symbols: [ _sym1, _sym2, _sym3, _sym4, $ld$hide$os9.0$_sym1 ]\n" + " objc-classes: [ class1, class2 ]\n" + " objc-eh-types: [ class1 ]\n" + " objc-ivars: [ class1._ivar1, class1._ivar2 ]\n" + " weak-def-symbols: [ _weak1, _weak2 ]\n" + " thread-local-symbols: [ _tlv1, _tlv3 ]\n" + " - archs: [ armv7 ]\n" + " symbols: [ _sym5 ]\n" + " objc-classes: [ class3 ]\n" + " objc-ivars: [ class1._ivar3 ]\n" + " weak-def-symbols: [ _weak3 ]\n" + " thread-local-symbols: [ _tlv3 ]\n" + "--- !tapi-tbd-v3\n" + "archs: [ armv7, arm64 ]\n" + "uuids: [ 'armv7: 00000000-0000-0000-0000-000000000000',\n" + " 'arm64: 11111111-1111-1111-1111-111111111111']\n" + "platform: ios\n" + "install-name: TestInline.dylib\n" + "swift-abi-version: 1.1\n" + "exports:\n" + " - archs: [ armv7, arm64 ]\n" + " symbols: [ _sym5, _sym6 ]\n" + "...\n"; + + auto Result = TextAPIReader::get(MemoryBufferRef(TBDv3Inlines, "Test.tbd")); + EXPECT_TRUE(!!Result); + auto File = std::move(Result.get()); + EXPECT_EQ(File->documents().size(), 1U); + EXPECT_EQ(FileType::TBD_V3, File->getFileType()); + auto Archs = AK_armv7 | AK_arm64; + auto Platform = PlatformKind::iOS; + TargetList Targets; + for (auto &&arch : Archs) + Targets.emplace_back(Target(arch, Platform)); + EXPECT_EQ(Archs, File->getArchitectures()); + UUIDs Uuids = {{Target(AK_armv7, PlatformKind::unknown), + "00000000-0000-0000-0000-000000000000"}, + {Target(AK_arm64, PlatformKind::unknown), + "11111111-1111-1111-1111-111111111111"}}; + EXPECT_EQ(Uuids, File->uuids()); + EXPECT_EQ(File->getPlatforms().size(), 1U); + EXPECT_EQ(Platform, *File->getPlatforms().begin()); + EXPECT_EQ(std::string("Test.dylib"), File->getInstallName()); + EXPECT_EQ(PackedVersion(2, 3, 4), File->getCurrentVersion()); + EXPECT_EQ(PackedVersion(1, 0, 0), File->getCompatibilityVersion()); + EXPECT_EQ(2U, File->getSwiftABIVersion()); + EXPECT_EQ(ObjCConstraintType::Retain_Release, File->getObjCConstraint()); + EXPECT_TRUE(File->isTwoLevelNamespace()); + EXPECT_TRUE(File->isApplicationExtensionSafe()); + EXPECT_FALSE(File->isInstallAPI()); + InterfaceFileRef Client("clientA", Targets); + const std::vector Reexports = { + InterfaceFileRef("/usr/lib/libfoo.dylib", Targets), + InterfaceFileRef("TestInline.dylib", Targets)}; + EXPECT_EQ(1U, File->allowableClients().size()); + EXPECT_EQ(Client, File->allowableClients().front()); + EXPECT_EQ(2U, File->reexportedLibraries().size()); + EXPECT_EQ(Reexports, File->reexportedLibraries()); + + ExportedSymbolSeq Exports; + for (const auto *Sym : File->symbols()) { + EXPECT_FALSE(Sym->isWeakReferenced()); + EXPECT_FALSE(Sym->isUndefined()); + Exports.emplace_back(ExportedSymbol{Sym->getKind(), Sym->getName().str(), + Sym->isWeakDefined(), + Sym->isThreadLocalValue()}); + } + llvm::sort(Exports.begin(), Exports.end()); + + EXPECT_EQ(sizeof(TBDv3Symbols) / sizeof(ExportedSymbol), Exports.size()); + EXPECT_TRUE( + std::equal(Exports.begin(), Exports.end(), std::begin(TBDv3Symbols))); + + // Check Second Document + Exports.clear(); + auto Document = File->documents().front(); + EXPECT_EQ(FileType::TBD_V3, Document->getFileType()); + EXPECT_EQ(Archs, Document->getArchitectures()); + EXPECT_EQ(Uuids, Document->uuids()); + EXPECT_EQ(Platform, *Document->getPlatforms().begin()); + EXPECT_EQ(std::string("TestInline.dylib"), Document->getInstallName()); + EXPECT_EQ(PackedVersion(1, 0, 0), Document->getCurrentVersion()); + EXPECT_EQ(PackedVersion(1, 0, 0), Document->getCompatibilityVersion()); + EXPECT_EQ(2U, Document->getSwiftABIVersion()); + + for (const auto *Sym : Document->symbols()) { + EXPECT_FALSE(Sym->isWeakReferenced()); + EXPECT_FALSE(Sym->isUndefined()); + Exports.emplace_back(ExportedSymbol{Sym->getKind(), Sym->getName().str(), + Sym->isWeakDefined(), + Sym->isThreadLocalValue()}); + } + llvm::sort(Exports.begin(), Exports.end()); + + ExportedSymbolSeq DocumentSymbols{ + {SymbolKind::GlobalSymbol, "_sym5", false, false}, + {SymbolKind::GlobalSymbol, "_sym6", false, false}, + }; + + EXPECT_EQ(DocumentSymbols.size(), Exports.size()); + EXPECT_TRUE( + std::equal(Exports.begin(), Exports.end(), DocumentSymbols.begin())); +} + TEST(TBDv3, WriteFile) { static const char TBDv3File3[] = "--- !tapi-tbd-v3\n" @@ -171,6 +292,87 @@ EXPECT_STREQ(TBDv3File3, Buffer.c_str()); } +TEST(TBDv3, WriteMultipleDocuments) { + static const char TBDv3Inlines[] = + "--- !tapi-tbd-v3\n" + "archs: [ i386, x86_64 ]\n" + "platform: zippered\n" + "install-name: '/usr/lib/libfoo.dylib'\n" + "current-version: 1.2.3\n" + "compatibility-version: 0\n" + "swift-abi-version: 5\n" + "exports:\n" + " - archs: [ x86_64 ]\n" + " allowable-clients: [ clientA ]\n" + " re-exports: [ '/usr/lib/libbar.dylib' ]\n" + " - archs: [ i386, x86_64 ]\n" + " symbols: [ _sym1 ]\n" + " objc-classes: [ Class1 ]\n" + " objc-eh-types: [ Class1 ]\n" + " objc-ivars: [ Class1._ivar1 ]\n" + " weak-def-symbols: [ _sym2 ]\n" + " thread-local-symbols: [ _symA ]\n" + "--- !tapi-tbd-v3\n" + "archs: [ i386 ]\n" + "platform: macosx\n" + "install-name: '/usr/lib/libbar.dylib'\n" + "current-version: 0\n" + "compatibility-version: 0\n" + "swift-abi-version: 5\n" + "objc-constraint: none\n" + "exports:\n" + " - archs: [ i386 ]\n" + " symbols: [ _sym3, _sym4 ]\n" + "...\n"; + + InterfaceFile File; + TargetList Targets; + for (auto &&arch : AK_i386 | AK_x86_64) { + Targets.emplace_back(Target(arch, PlatformKind::macOS)); + Targets.emplace_back(Target(arch, PlatformKind::macCatalyst)); + } + File.addTargets(Targets); + File.setPath("libfoo.dylib"); + File.setInstallName("/usr/lib/libfoo.dylib"); + File.setFileType(FileType::TBD_V3); + File.setCurrentVersion(PackedVersion(1, 2, 3)); + File.setTwoLevelNamespace(); + File.setApplicationExtensionSafe(); + File.setSwiftABIVersion(5); + File.setObjCConstraint(ObjCConstraintType::Retain_Release); + File.addAllowableClient("clientA", Targets[2]); + File.addReexportedLibrary("/usr/lib/libbar.dylib", Targets[2]); + File.addSymbol(SymbolKind::GlobalSymbol, "_sym1", Targets); + File.addSymbol(SymbolKind::GlobalSymbol, "_sym2", Targets, + SymbolFlags::WeakDefined); + File.addSymbol(SymbolKind::GlobalSymbol, "_symA", Targets, + SymbolFlags::ThreadLocalValue); + File.addSymbol(SymbolKind::ObjectiveCClass, "Class1", Targets); + File.addSymbol(SymbolKind::ObjectiveCClassEHType, "Class1", Targets); + File.addSymbol(SymbolKind::ObjectiveCInstanceVariable, "Class1._ivar1", + Targets); + + // Inline document + InterfaceFile Document; + Targets = {Target(AK_i386, PlatformKind::macOS)}; + Document.addTargets(Targets); + Document.setPath("libbar.dylib"); + Document.setInstallName("/usr/lib/libbar.dylib"); + Document.setFileType(FileType::TBD_V3); + Document.setTwoLevelNamespace(); + Document.setApplicationExtensionSafe(); + Document.setSwiftABIVersion(5); + Document.addSymbol(SymbolKind::GlobalSymbol, "_sym3", Targets); + Document.addSymbol(SymbolKind::GlobalSymbol, "_sym4", Targets); + File.addDocument(std::make_shared(std::move(Document))); + + SmallString<4096> Buffer; + raw_svector_ostream OS(Buffer); + auto Result = TextAPIWriter::writeToStream(OS, File); + EXPECT_FALSE(Result); + EXPECT_STREQ(TBDv3Inlines, Buffer.c_str()); +} + TEST(TBDv3, Platform_macOS) { static const char TBDv3PlatformMacOS[] = "--- !tapi-tbd-v3\n" "archs: [ x86_64 ]\n" diff --git a/llvm/unittests/TextAPI/TextStubV4Tests.cpp b/llvm/unittests/TextAPI/TextStubV4Tests.cpp --- a/llvm/unittests/TextAPI/TextStubV4Tests.cpp +++ b/llvm/unittests/TextAPI/TextStubV4Tests.cpp @@ -17,19 +17,6 @@ using namespace llvm; using namespace llvm::MachO; -static ExportedSymbol TBDv4ExportedSymbols[] = { - {SymbolKind::GlobalSymbol, "_symA", false, false}, - {SymbolKind::GlobalSymbol, "_symAB", false, false}, - {SymbolKind::GlobalSymbol, "_symB", false, false}, -}; - -static ExportedSymbol TBDv4ReexportedSymbols[] = { - {SymbolKind::GlobalSymbol, "_symC", false, false}, -}; - -static ExportedSymbol TBDv4UndefinedSymbols[] = { - {SymbolKind::GlobalSymbol, "_symD", false, false}, -}; namespace TBDv4 { @@ -141,18 +128,209 @@ llvm::sort(Reexports.begin(), Reexports.end()); llvm::sort(Undefineds.begin(), Undefineds.end()); - EXPECT_EQ(sizeof(TBDv4ExportedSymbols) / sizeof(ExportedSymbol), + static ExportedSymbol ExpectedExportedSymbols[] = { + {SymbolKind::GlobalSymbol, "_symA", false, false}, + {SymbolKind::GlobalSymbol, "_symAB", false, false}, + {SymbolKind::GlobalSymbol, "_symB", false, false}, + }; + + static ExportedSymbol ExpectedReexportedSymbols[] = { + {SymbolKind::GlobalSymbol, "_symC", false, false}, + }; + + static ExportedSymbol ExpectedUndefinedSymbols[] = { + {SymbolKind::GlobalSymbol, "_symD", false, false}, + }; + + EXPECT_EQ(sizeof(ExpectedExportedSymbols) / sizeof(ExportedSymbol), Exports.size()); - EXPECT_EQ(sizeof(TBDv4ReexportedSymbols) / sizeof(ExportedSymbol), + EXPECT_EQ(sizeof(ExpectedReexportedSymbols) / sizeof(ExportedSymbol), Reexports.size()); - EXPECT_EQ(sizeof(TBDv4UndefinedSymbols) / sizeof(ExportedSymbol), + EXPECT_EQ(sizeof(ExpectedUndefinedSymbols) / sizeof(ExportedSymbol), Undefineds.size()); EXPECT_TRUE(std::equal(Exports.begin(), Exports.end(), - std::begin(TBDv4ExportedSymbols))); + std::begin(ExpectedExportedSymbols))); EXPECT_TRUE(std::equal(Reexports.begin(), Reexports.end(), - std::begin(TBDv4ReexportedSymbols))); + std::begin(ExpectedReexportedSymbols))); EXPECT_TRUE(std::equal(Undefineds.begin(), Undefineds.end(), - std::begin(TBDv4UndefinedSymbols))); + std::begin(ExpectedUndefinedSymbols))); +} + +TEST(TBDv4, ReadMultipleDocuments) { + static const char TBDv4Inlines[] = + "--- !tapi-tbd\n" + "tbd-version: 4\n" + "targets: [ i386-macos, i386-maccatalyst, x86_64-macos, " + "x86_64-maccatalyst ]\n" + "uuids:\n" + " - target: i386-macos\n" + " value: 00000000-0000-0000-0000-000000000000\n" + " - target: i386-maccatalyst\n" + " value: 00000000-0000-0000-0000-000000000002\n" + " - target: x86_64-macos\n" + " value: 11111111-1111-1111-1111-111111111111\n" + " - target: x86_64-maccatalyst\n" + " value: 11111111-1111-1111-1111-111111111112\n" + "install-name: /System/Library/Frameworks/Umbrella.framework/Umbrella\n" + "parent-umbrella:\n" + " - targets: [ i386-macos, x86_64-macos ]\n" + " umbrella: System\n" + "reexported-libraries:\n" + " - targets: [ i386-macos, x86_64-macos ]\n" + " libraries: [ /System/Library/Frameworks/A.framework/A ]\n" + "--- !tapi-tbd\n" + "tbd-version: 4\n" + "targets: [ i386-macos, x86_64-macos ]\n" + "uuids:\n" + " - target: i386-macos\n" + " value: 20000000-0000-0000-0000-000000000000\n" + " - target: x86_64-macos\n" + " value: 21111111-1111-1111-1111-111111111111\n" + "flags: [ flat_namespace ]\n" + "install-name: /System/Library/Frameworks/A.framework/A\n" + "current-version: 1.2.3\n" + "compatibility-version: 1.2\n" + "swift-abi-version: 5\n" + "exports:\n" + " - targets: [ i386-macos ]\n" + " symbols: [ _symA ]\n" + " objc-classes: []\n" + " objc-eh-types: []\n" + " objc-ivars: []\n" + " weak-symbols: []\n" + " thread-local-symbols: []\n" + " - targets: [ x86_64-macos ]\n" + " symbols: [_symAB]\n" + "reexports:\n" + " - targets: [ i386-macos ]\n" + " symbols: [_symC]\n" + " objc-classes: []\n" + " objc-eh-types: []\n" + " objc-ivars: []\n" + " weak-symbols: []\n" + " thread-local-symbols: []\n" + "undefineds:\n" + " - targets: [ i386-macos ]\n" + " symbols: [ _symD ]\n" + " objc-classes: []\n" + " objc-eh-types: []\n" + " objc-ivars: []\n" + " weak-symbols: []\n" + " thread-local-symbols: []\n" + "...\n"; + + PlatformSet Platforms; + Platforms.insert(PlatformKind::macOS); + Platforms.insert(PlatformKind::macCatalyst); + ArchitectureSet Archs = AK_i386 | AK_x86_64; + TargetList Targets; + for (auto &&Arch : Archs) + for (auto &&Platform : Platforms) + Targets.emplace_back(Target(Arch, Platform)); + UUIDs Uuids = { + {Targets[0], "00000000-0000-0000-0000-000000000000"}, + {Targets[1], "00000000-0000-0000-0000-000000000002"}, + {Targets[2], "11111111-1111-1111-1111-111111111111"}, + {Targets[3], "11111111-1111-1111-1111-111111111112"}, + }; + + auto Result = TextAPIReader::get(MemoryBufferRef(TBDv4Inlines, "Test.tbd")); + EXPECT_TRUE(!!Result); + auto File = std::move(Result.get()); + EXPECT_EQ(FileType::TBD_V4, File->getFileType()); + EXPECT_EQ(Archs, File->getArchitectures()); + EXPECT_EQ(Uuids, File->uuids()); + EXPECT_EQ(Platforms, File->getPlatforms()); + EXPECT_EQ( + std::string("/System/Library/Frameworks/Umbrella.framework/Umbrella"), + File->getInstallName()); + EXPECT_TRUE(File->isTwoLevelNamespace()); + EXPECT_TRUE(File->isApplicationExtensionSafe()); + EXPECT_FALSE(File->isInstallAPI()); + EXPECT_EQ(PackedVersion(1, 0, 0), File->getCurrentVersion()); + EXPECT_EQ(PackedVersion(1, 0, 0), File->getCompatibilityVersion()); + InterfaceFileRef reexport("/System/Library/Frameworks/A.framework/A", + {Targets[0], Targets[2]}); + EXPECT_EQ(1U, File->reexportedLibraries().size()); + EXPECT_EQ(reexport, File->reexportedLibraries().front()); + ExportedSymbolSeq Exports; + for (const auto *Sym : File->symbols()) { + EXPECT_FALSE(Sym->isWeakReferenced()); + EXPECT_FALSE(Sym->isUndefined()); + Exports.emplace_back(ExportedSymbol{Sym->getKind(), Sym->getName().str(), + Sym->isWeakDefined(), + Sym->isThreadLocalValue()}); + } + EXPECT_EQ(0U, Exports.size()); + + // Check Inlined Document + Exports.clear(); + Targets.clear(); + Uuids.clear(); + PlatformKind Platform = PlatformKind::macOS; + for (auto &&Arch : Archs) + Targets.emplace_back(Target(Arch, Platform)); + Uuids = { + {Targets[0], "20000000-0000-0000-0000-000000000000"}, + {Targets[1], "21111111-1111-1111-1111-111111111111"}, + }; + + auto Document = File->documents().front(); + EXPECT_EQ(FileType::TBD_V4, Document->getFileType()); + EXPECT_EQ(Archs, Document->getArchitectures()); + EXPECT_EQ(Uuids, Document->uuids()); + EXPECT_EQ(1U, Document->getPlatforms().size()); + EXPECT_EQ(Platform, *(Document->getPlatforms().begin())); + EXPECT_EQ(std::string("/System/Library/Frameworks/A.framework/A"), + Document->getInstallName()); + EXPECT_EQ(PackedVersion(1, 2, 3), Document->getCurrentVersion()); + EXPECT_EQ(PackedVersion(1, 2, 0), Document->getCompatibilityVersion()); + EXPECT_EQ(5U, Document->getSwiftABIVersion()); + EXPECT_FALSE(Document->isTwoLevelNamespace()); + EXPECT_TRUE(Document->isApplicationExtensionSafe()); + EXPECT_FALSE(Document->isInstallAPI()); + + ExportedSymbolSeq Reexports, Undefineds; + for (const auto *Sym : Document->symbols()) { + ExportedSymbol Temp = + ExportedSymbol{Sym->getKind(), std::string(Sym->getName()), + Sym->isWeakDefined(), Sym->isThreadLocalValue()}; + EXPECT_FALSE(Sym->isWeakReferenced()); + 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.begin(), Exports.end()); + llvm::sort(Reexports.begin(), Reexports.end()); + llvm::sort(Undefineds.begin(), Undefineds.end()); + + static ExportedSymbol ExpectedExportedSymbols[] = { + {SymbolKind::GlobalSymbol, "_symA", false, false}, + {SymbolKind::GlobalSymbol, "_symAB", false, false}, + }; + + static ExportedSymbol ExpectedReexportedSymbols[] = { + {SymbolKind::GlobalSymbol, "_symC", false, false}, + }; + + static ExportedSymbol ExpectedUndefinedSymbols[] = { + {SymbolKind::GlobalSymbol, "_symD", false, false}, + }; + + EXPECT_EQ(sizeof(ExpectedExportedSymbols) / sizeof(ExportedSymbol), + Exports.size()); + EXPECT_EQ(sizeof(ExpectedReexportedSymbols) / sizeof(ExportedSymbol), + Reexports.size()); + EXPECT_EQ(sizeof(ExpectedUndefinedSymbols) / sizeof(ExportedSymbol), + 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(TBDv4, WriteFile) { @@ -218,6 +396,89 @@ EXPECT_STREQ(TBDv4File, Buffer.c_str()); } +TEST(TBDv4, WriteMultipleDocuments) { + static const char TBDv4Inlines[] = + "--- !tapi-tbd\n" + "tbd-version: 4\n" + "targets: [ i386-maccatalyst, x86_64-maccatalyst ]\n" + "uuids:\n" + " - target: i386-maccatalyst\n" + " value: 00000000-0000-0000-0000-000000000002\n" + " - target: x86_64-maccatalyst\n" + " value: 11111111-1111-1111-1111-111111111112\n" + "install-name: " + "'/System/Library/Frameworks/Umbrella.framework/Umbrella'\n" + "reexported-libraries:\n" + " - targets: [ i386-maccatalyst, x86_64-maccatalyst ]\n" + " libraries: [ '/System/Library/Frameworks/A.framework/A' ]\n" + "--- !tapi-tbd\n" + "tbd-version: 4\n" + "targets: [ i386-maccatalyst, x86_64-maccatalyst ]\n" + "uuids:\n" + " - target: i386-maccatalyst\n" + " value: 00000000-0000-0000-0000-000000000000\n" + " - target: x86_64-maccatalyst\n" + " value: 11111111-1111-1111-1111-111111111111\n" + "install-name: '/System/Library/Frameworks/A.framework/A'\n" + "exports:\n" + " - targets: [ i386-maccatalyst ]\n" + " weak-symbols: [ _symC ]\n" + " - targets: [ i386-maccatalyst, x86_64-maccatalyst ]\n" + " symbols: [ _symA ]\n" + " objc-classes: [ Class1 ]\n" + " - targets: [ x86_64-maccatalyst ]\n" + " symbols: [ _symAB ]\n" + "...\n"; + + InterfaceFile File; + PlatformKind Platform = PlatformKind::macCatalyst; + TargetList Targets = { + Target(AK_i386, Platform), + Target(AK_x86_64, Platform), + }; + UUIDs Uuids = {{Targets[0], "00000000-0000-0000-0000-000000000002"}, + {Targets[1], "11111111-1111-1111-1111-111111111112"}}; + File.setInstallName("/System/Library/Frameworks/Umbrella.framework/Umbrella"); + File.setFileType(FileType::TBD_V4); + File.addTargets(Targets); + File.addUUID(Uuids[0].first, Uuids[0].second); + File.addUUID(Uuids[1].first, Uuids[1].second); + File.setCompatibilityVersion(PackedVersion(1, 0, 0)); + File.setCurrentVersion(PackedVersion(1, 0, 0)); + File.setTwoLevelNamespace(); + File.setApplicationExtensionSafe(true); + File.addReexportedLibrary("/System/Library/Frameworks/A.framework/A", + Targets[0]); + File.addReexportedLibrary("/System/Library/Frameworks/A.framework/A", + Targets[1]); + + // Write Second Document + Uuids = {{Targets[0], "00000000-0000-0000-0000-000000000000"}, + {Targets[1], "11111111-1111-1111-1111-111111111111"}}; + InterfaceFile Document; + Document.setInstallName("/System/Library/Frameworks/A.framework/A"); + Document.setFileType(FileType::TBD_V4); + Document.addTargets(Targets); + Document.addUUID(Uuids[0].first, Uuids[0].second); + Document.addUUID(Uuids[1].first, Uuids[1].second); + Document.setCompatibilityVersion(PackedVersion(1, 0, 0)); + Document.setCurrentVersion(PackedVersion(1, 0, 0)); + Document.setTwoLevelNamespace(); + Document.setApplicationExtensionSafe(true); + Document.addSymbol(SymbolKind::GlobalSymbol, "_symA", Targets); + Document.addSymbol(SymbolKind::GlobalSymbol, "_symAB", {Targets[1]}); + Document.addSymbol(SymbolKind::GlobalSymbol, "_symC", {Targets[0]}, + SymbolFlags::WeakDefined); + Document.addSymbol(SymbolKind::ObjectiveCClass, "Class1", Targets); + File.addDocument(std::make_shared(std::move(Document))); + + SmallString<4096> Buffer; + raw_svector_ostream OS(Buffer); + auto Result = TextAPIWriter::writeToStream(OS, File); + EXPECT_FALSE(Result); + EXPECT_STREQ(TBDv4Inlines, Buffer.c_str()); +} + TEST(TBDv4, MultipleTargets) { static const char TBDv4MultipleTargets[] = "--- !tapi-tbd\n"