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/MachO/Architecture.h"
23 #include "llvm/TextAPI/MachO/ArchitectureSet.h"
24 #include "llvm/TextAPI/MachO/InterfaceFile.h"
25 #include "llvm/TextAPI/MachO/PackedVersion.h"
26 #include "llvm/TextAPI/MachO/TextAPIReader.h"
27 #include "llvm/TextAPI/MachO/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";
413 static StringRef
input(StringRef Scalar
, void *, Target
&Value
) {
414 auto Result
= Target::create(Scalar
);
416 return toString(Result
.takeError());
419 if (Value
.Arch
== AK_unknown
)
420 return "unknown architecture";
421 if (Value
.Platform
== PlatformKind::unknown
)
422 return "unknown platform";
427 static QuotingType
mustQuote(StringRef
) { return QuotingType::None
; }
430 template <> struct MappingTraits
<const InterfaceFile
*> {
431 struct NormalizedTBD
{
432 explicit NormalizedTBD(IO
&IO
) {}
433 NormalizedTBD(IO
&IO
, const InterfaceFile
*&File
) {
434 Architectures
= File
->getArchitectures();
435 UUIDs
= File
->uuids();
436 Platforms
= File
->getPlatforms();
437 InstallName
= File
->getInstallName();
438 CurrentVersion
= PackedVersion(File
->getCurrentVersion());
439 CompatibilityVersion
= PackedVersion(File
->getCompatibilityVersion());
440 SwiftABIVersion
= File
->getSwiftABIVersion();
441 ObjCConstraint
= File
->getObjCConstraint();
443 Flags
= TBDFlags::None
;
444 if (!File
->isApplicationExtensionSafe())
445 Flags
|= TBDFlags::NotApplicationExtensionSafe
;
447 if (!File
->isTwoLevelNamespace())
448 Flags
|= TBDFlags::FlatNamespace
;
450 if (File
->isInstallAPI())
451 Flags
|= TBDFlags::InstallAPI
;
453 for (const auto &Iter
: File
->umbrellas()) {
454 ParentUmbrella
= Iter
.second
;
458 std::set
<ArchitectureSet
> ArchSet
;
459 for (const auto &Library
: File
->allowableClients())
460 ArchSet
.insert(Library
.getArchitectures());
462 for (const auto &Library
: File
->reexportedLibraries())
463 ArchSet
.insert(Library
.getArchitectures());
465 std::map
<const Symbol
*, ArchitectureSet
> SymbolToArchSet
;
466 for (const auto *Symbol
: File
->exports()) {
467 auto Architectures
= Symbol
->getArchitectures();
468 SymbolToArchSet
[Symbol
] = Architectures
;
469 ArchSet
.insert(Architectures
);
472 for (auto Architectures
: ArchSet
) {
473 ExportSection Section
;
474 Section
.Architectures
= Architectures
;
476 for (const auto &Library
: File
->allowableClients())
477 if (Library
.getArchitectures() == Architectures
)
478 Section
.AllowableClients
.emplace_back(Library
.getInstallName());
480 for (const auto &Library
: File
->reexportedLibraries())
481 if (Library
.getArchitectures() == Architectures
)
482 Section
.ReexportedLibraries
.emplace_back(Library
.getInstallName());
484 for (const auto &SymArch
: SymbolToArchSet
) {
485 if (SymArch
.second
!= Architectures
)
488 const auto *Symbol
= SymArch
.first
;
489 switch (Symbol
->getKind()) {
490 case SymbolKind::GlobalSymbol
:
491 if (Symbol
->isWeakDefined())
492 Section
.WeakDefSymbols
.emplace_back(Symbol
->getName());
493 else if (Symbol
->isThreadLocalValue())
494 Section
.TLVSymbols
.emplace_back(Symbol
->getName());
496 Section
.Symbols
.emplace_back(Symbol
->getName());
498 case SymbolKind::ObjectiveCClass
:
499 if (File
->getFileType() != FileType::TBD_V3
)
500 Section
.Classes
.emplace_back(
501 copyString("_" + Symbol
->getName().str()));
503 Section
.Classes
.emplace_back(Symbol
->getName());
505 case SymbolKind::ObjectiveCClassEHType
:
506 if (File
->getFileType() != FileType::TBD_V3
)
507 Section
.Symbols
.emplace_back(
508 copyString("_OBJC_EHTYPE_$_" + Symbol
->getName().str()));
510 Section
.ClassEHs
.emplace_back(Symbol
->getName());
512 case SymbolKind::ObjectiveCInstanceVariable
:
513 if (File
->getFileType() != FileType::TBD_V3
)
514 Section
.IVars
.emplace_back(
515 copyString("_" + Symbol
->getName().str()));
517 Section
.IVars
.emplace_back(Symbol
->getName());
521 llvm::sort(Section
.Symbols
.begin(), Section
.Symbols
.end());
522 llvm::sort(Section
.Classes
.begin(), Section
.Classes
.end());
523 llvm::sort(Section
.ClassEHs
.begin(), Section
.ClassEHs
.end());
524 llvm::sort(Section
.IVars
.begin(), Section
.IVars
.end());
525 llvm::sort(Section
.WeakDefSymbols
.begin(),
526 Section
.WeakDefSymbols
.end());
527 llvm::sort(Section
.TLVSymbols
.begin(), Section
.TLVSymbols
.end());
528 Exports
.emplace_back(std::move(Section
));
532 SymbolToArchSet
.clear();
534 for (const auto *Symbol
: File
->undefineds()) {
535 auto Architectures
= Symbol
->getArchitectures();
536 SymbolToArchSet
[Symbol
] = Architectures
;
537 ArchSet
.insert(Architectures
);
540 for (auto Architectures
: ArchSet
) {
541 UndefinedSection Section
;
542 Section
.Architectures
= Architectures
;
544 for (const auto &SymArch
: SymbolToArchSet
) {
545 if (SymArch
.second
!= Architectures
)
548 const auto *Symbol
= SymArch
.first
;
549 switch (Symbol
->getKind()) {
550 case SymbolKind::GlobalSymbol
:
551 if (Symbol
->isWeakReferenced())
552 Section
.WeakRefSymbols
.emplace_back(Symbol
->getName());
554 Section
.Symbols
.emplace_back(Symbol
->getName());
556 case SymbolKind::ObjectiveCClass
:
557 if (File
->getFileType() != FileType::TBD_V3
)
558 Section
.Classes
.emplace_back(
559 copyString("_" + Symbol
->getName().str()));
561 Section
.Classes
.emplace_back(Symbol
->getName());
563 case SymbolKind::ObjectiveCClassEHType
:
564 if (File
->getFileType() != FileType::TBD_V3
)
565 Section
.Symbols
.emplace_back(
566 copyString("_OBJC_EHTYPE_$_" + Symbol
->getName().str()));
568 Section
.ClassEHs
.emplace_back(Symbol
->getName());
570 case SymbolKind::ObjectiveCInstanceVariable
:
571 if (File
->getFileType() != FileType::TBD_V3
)
572 Section
.IVars
.emplace_back(
573 copyString("_" + Symbol
->getName().str()));
575 Section
.IVars
.emplace_back(Symbol
->getName());
579 llvm::sort(Section
.Symbols
.begin(), Section
.Symbols
.end());
580 llvm::sort(Section
.Classes
.begin(), Section
.Classes
.end());
581 llvm::sort(Section
.ClassEHs
.begin(), Section
.ClassEHs
.end());
582 llvm::sort(Section
.IVars
.begin(), Section
.IVars
.end());
583 llvm::sort(Section
.WeakRefSymbols
.begin(),
584 Section
.WeakRefSymbols
.end());
585 Undefineds
.emplace_back(std::move(Section
));
589 // TBD v1 - TBD v3 files only support one platform and several
590 // architectures. It is possible to have more than one platform for TBD v3
591 // files, but the architectures don't apply to all
592 // platforms, specifically to filter out the i386 slice from
593 // platform macCatalyst.
594 TargetList
synthesizeTargets(ArchitectureSet Architectures
,
595 const PlatformSet
&Platforms
) {
598 for (auto Platform
: Platforms
) {
599 Platform
= mapToPlatformKind(Platform
, Architectures
.hasX86());
601 for (const auto &&Architecture
: Architectures
) {
602 if ((Architecture
== AK_i386
) &&
603 (Platform
== PlatformKind::macCatalyst
))
606 Targets
.emplace_back(Architecture
, Platform
);
612 const InterfaceFile
*denormalize(IO
&IO
) {
613 auto Ctx
= reinterpret_cast<TextAPIContext
*>(IO
.getContext());
616 auto *File
= new InterfaceFile
;
617 File
->setPath(Ctx
->Path
);
618 File
->setFileType(Ctx
->FileKind
);
619 File
->addTargets(synthesizeTargets(Architectures
, Platforms
));
620 for (auto &ID
: UUIDs
)
621 File
->addUUID(ID
.first
, ID
.second
);
622 File
->setInstallName(InstallName
);
623 File
->setCurrentVersion(CurrentVersion
);
624 File
->setCompatibilityVersion(CompatibilityVersion
);
625 File
->setSwiftABIVersion(SwiftABIVersion
);
626 File
->setObjCConstraint(ObjCConstraint
);
627 for (const auto &Target
: File
->targets())
628 File
->addParentUmbrella(Target
, ParentUmbrella
);
630 if (Ctx
->FileKind
== FileType::TBD_V1
) {
631 File
->setTwoLevelNamespace();
632 File
->setApplicationExtensionSafe();
634 File
->setTwoLevelNamespace(!(Flags
& TBDFlags::FlatNamespace
));
635 File
->setApplicationExtensionSafe(
636 !(Flags
& TBDFlags::NotApplicationExtensionSafe
));
637 File
->setInstallAPI(Flags
& TBDFlags::InstallAPI
);
640 for (const auto &Section
: Exports
) {
642 synthesizeTargets(Section
.Architectures
, Platforms
);
644 for (const auto &Lib
: Section
.AllowableClients
)
645 for (const auto &Target
: Targets
)
646 File
->addAllowableClient(Lib
, Target
);
648 for (const auto &Lib
: Section
.ReexportedLibraries
)
649 for (const auto &Target
: Targets
)
650 File
->addReexportedLibrary(Lib
, Target
);
652 for (const auto &Symbol
: Section
.Symbols
) {
653 if (Ctx
->FileKind
!= FileType::TBD_V3
&&
654 Symbol
.value
.startswith("_OBJC_EHTYPE_$_"))
655 File
->addSymbol(SymbolKind::ObjectiveCClassEHType
,
656 Symbol
.value
.drop_front(15), Targets
);
658 File
->addSymbol(SymbolKind::GlobalSymbol
, Symbol
, Targets
);
660 for (auto &Symbol
: Section
.Classes
) {
661 auto Name
= Symbol
.value
;
662 if (Ctx
->FileKind
!= FileType::TBD_V3
)
663 Name
= Name
.drop_front();
664 File
->addSymbol(SymbolKind::ObjectiveCClass
, Name
, Targets
);
666 for (auto &Symbol
: Section
.ClassEHs
)
667 File
->addSymbol(SymbolKind::ObjectiveCClassEHType
, Symbol
, Targets
);
668 for (auto &Symbol
: Section
.IVars
) {
669 auto Name
= Symbol
.value
;
670 if (Ctx
->FileKind
!= FileType::TBD_V3
)
671 Name
= Name
.drop_front();
672 File
->addSymbol(SymbolKind::ObjectiveCInstanceVariable
, Name
,
675 for (auto &Symbol
: Section
.WeakDefSymbols
)
676 File
->addSymbol(SymbolKind::GlobalSymbol
, Symbol
, Targets
,
677 SymbolFlags::WeakDefined
);
678 for (auto &Symbol
: Section
.TLVSymbols
)
679 File
->addSymbol(SymbolKind::GlobalSymbol
, Symbol
, Targets
,
680 SymbolFlags::ThreadLocalValue
);
683 for (const auto &Section
: Undefineds
) {
685 synthesizeTargets(Section
.Architectures
, Platforms
);
686 for (auto &Symbol
: Section
.Symbols
) {
687 if (Ctx
->FileKind
!= FileType::TBD_V3
&&
688 Symbol
.value
.startswith("_OBJC_EHTYPE_$_"))
689 File
->addSymbol(SymbolKind::ObjectiveCClassEHType
,
690 Symbol
.value
.drop_front(15), Targets
,
691 SymbolFlags::Undefined
);
693 File
->addSymbol(SymbolKind::GlobalSymbol
, Symbol
, Targets
,
694 SymbolFlags::Undefined
);
696 for (auto &Symbol
: Section
.Classes
) {
697 auto Name
= Symbol
.value
;
698 if (Ctx
->FileKind
!= FileType::TBD_V3
)
699 Name
= Name
.drop_front();
700 File
->addSymbol(SymbolKind::ObjectiveCClass
, Name
, Targets
,
701 SymbolFlags::Undefined
);
703 for (auto &Symbol
: Section
.ClassEHs
)
704 File
->addSymbol(SymbolKind::ObjectiveCClassEHType
, Symbol
, Targets
,
705 SymbolFlags::Undefined
);
706 for (auto &Symbol
: Section
.IVars
) {
707 auto Name
= Symbol
.value
;
708 if (Ctx
->FileKind
!= FileType::TBD_V3
)
709 Name
= Name
.drop_front();
710 File
->addSymbol(SymbolKind::ObjectiveCInstanceVariable
, Name
, Targets
,
711 SymbolFlags::Undefined
);
713 for (auto &Symbol
: Section
.WeakRefSymbols
)
714 File
->addSymbol(SymbolKind::GlobalSymbol
, Symbol
, Targets
,
715 SymbolFlags::Undefined
| SymbolFlags::WeakReferenced
);
721 llvm::BumpPtrAllocator Allocator
;
722 StringRef
copyString(StringRef String
) {
726 void *Ptr
= Allocator
.Allocate(String
.size(), 1);
727 memcpy(Ptr
, String
.data(), String
.size());
728 return StringRef(reinterpret_cast<const char *>(Ptr
), String
.size());
731 std::vector
<Architecture
> Architectures
;
732 std::vector
<UUID
> UUIDs
;
733 PlatformSet Platforms
;
734 StringRef InstallName
;
735 PackedVersion CurrentVersion
;
736 PackedVersion CompatibilityVersion
;
737 SwiftVersion SwiftABIVersion
{0};
738 ObjCConstraintType ObjCConstraint
{ObjCConstraintType::None
};
739 TBDFlags Flags
{TBDFlags::None
};
740 StringRef ParentUmbrella
;
741 std::vector
<ExportSection
> Exports
;
742 std::vector
<UndefinedSection
> Undefineds
;
745 static void setFileTypeForInput(TextAPIContext
*Ctx
, IO
&IO
) {
746 if (IO
.mapTag("!tapi-tbd", false))
747 Ctx
->FileKind
= FileType::TBD_V4
;
748 else if (IO
.mapTag("!tapi-tbd-v3", false))
749 Ctx
->FileKind
= FileType::TBD_V3
;
750 else if (IO
.mapTag("!tapi-tbd-v2", false))
751 Ctx
->FileKind
= FileType::TBD_V2
;
752 else if (IO
.mapTag("!tapi-tbd-v1", false) ||
753 IO
.mapTag("tag:yaml.org,2002:map", false))
754 Ctx
->FileKind
= FileType::TBD_V1
;
756 Ctx
->FileKind
= FileType::Invalid
;
761 static void mapping(IO
&IO
, const InterfaceFile
*&File
) {
762 auto *Ctx
= reinterpret_cast<TextAPIContext
*>(IO
.getContext());
763 assert((!Ctx
|| !IO
.outputting() ||
764 (Ctx
&& Ctx
->FileKind
!= FileType::Invalid
)) &&
765 "File type is not set in YAML context");
767 if (!IO
.outputting()) {
768 setFileTypeForInput(Ctx
, IO
);
769 switch (Ctx
->FileKind
) {
772 case FileType::TBD_V4
:
773 mapKeysToValuesV4(IO
, File
);
775 case FileType::Invalid
:
776 IO
.setError("unsupported file type");
780 // Set file type when writing.
781 switch (Ctx
->FileKind
) {
783 llvm_unreachable("unexpected file type");
784 case FileType::TBD_V4
:
785 mapKeysToValuesV4(IO
, File
);
787 case FileType::TBD_V3
:
788 IO
.mapTag("!tapi-tbd-v3", true);
790 case FileType::TBD_V2
:
791 IO
.mapTag("!tapi-tbd-v2", true);
793 case FileType::TBD_V1
:
794 // Don't write the tag into the .tbd file for TBD v1
798 mapKeysToValues(Ctx
->FileKind
, IO
, File
);
801 using SectionList
= std::vector
<SymbolSection
>;
802 struct NormalizedTBD_V4
{
803 explicit NormalizedTBD_V4(IO
&IO
) {}
804 NormalizedTBD_V4(IO
&IO
, const InterfaceFile
*&File
) {
805 auto Ctx
= reinterpret_cast<TextAPIContext
*>(IO
.getContext());
807 TBDVersion
= Ctx
->FileKind
>> 1;
808 Targets
.insert(Targets
.begin(), File
->targets().begin(),
809 File
->targets().end());
810 for (const auto &IT
: File
->uuids())
811 UUIDs
.emplace_back(IT
.first
, IT
.second
);
812 InstallName
= File
->getInstallName();
813 CurrentVersion
= File
->getCurrentVersion();
814 CompatibilityVersion
= File
->getCompatibilityVersion();
815 SwiftABIVersion
= File
->getSwiftABIVersion();
817 Flags
= TBDFlags::None
;
818 if (!File
->isApplicationExtensionSafe())
819 Flags
|= TBDFlags::NotApplicationExtensionSafe
;
821 if (!File
->isTwoLevelNamespace())
822 Flags
|= TBDFlags::FlatNamespace
;
824 if (File
->isInstallAPI())
825 Flags
|= TBDFlags::InstallAPI
;
828 std::map
<std::string
, TargetList
> valueToTargetList
;
829 for (const auto &it
: File
->umbrellas())
830 valueToTargetList
[it
.second
].emplace_back(it
.first
);
832 for (const auto &it
: valueToTargetList
) {
833 UmbrellaSection CurrentSection
;
834 CurrentSection
.Targets
.insert(CurrentSection
.Targets
.begin(),
835 it
.second
.begin(), it
.second
.end());
836 CurrentSection
.Umbrella
= it
.first
;
837 ParentUmbrellas
.emplace_back(std::move(CurrentSection
));
841 assignTargetsToLibrary(File
->allowableClients(), AllowableClients
);
842 assignTargetsToLibrary(File
->reexportedLibraries(), ReexportedLibraries
);
845 [](SectionList
&CurrentSections
,
846 InterfaceFile::const_filtered_symbol_range Symbols
,
847 std::function
<bool(const Symbol
*)> Pred
) {
848 std::set
<TargetList
> TargetSet
;
849 std::map
<const Symbol
*, TargetList
> SymbolToTargetList
;
850 for (const auto *Symbol
: Symbols
) {
853 TargetList
Targets(Symbol
->targets());
854 SymbolToTargetList
[Symbol
] = Targets
;
855 TargetSet
.emplace(std::move(Targets
));
857 for (const auto &TargetIDs
: TargetSet
) {
858 SymbolSection CurrentSection
;
859 CurrentSection
.Targets
.insert(CurrentSection
.Targets
.begin(),
860 TargetIDs
.begin(), TargetIDs
.end());
862 for (const auto &IT
: SymbolToTargetList
) {
863 if (IT
.second
!= TargetIDs
)
866 const auto *Symbol
= IT
.first
;
867 switch (Symbol
->getKind()) {
868 case SymbolKind::GlobalSymbol
:
869 if (Symbol
->isWeakDefined())
870 CurrentSection
.WeakSymbols
.emplace_back(Symbol
->getName());
871 else if (Symbol
->isThreadLocalValue())
872 CurrentSection
.TlvSymbols
.emplace_back(Symbol
->getName());
874 CurrentSection
.Symbols
.emplace_back(Symbol
->getName());
876 case SymbolKind::ObjectiveCClass
:
877 CurrentSection
.Classes
.emplace_back(Symbol
->getName());
879 case SymbolKind::ObjectiveCClassEHType
:
880 CurrentSection
.ClassEHs
.emplace_back(Symbol
->getName());
882 case SymbolKind::ObjectiveCInstanceVariable
:
883 CurrentSection
.Ivars
.emplace_back(Symbol
->getName());
887 sort(CurrentSection
.Symbols
);
888 sort(CurrentSection
.Classes
);
889 sort(CurrentSection
.ClassEHs
);
890 sort(CurrentSection
.Ivars
);
891 sort(CurrentSection
.WeakSymbols
);
892 sort(CurrentSection
.TlvSymbols
);
893 CurrentSections
.emplace_back(std::move(CurrentSection
));
897 handleSymbols(Exports
, File
->exports(), [](const Symbol
*Symbol
) {
898 return !Symbol
->isReexported();
900 handleSymbols(Reexports
, File
->exports(), [](const Symbol
*Symbol
) {
901 return Symbol
->isReexported();
903 handleSymbols(Undefineds
, File
->undefineds(),
904 [](const Symbol
*Symbol
) { return true; });
907 const InterfaceFile
*denormalize(IO
&IO
) {
908 auto Ctx
= reinterpret_cast<TextAPIContext
*>(IO
.getContext());
911 auto *File
= new InterfaceFile
;
912 File
->setPath(Ctx
->Path
);
913 File
->setFileType(Ctx
->FileKind
);
914 for (auto &id
: UUIDs
)
915 File
->addUUID(id
.TargetID
, id
.Value
);
916 File
->addTargets(Targets
);
917 File
->setInstallName(InstallName
);
918 File
->setCurrentVersion(CurrentVersion
);
919 File
->setCompatibilityVersion(CompatibilityVersion
);
920 File
->setSwiftABIVersion(SwiftABIVersion
);
921 for (const auto &CurrentSection
: ParentUmbrellas
)
922 for (const auto &target
: CurrentSection
.Targets
)
923 File
->addParentUmbrella(target
, CurrentSection
.Umbrella
);
924 File
->setTwoLevelNamespace(!(Flags
& TBDFlags::FlatNamespace
));
925 File
->setApplicationExtensionSafe(
926 !(Flags
& TBDFlags::NotApplicationExtensionSafe
));
927 File
->setInstallAPI(Flags
& TBDFlags::InstallAPI
);
929 for (const auto &CurrentSection
: AllowableClients
) {
930 for (const auto &lib
: CurrentSection
.Values
)
931 for (const auto &Target
: CurrentSection
.Targets
)
932 File
->addAllowableClient(lib
, Target
);
935 for (const auto &CurrentSection
: ReexportedLibraries
) {
936 for (const auto &Lib
: CurrentSection
.Values
)
937 for (const auto &Target
: CurrentSection
.Targets
)
938 File
->addReexportedLibrary(Lib
, Target
);
941 auto handleSymbols
= [File
](const SectionList
&CurrentSections
,
942 SymbolFlags Flag
= SymbolFlags::None
) {
943 for (const auto &CurrentSection
: CurrentSections
) {
944 for (auto &sym
: CurrentSection
.Symbols
)
945 File
->addSymbol(SymbolKind::GlobalSymbol
, sym
,
946 CurrentSection
.Targets
, Flag
);
948 for (auto &sym
: CurrentSection
.Classes
)
949 File
->addSymbol(SymbolKind::ObjectiveCClass
, sym
,
950 CurrentSection
.Targets
);
952 for (auto &sym
: CurrentSection
.ClassEHs
)
953 File
->addSymbol(SymbolKind::ObjectiveCClassEHType
, sym
,
954 CurrentSection
.Targets
);
956 for (auto &sym
: CurrentSection
.Ivars
)
957 File
->addSymbol(SymbolKind::ObjectiveCInstanceVariable
, sym
,
958 CurrentSection
.Targets
);
960 for (auto &sym
: CurrentSection
.WeakSymbols
)
961 File
->addSymbol(SymbolKind::GlobalSymbol
, sym
,
962 CurrentSection
.Targets
);
963 for (auto &sym
: CurrentSection
.TlvSymbols
)
964 File
->addSymbol(SymbolKind::GlobalSymbol
, sym
,
965 CurrentSection
.Targets
,
966 SymbolFlags::ThreadLocalValue
);
970 handleSymbols(Exports
);
971 handleSymbols(Reexports
, SymbolFlags::Rexported
);
972 handleSymbols(Undefineds
, SymbolFlags::Undefined
);
978 std::vector
<UUIDv4
> UUIDs
;
980 StringRef InstallName
;
981 PackedVersion CurrentVersion
;
982 PackedVersion CompatibilityVersion
;
983 SwiftVersion SwiftABIVersion
{0};
984 std::vector
<MetadataSection
> AllowableClients
;
985 std::vector
<MetadataSection
> ReexportedLibraries
;
986 TBDFlags Flags
{TBDFlags::None
};
987 std::vector
<UmbrellaSection
> ParentUmbrellas
;
989 SectionList Reexports
;
990 SectionList Undefineds
;
993 void assignTargetsToLibrary(const std::vector
<InterfaceFileRef
> &Libraries
,
994 std::vector
<MetadataSection
> &Section
) {
995 std::set
<TargetList
> targetSet
;
996 std::map
<const InterfaceFileRef
*, TargetList
> valueToTargetList
;
997 for (const auto &library
: Libraries
) {
998 TargetList
targets(library
.targets());
999 valueToTargetList
[&library
] = targets
;
1000 targetSet
.emplace(std::move(targets
));
1003 for (const auto &targets
: targetSet
) {
1004 MetadataSection CurrentSection
;
1005 CurrentSection
.Targets
.insert(CurrentSection
.Targets
.begin(),
1006 targets
.begin(), targets
.end());
1008 for (const auto &it
: valueToTargetList
) {
1009 if (it
.second
!= targets
)
1012 CurrentSection
.Values
.emplace_back(it
.first
->getInstallName());
1014 llvm::sort(CurrentSection
.Values
);
1015 Section
.emplace_back(std::move(CurrentSection
));
1020 static void mapKeysToValues(FileType FileKind
, IO
&IO
,
1021 const InterfaceFile
*&File
) {
1022 MappingNormalization
<NormalizedTBD
, const InterfaceFile
*> Keys(IO
, File
);
1023 IO
.mapRequired("archs", Keys
->Architectures
);
1024 if (FileKind
!= FileType::TBD_V1
)
1025 IO
.mapOptional("uuids", Keys
->UUIDs
);
1026 IO
.mapRequired("platform", Keys
->Platforms
);
1027 if (FileKind
!= FileType::TBD_V1
)
1028 IO
.mapOptional("flags", Keys
->Flags
, TBDFlags::None
);
1029 IO
.mapRequired("install-name", Keys
->InstallName
);
1030 IO
.mapOptional("current-version", Keys
->CurrentVersion
,
1031 PackedVersion(1, 0, 0));
1032 IO
.mapOptional("compatibility-version", Keys
->CompatibilityVersion
,
1033 PackedVersion(1, 0, 0));
1034 if (FileKind
!= FileType::TBD_V3
)
1035 IO
.mapOptional("swift-version", Keys
->SwiftABIVersion
, SwiftVersion(0));
1037 IO
.mapOptional("swift-abi-version", Keys
->SwiftABIVersion
,
1039 IO
.mapOptional("objc-constraint", Keys
->ObjCConstraint
,
1040 (FileKind
== FileType::TBD_V1
)
1041 ? ObjCConstraintType::None
1042 : ObjCConstraintType::Retain_Release
);
1043 if (FileKind
!= FileType::TBD_V1
)
1044 IO
.mapOptional("parent-umbrella", Keys
->ParentUmbrella
, StringRef());
1045 IO
.mapOptional("exports", Keys
->Exports
);
1046 if (FileKind
!= FileType::TBD_V1
)
1047 IO
.mapOptional("undefineds", Keys
->Undefineds
);
1050 static void mapKeysToValuesV4(IO
&IO
, const InterfaceFile
*&File
) {
1051 MappingNormalization
<NormalizedTBD_V4
, const InterfaceFile
*> Keys(IO
,
1053 IO
.mapTag("!tapi-tbd", true);
1054 IO
.mapRequired("tbd-version", Keys
->TBDVersion
);
1055 IO
.mapRequired("targets", Keys
->Targets
);
1056 IO
.mapOptional("uuids", Keys
->UUIDs
);
1057 IO
.mapOptional("flags", Keys
->Flags
, TBDFlags::None
);
1058 IO
.mapRequired("install-name", Keys
->InstallName
);
1059 IO
.mapOptional("current-version", Keys
->CurrentVersion
,
1060 PackedVersion(1, 0, 0));
1061 IO
.mapOptional("compatibility-version", Keys
->CompatibilityVersion
,
1062 PackedVersion(1, 0, 0));
1063 IO
.mapOptional("swift-abi-version", Keys
->SwiftABIVersion
, SwiftVersion(0));
1064 IO
.mapOptional("parent-umbrella", Keys
->ParentUmbrellas
);
1065 auto OptionKind
= MetadataSection::Option::Clients
;
1066 IO
.mapOptionalWithContext("allowable-clients", Keys
->AllowableClients
,
1068 OptionKind
= MetadataSection::Option::Libraries
;
1069 IO
.mapOptionalWithContext("reexported-libraries", Keys
->ReexportedLibraries
,
1071 IO
.mapOptional("exports", Keys
->Exports
);
1072 IO
.mapOptional("reexports", Keys
->Reexports
);
1073 IO
.mapOptional("undefineds", Keys
->Undefineds
);
1078 struct DocumentListTraits
<std::vector
<const MachO::InterfaceFile
*>> {
1079 static size_t size(IO
&IO
, std::vector
<const MachO::InterfaceFile
*> &Seq
) {
1082 static const InterfaceFile
*&
1083 element(IO
&IO
, std::vector
<const InterfaceFile
*> &Seq
, size_t Index
) {
1084 if (Index
>= Seq
.size())
1085 Seq
.resize(Index
+ 1);
1090 } // end namespace yaml.
1093 static void DiagHandler(const SMDiagnostic
&Diag
, void *Context
) {
1094 auto *File
= static_cast<TextAPIContext
*>(Context
);
1095 SmallString
<1024> Message
;
1096 raw_svector_ostream
S(Message
);
1098 SMDiagnostic
NewDiag(*Diag
.getSourceMgr(), Diag
.getLoc(), File
->Path
,
1099 Diag
.getLineNo(), Diag
.getColumnNo(), Diag
.getKind(),
1100 Diag
.getMessage(), Diag
.getLineContents(),
1101 Diag
.getRanges(), Diag
.getFixIts());
1103 NewDiag
.print(nullptr, S
);
1104 File
->ErrorMessage
= ("malformed file\n" + Message
).str();
1107 Expected
<std::unique_ptr
<InterfaceFile
>>
1108 TextAPIReader::get(MemoryBufferRef InputBuffer
) {
1110 Ctx
.Path
= InputBuffer
.getBufferIdentifier();
1111 yaml::Input
YAMLIn(InputBuffer
.getBuffer(), &Ctx
, DiagHandler
, &Ctx
);
1113 // Fill vector with interface file objects created by parsing the YAML file.
1114 std::vector
<const InterfaceFile
*> Files
;
1117 // YAMLIn dynamically allocates for Interface file and in case of error,
1118 // memory leak will occur unless wrapped around unique_ptr
1119 auto File
= std::unique_ptr
<InterfaceFile
>(
1120 const_cast<InterfaceFile
*>(Files
.front()));
1123 return make_error
<StringError
>(Ctx
.ErrorMessage
, YAMLIn
.error());
1125 return std::move(File
);
1128 Error
TextAPIWriter::writeToStream(raw_ostream
&OS
, const InterfaceFile
&File
) {
1130 Ctx
.Path
= File
.getPath();
1131 Ctx
.FileKind
= File
.getFileType();
1132 llvm::yaml::Output
YAMLOut(OS
, &Ctx
, /*WrapColumn=*/80);
1134 std::vector
<const InterfaceFile
*> Files
;
1135 Files
.emplace_back(&File
);
1140 return Error::success();
1143 } // end namespace MachO.
1144 } // end namespace llvm.