1 //===- TextStub.cpp -------------------------------------------------------===//
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7 //===----------------------------------------------------------------------===//
9 // Implements the text stub file reader/writer.
11 //===----------------------------------------------------------------------===//
13 #include "TextAPIContext.h"
14 #include "TextStubCommon.h"
15 #include "llvm/ADT/BitmaskEnum.h"
16 #include "llvm/ADT/SmallString.h"
17 #include "llvm/ADT/StringRef.h"
18 #include "llvm/Support/Allocator.h"
19 #include "llvm/Support/SourceMgr.h"
20 #include "llvm/Support/YAMLTraits.h"
21 #include "llvm/Support/raw_ostream.h"
22 #include "llvm/TextAPI/Architecture.h"
23 #include "llvm/TextAPI/ArchitectureSet.h"
24 #include "llvm/TextAPI/InterfaceFile.h"
25 #include "llvm/TextAPI/PackedVersion.h"
26 #include "llvm/TextAPI/TextAPIReader.h"
27 #include "llvm/TextAPI/TextAPIWriter.h"
34 YAML Format specification.
36 The TBD v1 format only support two level address libraries and is per
37 definition application extension safe.
39 --- # the tag !tapi-tbd-v1 is optional and
40 # shouldn't be emitted to support older linker.
41 archs: [ armv7, armv7s, arm64 ] # the list of architecture slices that are
42 # supported by this file.
43 platform: ios # Specifies the platform (macosx, ios, etc)
44 install-name: /u/l/libfoo.dylib #
45 current-version: 1.2.3 # Optional: defaults to 1.0
46 compatibility-version: 1.0 # Optional: defaults to 1.0
47 swift-version: 0 # Optional: defaults to 0
48 objc-constraint: none # Optional: defaults to none
49 exports: # List of export sections
52 Each export section is defined as following:
54 - archs: [ arm64 ] # the list of architecture slices
55 allowed-clients: [ client ] # Optional: List of clients
56 re-exports: [ ] # Optional: List of re-exports
57 symbols: [ _sym ] # Optional: List of symbols
58 objc-classes: [] # Optional: List of Objective-C classes
59 objc-ivars: [] # Optional: List of Objective C Instance
61 weak-def-symbols: [] # Optional: List of weak defined symbols
62 thread-local-symbols: [] # Optional: List of thread local symbols
67 YAML Format specification.
70 archs: [ armv7, armv7s, arm64 ] # the list of architecture slices that are
71 # supported by this file.
72 uuids: [ armv7:... ] # Optional: List of architecture and UUID pairs.
73 platform: ios # Specifies the platform (macosx, ios, etc)
75 install-name: /u/l/libfoo.dylib #
76 current-version: 1.2.3 # Optional: defaults to 1.0
77 compatibility-version: 1.0 # Optional: defaults to 1.0
78 swift-version: 0 # Optional: defaults to 0
79 objc-constraint: retain_release # Optional: defaults to retain_release
80 parent-umbrella: # Optional:
81 exports: # List of export sections
83 undefineds: # List of undefineds sections
86 Each export section is defined as following:
88 - archs: [ arm64 ] # the list of architecture slices
89 allowed-clients: [ client ] # Optional: List of clients
90 re-exports: [ ] # Optional: List of re-exports
91 symbols: [ _sym ] # Optional: List of symbols
92 objc-classes: [] # Optional: List of Objective-C classes
93 objc-ivars: [] # Optional: List of Objective C Instance
95 weak-def-symbols: [] # Optional: List of weak defined symbols
96 thread-local-symbols: [] # Optional: List of thread local symbols
98 Each undefineds section is defined as following:
99 - archs: [ arm64 ] # the list of architecture slices
100 symbols: [ _sym ] # Optional: List of symbols
101 objc-classes: [] # Optional: List of Objective-C classes
102 objc-ivars: [] # Optional: List of Objective C Instance Variables
103 weak-ref-symbols: [] # Optional: List of weak defined symbols
108 YAML Format specification.
111 archs: [ armv7, armv7s, arm64 ] # the list of architecture slices that are
112 # supported by this file.
113 uuids: [ armv7:... ] # Optional: List of architecture and UUID pairs.
114 platform: ios # Specifies the platform (macosx, ios, etc)
115 flags: [] # Optional:
116 install-name: /u/l/libfoo.dylib #
117 current-version: 1.2.3 # Optional: defaults to 1.0
118 compatibility-version: 1.0 # Optional: defaults to 1.0
119 swift-abi-version: 0 # Optional: defaults to 0
120 objc-constraint: retain_release # Optional: defaults to retain_release
121 parent-umbrella: # Optional:
122 exports: # List of export sections
124 undefineds: # List of undefineds sections
127 Each export section is defined as following:
129 - archs: [ arm64 ] # the list of architecture slices
130 allowed-clients: [ client ] # Optional: List of clients
131 re-exports: [ ] # Optional: List of re-exports
132 symbols: [ _sym ] # Optional: List of symbols
133 objc-classes: [] # Optional: List of Objective-C classes
134 objc-eh-types: [] # Optional: List of Objective-C classes
136 objc-ivars: [] # Optional: List of Objective C Instance
138 weak-def-symbols: [] # Optional: List of weak defined symbols
139 thread-local-symbols: [] # Optional: List of thread local symbols
141 Each undefineds section is defined as following:
142 - archs: [ arm64 ] # the list of architecture slices
143 symbols: [ _sym ] # Optional: List of symbols
144 objc-classes: [] # Optional: List of Objective-C classes
145 objc-eh-types: [] # Optional: List of Objective-C classes
147 objc-ivars: [] # Optional: List of Objective C Instance Variables
148 weak-ref-symbols: [] # Optional: List of weak defined symbols
153 YAML Format specification.
156 tbd-version: 4 # The tbd version for format
157 targets: [ armv7-ios, x86_64-maccatalyst ] # The list of applicable tapi supported target triples
158 uuids: # Optional: List of target and UUID pairs.
161 - target: x86_64-maccatalyst
163 flags: [] # Optional:
164 install-name: /u/l/libfoo.dylib #
165 current-version: 1.2.3 # Optional: defaults to 1.0
166 compatibility-version: 1.0 # Optional: defaults to 1.0
167 swift-abi-version: 0 # Optional: defaults to 0
168 parent-umbrella: # Optional:
170 - targets: [ armv7-ios ] # Optional:
172 exports: # List of export sections
174 re-exports: # List of reexport sections
176 undefineds: # List of undefineds sections
179 Each export and reexport section is defined as following:
181 - targets: [ arm64-macos ] # The list of target triples associated with symbols
182 symbols: [ _symA ] # Optional: List of symbols
183 objc-classes: [] # Optional: List of Objective-C classes
184 objc-eh-types: [] # Optional: List of Objective-C classes
186 objc-ivars: [] # Optional: List of Objective C Instance
188 weak-symbols: [] # Optional: List of weak defined symbols
189 thread-local-symbols: [] # Optional: List of thread local symbols
190 - targets: [ arm64-macos, x86_64-maccatalyst ] # Optional: Targets for applicable additional symbols
191 symbols: [ _symB ] # Optional: List of symbols
193 Each undefineds section is defined as following:
194 - targets: [ arm64-macos ] # The list of target triples associated with symbols
195 symbols: [ _symC ] # Optional: List of symbols
196 objc-classes: [] # Optional: List of Objective-C classes
197 objc-eh-types: [] # Optional: List of Objective-C classes
199 objc-ivars: [] # Optional: List of Objective C Instance Variables
200 weak-symbols: [] # Optional: List of weak defined symbols
204 using namespace llvm
;
205 using namespace llvm::yaml
;
206 using namespace llvm::MachO
;
209 struct ExportSection
{
210 std::vector
<Architecture
> Architectures
;
211 std::vector
<FlowStringRef
> AllowableClients
;
212 std::vector
<FlowStringRef
> ReexportedLibraries
;
213 std::vector
<FlowStringRef
> Symbols
;
214 std::vector
<FlowStringRef
> Classes
;
215 std::vector
<FlowStringRef
> ClassEHs
;
216 std::vector
<FlowStringRef
> IVars
;
217 std::vector
<FlowStringRef
> WeakDefSymbols
;
218 std::vector
<FlowStringRef
> TLVSymbols
;
221 struct UndefinedSection
{
222 std::vector
<Architecture
> Architectures
;
223 std::vector
<FlowStringRef
> Symbols
;
224 std::vector
<FlowStringRef
> Classes
;
225 std::vector
<FlowStringRef
> ClassEHs
;
226 std::vector
<FlowStringRef
> IVars
;
227 std::vector
<FlowStringRef
> WeakRefSymbols
;
230 // Sections for direct target mapping in TBDv4
231 struct SymbolSection
{
233 std::vector
<FlowStringRef
> Symbols
;
234 std::vector
<FlowStringRef
> Classes
;
235 std::vector
<FlowStringRef
> ClassEHs
;
236 std::vector
<FlowStringRef
> Ivars
;
237 std::vector
<FlowStringRef
> WeakSymbols
;
238 std::vector
<FlowStringRef
> TlvSymbols
;
241 struct MetadataSection
{
242 enum Option
{ Clients
, Libraries
};
243 std::vector
<Target
> Targets
;
244 std::vector
<FlowStringRef
> Values
;
247 struct UmbrellaSection
{
248 std::vector
<Target
> Targets
;
249 std::string Umbrella
;
252 // UUID's for TBDv4 are mapped to target not arch
258 UUIDv4(const Target
&TargetID
, const std::string
&Value
)
259 : TargetID(TargetID
), Value(Value
) {}
263 enum TBDFlags
: unsigned {
265 FlatNamespace
= 1U << 0,
266 NotApplicationExtensionSafe
= 1U << 1,
267 InstallAPI
= 1U << 2,
268 LLVM_MARK_AS_BITMASK_ENUM(/*LargestValue=*/InstallAPI
),
271 } // end anonymous namespace.
273 LLVM_YAML_IS_FLOW_SEQUENCE_VECTOR(Architecture
)
274 LLVM_YAML_IS_SEQUENCE_VECTOR(ExportSection
)
275 LLVM_YAML_IS_SEQUENCE_VECTOR(UndefinedSection
)
277 LLVM_YAML_IS_SEQUENCE_VECTOR(SymbolSection
)
278 LLVM_YAML_IS_SEQUENCE_VECTOR(MetadataSection
)
279 LLVM_YAML_IS_SEQUENCE_VECTOR(UmbrellaSection
)
280 LLVM_YAML_IS_FLOW_SEQUENCE_VECTOR(Target
)
281 LLVM_YAML_IS_SEQUENCE_VECTOR(UUIDv4
)
286 template <> struct MappingTraits
<ExportSection
> {
287 static void mapping(IO
&IO
, ExportSection
&Section
) {
288 const auto *Ctx
= reinterpret_cast<TextAPIContext
*>(IO
.getContext());
289 assert((!Ctx
|| (Ctx
&& Ctx
->FileKind
!= FileType::Invalid
)) &&
290 "File type is not set in YAML context");
292 IO
.mapRequired("archs", Section
.Architectures
);
293 if (Ctx
->FileKind
== FileType::TBD_V1
)
294 IO
.mapOptional("allowed-clients", Section
.AllowableClients
);
296 IO
.mapOptional("allowable-clients", Section
.AllowableClients
);
297 IO
.mapOptional("re-exports", Section
.ReexportedLibraries
);
298 IO
.mapOptional("symbols", Section
.Symbols
);
299 IO
.mapOptional("objc-classes", Section
.Classes
);
300 if (Ctx
->FileKind
== FileType::TBD_V3
)
301 IO
.mapOptional("objc-eh-types", Section
.ClassEHs
);
302 IO
.mapOptional("objc-ivars", Section
.IVars
);
303 IO
.mapOptional("weak-def-symbols", Section
.WeakDefSymbols
);
304 IO
.mapOptional("thread-local-symbols", Section
.TLVSymbols
);
308 template <> struct MappingTraits
<UndefinedSection
> {
309 static void mapping(IO
&IO
, UndefinedSection
&Section
) {
310 const auto *Ctx
= reinterpret_cast<TextAPIContext
*>(IO
.getContext());
311 assert((!Ctx
|| (Ctx
&& Ctx
->FileKind
!= FileType::Invalid
)) &&
312 "File type is not set in YAML context");
314 IO
.mapRequired("archs", Section
.Architectures
);
315 IO
.mapOptional("symbols", Section
.Symbols
);
316 IO
.mapOptional("objc-classes", Section
.Classes
);
317 if (Ctx
->FileKind
== FileType::TBD_V3
)
318 IO
.mapOptional("objc-eh-types", Section
.ClassEHs
);
319 IO
.mapOptional("objc-ivars", Section
.IVars
);
320 IO
.mapOptional("weak-ref-symbols", Section
.WeakRefSymbols
);
324 template <> struct MappingTraits
<SymbolSection
> {
325 static void mapping(IO
&IO
, SymbolSection
&Section
) {
326 IO
.mapRequired("targets", Section
.Targets
);
327 IO
.mapOptional("symbols", Section
.Symbols
);
328 IO
.mapOptional("objc-classes", Section
.Classes
);
329 IO
.mapOptional("objc-eh-types", Section
.ClassEHs
);
330 IO
.mapOptional("objc-ivars", Section
.Ivars
);
331 IO
.mapOptional("weak-symbols", Section
.WeakSymbols
);
332 IO
.mapOptional("thread-local-symbols", Section
.TlvSymbols
);
336 template <> struct MappingTraits
<UmbrellaSection
> {
337 static void mapping(IO
&IO
, UmbrellaSection
&Section
) {
338 IO
.mapRequired("targets", Section
.Targets
);
339 IO
.mapRequired("umbrella", Section
.Umbrella
);
343 template <> struct MappingTraits
<UUIDv4
> {
344 static void mapping(IO
&IO
, UUIDv4
&UUID
) {
345 IO
.mapRequired("target", UUID
.TargetID
);
346 IO
.mapRequired("value", UUID
.Value
);
351 struct MappingContextTraits
<MetadataSection
, MetadataSection::Option
> {
352 static void mapping(IO
&IO
, MetadataSection
&Section
,
353 MetadataSection::Option
&OptionKind
) {
354 IO
.mapRequired("targets", Section
.Targets
);
355 switch (OptionKind
) {
356 case MetadataSection::Option::Clients
:
357 IO
.mapRequired("clients", Section
.Values
);
359 case MetadataSection::Option::Libraries
:
360 IO
.mapRequired("libraries", Section
.Values
);
363 llvm_unreachable("unexpected option for metadata");
367 template <> struct ScalarBitSetTraits
<TBDFlags
> {
368 static void bitset(IO
&IO
, TBDFlags
&Flags
) {
369 IO
.bitSetCase(Flags
, "flat_namespace", TBDFlags::FlatNamespace
);
370 IO
.bitSetCase(Flags
, "not_app_extension_safe",
371 TBDFlags::NotApplicationExtensionSafe
);
372 IO
.bitSetCase(Flags
, "installapi", TBDFlags::InstallAPI
);
376 template <> struct ScalarTraits
<Target
> {
377 static void output(const Target
&Value
, void *, raw_ostream
&OS
) {
378 OS
<< Value
.Arch
<< "-";
379 switch (Value
.Platform
) {
383 case PlatformKind::macOS
:
386 case PlatformKind::iOS
:
389 case PlatformKind::tvOS
:
392 case PlatformKind::watchOS
:
395 case PlatformKind::bridgeOS
:
398 case PlatformKind::macCatalyst
:
401 case PlatformKind::iOSSimulator
:
402 OS
<< "ios-simulator";
404 case PlatformKind::tvOSSimulator
:
405 OS
<< "tvos-simulator";
407 case PlatformKind::watchOSSimulator
:
408 OS
<< "watchos-simulator";
410 case PlatformKind::driverKit
:
416 static StringRef
input(StringRef Scalar
, void *, Target
&Value
) {
417 auto Result
= Target::create(Scalar
);
419 consumeError(Result
.takeError());
420 return "unparsable target";
424 if (Value
.Arch
== AK_unknown
)
425 return "unknown architecture";
426 if (Value
.Platform
== PlatformKind::unknown
)
427 return "unknown platform";
432 static QuotingType
mustQuote(StringRef
) { return QuotingType::None
; }
435 template <> struct MappingTraits
<const InterfaceFile
*> {
436 struct NormalizedTBD
{
437 explicit NormalizedTBD(IO
&IO
) {}
438 NormalizedTBD(IO
&IO
, const InterfaceFile
*&File
) {
439 Architectures
= File
->getArchitectures();
440 UUIDs
= File
->uuids();
441 Platforms
= File
->getPlatforms();
442 InstallName
= File
->getInstallName();
443 CurrentVersion
= PackedVersion(File
->getCurrentVersion());
444 CompatibilityVersion
= PackedVersion(File
->getCompatibilityVersion());
445 SwiftABIVersion
= File
->getSwiftABIVersion();
446 ObjCConstraint
= File
->getObjCConstraint();
448 Flags
= TBDFlags::None
;
449 if (!File
->isApplicationExtensionSafe())
450 Flags
|= TBDFlags::NotApplicationExtensionSafe
;
452 if (!File
->isTwoLevelNamespace())
453 Flags
|= TBDFlags::FlatNamespace
;
455 if (File
->isInstallAPI())
456 Flags
|= TBDFlags::InstallAPI
;
458 if (!File
->umbrellas().empty())
459 ParentUmbrella
= File
->umbrellas().begin()->second
;
461 std::set
<ArchitectureSet
> ArchSet
;
462 for (const auto &Library
: File
->allowableClients())
463 ArchSet
.insert(Library
.getArchitectures());
465 for (const auto &Library
: File
->reexportedLibraries())
466 ArchSet
.insert(Library
.getArchitectures());
468 std::map
<const Symbol
*, ArchitectureSet
> SymbolToArchSet
;
469 for (const auto *Symbol
: File
->exports()) {
470 auto Architectures
= Symbol
->getArchitectures();
471 SymbolToArchSet
[Symbol
] = Architectures
;
472 ArchSet
.insert(Architectures
);
475 for (auto Architectures
: ArchSet
) {
476 ExportSection Section
;
477 Section
.Architectures
= Architectures
;
479 for (const auto &Library
: File
->allowableClients())
480 if (Library
.getArchitectures() == Architectures
)
481 Section
.AllowableClients
.emplace_back(Library
.getInstallName());
483 for (const auto &Library
: File
->reexportedLibraries())
484 if (Library
.getArchitectures() == Architectures
)
485 Section
.ReexportedLibraries
.emplace_back(Library
.getInstallName());
487 for (const auto &SymArch
: SymbolToArchSet
) {
488 if (SymArch
.second
!= Architectures
)
491 const auto *Symbol
= SymArch
.first
;
492 switch (Symbol
->getKind()) {
493 case SymbolKind::GlobalSymbol
:
494 if (Symbol
->isWeakDefined())
495 Section
.WeakDefSymbols
.emplace_back(Symbol
->getName());
496 else if (Symbol
->isThreadLocalValue())
497 Section
.TLVSymbols
.emplace_back(Symbol
->getName());
499 Section
.Symbols
.emplace_back(Symbol
->getName());
501 case SymbolKind::ObjectiveCClass
:
502 if (File
->getFileType() != FileType::TBD_V3
)
503 Section
.Classes
.emplace_back(
504 copyString("_" + Symbol
->getName().str()));
506 Section
.Classes
.emplace_back(Symbol
->getName());
508 case SymbolKind::ObjectiveCClassEHType
:
509 if (File
->getFileType() != FileType::TBD_V3
)
510 Section
.Symbols
.emplace_back(
511 copyString("_OBJC_EHTYPE_$_" + Symbol
->getName().str()));
513 Section
.ClassEHs
.emplace_back(Symbol
->getName());
515 case SymbolKind::ObjectiveCInstanceVariable
:
516 if (File
->getFileType() != FileType::TBD_V3
)
517 Section
.IVars
.emplace_back(
518 copyString("_" + Symbol
->getName().str()));
520 Section
.IVars
.emplace_back(Symbol
->getName());
524 llvm::sort(Section
.Symbols
);
525 llvm::sort(Section
.Classes
);
526 llvm::sort(Section
.ClassEHs
);
527 llvm::sort(Section
.IVars
);
528 llvm::sort(Section
.WeakDefSymbols
);
529 llvm::sort(Section
.TLVSymbols
);
530 Exports
.emplace_back(std::move(Section
));
534 SymbolToArchSet
.clear();
536 for (const auto *Symbol
: File
->undefineds()) {
537 auto Architectures
= Symbol
->getArchitectures();
538 SymbolToArchSet
[Symbol
] = Architectures
;
539 ArchSet
.insert(Architectures
);
542 for (auto Architectures
: ArchSet
) {
543 UndefinedSection Section
;
544 Section
.Architectures
= Architectures
;
546 for (const auto &SymArch
: SymbolToArchSet
) {
547 if (SymArch
.second
!= Architectures
)
550 const auto *Symbol
= SymArch
.first
;
551 switch (Symbol
->getKind()) {
552 case SymbolKind::GlobalSymbol
:
553 if (Symbol
->isWeakReferenced())
554 Section
.WeakRefSymbols
.emplace_back(Symbol
->getName());
556 Section
.Symbols
.emplace_back(Symbol
->getName());
558 case SymbolKind::ObjectiveCClass
:
559 if (File
->getFileType() != FileType::TBD_V3
)
560 Section
.Classes
.emplace_back(
561 copyString("_" + Symbol
->getName().str()));
563 Section
.Classes
.emplace_back(Symbol
->getName());
565 case SymbolKind::ObjectiveCClassEHType
:
566 if (File
->getFileType() != FileType::TBD_V3
)
567 Section
.Symbols
.emplace_back(
568 copyString("_OBJC_EHTYPE_$_" + Symbol
->getName().str()));
570 Section
.ClassEHs
.emplace_back(Symbol
->getName());
572 case SymbolKind::ObjectiveCInstanceVariable
:
573 if (File
->getFileType() != FileType::TBD_V3
)
574 Section
.IVars
.emplace_back(
575 copyString("_" + Symbol
->getName().str()));
577 Section
.IVars
.emplace_back(Symbol
->getName());
581 llvm::sort(Section
.Symbols
);
582 llvm::sort(Section
.Classes
);
583 llvm::sort(Section
.ClassEHs
);
584 llvm::sort(Section
.IVars
);
585 llvm::sort(Section
.WeakRefSymbols
);
586 Undefineds
.emplace_back(std::move(Section
));
590 // TBD v1 - TBD v3 files only support one platform and several
591 // architectures. It is possible to have more than one platform for TBD v3
592 // files, but the architectures don't apply to all
593 // platforms, specifically to filter out the i386 slice from
594 // platform macCatalyst.
595 TargetList
synthesizeTargets(ArchitectureSet Architectures
,
596 const PlatformSet
&Platforms
) {
599 for (auto Platform
: Platforms
) {
600 Platform
= mapToPlatformKind(Platform
, Architectures
.hasX86());
602 for (const auto &&Architecture
: Architectures
) {
603 if ((Architecture
== AK_i386
) &&
604 (Platform
== PlatformKind::macCatalyst
))
607 Targets
.emplace_back(Architecture
, Platform
);
613 const InterfaceFile
*denormalize(IO
&IO
) {
614 auto Ctx
= reinterpret_cast<TextAPIContext
*>(IO
.getContext());
617 auto *File
= new InterfaceFile
;
618 File
->setPath(Ctx
->Path
);
619 File
->setFileType(Ctx
->FileKind
);
620 File
->addTargets(synthesizeTargets(Architectures
, Platforms
));
621 for (auto &ID
: UUIDs
)
622 File
->addUUID(ID
.first
, ID
.second
);
623 File
->setInstallName(InstallName
);
624 File
->setCurrentVersion(CurrentVersion
);
625 File
->setCompatibilityVersion(CompatibilityVersion
);
626 File
->setSwiftABIVersion(SwiftABIVersion
);
627 File
->setObjCConstraint(ObjCConstraint
);
628 for (const auto &Target
: File
->targets())
629 File
->addParentUmbrella(Target
, ParentUmbrella
);
631 if (Ctx
->FileKind
== FileType::TBD_V1
) {
632 File
->setTwoLevelNamespace();
633 File
->setApplicationExtensionSafe();
635 File
->setTwoLevelNamespace(!(Flags
& TBDFlags::FlatNamespace
));
636 File
->setApplicationExtensionSafe(
637 !(Flags
& TBDFlags::NotApplicationExtensionSafe
));
638 File
->setInstallAPI(Flags
& TBDFlags::InstallAPI
);
641 for (const auto &Section
: Exports
) {
643 synthesizeTargets(Section
.Architectures
, Platforms
);
645 for (const auto &Lib
: Section
.AllowableClients
)
646 for (const auto &Target
: Targets
)
647 File
->addAllowableClient(Lib
, Target
);
649 for (const auto &Lib
: Section
.ReexportedLibraries
)
650 for (const auto &Target
: Targets
)
651 File
->addReexportedLibrary(Lib
, Target
);
653 for (const auto &Symbol
: Section
.Symbols
) {
654 if (Ctx
->FileKind
!= FileType::TBD_V3
&&
655 Symbol
.value
.startswith("_OBJC_EHTYPE_$_"))
656 File
->addSymbol(SymbolKind::ObjectiveCClassEHType
,
657 Symbol
.value
.drop_front(15), Targets
);
659 File
->addSymbol(SymbolKind::GlobalSymbol
, Symbol
, Targets
);
661 for (auto &Symbol
: Section
.Classes
) {
662 auto Name
= Symbol
.value
;
663 if (Ctx
->FileKind
!= FileType::TBD_V3
)
664 Name
= Name
.drop_front();
665 File
->addSymbol(SymbolKind::ObjectiveCClass
, Name
, Targets
);
667 for (auto &Symbol
: Section
.ClassEHs
)
668 File
->addSymbol(SymbolKind::ObjectiveCClassEHType
, Symbol
, Targets
);
669 for (auto &Symbol
: Section
.IVars
) {
670 auto Name
= Symbol
.value
;
671 if (Ctx
->FileKind
!= FileType::TBD_V3
)
672 Name
= Name
.drop_front();
673 File
->addSymbol(SymbolKind::ObjectiveCInstanceVariable
, Name
,
676 for (auto &Symbol
: Section
.WeakDefSymbols
)
677 File
->addSymbol(SymbolKind::GlobalSymbol
, Symbol
, Targets
,
678 SymbolFlags::WeakDefined
);
679 for (auto &Symbol
: Section
.TLVSymbols
)
680 File
->addSymbol(SymbolKind::GlobalSymbol
, Symbol
, Targets
,
681 SymbolFlags::ThreadLocalValue
);
684 for (const auto &Section
: Undefineds
) {
686 synthesizeTargets(Section
.Architectures
, Platforms
);
687 for (auto &Symbol
: Section
.Symbols
) {
688 if (Ctx
->FileKind
!= FileType::TBD_V3
&&
689 Symbol
.value
.startswith("_OBJC_EHTYPE_$_"))
690 File
->addSymbol(SymbolKind::ObjectiveCClassEHType
,
691 Symbol
.value
.drop_front(15), Targets
,
692 SymbolFlags::Undefined
);
694 File
->addSymbol(SymbolKind::GlobalSymbol
, Symbol
, Targets
,
695 SymbolFlags::Undefined
);
697 for (auto &Symbol
: Section
.Classes
) {
698 auto Name
= Symbol
.value
;
699 if (Ctx
->FileKind
!= FileType::TBD_V3
)
700 Name
= Name
.drop_front();
701 File
->addSymbol(SymbolKind::ObjectiveCClass
, Name
, Targets
,
702 SymbolFlags::Undefined
);
704 for (auto &Symbol
: Section
.ClassEHs
)
705 File
->addSymbol(SymbolKind::ObjectiveCClassEHType
, Symbol
, Targets
,
706 SymbolFlags::Undefined
);
707 for (auto &Symbol
: Section
.IVars
) {
708 auto Name
= Symbol
.value
;
709 if (Ctx
->FileKind
!= FileType::TBD_V3
)
710 Name
= Name
.drop_front();
711 File
->addSymbol(SymbolKind::ObjectiveCInstanceVariable
, Name
, Targets
,
712 SymbolFlags::Undefined
);
714 for (auto &Symbol
: Section
.WeakRefSymbols
)
715 File
->addSymbol(SymbolKind::GlobalSymbol
, Symbol
, Targets
,
716 SymbolFlags::Undefined
| SymbolFlags::WeakReferenced
);
722 llvm::BumpPtrAllocator Allocator
;
723 StringRef
copyString(StringRef String
) {
727 void *Ptr
= Allocator
.Allocate(String
.size(), 1);
728 memcpy(Ptr
, String
.data(), String
.size());
729 return StringRef(reinterpret_cast<const char *>(Ptr
), String
.size());
732 std::vector
<Architecture
> Architectures
;
733 std::vector
<UUID
> UUIDs
;
734 PlatformSet Platforms
;
735 StringRef InstallName
;
736 PackedVersion CurrentVersion
;
737 PackedVersion CompatibilityVersion
;
738 SwiftVersion SwiftABIVersion
{0};
739 ObjCConstraintType ObjCConstraint
{ObjCConstraintType::None
};
740 TBDFlags Flags
{TBDFlags::None
};
741 StringRef ParentUmbrella
;
742 std::vector
<ExportSection
> Exports
;
743 std::vector
<UndefinedSection
> Undefineds
;
746 static void setFileTypeForInput(TextAPIContext
*Ctx
, IO
&IO
) {
747 if (IO
.mapTag("!tapi-tbd", false))
748 Ctx
->FileKind
= FileType::TBD_V4
;
749 else if (IO
.mapTag("!tapi-tbd-v3", false))
750 Ctx
->FileKind
= FileType::TBD_V3
;
751 else if (IO
.mapTag("!tapi-tbd-v2", false))
752 Ctx
->FileKind
= FileType::TBD_V2
;
753 else if (IO
.mapTag("!tapi-tbd-v1", false) ||
754 IO
.mapTag("tag:yaml.org,2002:map", false))
755 Ctx
->FileKind
= FileType::TBD_V1
;
757 Ctx
->FileKind
= FileType::Invalid
;
762 static void mapping(IO
&IO
, const InterfaceFile
*&File
) {
763 auto *Ctx
= reinterpret_cast<TextAPIContext
*>(IO
.getContext());
764 assert((!Ctx
|| !IO
.outputting() ||
765 (Ctx
&& Ctx
->FileKind
!= FileType::Invalid
)) &&
766 "File type is not set in YAML context");
768 if (!IO
.outputting()) {
769 setFileTypeForInput(Ctx
, IO
);
770 switch (Ctx
->FileKind
) {
773 case FileType::TBD_V4
:
774 mapKeysToValuesV4(IO
, File
);
776 case FileType::Invalid
:
777 IO
.setError("unsupported file type");
781 // Set file type when writing.
782 switch (Ctx
->FileKind
) {
784 llvm_unreachable("unexpected file type");
785 case FileType::TBD_V4
:
786 mapKeysToValuesV4(IO
, File
);
788 case FileType::TBD_V3
:
789 IO
.mapTag("!tapi-tbd-v3", true);
791 case FileType::TBD_V2
:
792 IO
.mapTag("!tapi-tbd-v2", true);
794 case FileType::TBD_V1
:
795 // Don't write the tag into the .tbd file for TBD v1
799 mapKeysToValues(Ctx
->FileKind
, IO
, File
);
802 using SectionList
= std::vector
<SymbolSection
>;
803 struct NormalizedTBD_V4
{
804 explicit NormalizedTBD_V4(IO
&IO
) {}
805 NormalizedTBD_V4(IO
&IO
, const InterfaceFile
*&File
) {
806 auto Ctx
= reinterpret_cast<TextAPIContext
*>(IO
.getContext());
808 TBDVersion
= Ctx
->FileKind
>> 1;
809 Targets
.insert(Targets
.begin(), File
->targets().begin(),
810 File
->targets().end());
811 for (const auto &IT
: File
->uuids())
812 UUIDs
.emplace_back(IT
.first
, IT
.second
);
813 InstallName
= File
->getInstallName();
814 CurrentVersion
= File
->getCurrentVersion();
815 CompatibilityVersion
= File
->getCompatibilityVersion();
816 SwiftABIVersion
= File
->getSwiftABIVersion();
818 Flags
= TBDFlags::None
;
819 if (!File
->isApplicationExtensionSafe())
820 Flags
|= TBDFlags::NotApplicationExtensionSafe
;
822 if (!File
->isTwoLevelNamespace())
823 Flags
|= TBDFlags::FlatNamespace
;
825 if (File
->isInstallAPI())
826 Flags
|= TBDFlags::InstallAPI
;
829 std::map
<std::string
, TargetList
> valueToTargetList
;
830 for (const auto &it
: File
->umbrellas())
831 valueToTargetList
[it
.second
].emplace_back(it
.first
);
833 for (const auto &it
: valueToTargetList
) {
834 UmbrellaSection CurrentSection
;
835 CurrentSection
.Targets
.insert(CurrentSection
.Targets
.begin(),
836 it
.second
.begin(), it
.second
.end());
837 CurrentSection
.Umbrella
= it
.first
;
838 ParentUmbrellas
.emplace_back(std::move(CurrentSection
));
842 assignTargetsToLibrary(File
->allowableClients(), AllowableClients
);
843 assignTargetsToLibrary(File
->reexportedLibraries(), ReexportedLibraries
);
846 [](SectionList
&CurrentSections
,
847 InterfaceFile::const_filtered_symbol_range Symbols
,
848 std::function
<bool(const Symbol
*)> Pred
) {
849 std::set
<TargetList
> TargetSet
;
850 std::map
<const Symbol
*, TargetList
> SymbolToTargetList
;
851 for (const auto *Symbol
: Symbols
) {
854 TargetList
Targets(Symbol
->targets());
855 SymbolToTargetList
[Symbol
] = Targets
;
856 TargetSet
.emplace(std::move(Targets
));
858 for (const auto &TargetIDs
: TargetSet
) {
859 SymbolSection CurrentSection
;
860 CurrentSection
.Targets
.insert(CurrentSection
.Targets
.begin(),
861 TargetIDs
.begin(), TargetIDs
.end());
863 for (const auto &IT
: SymbolToTargetList
) {
864 if (IT
.second
!= TargetIDs
)
867 const auto *Symbol
= IT
.first
;
868 switch (Symbol
->getKind()) {
869 case SymbolKind::GlobalSymbol
:
870 if (Symbol
->isWeakDefined())
871 CurrentSection
.WeakSymbols
.emplace_back(Symbol
->getName());
872 else if (Symbol
->isThreadLocalValue())
873 CurrentSection
.TlvSymbols
.emplace_back(Symbol
->getName());
875 CurrentSection
.Symbols
.emplace_back(Symbol
->getName());
877 case SymbolKind::ObjectiveCClass
:
878 CurrentSection
.Classes
.emplace_back(Symbol
->getName());
880 case SymbolKind::ObjectiveCClassEHType
:
881 CurrentSection
.ClassEHs
.emplace_back(Symbol
->getName());
883 case SymbolKind::ObjectiveCInstanceVariable
:
884 CurrentSection
.Ivars
.emplace_back(Symbol
->getName());
888 sort(CurrentSection
.Symbols
);
889 sort(CurrentSection
.Classes
);
890 sort(CurrentSection
.ClassEHs
);
891 sort(CurrentSection
.Ivars
);
892 sort(CurrentSection
.WeakSymbols
);
893 sort(CurrentSection
.TlvSymbols
);
894 CurrentSections
.emplace_back(std::move(CurrentSection
));
898 handleSymbols(Exports
, File
->exports(), [](const Symbol
*Symbol
) {
899 return !Symbol
->isReexported();
901 handleSymbols(Reexports
, File
->exports(), [](const Symbol
*Symbol
) {
902 return Symbol
->isReexported();
904 handleSymbols(Undefineds
, File
->undefineds(),
905 [](const Symbol
*Symbol
) { return true; });
908 const InterfaceFile
*denormalize(IO
&IO
) {
909 auto Ctx
= reinterpret_cast<TextAPIContext
*>(IO
.getContext());
912 auto *File
= new InterfaceFile
;
913 File
->setPath(Ctx
->Path
);
914 File
->setFileType(Ctx
->FileKind
);
915 for (auto &id
: UUIDs
)
916 File
->addUUID(id
.TargetID
, id
.Value
);
917 File
->addTargets(Targets
);
918 File
->setInstallName(InstallName
);
919 File
->setCurrentVersion(CurrentVersion
);
920 File
->setCompatibilityVersion(CompatibilityVersion
);
921 File
->setSwiftABIVersion(SwiftABIVersion
);
922 for (const auto &CurrentSection
: ParentUmbrellas
)
923 for (const auto &target
: CurrentSection
.Targets
)
924 File
->addParentUmbrella(target
, CurrentSection
.Umbrella
);
925 File
->setTwoLevelNamespace(!(Flags
& TBDFlags::FlatNamespace
));
926 File
->setApplicationExtensionSafe(
927 !(Flags
& TBDFlags::NotApplicationExtensionSafe
));
928 File
->setInstallAPI(Flags
& TBDFlags::InstallAPI
);
930 for (const auto &CurrentSection
: AllowableClients
) {
931 for (const auto &lib
: CurrentSection
.Values
)
932 for (const auto &Target
: CurrentSection
.Targets
)
933 File
->addAllowableClient(lib
, Target
);
936 for (const auto &CurrentSection
: ReexportedLibraries
) {
937 for (const auto &Lib
: CurrentSection
.Values
)
938 for (const auto &Target
: CurrentSection
.Targets
)
939 File
->addReexportedLibrary(Lib
, Target
);
942 auto handleSymbols
= [File
](const SectionList
&CurrentSections
,
943 SymbolFlags Flag
= SymbolFlags::None
) {
944 for (const auto &CurrentSection
: CurrentSections
) {
945 for (auto &sym
: CurrentSection
.Symbols
)
946 File
->addSymbol(SymbolKind::GlobalSymbol
, sym
,
947 CurrentSection
.Targets
, Flag
);
949 for (auto &sym
: CurrentSection
.Classes
)
950 File
->addSymbol(SymbolKind::ObjectiveCClass
, sym
,
951 CurrentSection
.Targets
);
953 for (auto &sym
: CurrentSection
.ClassEHs
)
954 File
->addSymbol(SymbolKind::ObjectiveCClassEHType
, sym
,
955 CurrentSection
.Targets
);
957 for (auto &sym
: CurrentSection
.Ivars
)
958 File
->addSymbol(SymbolKind::ObjectiveCInstanceVariable
, sym
,
959 CurrentSection
.Targets
);
961 for (auto &sym
: CurrentSection
.WeakSymbols
)
962 File
->addSymbol(SymbolKind::GlobalSymbol
, sym
,
963 CurrentSection
.Targets
, SymbolFlags::WeakDefined
);
965 for (auto &sym
: CurrentSection
.TlvSymbols
)
966 File
->addSymbol(SymbolKind::GlobalSymbol
, sym
,
967 CurrentSection
.Targets
,
968 SymbolFlags::ThreadLocalValue
);
972 handleSymbols(Exports
);
973 handleSymbols(Reexports
, SymbolFlags::Rexported
);
974 handleSymbols(Undefineds
, SymbolFlags::Undefined
);
980 std::vector
<UUIDv4
> UUIDs
;
982 StringRef InstallName
;
983 PackedVersion CurrentVersion
;
984 PackedVersion CompatibilityVersion
;
985 SwiftVersion SwiftABIVersion
{0};
986 std::vector
<MetadataSection
> AllowableClients
;
987 std::vector
<MetadataSection
> ReexportedLibraries
;
988 TBDFlags Flags
{TBDFlags::None
};
989 std::vector
<UmbrellaSection
> ParentUmbrellas
;
991 SectionList Reexports
;
992 SectionList Undefineds
;
995 void assignTargetsToLibrary(const std::vector
<InterfaceFileRef
> &Libraries
,
996 std::vector
<MetadataSection
> &Section
) {
997 std::set
<TargetList
> targetSet
;
998 std::map
<const InterfaceFileRef
*, TargetList
> valueToTargetList
;
999 for (const auto &library
: Libraries
) {
1000 TargetList
targets(library
.targets());
1001 valueToTargetList
[&library
] = targets
;
1002 targetSet
.emplace(std::move(targets
));
1005 for (const auto &targets
: targetSet
) {
1006 MetadataSection CurrentSection
;
1007 CurrentSection
.Targets
.insert(CurrentSection
.Targets
.begin(),
1008 targets
.begin(), targets
.end());
1010 for (const auto &it
: valueToTargetList
) {
1011 if (it
.second
!= targets
)
1014 CurrentSection
.Values
.emplace_back(it
.first
->getInstallName());
1016 llvm::sort(CurrentSection
.Values
);
1017 Section
.emplace_back(std::move(CurrentSection
));
1022 static void mapKeysToValues(FileType FileKind
, IO
&IO
,
1023 const InterfaceFile
*&File
) {
1024 MappingNormalization
<NormalizedTBD
, const InterfaceFile
*> Keys(IO
, File
);
1025 IO
.mapRequired("archs", Keys
->Architectures
);
1026 if (FileKind
!= FileType::TBD_V1
)
1027 IO
.mapOptional("uuids", Keys
->UUIDs
);
1028 IO
.mapRequired("platform", Keys
->Platforms
);
1029 if (FileKind
!= FileType::TBD_V1
)
1030 IO
.mapOptional("flags", Keys
->Flags
, TBDFlags::None
);
1031 IO
.mapRequired("install-name", Keys
->InstallName
);
1032 IO
.mapOptional("current-version", Keys
->CurrentVersion
,
1033 PackedVersion(1, 0, 0));
1034 IO
.mapOptional("compatibility-version", Keys
->CompatibilityVersion
,
1035 PackedVersion(1, 0, 0));
1036 if (FileKind
!= FileType::TBD_V3
)
1037 IO
.mapOptional("swift-version", Keys
->SwiftABIVersion
, SwiftVersion(0));
1039 IO
.mapOptional("swift-abi-version", Keys
->SwiftABIVersion
,
1041 IO
.mapOptional("objc-constraint", Keys
->ObjCConstraint
,
1042 (FileKind
== FileType::TBD_V1
)
1043 ? ObjCConstraintType::None
1044 : ObjCConstraintType::Retain_Release
);
1045 if (FileKind
!= FileType::TBD_V1
)
1046 IO
.mapOptional("parent-umbrella", Keys
->ParentUmbrella
, StringRef());
1047 IO
.mapOptional("exports", Keys
->Exports
);
1048 if (FileKind
!= FileType::TBD_V1
)
1049 IO
.mapOptional("undefineds", Keys
->Undefineds
);
1052 static void mapKeysToValuesV4(IO
&IO
, const InterfaceFile
*&File
) {
1053 MappingNormalization
<NormalizedTBD_V4
, const InterfaceFile
*> Keys(IO
,
1055 IO
.mapTag("!tapi-tbd", true);
1056 IO
.mapRequired("tbd-version", Keys
->TBDVersion
);
1057 IO
.mapRequired("targets", Keys
->Targets
);
1058 IO
.mapOptional("uuids", Keys
->UUIDs
);
1059 IO
.mapOptional("flags", Keys
->Flags
, TBDFlags::None
);
1060 IO
.mapRequired("install-name", Keys
->InstallName
);
1061 IO
.mapOptional("current-version", Keys
->CurrentVersion
,
1062 PackedVersion(1, 0, 0));
1063 IO
.mapOptional("compatibility-version", Keys
->CompatibilityVersion
,
1064 PackedVersion(1, 0, 0));
1065 IO
.mapOptional("swift-abi-version", Keys
->SwiftABIVersion
, SwiftVersion(0));
1066 IO
.mapOptional("parent-umbrella", Keys
->ParentUmbrellas
);
1067 auto OptionKind
= MetadataSection::Option::Clients
;
1068 IO
.mapOptionalWithContext("allowable-clients", Keys
->AllowableClients
,
1070 OptionKind
= MetadataSection::Option::Libraries
;
1071 IO
.mapOptionalWithContext("reexported-libraries", Keys
->ReexportedLibraries
,
1073 IO
.mapOptional("exports", Keys
->Exports
);
1074 IO
.mapOptional("reexports", Keys
->Reexports
);
1075 IO
.mapOptional("undefineds", Keys
->Undefineds
);
1080 struct DocumentListTraits
<std::vector
<const MachO::InterfaceFile
*>> {
1081 static size_t size(IO
&IO
, std::vector
<const MachO::InterfaceFile
*> &Seq
) {
1084 static const InterfaceFile
*&
1085 element(IO
&IO
, std::vector
<const InterfaceFile
*> &Seq
, size_t Index
) {
1086 if (Index
>= Seq
.size())
1087 Seq
.resize(Index
+ 1);
1092 } // end namespace yaml.
1095 static void DiagHandler(const SMDiagnostic
&Diag
, void *Context
) {
1096 auto *File
= static_cast<TextAPIContext
*>(Context
);
1097 SmallString
<1024> Message
;
1098 raw_svector_ostream
S(Message
);
1100 SMDiagnostic
NewDiag(*Diag
.getSourceMgr(), Diag
.getLoc(), File
->Path
,
1101 Diag
.getLineNo(), Diag
.getColumnNo(), Diag
.getKind(),
1102 Diag
.getMessage(), Diag
.getLineContents(),
1103 Diag
.getRanges(), Diag
.getFixIts());
1105 NewDiag
.print(nullptr, S
);
1106 File
->ErrorMessage
= ("malformed file\n" + Message
).str();
1109 Expected
<std::unique_ptr
<InterfaceFile
>>
1110 TextAPIReader::get(MemoryBufferRef InputBuffer
) {
1112 Ctx
.Path
= std::string(InputBuffer
.getBufferIdentifier());
1113 yaml::Input
YAMLIn(InputBuffer
.getBuffer(), &Ctx
, DiagHandler
, &Ctx
);
1115 // Fill vector with interface file objects created by parsing the YAML file.
1116 std::vector
<const InterfaceFile
*> Files
;
1119 // YAMLIn dynamically allocates for Interface file and in case of error,
1120 // memory leak will occur unless wrapped around unique_ptr
1121 auto File
= std::unique_ptr
<InterfaceFile
>(
1122 const_cast<InterfaceFile
*>(Files
.front()));
1124 for (auto Iter
= std::next(Files
.begin()); Iter
!= Files
.end(); ++Iter
)
1126 std::shared_ptr
<InterfaceFile
>(const_cast<InterfaceFile
*>(*Iter
)));
1129 return make_error
<StringError
>(Ctx
.ErrorMessage
, YAMLIn
.error());
1131 return std::move(File
);
1134 Error
TextAPIWriter::writeToStream(raw_ostream
&OS
, const InterfaceFile
&File
) {
1136 Ctx
.Path
= std::string(File
.getPath());
1137 Ctx
.FileKind
= File
.getFileType();
1138 llvm::yaml::Output
YAMLOut(OS
, &Ctx
, /*WrapColumn=*/80);
1140 std::vector
<const InterfaceFile
*> Files
;
1141 Files
.emplace_back(&File
);
1143 for (auto Document
: File
.documents())
1144 Files
.emplace_back(Document
.get());
1149 return Error::success();