
The PlatformKind/PlatformType enums contain the same information, which requires them to be kept in-sync. This commit changes over to PlatformType as the sole source of truth, which allows the removal of the redundant PlatformKind. The majority of the changes were in LLD and TextAPI. Reviewed By: cishida Differential Revision: https://reviews.llvm.org/D117163
1150 lines
43 KiB
C++
1150 lines
43 KiB
C++
//===- TextStub.cpp -------------------------------------------------------===//
|
|
//
|
|
// 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
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
//
|
|
// Implements the text stub file reader/writer.
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#include "TextAPIContext.h"
|
|
#include "TextStubCommon.h"
|
|
#include "llvm/ADT/BitmaskEnum.h"
|
|
#include "llvm/ADT/SmallString.h"
|
|
#include "llvm/ADT/StringRef.h"
|
|
#include "llvm/Support/Allocator.h"
|
|
#include "llvm/Support/SourceMgr.h"
|
|
#include "llvm/Support/YAMLTraits.h"
|
|
#include "llvm/Support/raw_ostream.h"
|
|
#include "llvm/TextAPI/Architecture.h"
|
|
#include "llvm/TextAPI/ArchitectureSet.h"
|
|
#include "llvm/TextAPI/InterfaceFile.h"
|
|
#include "llvm/TextAPI/PackedVersion.h"
|
|
#include "llvm/TextAPI/TextAPIReader.h"
|
|
#include "llvm/TextAPI/TextAPIWriter.h"
|
|
#include <algorithm>
|
|
#include <set>
|
|
|
|
// clang-format off
|
|
/*
|
|
|
|
YAML Format specification.
|
|
|
|
The TBD v1 format only support two level address libraries and is per
|
|
definition application extension safe.
|
|
|
|
--- # the tag !tapi-tbd-v1 is optional and
|
|
# shouldn't be emitted to support older linker.
|
|
archs: [ armv7, armv7s, arm64 ] # the list of architecture slices that are
|
|
# supported by this file.
|
|
platform: ios # Specifies the platform (macosx, ios, etc)
|
|
install-name: /u/l/libfoo.dylib #
|
|
current-version: 1.2.3 # Optional: defaults to 1.0
|
|
compatibility-version: 1.0 # Optional: defaults to 1.0
|
|
swift-version: 0 # Optional: defaults to 0
|
|
objc-constraint: none # Optional: defaults to none
|
|
exports: # List of export sections
|
|
...
|
|
|
|
Each export section is defined as following:
|
|
|
|
- archs: [ arm64 ] # the list of architecture slices
|
|
allowed-clients: [ client ] # Optional: List of clients
|
|
re-exports: [ ] # Optional: List of re-exports
|
|
symbols: [ _sym ] # Optional: List of symbols
|
|
objc-classes: [] # Optional: List of Objective-C classes
|
|
objc-ivars: [] # Optional: List of Objective C Instance
|
|
# Variables
|
|
weak-def-symbols: [] # Optional: List of weak defined symbols
|
|
thread-local-symbols: [] # Optional: List of thread local symbols
|
|
*/
|
|
|
|
/*
|
|
|
|
YAML Format specification.
|
|
|
|
--- !tapi-tbd-v2
|
|
archs: [ armv7, armv7s, arm64 ] # the list of architecture slices that are
|
|
# supported by this file.
|
|
uuids: [ armv7:... ] # Optional: List of architecture and UUID pairs.
|
|
platform: ios # Specifies the platform (macosx, ios, etc)
|
|
flags: [] # Optional:
|
|
install-name: /u/l/libfoo.dylib #
|
|
current-version: 1.2.3 # Optional: defaults to 1.0
|
|
compatibility-version: 1.0 # Optional: defaults to 1.0
|
|
swift-version: 0 # Optional: defaults to 0
|
|
objc-constraint: retain_release # Optional: defaults to retain_release
|
|
parent-umbrella: # Optional:
|
|
exports: # List of export sections
|
|
...
|
|
undefineds: # List of undefineds sections
|
|
...
|
|
|
|
Each export section is defined as following:
|
|
|
|
- archs: [ arm64 ] # the list of architecture slices
|
|
allowed-clients: [ client ] # Optional: List of clients
|
|
re-exports: [ ] # Optional: List of re-exports
|
|
symbols: [ _sym ] # Optional: List of symbols
|
|
objc-classes: [] # Optional: List of Objective-C classes
|
|
objc-ivars: [] # Optional: List of Objective C Instance
|
|
# Variables
|
|
weak-def-symbols: [] # Optional: List of weak defined symbols
|
|
thread-local-symbols: [] # Optional: List of thread local symbols
|
|
|
|
Each undefineds section is defined as following:
|
|
- archs: [ arm64 ] # the list of architecture slices
|
|
symbols: [ _sym ] # Optional: List of symbols
|
|
objc-classes: [] # Optional: List of Objective-C classes
|
|
objc-ivars: [] # Optional: List of Objective C Instance Variables
|
|
weak-ref-symbols: [] # Optional: List of weak defined symbols
|
|
*/
|
|
|
|
/*
|
|
|
|
YAML Format specification.
|
|
|
|
--- !tapi-tbd-v3
|
|
archs: [ armv7, armv7s, arm64 ] # the list of architecture slices that are
|
|
# supported by this file.
|
|
uuids: [ armv7:... ] # Optional: List of architecture and UUID pairs.
|
|
platform: ios # Specifies the platform (macosx, ios, etc)
|
|
flags: [] # Optional:
|
|
install-name: /u/l/libfoo.dylib #
|
|
current-version: 1.2.3 # Optional: defaults to 1.0
|
|
compatibility-version: 1.0 # Optional: defaults to 1.0
|
|
swift-abi-version: 0 # Optional: defaults to 0
|
|
objc-constraint: retain_release # Optional: defaults to retain_release
|
|
parent-umbrella: # Optional:
|
|
exports: # List of export sections
|
|
...
|
|
undefineds: # List of undefineds sections
|
|
...
|
|
|
|
Each export section is defined as following:
|
|
|
|
- archs: [ arm64 ] # the list of architecture slices
|
|
allowed-clients: [ client ] # Optional: List of clients
|
|
re-exports: [ ] # Optional: List of re-exports
|
|
symbols: [ _sym ] # Optional: List of symbols
|
|
objc-classes: [] # Optional: List of Objective-C classes
|
|
objc-eh-types: [] # Optional: List of Objective-C classes
|
|
# with EH
|
|
objc-ivars: [] # Optional: List of Objective C Instance
|
|
# Variables
|
|
weak-def-symbols: [] # Optional: List of weak defined symbols
|
|
thread-local-symbols: [] # Optional: List of thread local symbols
|
|
|
|
Each undefineds section is defined as following:
|
|
- archs: [ arm64 ] # the list of architecture slices
|
|
symbols: [ _sym ] # Optional: List of symbols
|
|
objc-classes: [] # Optional: List of Objective-C classes
|
|
objc-eh-types: [] # Optional: List of Objective-C classes
|
|
# with EH
|
|
objc-ivars: [] # Optional: List of Objective C Instance Variables
|
|
weak-ref-symbols: [] # Optional: List of weak defined symbols
|
|
*/
|
|
|
|
/*
|
|
|
|
YAML Format specification.
|
|
|
|
--- !tapi-tbd
|
|
tbd-version: 4 # The tbd version for format
|
|
targets: [ armv7-ios, x86_64-maccatalyst ] # The list of applicable tapi supported target triples
|
|
uuids: # Optional: List of target and UUID pairs.
|
|
- target: armv7-ios
|
|
value: ...
|
|
- target: x86_64-maccatalyst
|
|
value: ...
|
|
flags: [] # Optional:
|
|
install-name: /u/l/libfoo.dylib #
|
|
current-version: 1.2.3 # Optional: defaults to 1.0
|
|
compatibility-version: 1.0 # Optional: defaults to 1.0
|
|
swift-abi-version: 0 # Optional: defaults to 0
|
|
parent-umbrella: # Optional:
|
|
allowable-clients:
|
|
- targets: [ armv7-ios ] # Optional:
|
|
clients: [ clientA ]
|
|
exports: # List of export sections
|
|
...
|
|
re-exports: # List of reexport sections
|
|
...
|
|
undefineds: # List of undefineds sections
|
|
...
|
|
|
|
Each export and reexport section is defined as following:
|
|
|
|
- targets: [ arm64-macos ] # The list of target triples associated with symbols
|
|
symbols: [ _symA ] # Optional: List of symbols
|
|
objc-classes: [] # Optional: List of Objective-C classes
|
|
objc-eh-types: [] # Optional: List of Objective-C classes
|
|
# with EH
|
|
objc-ivars: [] # Optional: List of Objective C Instance
|
|
# Variables
|
|
weak-symbols: [] # Optional: List of weak defined symbols
|
|
thread-local-symbols: [] # Optional: List of thread local symbols
|
|
- targets: [ arm64-macos, x86_64-maccatalyst ] # Optional: Targets for applicable additional symbols
|
|
symbols: [ _symB ] # Optional: List of symbols
|
|
|
|
Each undefineds section is defined as following:
|
|
- targets: [ arm64-macos ] # The list of target triples associated with symbols
|
|
symbols: [ _symC ] # Optional: List of symbols
|
|
objc-classes: [] # Optional: List of Objective-C classes
|
|
objc-eh-types: [] # Optional: List of Objective-C classes
|
|
# with EH
|
|
objc-ivars: [] # Optional: List of Objective C Instance Variables
|
|
weak-symbols: [] # Optional: List of weak defined symbols
|
|
*/
|
|
// clang-format on
|
|
|
|
using namespace llvm;
|
|
using namespace llvm::yaml;
|
|
using namespace llvm::MachO;
|
|
|
|
namespace {
|
|
struct ExportSection {
|
|
std::vector<Architecture> Architectures;
|
|
std::vector<FlowStringRef> AllowableClients;
|
|
std::vector<FlowStringRef> ReexportedLibraries;
|
|
std::vector<FlowStringRef> Symbols;
|
|
std::vector<FlowStringRef> Classes;
|
|
std::vector<FlowStringRef> ClassEHs;
|
|
std::vector<FlowStringRef> IVars;
|
|
std::vector<FlowStringRef> WeakDefSymbols;
|
|
std::vector<FlowStringRef> TLVSymbols;
|
|
};
|
|
|
|
struct UndefinedSection {
|
|
std::vector<Architecture> Architectures;
|
|
std::vector<FlowStringRef> Symbols;
|
|
std::vector<FlowStringRef> Classes;
|
|
std::vector<FlowStringRef> ClassEHs;
|
|
std::vector<FlowStringRef> IVars;
|
|
std::vector<FlowStringRef> WeakRefSymbols;
|
|
};
|
|
|
|
// Sections for direct target mapping in TBDv4
|
|
struct SymbolSection {
|
|
TargetList Targets;
|
|
std::vector<FlowStringRef> Symbols;
|
|
std::vector<FlowStringRef> Classes;
|
|
std::vector<FlowStringRef> ClassEHs;
|
|
std::vector<FlowStringRef> Ivars;
|
|
std::vector<FlowStringRef> WeakSymbols;
|
|
std::vector<FlowStringRef> TlvSymbols;
|
|
};
|
|
|
|
struct MetadataSection {
|
|
enum Option { Clients, Libraries };
|
|
std::vector<Target> Targets;
|
|
std::vector<FlowStringRef> Values;
|
|
};
|
|
|
|
struct UmbrellaSection {
|
|
std::vector<Target> Targets;
|
|
std::string Umbrella;
|
|
};
|
|
|
|
// UUID's for TBDv4 are mapped to target not arch
|
|
struct UUIDv4 {
|
|
Target TargetID;
|
|
std::string Value;
|
|
|
|
UUIDv4() = default;
|
|
UUIDv4(const Target &TargetID, const std::string &Value)
|
|
: TargetID(TargetID), Value(Value) {}
|
|
};
|
|
|
|
// clang-format off
|
|
enum TBDFlags : unsigned {
|
|
None = 0U,
|
|
FlatNamespace = 1U << 0,
|
|
NotApplicationExtensionSafe = 1U << 1,
|
|
InstallAPI = 1U << 2,
|
|
LLVM_MARK_AS_BITMASK_ENUM(/*LargestValue=*/InstallAPI),
|
|
};
|
|
// clang-format on
|
|
} // end anonymous namespace.
|
|
|
|
LLVM_YAML_IS_FLOW_SEQUENCE_VECTOR(Architecture)
|
|
LLVM_YAML_IS_SEQUENCE_VECTOR(ExportSection)
|
|
LLVM_YAML_IS_SEQUENCE_VECTOR(UndefinedSection)
|
|
// Specific to TBDv4
|
|
LLVM_YAML_IS_SEQUENCE_VECTOR(SymbolSection)
|
|
LLVM_YAML_IS_SEQUENCE_VECTOR(MetadataSection)
|
|
LLVM_YAML_IS_SEQUENCE_VECTOR(UmbrellaSection)
|
|
LLVM_YAML_IS_FLOW_SEQUENCE_VECTOR(Target)
|
|
LLVM_YAML_IS_SEQUENCE_VECTOR(UUIDv4)
|
|
|
|
namespace llvm {
|
|
namespace yaml {
|
|
|
|
template <> struct MappingTraits<ExportSection> {
|
|
static void mapping(IO &IO, ExportSection &Section) {
|
|
const auto *Ctx = reinterpret_cast<TextAPIContext *>(IO.getContext());
|
|
assert((!Ctx || (Ctx && Ctx->FileKind != FileType::Invalid)) &&
|
|
"File type is not set in YAML context");
|
|
|
|
IO.mapRequired("archs", Section.Architectures);
|
|
if (Ctx->FileKind == FileType::TBD_V1)
|
|
IO.mapOptional("allowed-clients", Section.AllowableClients);
|
|
else
|
|
IO.mapOptional("allowable-clients", Section.AllowableClients);
|
|
IO.mapOptional("re-exports", Section.ReexportedLibraries);
|
|
IO.mapOptional("symbols", Section.Symbols);
|
|
IO.mapOptional("objc-classes", Section.Classes);
|
|
if (Ctx->FileKind == FileType::TBD_V3)
|
|
IO.mapOptional("objc-eh-types", Section.ClassEHs);
|
|
IO.mapOptional("objc-ivars", Section.IVars);
|
|
IO.mapOptional("weak-def-symbols", Section.WeakDefSymbols);
|
|
IO.mapOptional("thread-local-symbols", Section.TLVSymbols);
|
|
}
|
|
};
|
|
|
|
template <> struct MappingTraits<UndefinedSection> {
|
|
static void mapping(IO &IO, UndefinedSection &Section) {
|
|
const auto *Ctx = reinterpret_cast<TextAPIContext *>(IO.getContext());
|
|
assert((!Ctx || (Ctx && Ctx->FileKind != FileType::Invalid)) &&
|
|
"File type is not set in YAML context");
|
|
|
|
IO.mapRequired("archs", Section.Architectures);
|
|
IO.mapOptional("symbols", Section.Symbols);
|
|
IO.mapOptional("objc-classes", Section.Classes);
|
|
if (Ctx->FileKind == FileType::TBD_V3)
|
|
IO.mapOptional("objc-eh-types", Section.ClassEHs);
|
|
IO.mapOptional("objc-ivars", Section.IVars);
|
|
IO.mapOptional("weak-ref-symbols", Section.WeakRefSymbols);
|
|
}
|
|
};
|
|
|
|
template <> struct MappingTraits<SymbolSection> {
|
|
static void mapping(IO &IO, SymbolSection &Section) {
|
|
IO.mapRequired("targets", Section.Targets);
|
|
IO.mapOptional("symbols", Section.Symbols);
|
|
IO.mapOptional("objc-classes", Section.Classes);
|
|
IO.mapOptional("objc-eh-types", Section.ClassEHs);
|
|
IO.mapOptional("objc-ivars", Section.Ivars);
|
|
IO.mapOptional("weak-symbols", Section.WeakSymbols);
|
|
IO.mapOptional("thread-local-symbols", Section.TlvSymbols);
|
|
}
|
|
};
|
|
|
|
template <> struct MappingTraits<UmbrellaSection> {
|
|
static void mapping(IO &IO, UmbrellaSection &Section) {
|
|
IO.mapRequired("targets", Section.Targets);
|
|
IO.mapRequired("umbrella", Section.Umbrella);
|
|
}
|
|
};
|
|
|
|
template <> struct MappingTraits<UUIDv4> {
|
|
static void mapping(IO &IO, UUIDv4 &UUID) {
|
|
IO.mapRequired("target", UUID.TargetID);
|
|
IO.mapRequired("value", UUID.Value);
|
|
}
|
|
};
|
|
|
|
template <>
|
|
struct MappingContextTraits<MetadataSection, MetadataSection::Option> {
|
|
static void mapping(IO &IO, MetadataSection &Section,
|
|
MetadataSection::Option &OptionKind) {
|
|
IO.mapRequired("targets", Section.Targets);
|
|
switch (OptionKind) {
|
|
case MetadataSection::Option::Clients:
|
|
IO.mapRequired("clients", Section.Values);
|
|
return;
|
|
case MetadataSection::Option::Libraries:
|
|
IO.mapRequired("libraries", Section.Values);
|
|
return;
|
|
}
|
|
llvm_unreachable("unexpected option for metadata");
|
|
}
|
|
};
|
|
|
|
template <> struct ScalarBitSetTraits<TBDFlags> {
|
|
static void bitset(IO &IO, TBDFlags &Flags) {
|
|
IO.bitSetCase(Flags, "flat_namespace", TBDFlags::FlatNamespace);
|
|
IO.bitSetCase(Flags, "not_app_extension_safe",
|
|
TBDFlags::NotApplicationExtensionSafe);
|
|
IO.bitSetCase(Flags, "installapi", TBDFlags::InstallAPI);
|
|
}
|
|
};
|
|
|
|
template <> struct ScalarTraits<Target> {
|
|
static void output(const Target &Value, void *, raw_ostream &OS) {
|
|
OS << Value.Arch << "-";
|
|
switch (Value.Platform) {
|
|
default:
|
|
OS << "unknown";
|
|
break;
|
|
case PLATFORM_MACOS:
|
|
OS << "macos";
|
|
break;
|
|
case PLATFORM_IOS:
|
|
OS << "ios";
|
|
break;
|
|
case PLATFORM_TVOS:
|
|
OS << "tvos";
|
|
break;
|
|
case PLATFORM_WATCHOS:
|
|
OS << "watchos";
|
|
break;
|
|
case PLATFORM_BRIDGEOS:
|
|
OS << "bridgeos";
|
|
break;
|
|
case PLATFORM_MACCATALYST:
|
|
OS << "maccatalyst";
|
|
break;
|
|
case PLATFORM_IOSSIMULATOR:
|
|
OS << "ios-simulator";
|
|
break;
|
|
case PLATFORM_TVOSSIMULATOR:
|
|
OS << "tvos-simulator";
|
|
break;
|
|
case PLATFORM_WATCHOSSIMULATOR:
|
|
OS << "watchos-simulator";
|
|
break;
|
|
case PLATFORM_DRIVERKIT:
|
|
OS << "driverkit";
|
|
break;
|
|
}
|
|
}
|
|
|
|
static StringRef input(StringRef Scalar, void *, Target &Value) {
|
|
auto Result = Target::create(Scalar);
|
|
if (!Result) {
|
|
consumeError(Result.takeError());
|
|
return "unparsable target";
|
|
}
|
|
|
|
Value = *Result;
|
|
if (Value.Arch == AK_unknown)
|
|
return "unknown architecture";
|
|
if (Value.Platform == PLATFORM_UNKNOWN)
|
|
return "unknown platform";
|
|
|
|
return {};
|
|
}
|
|
|
|
static QuotingType mustQuote(StringRef) { return QuotingType::None; }
|
|
};
|
|
|
|
template <> struct MappingTraits<const InterfaceFile *> {
|
|
struct NormalizedTBD {
|
|
explicit NormalizedTBD(IO &IO) {}
|
|
NormalizedTBD(IO &IO, const InterfaceFile *&File) {
|
|
Architectures = File->getArchitectures();
|
|
UUIDs = File->uuids();
|
|
Platforms = File->getPlatforms();
|
|
InstallName = File->getInstallName();
|
|
CurrentVersion = PackedVersion(File->getCurrentVersion());
|
|
CompatibilityVersion = PackedVersion(File->getCompatibilityVersion());
|
|
SwiftABIVersion = File->getSwiftABIVersion();
|
|
ObjCConstraint = File->getObjCConstraint();
|
|
|
|
Flags = TBDFlags::None;
|
|
if (!File->isApplicationExtensionSafe())
|
|
Flags |= TBDFlags::NotApplicationExtensionSafe;
|
|
|
|
if (!File->isTwoLevelNamespace())
|
|
Flags |= TBDFlags::FlatNamespace;
|
|
|
|
if (File->isInstallAPI())
|
|
Flags |= TBDFlags::InstallAPI;
|
|
|
|
if (!File->umbrellas().empty())
|
|
ParentUmbrella = File->umbrellas().begin()->second;
|
|
|
|
std::set<ArchitectureSet> ArchSet;
|
|
for (const auto &Library : File->allowableClients())
|
|
ArchSet.insert(Library.getArchitectures());
|
|
|
|
for (const auto &Library : File->reexportedLibraries())
|
|
ArchSet.insert(Library.getArchitectures());
|
|
|
|
std::map<const Symbol *, ArchitectureSet> SymbolToArchSet;
|
|
for (const auto *Symbol : File->exports()) {
|
|
auto Architectures = Symbol->getArchitectures();
|
|
SymbolToArchSet[Symbol] = Architectures;
|
|
ArchSet.insert(Architectures);
|
|
}
|
|
|
|
for (auto Architectures : ArchSet) {
|
|
ExportSection Section;
|
|
Section.Architectures = Architectures;
|
|
|
|
for (const auto &Library : File->allowableClients())
|
|
if (Library.getArchitectures() == Architectures)
|
|
Section.AllowableClients.emplace_back(Library.getInstallName());
|
|
|
|
for (const auto &Library : File->reexportedLibraries())
|
|
if (Library.getArchitectures() == Architectures)
|
|
Section.ReexportedLibraries.emplace_back(Library.getInstallName());
|
|
|
|
for (const auto &SymArch : SymbolToArchSet) {
|
|
if (SymArch.second != Architectures)
|
|
continue;
|
|
|
|
const auto *Symbol = SymArch.first;
|
|
switch (Symbol->getKind()) {
|
|
case SymbolKind::GlobalSymbol:
|
|
if (Symbol->isWeakDefined())
|
|
Section.WeakDefSymbols.emplace_back(Symbol->getName());
|
|
else if (Symbol->isThreadLocalValue())
|
|
Section.TLVSymbols.emplace_back(Symbol->getName());
|
|
else
|
|
Section.Symbols.emplace_back(Symbol->getName());
|
|
break;
|
|
case SymbolKind::ObjectiveCClass:
|
|
if (File->getFileType() != FileType::TBD_V3)
|
|
Section.Classes.emplace_back(
|
|
copyString("_" + Symbol->getName().str()));
|
|
else
|
|
Section.Classes.emplace_back(Symbol->getName());
|
|
break;
|
|
case SymbolKind::ObjectiveCClassEHType:
|
|
if (File->getFileType() != FileType::TBD_V3)
|
|
Section.Symbols.emplace_back(
|
|
copyString("_OBJC_EHTYPE_$_" + Symbol->getName().str()));
|
|
else
|
|
Section.ClassEHs.emplace_back(Symbol->getName());
|
|
break;
|
|
case SymbolKind::ObjectiveCInstanceVariable:
|
|
if (File->getFileType() != FileType::TBD_V3)
|
|
Section.IVars.emplace_back(
|
|
copyString("_" + Symbol->getName().str()));
|
|
else
|
|
Section.IVars.emplace_back(Symbol->getName());
|
|
break;
|
|
}
|
|
}
|
|
llvm::sort(Section.Symbols);
|
|
llvm::sort(Section.Classes);
|
|
llvm::sort(Section.ClassEHs);
|
|
llvm::sort(Section.IVars);
|
|
llvm::sort(Section.WeakDefSymbols);
|
|
llvm::sort(Section.TLVSymbols);
|
|
Exports.emplace_back(std::move(Section));
|
|
}
|
|
|
|
ArchSet.clear();
|
|
SymbolToArchSet.clear();
|
|
|
|
for (const auto *Symbol : File->undefineds()) {
|
|
auto Architectures = Symbol->getArchitectures();
|
|
SymbolToArchSet[Symbol] = Architectures;
|
|
ArchSet.insert(Architectures);
|
|
}
|
|
|
|
for (auto Architectures : ArchSet) {
|
|
UndefinedSection Section;
|
|
Section.Architectures = Architectures;
|
|
|
|
for (const auto &SymArch : SymbolToArchSet) {
|
|
if (SymArch.second != Architectures)
|
|
continue;
|
|
|
|
const auto *Symbol = SymArch.first;
|
|
switch (Symbol->getKind()) {
|
|
case SymbolKind::GlobalSymbol:
|
|
if (Symbol->isWeakReferenced())
|
|
Section.WeakRefSymbols.emplace_back(Symbol->getName());
|
|
else
|
|
Section.Symbols.emplace_back(Symbol->getName());
|
|
break;
|
|
case SymbolKind::ObjectiveCClass:
|
|
if (File->getFileType() != FileType::TBD_V3)
|
|
Section.Classes.emplace_back(
|
|
copyString("_" + Symbol->getName().str()));
|
|
else
|
|
Section.Classes.emplace_back(Symbol->getName());
|
|
break;
|
|
case SymbolKind::ObjectiveCClassEHType:
|
|
if (File->getFileType() != FileType::TBD_V3)
|
|
Section.Symbols.emplace_back(
|
|
copyString("_OBJC_EHTYPE_$_" + Symbol->getName().str()));
|
|
else
|
|
Section.ClassEHs.emplace_back(Symbol->getName());
|
|
break;
|
|
case SymbolKind::ObjectiveCInstanceVariable:
|
|
if (File->getFileType() != FileType::TBD_V3)
|
|
Section.IVars.emplace_back(
|
|
copyString("_" + Symbol->getName().str()));
|
|
else
|
|
Section.IVars.emplace_back(Symbol->getName());
|
|
break;
|
|
}
|
|
}
|
|
llvm::sort(Section.Symbols);
|
|
llvm::sort(Section.Classes);
|
|
llvm::sort(Section.ClassEHs);
|
|
llvm::sort(Section.IVars);
|
|
llvm::sort(Section.WeakRefSymbols);
|
|
Undefineds.emplace_back(std::move(Section));
|
|
}
|
|
}
|
|
|
|
// TBD v1 - TBD v3 files only support one platform and several
|
|
// architectures. It is possible to have more than one platform for TBD v3
|
|
// files, but the architectures don't apply to all
|
|
// platforms, specifically to filter out the i386 slice from
|
|
// platform macCatalyst.
|
|
TargetList synthesizeTargets(ArchitectureSet Architectures,
|
|
const PlatformSet &Platforms) {
|
|
TargetList Targets;
|
|
|
|
for (auto Platform : Platforms) {
|
|
Platform = mapToPlatformType(Platform, Architectures.hasX86());
|
|
|
|
for (const auto &&Architecture : Architectures) {
|
|
if ((Architecture == AK_i386) && (Platform == PLATFORM_MACCATALYST))
|
|
continue;
|
|
|
|
Targets.emplace_back(Architecture, Platform);
|
|
}
|
|
}
|
|
return Targets;
|
|
}
|
|
|
|
const InterfaceFile *denormalize(IO &IO) {
|
|
auto Ctx = reinterpret_cast<TextAPIContext *>(IO.getContext());
|
|
assert(Ctx);
|
|
|
|
auto *File = new InterfaceFile;
|
|
File->setPath(Ctx->Path);
|
|
File->setFileType(Ctx->FileKind);
|
|
File->addTargets(synthesizeTargets(Architectures, Platforms));
|
|
for (auto &ID : UUIDs)
|
|
File->addUUID(ID.first, ID.second);
|
|
File->setInstallName(InstallName);
|
|
File->setCurrentVersion(CurrentVersion);
|
|
File->setCompatibilityVersion(CompatibilityVersion);
|
|
File->setSwiftABIVersion(SwiftABIVersion);
|
|
File->setObjCConstraint(ObjCConstraint);
|
|
for (const auto &Target : File->targets())
|
|
File->addParentUmbrella(Target, ParentUmbrella);
|
|
|
|
if (Ctx->FileKind == FileType::TBD_V1) {
|
|
File->setTwoLevelNamespace();
|
|
File->setApplicationExtensionSafe();
|
|
} else {
|
|
File->setTwoLevelNamespace(!(Flags & TBDFlags::FlatNamespace));
|
|
File->setApplicationExtensionSafe(
|
|
!(Flags & TBDFlags::NotApplicationExtensionSafe));
|
|
File->setInstallAPI(Flags & TBDFlags::InstallAPI);
|
|
}
|
|
|
|
for (const auto &Section : Exports) {
|
|
const auto Targets =
|
|
synthesizeTargets(Section.Architectures, Platforms);
|
|
|
|
for (const auto &Lib : Section.AllowableClients)
|
|
for (const auto &Target : Targets)
|
|
File->addAllowableClient(Lib, Target);
|
|
|
|
for (const auto &Lib : Section.ReexportedLibraries)
|
|
for (const auto &Target : Targets)
|
|
File->addReexportedLibrary(Lib, Target);
|
|
|
|
for (const auto &Symbol : Section.Symbols) {
|
|
if (Ctx->FileKind != FileType::TBD_V3 &&
|
|
Symbol.value.startswith("_OBJC_EHTYPE_$_"))
|
|
File->addSymbol(SymbolKind::ObjectiveCClassEHType,
|
|
Symbol.value.drop_front(15), Targets);
|
|
else
|
|
File->addSymbol(SymbolKind::GlobalSymbol, Symbol, Targets);
|
|
}
|
|
for (auto &Symbol : Section.Classes) {
|
|
auto Name = Symbol.value;
|
|
if (Ctx->FileKind != FileType::TBD_V3)
|
|
Name = Name.drop_front();
|
|
File->addSymbol(SymbolKind::ObjectiveCClass, Name, Targets);
|
|
}
|
|
for (auto &Symbol : Section.ClassEHs)
|
|
File->addSymbol(SymbolKind::ObjectiveCClassEHType, Symbol, Targets);
|
|
for (auto &Symbol : Section.IVars) {
|
|
auto Name = Symbol.value;
|
|
if (Ctx->FileKind != FileType::TBD_V3)
|
|
Name = Name.drop_front();
|
|
File->addSymbol(SymbolKind::ObjectiveCInstanceVariable, Name,
|
|
Targets);
|
|
}
|
|
for (auto &Symbol : Section.WeakDefSymbols)
|
|
File->addSymbol(SymbolKind::GlobalSymbol, Symbol, Targets,
|
|
SymbolFlags::WeakDefined);
|
|
for (auto &Symbol : Section.TLVSymbols)
|
|
File->addSymbol(SymbolKind::GlobalSymbol, Symbol, Targets,
|
|
SymbolFlags::ThreadLocalValue);
|
|
}
|
|
|
|
for (const auto &Section : Undefineds) {
|
|
const auto Targets =
|
|
synthesizeTargets(Section.Architectures, Platforms);
|
|
for (auto &Symbol : Section.Symbols) {
|
|
if (Ctx->FileKind != FileType::TBD_V3 &&
|
|
Symbol.value.startswith("_OBJC_EHTYPE_$_"))
|
|
File->addSymbol(SymbolKind::ObjectiveCClassEHType,
|
|
Symbol.value.drop_front(15), Targets,
|
|
SymbolFlags::Undefined);
|
|
else
|
|
File->addSymbol(SymbolKind::GlobalSymbol, Symbol, Targets,
|
|
SymbolFlags::Undefined);
|
|
}
|
|
for (auto &Symbol : Section.Classes) {
|
|
auto Name = Symbol.value;
|
|
if (Ctx->FileKind != FileType::TBD_V3)
|
|
Name = Name.drop_front();
|
|
File->addSymbol(SymbolKind::ObjectiveCClass, Name, Targets,
|
|
SymbolFlags::Undefined);
|
|
}
|
|
for (auto &Symbol : Section.ClassEHs)
|
|
File->addSymbol(SymbolKind::ObjectiveCClassEHType, Symbol, Targets,
|
|
SymbolFlags::Undefined);
|
|
for (auto &Symbol : Section.IVars) {
|
|
auto Name = Symbol.value;
|
|
if (Ctx->FileKind != FileType::TBD_V3)
|
|
Name = Name.drop_front();
|
|
File->addSymbol(SymbolKind::ObjectiveCInstanceVariable, Name, Targets,
|
|
SymbolFlags::Undefined);
|
|
}
|
|
for (auto &Symbol : Section.WeakRefSymbols)
|
|
File->addSymbol(SymbolKind::GlobalSymbol, Symbol, Targets,
|
|
SymbolFlags::Undefined | SymbolFlags::WeakReferenced);
|
|
}
|
|
|
|
return File;
|
|
}
|
|
|
|
llvm::BumpPtrAllocator Allocator;
|
|
StringRef copyString(StringRef String) {
|
|
if (String.empty())
|
|
return {};
|
|
|
|
void *Ptr = Allocator.Allocate(String.size(), 1);
|
|
memcpy(Ptr, String.data(), String.size());
|
|
return StringRef(reinterpret_cast<const char *>(Ptr), String.size());
|
|
}
|
|
|
|
std::vector<Architecture> Architectures;
|
|
std::vector<UUID> UUIDs;
|
|
PlatformSet Platforms;
|
|
StringRef InstallName;
|
|
PackedVersion CurrentVersion;
|
|
PackedVersion CompatibilityVersion;
|
|
SwiftVersion SwiftABIVersion{0};
|
|
ObjCConstraintType ObjCConstraint{ObjCConstraintType::None};
|
|
TBDFlags Flags{TBDFlags::None};
|
|
StringRef ParentUmbrella;
|
|
std::vector<ExportSection> Exports;
|
|
std::vector<UndefinedSection> Undefineds;
|
|
};
|
|
|
|
static void setFileTypeForInput(TextAPIContext *Ctx, IO &IO) {
|
|
if (IO.mapTag("!tapi-tbd", false))
|
|
Ctx->FileKind = FileType::TBD_V4;
|
|
else if (IO.mapTag("!tapi-tbd-v3", false))
|
|
Ctx->FileKind = FileType::TBD_V3;
|
|
else if (IO.mapTag("!tapi-tbd-v2", false))
|
|
Ctx->FileKind = FileType::TBD_V2;
|
|
else if (IO.mapTag("!tapi-tbd-v1", false) ||
|
|
IO.mapTag("tag:yaml.org,2002:map", false))
|
|
Ctx->FileKind = FileType::TBD_V1;
|
|
else {
|
|
Ctx->FileKind = FileType::Invalid;
|
|
return;
|
|
}
|
|
}
|
|
|
|
static void mapping(IO &IO, const InterfaceFile *&File) {
|
|
auto *Ctx = reinterpret_cast<TextAPIContext *>(IO.getContext());
|
|
assert((!Ctx || !IO.outputting() ||
|
|
(Ctx && Ctx->FileKind != FileType::Invalid)) &&
|
|
"File type is not set in YAML context");
|
|
|
|
if (!IO.outputting()) {
|
|
setFileTypeForInput(Ctx, IO);
|
|
switch (Ctx->FileKind) {
|
|
default:
|
|
break;
|
|
case FileType::TBD_V4:
|
|
mapKeysToValuesV4(IO, File);
|
|
return;
|
|
case FileType::Invalid:
|
|
IO.setError("unsupported file type");
|
|
return;
|
|
}
|
|
} else {
|
|
// Set file type when writing.
|
|
switch (Ctx->FileKind) {
|
|
default:
|
|
llvm_unreachable("unexpected file type");
|
|
case FileType::TBD_V4:
|
|
mapKeysToValuesV4(IO, File);
|
|
return;
|
|
case FileType::TBD_V3:
|
|
IO.mapTag("!tapi-tbd-v3", true);
|
|
break;
|
|
case FileType::TBD_V2:
|
|
IO.mapTag("!tapi-tbd-v2", true);
|
|
break;
|
|
case FileType::TBD_V1:
|
|
// Don't write the tag into the .tbd file for TBD v1
|
|
break;
|
|
}
|
|
}
|
|
mapKeysToValues(Ctx->FileKind, IO, File);
|
|
}
|
|
|
|
using SectionList = std::vector<SymbolSection>;
|
|
struct NormalizedTBD_V4 {
|
|
explicit NormalizedTBD_V4(IO &IO) {}
|
|
NormalizedTBD_V4(IO &IO, const InterfaceFile *&File) {
|
|
auto Ctx = reinterpret_cast<TextAPIContext *>(IO.getContext());
|
|
assert(Ctx);
|
|
TBDVersion = Ctx->FileKind >> 1;
|
|
Targets.insert(Targets.begin(), File->targets().begin(),
|
|
File->targets().end());
|
|
for (const auto &IT : File->uuids())
|
|
UUIDs.emplace_back(IT.first, IT.second);
|
|
InstallName = File->getInstallName();
|
|
CurrentVersion = File->getCurrentVersion();
|
|
CompatibilityVersion = File->getCompatibilityVersion();
|
|
SwiftABIVersion = File->getSwiftABIVersion();
|
|
|
|
Flags = TBDFlags::None;
|
|
if (!File->isApplicationExtensionSafe())
|
|
Flags |= TBDFlags::NotApplicationExtensionSafe;
|
|
|
|
if (!File->isTwoLevelNamespace())
|
|
Flags |= TBDFlags::FlatNamespace;
|
|
|
|
if (File->isInstallAPI())
|
|
Flags |= TBDFlags::InstallAPI;
|
|
|
|
{
|
|
std::map<std::string, TargetList> valueToTargetList;
|
|
for (const auto &it : File->umbrellas())
|
|
valueToTargetList[it.second].emplace_back(it.first);
|
|
|
|
for (const auto &it : valueToTargetList) {
|
|
UmbrellaSection CurrentSection;
|
|
CurrentSection.Targets.insert(CurrentSection.Targets.begin(),
|
|
it.second.begin(), it.second.end());
|
|
CurrentSection.Umbrella = it.first;
|
|
ParentUmbrellas.emplace_back(std::move(CurrentSection));
|
|
}
|
|
}
|
|
|
|
assignTargetsToLibrary(File->allowableClients(), AllowableClients);
|
|
assignTargetsToLibrary(File->reexportedLibraries(), ReexportedLibraries);
|
|
|
|
auto handleSymbols =
|
|
[](SectionList &CurrentSections,
|
|
InterfaceFile::const_filtered_symbol_range Symbols,
|
|
std::function<bool(const Symbol *)> Pred) {
|
|
std::set<TargetList> TargetSet;
|
|
std::map<const Symbol *, TargetList> SymbolToTargetList;
|
|
for (const auto *Symbol : Symbols) {
|
|
if (!Pred(Symbol))
|
|
continue;
|
|
TargetList Targets(Symbol->targets());
|
|
SymbolToTargetList[Symbol] = Targets;
|
|
TargetSet.emplace(std::move(Targets));
|
|
}
|
|
for (const auto &TargetIDs : TargetSet) {
|
|
SymbolSection CurrentSection;
|
|
CurrentSection.Targets.insert(CurrentSection.Targets.begin(),
|
|
TargetIDs.begin(), TargetIDs.end());
|
|
|
|
for (const auto &IT : SymbolToTargetList) {
|
|
if (IT.second != TargetIDs)
|
|
continue;
|
|
|
|
const auto *Symbol = IT.first;
|
|
switch (Symbol->getKind()) {
|
|
case SymbolKind::GlobalSymbol:
|
|
if (Symbol->isWeakDefined())
|
|
CurrentSection.WeakSymbols.emplace_back(Symbol->getName());
|
|
else if (Symbol->isThreadLocalValue())
|
|
CurrentSection.TlvSymbols.emplace_back(Symbol->getName());
|
|
else
|
|
CurrentSection.Symbols.emplace_back(Symbol->getName());
|
|
break;
|
|
case SymbolKind::ObjectiveCClass:
|
|
CurrentSection.Classes.emplace_back(Symbol->getName());
|
|
break;
|
|
case SymbolKind::ObjectiveCClassEHType:
|
|
CurrentSection.ClassEHs.emplace_back(Symbol->getName());
|
|
break;
|
|
case SymbolKind::ObjectiveCInstanceVariable:
|
|
CurrentSection.Ivars.emplace_back(Symbol->getName());
|
|
break;
|
|
}
|
|
}
|
|
sort(CurrentSection.Symbols);
|
|
sort(CurrentSection.Classes);
|
|
sort(CurrentSection.ClassEHs);
|
|
sort(CurrentSection.Ivars);
|
|
sort(CurrentSection.WeakSymbols);
|
|
sort(CurrentSection.TlvSymbols);
|
|
CurrentSections.emplace_back(std::move(CurrentSection));
|
|
}
|
|
};
|
|
|
|
handleSymbols(Exports, File->exports(), [](const Symbol *Symbol) {
|
|
return !Symbol->isReexported();
|
|
});
|
|
handleSymbols(Reexports, File->exports(), [](const Symbol *Symbol) {
|
|
return Symbol->isReexported();
|
|
});
|
|
handleSymbols(Undefineds, File->undefineds(),
|
|
[](const Symbol *Symbol) { return true; });
|
|
}
|
|
|
|
const InterfaceFile *denormalize(IO &IO) {
|
|
auto Ctx = reinterpret_cast<TextAPIContext *>(IO.getContext());
|
|
assert(Ctx);
|
|
|
|
auto *File = new InterfaceFile;
|
|
File->setPath(Ctx->Path);
|
|
File->setFileType(Ctx->FileKind);
|
|
for (auto &id : UUIDs)
|
|
File->addUUID(id.TargetID, id.Value);
|
|
File->addTargets(Targets);
|
|
File->setInstallName(InstallName);
|
|
File->setCurrentVersion(CurrentVersion);
|
|
File->setCompatibilityVersion(CompatibilityVersion);
|
|
File->setSwiftABIVersion(SwiftABIVersion);
|
|
for (const auto &CurrentSection : ParentUmbrellas)
|
|
for (const auto &target : CurrentSection.Targets)
|
|
File->addParentUmbrella(target, CurrentSection.Umbrella);
|
|
File->setTwoLevelNamespace(!(Flags & TBDFlags::FlatNamespace));
|
|
File->setApplicationExtensionSafe(
|
|
!(Flags & TBDFlags::NotApplicationExtensionSafe));
|
|
File->setInstallAPI(Flags & TBDFlags::InstallAPI);
|
|
|
|
for (const auto &CurrentSection : AllowableClients) {
|
|
for (const auto &lib : CurrentSection.Values)
|
|
for (const auto &Target : CurrentSection.Targets)
|
|
File->addAllowableClient(lib, Target);
|
|
}
|
|
|
|
for (const auto &CurrentSection : ReexportedLibraries) {
|
|
for (const auto &Lib : CurrentSection.Values)
|
|
for (const auto &Target : CurrentSection.Targets)
|
|
File->addReexportedLibrary(Lib, Target);
|
|
}
|
|
|
|
auto handleSymbols = [File](const SectionList &CurrentSections,
|
|
SymbolFlags Flag = SymbolFlags::None) {
|
|
for (const auto &CurrentSection : CurrentSections) {
|
|
for (auto &sym : CurrentSection.Symbols)
|
|
File->addSymbol(SymbolKind::GlobalSymbol, sym,
|
|
CurrentSection.Targets, Flag);
|
|
|
|
for (auto &sym : CurrentSection.Classes)
|
|
File->addSymbol(SymbolKind::ObjectiveCClass, sym,
|
|
CurrentSection.Targets);
|
|
|
|
for (auto &sym : CurrentSection.ClassEHs)
|
|
File->addSymbol(SymbolKind::ObjectiveCClassEHType, sym,
|
|
CurrentSection.Targets);
|
|
|
|
for (auto &sym : CurrentSection.Ivars)
|
|
File->addSymbol(SymbolKind::ObjectiveCInstanceVariable, sym,
|
|
CurrentSection.Targets);
|
|
|
|
for (auto &sym : CurrentSection.WeakSymbols)
|
|
File->addSymbol(SymbolKind::GlobalSymbol, sym,
|
|
CurrentSection.Targets, SymbolFlags::WeakDefined);
|
|
|
|
for (auto &sym : CurrentSection.TlvSymbols)
|
|
File->addSymbol(SymbolKind::GlobalSymbol, sym,
|
|
CurrentSection.Targets,
|
|
SymbolFlags::ThreadLocalValue);
|
|
}
|
|
};
|
|
|
|
handleSymbols(Exports);
|
|
handleSymbols(Reexports, SymbolFlags::Rexported);
|
|
handleSymbols(Undefineds, SymbolFlags::Undefined);
|
|
|
|
return File;
|
|
}
|
|
|
|
unsigned TBDVersion;
|
|
std::vector<UUIDv4> UUIDs;
|
|
TargetList Targets;
|
|
StringRef InstallName;
|
|
PackedVersion CurrentVersion;
|
|
PackedVersion CompatibilityVersion;
|
|
SwiftVersion SwiftABIVersion{0};
|
|
std::vector<MetadataSection> AllowableClients;
|
|
std::vector<MetadataSection> ReexportedLibraries;
|
|
TBDFlags Flags{TBDFlags::None};
|
|
std::vector<UmbrellaSection> ParentUmbrellas;
|
|
SectionList Exports;
|
|
SectionList Reexports;
|
|
SectionList Undefineds;
|
|
|
|
private:
|
|
void assignTargetsToLibrary(const std::vector<InterfaceFileRef> &Libraries,
|
|
std::vector<MetadataSection> &Section) {
|
|
std::set<TargetList> targetSet;
|
|
std::map<const InterfaceFileRef *, TargetList> valueToTargetList;
|
|
for (const auto &library : Libraries) {
|
|
TargetList targets(library.targets());
|
|
valueToTargetList[&library] = targets;
|
|
targetSet.emplace(std::move(targets));
|
|
}
|
|
|
|
for (const auto &targets : targetSet) {
|
|
MetadataSection CurrentSection;
|
|
CurrentSection.Targets.insert(CurrentSection.Targets.begin(),
|
|
targets.begin(), targets.end());
|
|
|
|
for (const auto &it : valueToTargetList) {
|
|
if (it.second != targets)
|
|
continue;
|
|
|
|
CurrentSection.Values.emplace_back(it.first->getInstallName());
|
|
}
|
|
llvm::sort(CurrentSection.Values);
|
|
Section.emplace_back(std::move(CurrentSection));
|
|
}
|
|
}
|
|
};
|
|
|
|
static void mapKeysToValues(FileType FileKind, IO &IO,
|
|
const InterfaceFile *&File) {
|
|
MappingNormalization<NormalizedTBD, const InterfaceFile *> Keys(IO, File);
|
|
IO.mapRequired("archs", Keys->Architectures);
|
|
if (FileKind != FileType::TBD_V1)
|
|
IO.mapOptional("uuids", Keys->UUIDs);
|
|
IO.mapRequired("platform", Keys->Platforms);
|
|
if (FileKind != FileType::TBD_V1)
|
|
IO.mapOptional("flags", Keys->Flags, TBDFlags::None);
|
|
IO.mapRequired("install-name", Keys->InstallName);
|
|
IO.mapOptional("current-version", Keys->CurrentVersion,
|
|
PackedVersion(1, 0, 0));
|
|
IO.mapOptional("compatibility-version", Keys->CompatibilityVersion,
|
|
PackedVersion(1, 0, 0));
|
|
if (FileKind != FileType::TBD_V3)
|
|
IO.mapOptional("swift-version", Keys->SwiftABIVersion, SwiftVersion(0));
|
|
else
|
|
IO.mapOptional("swift-abi-version", Keys->SwiftABIVersion,
|
|
SwiftVersion(0));
|
|
IO.mapOptional("objc-constraint", Keys->ObjCConstraint,
|
|
(FileKind == FileType::TBD_V1)
|
|
? ObjCConstraintType::None
|
|
: ObjCConstraintType::Retain_Release);
|
|
if (FileKind != FileType::TBD_V1)
|
|
IO.mapOptional("parent-umbrella", Keys->ParentUmbrella, StringRef());
|
|
IO.mapOptional("exports", Keys->Exports);
|
|
if (FileKind != FileType::TBD_V1)
|
|
IO.mapOptional("undefineds", Keys->Undefineds);
|
|
}
|
|
|
|
static void mapKeysToValuesV4(IO &IO, const InterfaceFile *&File) {
|
|
MappingNormalization<NormalizedTBD_V4, const InterfaceFile *> Keys(IO,
|
|
File);
|
|
IO.mapTag("!tapi-tbd", true);
|
|
IO.mapRequired("tbd-version", Keys->TBDVersion);
|
|
IO.mapRequired("targets", Keys->Targets);
|
|
IO.mapOptional("uuids", Keys->UUIDs);
|
|
IO.mapOptional("flags", Keys->Flags, TBDFlags::None);
|
|
IO.mapRequired("install-name", Keys->InstallName);
|
|
IO.mapOptional("current-version", Keys->CurrentVersion,
|
|
PackedVersion(1, 0, 0));
|
|
IO.mapOptional("compatibility-version", Keys->CompatibilityVersion,
|
|
PackedVersion(1, 0, 0));
|
|
IO.mapOptional("swift-abi-version", Keys->SwiftABIVersion, SwiftVersion(0));
|
|
IO.mapOptional("parent-umbrella", Keys->ParentUmbrellas);
|
|
auto OptionKind = MetadataSection::Option::Clients;
|
|
IO.mapOptionalWithContext("allowable-clients", Keys->AllowableClients,
|
|
OptionKind);
|
|
OptionKind = MetadataSection::Option::Libraries;
|
|
IO.mapOptionalWithContext("reexported-libraries", Keys->ReexportedLibraries,
|
|
OptionKind);
|
|
IO.mapOptional("exports", Keys->Exports);
|
|
IO.mapOptional("reexports", Keys->Reexports);
|
|
IO.mapOptional("undefineds", Keys->Undefineds);
|
|
}
|
|
};
|
|
|
|
template <>
|
|
struct DocumentListTraits<std::vector<const MachO::InterfaceFile *>> {
|
|
static size_t size(IO &IO, std::vector<const MachO::InterfaceFile *> &Seq) {
|
|
return Seq.size();
|
|
}
|
|
static const InterfaceFile *&
|
|
element(IO &IO, std::vector<const InterfaceFile *> &Seq, size_t Index) {
|
|
if (Index >= Seq.size())
|
|
Seq.resize(Index + 1);
|
|
return Seq[Index];
|
|
}
|
|
};
|
|
|
|
} // end namespace yaml.
|
|
} // namespace llvm
|
|
|
|
static void DiagHandler(const SMDiagnostic &Diag, void *Context) {
|
|
auto *File = static_cast<TextAPIContext *>(Context);
|
|
SmallString<1024> Message;
|
|
raw_svector_ostream S(Message);
|
|
|
|
SMDiagnostic NewDiag(*Diag.getSourceMgr(), Diag.getLoc(), File->Path,
|
|
Diag.getLineNo(), Diag.getColumnNo(), Diag.getKind(),
|
|
Diag.getMessage(), Diag.getLineContents(),
|
|
Diag.getRanges(), Diag.getFixIts());
|
|
|
|
NewDiag.print(nullptr, S);
|
|
File->ErrorMessage = ("malformed file\n" + Message).str();
|
|
}
|
|
|
|
Expected<std::unique_ptr<InterfaceFile>>
|
|
TextAPIReader::get(MemoryBufferRef InputBuffer) {
|
|
TextAPIContext Ctx;
|
|
Ctx.Path = std::string(InputBuffer.getBufferIdentifier());
|
|
yaml::Input YAMLIn(InputBuffer.getBuffer(), &Ctx, DiagHandler, &Ctx);
|
|
|
|
// Fill vector with interface file objects created by parsing the YAML file.
|
|
std::vector<const InterfaceFile *> Files;
|
|
YAMLIn >> Files;
|
|
|
|
// YAMLIn dynamically allocates for Interface file and in case of error,
|
|
// memory leak will occur unless wrapped around unique_ptr
|
|
auto File = std::unique_ptr<InterfaceFile>(
|
|
const_cast<InterfaceFile *>(Files.front()));
|
|
|
|
for (const InterfaceFile *FI : llvm::drop_begin(Files))
|
|
File->addDocument(
|
|
std::shared_ptr<InterfaceFile>(const_cast<InterfaceFile *>(FI)));
|
|
|
|
if (YAMLIn.error())
|
|
return make_error<StringError>(Ctx.ErrorMessage, YAMLIn.error());
|
|
|
|
return std::move(File);
|
|
}
|
|
|
|
Error TextAPIWriter::writeToStream(raw_ostream &OS, const InterfaceFile &File) {
|
|
TextAPIContext Ctx;
|
|
Ctx.Path = std::string(File.getPath());
|
|
Ctx.FileKind = File.getFileType();
|
|
llvm::yaml::Output YAMLOut(OS, &Ctx, /*WrapColumn=*/80);
|
|
|
|
std::vector<const InterfaceFile *> Files;
|
|
Files.emplace_back(&File);
|
|
|
|
for (auto Document : File.documents())
|
|
Files.emplace_back(Document.get());
|
|
|
|
// Stream out yaml.
|
|
YAMLOut << Files;
|
|
|
|
return Error::success();
|
|
}
|