mirror of
https://github.com/llvm/llvm-project.git
synced 2025-04-28 12:06:09 +00:00
2455 lines
66 KiB
C++
2455 lines
66 KiB
C++
//===-- TextStubV5Tests.cpp - TBD V5 File Test ----------------------------===//
|
|
//
|
|
// 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
|
|
//
|
|
//===-----------------------------------------------------------------------===/
|
|
|
|
#include "TextStubHelpers.h"
|
|
#include "llvm/TextAPI/InterfaceFile.h"
|
|
#include "llvm/TextAPI/TextAPIReader.h"
|
|
#include "llvm/TextAPI/TextAPIWriter.h"
|
|
#include "gtest/gtest.h"
|
|
#include <string>
|
|
#include <vector>
|
|
|
|
using namespace llvm;
|
|
using namespace llvm::MachO;
|
|
|
|
namespace TBDv5 {
|
|
|
|
TEST(TBDv5, ReadFile) {
|
|
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": []
|
|
})";
|
|
|
|
MemoryBufferRef InputBuf = MemoryBufferRef(TBDv5File, "Test.tbd");
|
|
Expected<FileType> ExpectedFT = TextAPIReader::canRead(InputBuf);
|
|
EXPECT_TRUE(!!ExpectedFT);
|
|
|
|
Expected<TBDFile> Result = TextAPIReader::get(InputBuf);
|
|
EXPECT_TRUE(!!Result);
|
|
TBDFile File = std::move(Result.get());
|
|
EXPECT_EQ(FileType::TBD_V5, File->getFileType());
|
|
EXPECT_EQ(*ExpectedFT, File->getFileType());
|
|
EXPECT_EQ(std::string("/S/L/F/Foo.framework/Foo"), File->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)),
|
|
};
|
|
std::set<Target> FileTargets{File->targets().begin(), File->targets().end()};
|
|
EXPECT_EQ(mapToPlatformSet(AllTargets), File->getPlatforms());
|
|
EXPECT_EQ(mapToArchitectureSet(AllTargets), File->getArchitectures());
|
|
EXPECT_EQ(FileTargets.size(), AllTargets.size());
|
|
for (const auto &Targ : AllTargets) {
|
|
auto FileTarg = FileTargets.find(Targ);
|
|
EXPECT_FALSE(FileTarg == FileTargets.end());
|
|
EXPECT_EQ(*FileTarg, Targ);
|
|
PackedVersion MD = Targ.MinDeployment;
|
|
PackedVersion FileMD = FileTarg->MinDeployment;
|
|
EXPECT_EQ(MD, FileMD);
|
|
}
|
|
|
|
EXPECT_EQ(PackedVersion(1, 2, 0), File->getCurrentVersion());
|
|
EXPECT_EQ(PackedVersion(1, 1, 0), File->getCompatibilityVersion());
|
|
EXPECT_TRUE(File->isApplicationExtensionSafe());
|
|
EXPECT_FALSE(File->isTwoLevelNamespace());
|
|
EXPECT_FALSE(File->isOSLibNotForSharedCache());
|
|
EXPECT_EQ(0U, File->documents().size());
|
|
|
|
InterfaceFileRef ClientA("ClientA", AllTargets);
|
|
InterfaceFileRef ClientB("ClientB", AllTargets);
|
|
EXPECT_EQ(2U, File->allowableClients().size());
|
|
EXPECT_EQ(ClientA, File->allowableClients().at(0));
|
|
EXPECT_EQ(ClientB, File->allowableClients().at(1));
|
|
|
|
InterfaceFileRef ReexportA("/u/l/l/libbar.dylib", AllTargets);
|
|
InterfaceFileRef ReexportB("/u/l/l/libfoo.dylib", AllTargets);
|
|
EXPECT_EQ(2U, File->reexportedLibraries().size());
|
|
EXPECT_EQ(ReexportA, File->reexportedLibraries().at(0));
|
|
EXPECT_EQ(ReexportB, File->reexportedLibraries().at(1));
|
|
|
|
TargetToAttr RPaths = {
|
|
{Target(AK_x86_64, PLATFORM_MACOS), "@executable_path/.../Frameworks"},
|
|
};
|
|
EXPECT_EQ(RPaths, File->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, File->umbrellas());
|
|
|
|
ExportedSymbolSeq Exports, Reexports, Undefineds;
|
|
for (const auto *Sym : File->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 = {
|
|
{EncodeKind::GlobalSymbol, "_func", false, false, false, MacOSTargets},
|
|
{EncodeKind::GlobalSymbol,
|
|
"_funcFoo",
|
|
false,
|
|
false,
|
|
false,
|
|
{Target(AK_x86_64, PLATFORM_MACOS)}},
|
|
{EncodeKind::GlobalSymbol, "_global", false, false, true, MacOSTargets},
|
|
{EncodeKind::GlobalSymbol,
|
|
"_globalVar",
|
|
false,
|
|
false,
|
|
true,
|
|
{Target(AK_x86_64, PLATFORM_MACOS)}},
|
|
{EncodeKind::ObjectiveCClass,
|
|
"ClassA",
|
|
false,
|
|
false,
|
|
true,
|
|
{Target(AK_x86_64, PLATFORM_MACOS)}},
|
|
{EncodeKind::ObjectiveCClass,
|
|
"ClassB",
|
|
false,
|
|
false,
|
|
true,
|
|
{Target(AK_x86_64, PLATFORM_MACOS)}},
|
|
{EncodeKind::ObjectiveCClass,
|
|
"ClassData",
|
|
false,
|
|
false,
|
|
true,
|
|
{Target(AK_x86_64, PLATFORM_MACOS)}},
|
|
{EncodeKind::ObjectiveCClassEHType,
|
|
"ClassA",
|
|
false,
|
|
false,
|
|
true,
|
|
{Target(AK_x86_64, PLATFORM_MACOS)}},
|
|
{EncodeKind::ObjectiveCClassEHType,
|
|
"ClassB",
|
|
false,
|
|
false,
|
|
true,
|
|
{Target(AK_x86_64, PLATFORM_MACOS)}},
|
|
{EncodeKind::ObjectiveCInstanceVariable,
|
|
"ClassA.ivar1",
|
|
false,
|
|
false,
|
|
true,
|
|
{Target(AK_x86_64, PLATFORM_MACOS)}},
|
|
{EncodeKind::ObjectiveCInstanceVariable,
|
|
"ClassA.ivar2",
|
|
false,
|
|
false,
|
|
true,
|
|
{Target(AK_x86_64, PLATFORM_MACOS)}},
|
|
{EncodeKind::ObjectiveCInstanceVariable,
|
|
"ClassC.ivar1",
|
|
false,
|
|
false,
|
|
true,
|
|
{Target(AK_x86_64, PLATFORM_MACOS)}},
|
|
};
|
|
std::vector<ExportedSymbol> ExpectedReexportedSymbols = {
|
|
{EncodeKind::GlobalSymbol, "_funcA", false, false, false, MacOSTargets},
|
|
{EncodeKind::GlobalSymbol, "_globalRe", false, false, true, MacOSTargets},
|
|
{EncodeKind::ObjectiveCClass, "ClassRexport", false, false, true,
|
|
MacOSTargets},
|
|
};
|
|
|
|
std::vector<ExportedSymbol> ExpectedUndefinedSymbols = {
|
|
{EncodeKind::GlobalSymbol,
|
|
"_globalBind",
|
|
false,
|
|
false,
|
|
true,
|
|
{Target(AK_x86_64, PLATFORM_MACOS)}},
|
|
{EncodeKind::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)));
|
|
|
|
EXPECT_TRUE(
|
|
File->getSymbol(EncodeKind::GlobalSymbol, "_globalBind").has_value());
|
|
}
|
|
|
|
TEST(TBDv5, ReadMultipleTargets) {
|
|
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"
|
|
}
|
|
],
|
|
"install_names":[
|
|
{ "name":"/usr/lib/libFoo.dylib" }
|
|
],
|
|
"swift_abi":[ { "abi":8 } ],
|
|
"reexported_libraries": [
|
|
{
|
|
"targets": [ "x86_64-maccatalyst" ],
|
|
"names": [
|
|
"/u/l/l/libfoo.dylib",
|
|
"/u/l/l/libbar.dylib"
|
|
]
|
|
},
|
|
{
|
|
"targets": [ "arm64-maccatalyst" ],
|
|
"names": [ "/u/l/l/libArmOnly.dylib" ]
|
|
}
|
|
]
|
|
}
|
|
})";
|
|
|
|
Expected<TBDFile> Result =
|
|
TextAPIReader::get(MemoryBufferRef(TBDv5File, "Test.tbd"));
|
|
EXPECT_TRUE(!!Result);
|
|
TBDFile File = std::move(Result.get());
|
|
EXPECT_EQ(FileType::TBD_V5, File->getFileType());
|
|
EXPECT_EQ(std::string("/usr/lib/libFoo.dylib"), File->getInstallName());
|
|
EXPECT_TRUE(File->isApplicationExtensionSafe());
|
|
EXPECT_TRUE(File->isTwoLevelNamespace());
|
|
EXPECT_EQ(PackedVersion(1, 0, 0), File->getCurrentVersion());
|
|
EXPECT_EQ(PackedVersion(1, 0, 0), File->getCompatibilityVersion());
|
|
EXPECT_EQ(8U, File->getSwiftABIVersion());
|
|
|
|
TargetList AllTargets = {
|
|
Target(AK_x86_64, PLATFORM_MACOS, VersionTuple(10, 14)),
|
|
Target(AK_arm64, PLATFORM_MACOS, VersionTuple(10, 14)),
|
|
Target(AK_arm64, PLATFORM_MACCATALYST, VersionTuple(12, 1)),
|
|
};
|
|
EXPECT_EQ(mapToPlatformSet(AllTargets), File->getPlatforms());
|
|
EXPECT_EQ(mapToArchitectureSet(AllTargets), File->getArchitectures());
|
|
|
|
InterfaceFileRef ReexportA("/u/l/l/libArmOnly.dylib",
|
|
{Target(AK_arm64, PLATFORM_MACCATALYST)});
|
|
InterfaceFileRef ReexportB("/u/l/l/libbar.dylib",
|
|
{Target(AK_x86_64, PLATFORM_MACCATALYST)});
|
|
InterfaceFileRef ReexportC("/u/l/l/libfoo.dylib",
|
|
{Target(AK_x86_64, PLATFORM_MACCATALYST)});
|
|
EXPECT_EQ(3U, File->reexportedLibraries().size());
|
|
EXPECT_EQ(ReexportA, File->reexportedLibraries().at(0));
|
|
EXPECT_EQ(ReexportB, File->reexportedLibraries().at(1));
|
|
EXPECT_EQ(ReexportC, File->reexportedLibraries().at(2));
|
|
}
|
|
|
|
TEST(TBDv5, ReadMultipleDocuments) {
|
|
static const char TBDv5File[] = R"({
|
|
"tapi_tbd_version": 5,
|
|
"main_library": {
|
|
"target_info": [
|
|
{
|
|
"target": "armv7-ios",
|
|
"min_deployment": "11.0"
|
|
}
|
|
],
|
|
"install_names":[
|
|
{ "name":"/S/L/F/Foo.framework/Foo" }
|
|
],
|
|
"reexported_libraries": [
|
|
{ "names": ["/u/l/l/libfoo.dylib"] }
|
|
]
|
|
},
|
|
"libraries": [
|
|
{
|
|
"target_info": [
|
|
{
|
|
"target": "armv7-ios",
|
|
"min_deployment": "11.0"
|
|
}
|
|
],
|
|
"install_names":[
|
|
{ "name":"/u/l/l/libfoo.dylib" }
|
|
],
|
|
"flags":[
|
|
{ "attributes": ["not_app_extension_safe"] }
|
|
],
|
|
"exported_symbols": [
|
|
{
|
|
"data": {
|
|
"thread_local": [ "_globalVar" ],
|
|
"objc_class": [ "ClassData", "ClassA", "ClassB"],
|
|
"objc_eh_type": [ "ClassA", "ClassB" ]
|
|
},
|
|
"text": {
|
|
"global": [ "_funcFoo" ]
|
|
}
|
|
}
|
|
]
|
|
}
|
|
]})";
|
|
|
|
Expected<TBDFile> Result =
|
|
TextAPIReader::get(MemoryBufferRef(TBDv5File, "Test.tbd"));
|
|
EXPECT_TRUE(!!Result);
|
|
TBDFile File = std::move(Result.get());
|
|
EXPECT_EQ(FileType::TBD_V5, File->getFileType());
|
|
EXPECT_EQ(std::string("/S/L/F/Foo.framework/Foo"), File->getInstallName());
|
|
EXPECT_TRUE(File->isTwoLevelNamespace());
|
|
EXPECT_TRUE(File->isApplicationExtensionSafe());
|
|
|
|
TargetList Targets(File->targets().begin(), File->targets().end());
|
|
Target iOSTarget(AK_armv7, PLATFORM_IOS, VersionTuple(11, 0));
|
|
EXPECT_EQ(TargetList{iOSTarget}, Targets);
|
|
std::vector<const Symbol *> Symbols(File->symbols().begin(),
|
|
File->symbols().end());
|
|
EXPECT_EQ(0U, Symbols.size());
|
|
|
|
InterfaceFileRef Reexport("/u/l/l/libfoo.dylib", {iOSTarget});
|
|
EXPECT_EQ(1U, File->reexportedLibraries().size());
|
|
EXPECT_EQ(Reexport, File->reexportedLibraries().at(0));
|
|
|
|
// Check inlined library.
|
|
EXPECT_EQ(1U, File->documents().size());
|
|
TBDReexportFile Document = File->documents().front();
|
|
Targets = {Document->targets().begin(), Document->targets().end()};
|
|
EXPECT_EQ(TargetList{iOSTarget}, Targets);
|
|
EXPECT_EQ(std::string("/u/l/l/libfoo.dylib"), Document->getInstallName());
|
|
EXPECT_EQ(0U, Document->getSwiftABIVersion());
|
|
EXPECT_TRUE(Document->isTwoLevelNamespace());
|
|
EXPECT_FALSE(Document->isApplicationExtensionSafe());
|
|
|
|
ExportedSymbolSeq Exports;
|
|
for (const auto *Sym : Document->symbols())
|
|
Exports.emplace_back(
|
|
ExportedSymbol{Sym->getKind(),
|
|
std::string(Sym->getName()),
|
|
Sym->isWeakDefined() || Sym->isWeakReferenced(),
|
|
Sym->isThreadLocalValue(),
|
|
Sym->isData(),
|
|
{iOSTarget}});
|
|
|
|
llvm::sort(Exports);
|
|
ExportedSymbolSeq ExpectedExports = {
|
|
{EncodeKind::GlobalSymbol, "_funcFoo", false, false, false, {iOSTarget}},
|
|
{EncodeKind::GlobalSymbol, "_globalVar", false, true, true, {iOSTarget}},
|
|
{EncodeKind::ObjectiveCClass, "ClassA", false, false, true, {iOSTarget}},
|
|
{EncodeKind::ObjectiveCClass, "ClassB", false, false, true, {iOSTarget}},
|
|
{EncodeKind::ObjectiveCClass,
|
|
"ClassData",
|
|
false,
|
|
false,
|
|
true,
|
|
{iOSTarget}},
|
|
{EncodeKind::ObjectiveCClassEHType,
|
|
"ClassA",
|
|
false,
|
|
false,
|
|
true,
|
|
{iOSTarget}},
|
|
{EncodeKind::ObjectiveCClassEHType,
|
|
"ClassB",
|
|
false,
|
|
false,
|
|
true,
|
|
{iOSTarget}},
|
|
};
|
|
|
|
EXPECT_EQ(ExpectedExports.size(), Exports.size());
|
|
EXPECT_TRUE(
|
|
std::equal(Exports.begin(), Exports.end(), std::begin(ExpectedExports)));
|
|
}
|
|
|
|
TEST(TBDv5, WriteFile) {
|
|
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"
|
|
}
|
|
],
|
|
"install_names": [
|
|
{
|
|
"name": "@rpath/S/L/F/Foo.framework/Foo"
|
|
}
|
|
],
|
|
"current_versions": [
|
|
{
|
|
"version": "1.2"
|
|
}
|
|
],
|
|
"compatibility_versions": [
|
|
{ "version": "1.1" }
|
|
],
|
|
"flags": [
|
|
{
|
|
"attributes": [
|
|
"flat_namespace"
|
|
]
|
|
}
|
|
],
|
|
"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": [
|
|
{
|
|
"data": {
|
|
"global": [
|
|
"_globalRe"
|
|
],
|
|
"objc_class": [
|
|
"ClassRexport"
|
|
]
|
|
},
|
|
"text": {
|
|
"global": [
|
|
"_funcA"
|
|
]
|
|
}
|
|
}
|
|
],
|
|
"undefined_symbols": [
|
|
{
|
|
"targets": [
|
|
"x86_64-macos"
|
|
],
|
|
"data": {
|
|
"global": [
|
|
"_globalBind"
|
|
],
|
|
"weak": [
|
|
"referenced_sym"
|
|
]
|
|
}
|
|
}
|
|
]
|
|
}})";
|
|
|
|
InterfaceFile File;
|
|
File.setFileType(FileType::TBD_V5);
|
|
|
|
TargetList AllTargets = {
|
|
Target(AK_x86_64, PLATFORM_MACOS, VersionTuple(10, 14)),
|
|
Target(AK_arm64, PLATFORM_MACOS, VersionTuple(10, 14)),
|
|
Target(AK_arm64, PLATFORM_MACCATALYST, VersionTuple(12, 1)),
|
|
};
|
|
File.addTargets(AllTargets);
|
|
File.setInstallName("@rpath/S/L/F/Foo.framework/Foo");
|
|
File.setCurrentVersion(PackedVersion(1, 2, 0));
|
|
File.setCompatibilityVersion(PackedVersion(1, 1, 0));
|
|
File.addRPath("@executable_path/.../Frameworks", AllTargets[0]);
|
|
|
|
for (const auto &Targ : AllTargets) {
|
|
File.addParentUmbrella(Targ, "System");
|
|
File.addAllowableClient("ClientA", Targ);
|
|
File.addAllowableClient("ClientB", Targ);
|
|
File.addReexportedLibrary("/u/l/l/libfoo.dylib", Targ);
|
|
File.addReexportedLibrary("/u/l/l/libbar.dylib", Targ);
|
|
}
|
|
|
|
SymbolFlags Flags = SymbolFlags::None;
|
|
// Exports.
|
|
File.addSymbol(EncodeKind::GlobalSymbol, "_global",
|
|
{AllTargets[0], AllTargets[1]}, Flags | SymbolFlags::Data);
|
|
File.addSymbol(EncodeKind::GlobalSymbol, "_func",
|
|
{AllTargets[0], AllTargets[1]}, Flags | SymbolFlags::Text);
|
|
File.addSymbol(EncodeKind::ObjectiveCClass, "ClassA",
|
|
{AllTargets[0], AllTargets[1]}, Flags | SymbolFlags::Data);
|
|
File.addSymbol(EncodeKind::GlobalSymbol, "_funcFoo", {AllTargets[0]},
|
|
Flags | SymbolFlags::Text);
|
|
File.addSymbol(EncodeKind::GlobalSymbol, "_globalVar", {AllTargets[0]},
|
|
Flags | SymbolFlags::Data);
|
|
File.addSymbol(EncodeKind::ObjectiveCClass, "ClassData", {AllTargets[0]},
|
|
Flags | SymbolFlags::Data);
|
|
File.addSymbol(EncodeKind::ObjectiveCClassEHType, "ClassA", {AllTargets[0]},
|
|
Flags | SymbolFlags::Data);
|
|
File.addSymbol(EncodeKind::ObjectiveCClassEHType, "ClassB", {AllTargets[0]},
|
|
Flags | SymbolFlags::Data);
|
|
File.addSymbol(EncodeKind::ObjectiveCInstanceVariable, "ClassA.ivar1",
|
|
{AllTargets[0]}, Flags | SymbolFlags::Data);
|
|
File.addSymbol(EncodeKind::ObjectiveCInstanceVariable, "ClassA.ivar2",
|
|
{AllTargets[0]}, Flags | SymbolFlags::Data);
|
|
File.addSymbol(EncodeKind::ObjectiveCInstanceVariable, "ClassC.ivar1",
|
|
{AllTargets[0]}, Flags | SymbolFlags::Data);
|
|
|
|
// Reexports.
|
|
Flags = SymbolFlags::Rexported;
|
|
File.addSymbol(EncodeKind::GlobalSymbol, "_globalRe", AllTargets,
|
|
Flags | SymbolFlags::Data);
|
|
File.addSymbol(EncodeKind::GlobalSymbol, "_funcA", AllTargets,
|
|
Flags | SymbolFlags::Text);
|
|
File.addSymbol(EncodeKind::ObjectiveCClass, "ClassRexport", AllTargets,
|
|
Flags | SymbolFlags::Data);
|
|
|
|
// Undefineds.
|
|
Flags = SymbolFlags::Undefined;
|
|
File.addSymbol(EncodeKind::GlobalSymbol, "_globalBind", {AllTargets[0]},
|
|
Flags | SymbolFlags::Data);
|
|
File.addSymbol(EncodeKind::GlobalSymbol, "referenced_sym", {AllTargets[0]},
|
|
Flags | SymbolFlags::Data | SymbolFlags::WeakReferenced);
|
|
|
|
File.setTwoLevelNamespace(false);
|
|
File.setApplicationExtensionSafe(true);
|
|
|
|
// Write out file then process it back into IF and compare equality
|
|
// against TBDv5File.
|
|
SmallString<4096> Buffer;
|
|
raw_svector_ostream OS(Buffer);
|
|
Error Result = TextAPIWriter::writeToStream(OS, File);
|
|
EXPECT_FALSE(Result);
|
|
|
|
Expected<TBDFile> Input =
|
|
TextAPIReader::get(MemoryBufferRef(TBDv5File, "Input.tbd"));
|
|
EXPECT_TRUE(!!Input);
|
|
TBDFile InputFile = std::move(Input.get());
|
|
|
|
Expected<TBDFile> Output =
|
|
TextAPIReader::get(MemoryBufferRef(Buffer, "Output.tbd"));
|
|
EXPECT_TRUE(!!Output);
|
|
TBDFile OutputFile = std::move(Output.get());
|
|
EXPECT_EQ(*InputFile, *OutputFile);
|
|
}
|
|
|
|
TEST(TBDv5, WriteMultipleDocuments) {
|
|
static const char TBDv5File[] = R"({
|
|
"tapi_tbd_version": 5,
|
|
"main_library": {
|
|
"target_info": [
|
|
{
|
|
"target": "armv7-ios",
|
|
"min_deployment": "11.0"
|
|
}
|
|
],
|
|
"install_names":[
|
|
{ "name":"/S/L/F/Foo.framework/Foo" }
|
|
],
|
|
"reexported_libraries": [
|
|
{ "names": ["/u/l/l/libfoo.dylib"]
|
|
}
|
|
]
|
|
},
|
|
"libraries": [
|
|
{
|
|
"target_info": [
|
|
{
|
|
"target": "armv7-ios",
|
|
"min_deployment": "11.0"
|
|
},
|
|
{
|
|
"target": "armv7s-ios",
|
|
"min_deployment": "11.0"
|
|
}
|
|
],
|
|
"install_names":[
|
|
{ "name":"/u/l/l/libfoo.dylib" }
|
|
],
|
|
"current_versions": [
|
|
{
|
|
"version": "2.1.1"
|
|
}
|
|
],
|
|
"rpaths": [
|
|
{
|
|
"targets": [
|
|
"armv7-ios"
|
|
],
|
|
"paths": [
|
|
"@executable_path/.../Frameworks"
|
|
]
|
|
}],
|
|
"reexported_libraries": [ { "names": ["@rpath/libfoo.dylib"] } ],
|
|
"flags":[
|
|
{ "attributes": ["not_app_extension_safe"] }
|
|
],
|
|
"exported_symbols": [
|
|
{
|
|
"text": {
|
|
"global": [ "_funcFoo" ]
|
|
}
|
|
}
|
|
]
|
|
},
|
|
{
|
|
"target_info": [
|
|
{
|
|
"target": "armv7-ios",
|
|
"min_deployment": "11.0"
|
|
}
|
|
],
|
|
"install_names":[
|
|
{ "name":"@rpath/libfoo.dylib" }
|
|
],
|
|
"exported_symbols": [
|
|
{
|
|
"data": {
|
|
"global": [ "_varFooBaz" ]
|
|
}
|
|
}
|
|
]
|
|
}
|
|
]})";
|
|
|
|
InterfaceFile File;
|
|
File.setFileType(FileType::TBD_V5);
|
|
|
|
TargetList AllTargets = {
|
|
Target(AK_armv7, PLATFORM_IOS, VersionTuple(11, 0)),
|
|
Target(AK_armv7s, PLATFORM_IOS, VersionTuple(11, 0)),
|
|
};
|
|
File.setInstallName("/S/L/F/Foo.framework/Foo");
|
|
File.addTarget(AllTargets[0]);
|
|
File.setCurrentVersion(PackedVersion(1, 0, 0));
|
|
File.setCompatibilityVersion(PackedVersion(1, 0, 0));
|
|
File.addReexportedLibrary("/u/l/l/libfoo.dylib", AllTargets[0]);
|
|
File.setTwoLevelNamespace();
|
|
File.setApplicationExtensionSafe(true);
|
|
|
|
InterfaceFile NestedFile;
|
|
NestedFile.setFileType(FileType::TBD_V5);
|
|
NestedFile.setInstallName("/u/l/l/libfoo.dylib");
|
|
NestedFile.addTargets(AllTargets);
|
|
NestedFile.setCompatibilityVersion(PackedVersion(1, 0, 0));
|
|
NestedFile.setTwoLevelNamespace();
|
|
NestedFile.setApplicationExtensionSafe(false);
|
|
NestedFile.setCurrentVersion(PackedVersion(2, 1, 1));
|
|
NestedFile.addRPath("@executable_path/.../Frameworks", AllTargets[0]);
|
|
for (const auto &Targ : AllTargets)
|
|
NestedFile.addReexportedLibrary("@rpath/libfoo.dylib", Targ);
|
|
NestedFile.addSymbol(EncodeKind::GlobalSymbol, "_funcFoo", AllTargets,
|
|
SymbolFlags::Text);
|
|
File.addDocument(std::make_shared<InterfaceFile>(std::move(NestedFile)));
|
|
|
|
InterfaceFile NestedFileB;
|
|
NestedFileB.setFileType(FileType::TBD_V5);
|
|
NestedFileB.setInstallName("@rpath/libfoo.dylib");
|
|
NestedFileB.addTarget(AllTargets[0]);
|
|
NestedFileB.setCompatibilityVersion(PackedVersion(1, 0, 0));
|
|
NestedFileB.setCurrentVersion(PackedVersion(1, 0, 0));
|
|
NestedFileB.setTwoLevelNamespace();
|
|
NestedFileB.setApplicationExtensionSafe(true);
|
|
NestedFileB.addSymbol(EncodeKind::GlobalSymbol, "_varFooBaz", {AllTargets[0]},
|
|
SymbolFlags::Data);
|
|
File.addDocument(std::make_shared<InterfaceFile>(std::move(NestedFileB)));
|
|
|
|
// Write out file then process it back into IF and compare equality
|
|
// against TBDv5File.
|
|
SmallString<4096> Buffer;
|
|
raw_svector_ostream OS(Buffer);
|
|
Error Result = TextAPIWriter::writeToStream(OS, File, FileType::Invalid,
|
|
/*Compact=*/true);
|
|
EXPECT_FALSE(Result);
|
|
|
|
Expected<TBDFile> Input =
|
|
TextAPIReader::get(MemoryBufferRef(TBDv5File, "Input.tbd"));
|
|
EXPECT_TRUE(!!Input);
|
|
TBDFile InputFile = std::move(Input.get());
|
|
|
|
Expected<TBDFile> Output =
|
|
TextAPIReader::get(MemoryBufferRef(Buffer, "Output.tbd"));
|
|
EXPECT_TRUE(!!Output);
|
|
TBDFile OutputFile = std::move(Output.get());
|
|
EXPECT_EQ(*InputFile, *OutputFile);
|
|
}
|
|
|
|
TEST(TBDv5, Target_Simulator) {
|
|
static const char TBDv5File[] = R"({
|
|
"tapi_tbd_version": 5,
|
|
"main_library": {
|
|
"target_info": [
|
|
{
|
|
"target": "arm64-ios-simulator",
|
|
"min_deployment": "11.0"
|
|
},
|
|
{
|
|
"target": "x86_64-ios-simulator",
|
|
"min_deployment": "11.3"
|
|
}
|
|
],
|
|
"install_names":[
|
|
{ "name":"/S/L/F/Foo.framework/Foo" }
|
|
]
|
|
}})";
|
|
|
|
Expected<TBDFile> Result =
|
|
TextAPIReader::get(MemoryBufferRef(TBDv5File, "Test.tbd"));
|
|
EXPECT_TRUE(!!Result);
|
|
TBDFile File = std::move(Result.get());
|
|
EXPECT_EQ(FileType::TBD_V5, File->getFileType());
|
|
TargetList ExpectedTargets = {
|
|
Target(AK_x86_64, PLATFORM_IOSSIMULATOR, VersionTuple(11, 3)),
|
|
Target(AK_arm64, PLATFORM_IOSSIMULATOR, VersionTuple(14, 0)),
|
|
};
|
|
TargetList Targets{File->targets().begin(), File->targets().end()};
|
|
llvm::sort(Targets);
|
|
EXPECT_EQ(Targets, ExpectedTargets);
|
|
|
|
SmallString<4096> Buffer;
|
|
raw_svector_ostream OS(Buffer);
|
|
Error WriteResult = TextAPIWriter::writeToStream(OS, *File);
|
|
EXPECT_TRUE(!WriteResult);
|
|
|
|
Expected<TBDFile> Output =
|
|
TextAPIReader::get(MemoryBufferRef(Buffer, "Output.tbd"));
|
|
EXPECT_TRUE(!!Output);
|
|
TBDFile WriteResultFile = std::move(Output.get());
|
|
EXPECT_EQ(*File, *WriteResultFile);
|
|
}
|
|
|
|
TEST(TBDv5, Target_UnsupportedMinOS) {
|
|
static const char TBDv5File[] = R"({
|
|
"tapi_tbd_version": 5,
|
|
"main_library": {
|
|
"target_info": [
|
|
{
|
|
"target": "arm64-macos",
|
|
"min_deployment": "10.14"
|
|
},
|
|
{
|
|
"target": "x86_64-macos",
|
|
"min_deployment": "10.14"
|
|
}
|
|
],
|
|
"install_names":[
|
|
{ "name":"/S/L/F/Foo.framework/Foo" }
|
|
]
|
|
}})";
|
|
|
|
Expected<TBDFile> Result =
|
|
TextAPIReader::get(MemoryBufferRef(TBDv5File, "Test.tbd"));
|
|
EXPECT_TRUE(!!Result);
|
|
TBDFile File = std::move(Result.get());
|
|
EXPECT_EQ(FileType::TBD_V5, File->getFileType());
|
|
TargetList ExpectedTargets = {
|
|
Target(AK_x86_64, PLATFORM_MACOS, VersionTuple(10, 14)),
|
|
Target(AK_arm64, PLATFORM_MACOS, VersionTuple(11, 0)),
|
|
};
|
|
TargetList Targets{File->targets().begin(), File->targets().end()};
|
|
llvm::sort(Targets);
|
|
EXPECT_EQ(Targets, ExpectedTargets);
|
|
|
|
SmallString<4096> Buffer;
|
|
raw_svector_ostream OS(Buffer);
|
|
Error WriteResult = TextAPIWriter::writeToStream(OS, *File);
|
|
EXPECT_TRUE(!WriteResult);
|
|
|
|
Expected<TBDFile> Output =
|
|
TextAPIReader::get(MemoryBufferRef(Buffer, "Output.tbd"));
|
|
EXPECT_TRUE(!!Output);
|
|
TBDFile WriteResultFile = std::move(Output.get());
|
|
EXPECT_EQ(*File, *WriteResultFile);
|
|
}
|
|
|
|
TEST(TBDv5, MisspelledKey) {
|
|
static const char TBDv5File[] = R"({
|
|
"tapi_tbd_version": 5,
|
|
"main_library": {
|
|
"target_info": [
|
|
{
|
|
"target": "arm64-ios-simulator",
|
|
"min_deployment": "11.0"
|
|
}
|
|
],
|
|
"intall_names":[
|
|
{ "name":"/S/L/F/Foo.framework/Foo" }
|
|
]
|
|
}})";
|
|
|
|
Expected<TBDFile> Result =
|
|
TextAPIReader::get(MemoryBufferRef(TBDv5File, "Test.tbd"));
|
|
EXPECT_FALSE(!!Result);
|
|
std::string ErrorMessage = toString(Result.takeError());
|
|
EXPECT_EQ("invalid install_names section\n", ErrorMessage);
|
|
}
|
|
|
|
TEST(TBDv5, InvalidVersion) {
|
|
static const char TBDv5File[] = R"({
|
|
"tapi_tbd_version": 11,
|
|
"main_library": {
|
|
"target_info": [
|
|
{
|
|
"target": "arm64-ios-simulator",
|
|
"min_deployment": "11.0"
|
|
}
|
|
],
|
|
"install_names":[
|
|
{ "name":"/S/L/F/Foo.framework/Foo" }
|
|
]
|
|
}})";
|
|
|
|
Expected<TBDFile> Result =
|
|
TextAPIReader::get(MemoryBufferRef(TBDv5File, "Test.tbd"));
|
|
EXPECT_FALSE(!!Result);
|
|
std::string ErrorMessage = toString(Result.takeError());
|
|
EXPECT_EQ("invalid tapi_tbd_version section\n", ErrorMessage);
|
|
}
|
|
|
|
TEST(TBDv5, MissingRequiredKey) {
|
|
static const char TBDv5File[] = R"({
|
|
"main_library": {
|
|
"target_info": [
|
|
{
|
|
"target": "arm64-ios-simulator",
|
|
"min_deployment": "11.0"
|
|
}
|
|
],
|
|
"install_names":[
|
|
{ "name":"/S/L/F/Foo.framework/Foo" }
|
|
]
|
|
}})";
|
|
|
|
Expected<TBDFile> Result =
|
|
TextAPIReader::get(MemoryBufferRef(TBDv5File, "Test.tbd"));
|
|
EXPECT_FALSE(!!Result);
|
|
std::string ErrorMessage = toString(Result.takeError());
|
|
EXPECT_EQ("invalid tapi_tbd_version section\n", ErrorMessage);
|
|
}
|
|
|
|
TEST(TBDv5, InvalidSymbols) {
|
|
static const char TBDv5File[] = R"({
|
|
"tapi_tbd_version": 5,
|
|
"main_library": {
|
|
"target_info": [
|
|
{
|
|
"target": "arm64-driverkit",
|
|
"min_deployment": "11.0"
|
|
}
|
|
],
|
|
"install_names":[
|
|
{ "name":"/S/L/F/Foo.framework/Foo" }
|
|
],
|
|
"exported_symbols": [
|
|
{
|
|
"daa": {
|
|
"global": {
|
|
"weak": []
|
|
}
|
|
}
|
|
}
|
|
]
|
|
}})";
|
|
|
|
Expected<TBDFile> Result =
|
|
TextAPIReader::get(MemoryBufferRef(TBDv5File, "Test.tbd"));
|
|
EXPECT_FALSE(!!Result);
|
|
std::string ErrorMessage = toString(Result.takeError());
|
|
EXPECT_EQ("invalid exported_symbols section\n", ErrorMessage);
|
|
}
|
|
|
|
TEST(TBDv5, DefaultMinOS) {
|
|
static const char TBDv5File[] = R"({
|
|
"tapi_tbd_version": 5,
|
|
"main_library": {
|
|
"target_info": [
|
|
{
|
|
"target": "arm64-ios-simulator"
|
|
}
|
|
],
|
|
"install_names":[
|
|
{ "name":"/S/L/F/Foo.framework/Foo" }
|
|
]
|
|
}})";
|
|
|
|
Expected<TBDFile> Result =
|
|
TextAPIReader::get(MemoryBufferRef(TBDv5File, "Test.tbd"));
|
|
EXPECT_TRUE(!!Result);
|
|
TBDFile File = std::move(Result.get());
|
|
EXPECT_EQ(FileType::TBD_V5, File->getFileType());
|
|
EXPECT_EQ(std::string("/S/L/F/Foo.framework/Foo"), File->getInstallName());
|
|
EXPECT_TRUE(File->targets().begin() != File->targets().end());
|
|
EXPECT_EQ(*File->targets().begin(),
|
|
Target(AK_arm64, PLATFORM_IOSSIMULATOR, VersionTuple(0, 0)));
|
|
}
|
|
|
|
TEST(TBDv5, InvalidMinOS) {
|
|
static const char TBDv5File[] = R"({
|
|
"tapi_tbd_version": 5,
|
|
"main_library": {
|
|
"target_info": [
|
|
{
|
|
"target": "arm64-ios-simulator",
|
|
"min_deployment": "swift-abi"
|
|
}
|
|
],
|
|
"install_names":[
|
|
{ "name":"/S/L/F/Foo.framework/Foo" }
|
|
]
|
|
}})";
|
|
|
|
Expected<TBDFile> Result =
|
|
TextAPIReader::get(MemoryBufferRef(TBDv5File, "Test.tbd"));
|
|
EXPECT_FALSE(!!Result);
|
|
std::string ErrorMessage = toString(Result.takeError());
|
|
EXPECT_EQ("invalid min_deployment section\n", ErrorMessage);
|
|
}
|
|
|
|
TEST(TBDv5, SimSupport) {
|
|
static const char TBDv5File[] = R"({
|
|
"tapi_tbd_version": 5,
|
|
"main_library": {
|
|
"target_info": [
|
|
{
|
|
"target": "arm64-macos",
|
|
"min_deployment": "11.1"
|
|
}
|
|
],
|
|
"install_names":[
|
|
{ "name":"/S/L/F/Foo.framework/Foo" }
|
|
],
|
|
"flags":[
|
|
{ "attributes": ["sim_support"] }
|
|
]
|
|
}})";
|
|
|
|
Expected<TBDFile> Result =
|
|
TextAPIReader::get(MemoryBufferRef(TBDv5File, "Test.tbd"));
|
|
EXPECT_TRUE(!!Result);
|
|
Target ExpectedTarget = Target(AK_arm64, PLATFORM_MACOS, VersionTuple(11, 1));
|
|
TBDFile ReadFile = std::move(Result.get());
|
|
EXPECT_EQ(FileType::TBD_V5, ReadFile->getFileType());
|
|
EXPECT_EQ(std::string("/S/L/F/Foo.framework/Foo"),
|
|
ReadFile->getInstallName());
|
|
EXPECT_TRUE(ReadFile->targets().begin() != ReadFile->targets().end());
|
|
EXPECT_EQ(*ReadFile->targets().begin(), ExpectedTarget);
|
|
EXPECT_TRUE(ReadFile->hasSimulatorSupport());
|
|
}
|
|
|
|
TEST(TBDv5, NotForSharedCache) {
|
|
static const char TBDv5File[] = R"({
|
|
"tapi_tbd_version": 5,
|
|
"main_library": {
|
|
"target_info": [
|
|
{
|
|
"target": "arm64-macos",
|
|
"min_deployment": "11.1"
|
|
}
|
|
],
|
|
"install_names":[
|
|
{ "name":"/S/L/F/Foo.framework/Foo" }
|
|
],
|
|
"flags":[
|
|
{ "attributes": ["not_for_dyld_shared_cache"] }
|
|
]
|
|
}})";
|
|
|
|
Expected<TBDFile> Result =
|
|
TextAPIReader::get(MemoryBufferRef(TBDv5File, "Test.tbd"));
|
|
EXPECT_TRUE(!!Result);
|
|
Target ExpectedTarget = Target(AK_arm64, PLATFORM_MACOS, VersionTuple(11, 1));
|
|
TBDFile ReadFile = std::move(Result.get());
|
|
EXPECT_EQ(FileType::TBD_V5, ReadFile->getFileType());
|
|
EXPECT_EQ(std::string("/S/L/F/Foo.framework/Foo"),
|
|
ReadFile->getInstallName());
|
|
EXPECT_TRUE(ReadFile->targets().begin() != ReadFile->targets().end());
|
|
EXPECT_EQ(*ReadFile->targets().begin(), ExpectedTarget);
|
|
EXPECT_FALSE(ReadFile->hasSimulatorSupport());
|
|
EXPECT_TRUE(ReadFile->isOSLibNotForSharedCache());
|
|
}
|
|
|
|
TEST(TBDv5, ObjCInterfaces) {
|
|
static const char TBDv5File[] = R"({
|
|
"tapi_tbd_version": 5,
|
|
"main_library": {
|
|
"target_info": [
|
|
{
|
|
"target": "arm64-ios-simulator",
|
|
"min_deployment": "14.0"
|
|
}
|
|
],
|
|
"install_names":[
|
|
{ "name":"/S/L/F/Foo.framework/Foo" }
|
|
],
|
|
"exported_symbols": [
|
|
{
|
|
"data": {
|
|
"global": [
|
|
"_global",
|
|
"_OBJC_METACLASS_$_Standalone",
|
|
"_OBJC_CLASS_$_Standalone2"
|
|
],
|
|
"weak": ["_OBJC_EHTYPE_$_NSObject"],
|
|
"objc_class": [
|
|
"ClassA",
|
|
"ClassB"
|
|
],
|
|
"objc_eh_type": ["ClassA"]
|
|
}
|
|
}]
|
|
}})";
|
|
|
|
Expected<TBDFile> Result =
|
|
TextAPIReader::get(MemoryBufferRef(TBDv5File, "Test.tbd"));
|
|
EXPECT_TRUE(!!Result);
|
|
TBDFile File = std::move(Result.get());
|
|
EXPECT_EQ(FileType::TBD_V5, File->getFileType());
|
|
Target ExpectedTarget =
|
|
Target(AK_arm64, PLATFORM_IOSSIMULATOR, VersionTuple(14, 0));
|
|
EXPECT_EQ(*File->targets().begin(), ExpectedTarget);
|
|
|
|
// Check Symbols.
|
|
ExportedSymbolSeq Exports;
|
|
for (const auto *Sym : File->symbols()) {
|
|
ExportedSymbol Temp =
|
|
ExportedSymbol{Sym->getKind(), std::string(Sym->getName()),
|
|
Sym->isWeakDefined() || Sym->isWeakReferenced(),
|
|
Sym->isThreadLocalValue(), Sym->isData()};
|
|
Exports.emplace_back(std::move(Temp));
|
|
}
|
|
llvm::sort(Exports);
|
|
|
|
std::vector<ExportedSymbol> ExpectedExports = {
|
|
{EncodeKind::GlobalSymbol, "_OBJC_CLASS_$_Standalone2", false, false,
|
|
true},
|
|
{EncodeKind::GlobalSymbol, "_OBJC_EHTYPE_$_NSObject", true, false, true},
|
|
{EncodeKind::GlobalSymbol, "_OBJC_METACLASS_$_Standalone", false, false,
|
|
true},
|
|
{EncodeKind::GlobalSymbol, "_global", false, false, true},
|
|
{EncodeKind::ObjectiveCClass, "ClassA", false, false, true},
|
|
{EncodeKind::ObjectiveCClass, "ClassB", false, false, true},
|
|
{EncodeKind::ObjectiveCClassEHType, "ClassA", false, false, true}};
|
|
|
|
EXPECT_EQ(ExpectedExports.size(), Exports.size());
|
|
EXPECT_TRUE(
|
|
std::equal(Exports.begin(), Exports.end(), std::begin(ExpectedExports)));
|
|
|
|
SmallString<4096> Buffer;
|
|
raw_svector_ostream OS(Buffer);
|
|
Error WriteResult = TextAPIWriter::writeToStream(OS, *File);
|
|
EXPECT_TRUE(!WriteResult);
|
|
|
|
Expected<TBDFile> Output =
|
|
TextAPIReader::get(MemoryBufferRef(Buffer, "Output.tbd"));
|
|
EXPECT_TRUE(!!Output);
|
|
TBDFile WriteResultFile = std::move(Output.get());
|
|
EXPECT_EQ(*File, *WriteResultFile);
|
|
}
|
|
|
|
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 = {
|
|
{EncodeKind::GlobalSymbol, "_func", false, false, false, MacOSTargets},
|
|
{EncodeKind::GlobalSymbol,
|
|
"_funcFoo",
|
|
false,
|
|
false,
|
|
false,
|
|
{Target(AK_x86_64, PLATFORM_MACOS)}},
|
|
{EncodeKind::GlobalSymbol,
|
|
"_funcFooZ",
|
|
false,
|
|
false,
|
|
false,
|
|
{Target(AK_x86_64, PLATFORM_MACOS)}},
|
|
{EncodeKind::GlobalSymbol, "_funcZ", false, false, false, MacOSTargets},
|
|
{EncodeKind::GlobalSymbol, "_global", false, false, true, MacOSTargets},
|
|
{EncodeKind::GlobalSymbol,
|
|
"_globalVar",
|
|
false,
|
|
false,
|
|
true,
|
|
{Target(AK_x86_64, PLATFORM_MACOS)}},
|
|
{EncodeKind::GlobalSymbol,
|
|
"_globalVarZ",
|
|
false,
|
|
false,
|
|
true,
|
|
{Target(AK_x86_64, PLATFORM_MACOS)}},
|
|
{EncodeKind::GlobalSymbol, "_globalZ", false, false, true, MacOSTargets},
|
|
{EncodeKind::ObjectiveCClass,
|
|
"ClassA",
|
|
false,
|
|
false,
|
|
true,
|
|
{Target(AK_x86_64, PLATFORM_MACOS)}},
|
|
{EncodeKind::ObjectiveCClass,
|
|
"ClassB",
|
|
false,
|
|
false,
|
|
true,
|
|
{Target(AK_x86_64, PLATFORM_MACOS)}},
|
|
{EncodeKind::ObjectiveCClass,
|
|
"ClassData",
|
|
false,
|
|
false,
|
|
true,
|
|
{Target(AK_x86_64, PLATFORM_MACOS)}},
|
|
{EncodeKind::ObjectiveCClass,
|
|
"ClassF",
|
|
false,
|
|
false,
|
|
true,
|
|
{Target(AK_x86_64, PLATFORM_MACOS)}},
|
|
{EncodeKind::ObjectiveCClass,
|
|
"ClassZ",
|
|
false,
|
|
false,
|
|
true,
|
|
{Target(AK_x86_64, PLATFORM_MACOS)}},
|
|
{EncodeKind::ObjectiveCClassEHType,
|
|
"ClassA",
|
|
false,
|
|
false,
|
|
true,
|
|
{Target(AK_x86_64, PLATFORM_MACOS)}},
|
|
{EncodeKind::ObjectiveCClassEHType,
|
|
"ClassB",
|
|
false,
|
|
false,
|
|
true,
|
|
{Target(AK_x86_64, PLATFORM_MACOS)}},
|
|
{EncodeKind::ObjectiveCClassEHType,
|
|
"ClassF",
|
|
false,
|
|
false,
|
|
true,
|
|
{Target(AK_x86_64, PLATFORM_MACOS)}},
|
|
{EncodeKind::ObjectiveCClassEHType,
|
|
"ClassZ",
|
|
false,
|
|
false,
|
|
true,
|
|
{Target(AK_x86_64, PLATFORM_MACOS)}},
|
|
{EncodeKind::ObjectiveCInstanceVariable,
|
|
"ClassA.ivar1",
|
|
false,
|
|
false,
|
|
true,
|
|
{Target(AK_x86_64, PLATFORM_MACOS)}},
|
|
{EncodeKind::ObjectiveCInstanceVariable,
|
|
"ClassA.ivar2",
|
|
false,
|
|
false,
|
|
true,
|
|
{Target(AK_x86_64, PLATFORM_MACOS)}},
|
|
{EncodeKind::ObjectiveCInstanceVariable,
|
|
"ClassC.ivar1",
|
|
false,
|
|
false,
|
|
true,
|
|
{Target(AK_x86_64, PLATFORM_MACOS)}},
|
|
{EncodeKind::ObjectiveCInstanceVariable,
|
|
"ClassF.ivar1",
|
|
false,
|
|
false,
|
|
true,
|
|
{Target(AK_x86_64, PLATFORM_MACOS)}},
|
|
{EncodeKind::ObjectiveCInstanceVariable,
|
|
"ClassZ.ivar1",
|
|
false,
|
|
false,
|
|
true,
|
|
{Target(AK_x86_64, PLATFORM_MACOS)}},
|
|
{EncodeKind::ObjectiveCInstanceVariable,
|
|
"ClassZ.ivar2",
|
|
false,
|
|
false,
|
|
true,
|
|
{Target(AK_x86_64, PLATFORM_MACOS)}},
|
|
};
|
|
|
|
std::vector<ExportedSymbol> ExpectedReexportedSymbols = {
|
|
{EncodeKind::GlobalSymbol, "_funcA", false, false, false, MacOSTargets},
|
|
{EncodeKind::GlobalSymbol, "_globalRe", false, false, true, MacOSTargets},
|
|
{EncodeKind::ObjectiveCClass, "ClassRexport", false, false, true,
|
|
MacOSTargets},
|
|
};
|
|
|
|
std::vector<ExportedSymbol> ExpectedUndefinedSymbols = {
|
|
{EncodeKind::GlobalSymbol,
|
|
"_globalBind",
|
|
false,
|
|
false,
|
|
true,
|
|
{Target(AK_x86_64, PLATFORM_MACOS)}},
|
|
{EncodeKind::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 = {
|
|
{EncodeKind::GlobalSymbol, "_func", false, false, false, MacOSTargets},
|
|
{EncodeKind::GlobalSymbol, "_global", false, false, true, MacOSTargets},
|
|
{EncodeKind::ObjectiveCClass, "ClassA", false, false, true, MacOSTargets},
|
|
};
|
|
std::vector<ExportedSymbol> ExpectedReexportedSymbols = {
|
|
{EncodeKind::GlobalSymbol, "_funcA", false, false, false, MacOSTargets},
|
|
{EncodeKind::GlobalSymbol, "_globalRe", false, false, true, MacOSTargets},
|
|
{EncodeKind::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",
|
|
"not_for_dyld_shared_cache"
|
|
]
|
|
}
|
|
],
|
|
"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_TRUE(RemovedFile->isOSLibNotForSharedCache());
|
|
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 = {
|
|
{EncodeKind::GlobalSymbol, "_func", false, false, false, MacOSTargets},
|
|
{EncodeKind::GlobalSymbol, "_global", false, false, true, MacOSTargets},
|
|
{EncodeKind::ObjectiveCClass, "ClassA", false, false, true, MacOSTargets},
|
|
};
|
|
std::vector<ExportedSymbol> ExpectedReexportedSymbols = {
|
|
{EncodeKind::GlobalSymbol, "_funcA", false, false, false, MacOSTargets},
|
|
{EncodeKind::GlobalSymbol, "_globalRe", false, false, true, MacOSTargets},
|
|
{EncodeKind::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 = {
|
|
{EncodeKind::GlobalSymbol, "_global", false, false, true, AllTargets},
|
|
{EncodeKind::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
|