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
) {}
261 } // end anonymous namespace.
263 LLVM_YAML_IS_FLOW_SEQUENCE_VECTOR(Architecture
)
264 LLVM_YAML_IS_SEQUENCE_VECTOR(ExportSection
)
265 LLVM_YAML_IS_SEQUENCE_VECTOR(UndefinedSection
)
267 LLVM_YAML_IS_SEQUENCE_VECTOR(SymbolSection
)
268 LLVM_YAML_IS_SEQUENCE_VECTOR(MetadataSection
)
269 LLVM_YAML_IS_SEQUENCE_VECTOR(UmbrellaSection
)
270 LLVM_YAML_IS_FLOW_SEQUENCE_VECTOR(Target
)
271 LLVM_YAML_IS_SEQUENCE_VECTOR(UUIDv4
)
276 template <> struct MappingTraits
<ExportSection
> {
277 static void mapping(IO
&IO
, ExportSection
&Section
) {
278 const auto *Ctx
= reinterpret_cast<TextAPIContext
*>(IO
.getContext());
279 assert((!Ctx
|| Ctx
->FileKind
!= FileType::Invalid
) &&
280 "File type is not set in YAML context");
282 IO
.mapRequired("archs", Section
.Architectures
);
283 if (Ctx
->FileKind
== FileType::TBD_V1
)
284 IO
.mapOptional("allowed-clients", Section
.AllowableClients
);
286 IO
.mapOptional("allowable-clients", Section
.AllowableClients
);
287 IO
.mapOptional("re-exports", Section
.ReexportedLibraries
);
288 IO
.mapOptional("symbols", Section
.Symbols
);
289 IO
.mapOptional("objc-classes", Section
.Classes
);
290 if (Ctx
->FileKind
== FileType::TBD_V3
)
291 IO
.mapOptional("objc-eh-types", Section
.ClassEHs
);
292 IO
.mapOptional("objc-ivars", Section
.IVars
);
293 IO
.mapOptional("weak-def-symbols", Section
.WeakDefSymbols
);
294 IO
.mapOptional("thread-local-symbols", Section
.TLVSymbols
);
298 template <> struct MappingTraits
<UndefinedSection
> {
299 static void mapping(IO
&IO
, UndefinedSection
&Section
) {
300 const auto *Ctx
= reinterpret_cast<TextAPIContext
*>(IO
.getContext());
301 assert((!Ctx
|| Ctx
->FileKind
!= FileType::Invalid
) &&
302 "File type is not set in YAML context");
304 IO
.mapRequired("archs", Section
.Architectures
);
305 IO
.mapOptional("symbols", Section
.Symbols
);
306 IO
.mapOptional("objc-classes", Section
.Classes
);
307 if (Ctx
->FileKind
== FileType::TBD_V3
)
308 IO
.mapOptional("objc-eh-types", Section
.ClassEHs
);
309 IO
.mapOptional("objc-ivars", Section
.IVars
);
310 IO
.mapOptional("weak-ref-symbols", Section
.WeakRefSymbols
);
314 template <> struct MappingTraits
<SymbolSection
> {
315 static void mapping(IO
&IO
, SymbolSection
&Section
) {
316 IO
.mapRequired("targets", Section
.Targets
);
317 IO
.mapOptional("symbols", Section
.Symbols
);
318 IO
.mapOptional("objc-classes", Section
.Classes
);
319 IO
.mapOptional("objc-eh-types", Section
.ClassEHs
);
320 IO
.mapOptional("objc-ivars", Section
.Ivars
);
321 IO
.mapOptional("weak-symbols", Section
.WeakSymbols
);
322 IO
.mapOptional("thread-local-symbols", Section
.TlvSymbols
);
326 template <> struct MappingTraits
<UmbrellaSection
> {
327 static void mapping(IO
&IO
, UmbrellaSection
&Section
) {
328 IO
.mapRequired("targets", Section
.Targets
);
329 IO
.mapRequired("umbrella", Section
.Umbrella
);
333 template <> struct MappingTraits
<UUIDv4
> {
334 static void mapping(IO
&IO
, UUIDv4
&UUID
) {
335 IO
.mapRequired("target", UUID
.TargetID
);
336 IO
.mapRequired("value", UUID
.Value
);
341 struct MappingContextTraits
<MetadataSection
, MetadataSection::Option
> {
342 static void mapping(IO
&IO
, MetadataSection
&Section
,
343 MetadataSection::Option
&OptionKind
) {
344 IO
.mapRequired("targets", Section
.Targets
);
345 switch (OptionKind
) {
346 case MetadataSection::Option::Clients
:
347 IO
.mapRequired("clients", Section
.Values
);
349 case MetadataSection::Option::Libraries
:
350 IO
.mapRequired("libraries", Section
.Values
);
353 llvm_unreachable("unexpected option for metadata");
357 template <> struct ScalarBitSetTraits
<TBDFlags
> {
358 static void bitset(IO
&IO
, TBDFlags
&Flags
) {
359 IO
.bitSetCase(Flags
, "flat_namespace", TBDFlags::FlatNamespace
);
360 IO
.bitSetCase(Flags
, "not_app_extension_safe",
361 TBDFlags::NotApplicationExtensionSafe
);
362 IO
.bitSetCase(Flags
, "installapi", TBDFlags::InstallAPI
);
363 IO
.bitSetCase(Flags
, "not_for_dyld_shared_cache",
364 TBDFlags::OSLibNotForSharedCache
);
368 template <> struct ScalarTraits
<Target
> {
369 static void output(const Target
&Value
, void *, raw_ostream
&OS
) {
370 OS
<< Value
.Arch
<< "-";
371 switch (Value
.Platform
) {
372 #define PLATFORM(platform, id, name, build_name, target, tapi_target, \
374 case PLATFORM_##platform: \
375 OS << #tapi_target; \
377 #include "llvm/BinaryFormat/MachO.def"
381 static StringRef
input(StringRef Scalar
, void *, Target
&Value
) {
382 auto Result
= Target::create(Scalar
);
384 consumeError(Result
.takeError());
385 return "unparsable target";
389 if (Value
.Arch
== AK_unknown
)
390 return "unknown architecture";
391 if (Value
.Platform
== PLATFORM_UNKNOWN
)
392 return "unknown platform";
397 static QuotingType
mustQuote(StringRef
) { return QuotingType::None
; }
400 template <> struct MappingTraits
<const InterfaceFile
*> {
401 struct NormalizedTBD
{
402 explicit NormalizedTBD(IO
&IO
) {}
403 NormalizedTBD(IO
&IO
, const InterfaceFile
*&File
) {
404 Architectures
= File
->getArchitectures();
405 Platforms
= File
->getPlatforms();
406 InstallName
= File
->getInstallName();
407 CurrentVersion
= PackedVersion(File
->getCurrentVersion());
408 CompatibilityVersion
= PackedVersion(File
->getCompatibilityVersion());
409 SwiftABIVersion
= File
->getSwiftABIVersion();
410 ObjCConstraint
= File
->getObjCConstraint();
412 Flags
= TBDFlags::None
;
413 if (!File
->isApplicationExtensionSafe())
414 Flags
|= TBDFlags::NotApplicationExtensionSafe
;
416 if (!File
->isTwoLevelNamespace())
417 Flags
|= TBDFlags::FlatNamespace
;
419 if (!File
->umbrellas().empty())
420 ParentUmbrella
= File
->umbrellas().begin()->second
;
422 std::set
<ArchitectureSet
> ArchSet
;
423 for (const auto &Library
: File
->allowableClients())
424 ArchSet
.insert(Library
.getArchitectures());
426 for (const auto &Library
: File
->reexportedLibraries())
427 ArchSet
.insert(Library
.getArchitectures());
429 std::map
<const Symbol
*, ArchitectureSet
> SymbolToArchSet
;
430 for (const auto *Symbol
: File
->symbols()) {
431 auto Architectures
= Symbol
->getArchitectures();
432 SymbolToArchSet
[Symbol
] = Architectures
;
433 ArchSet
.insert(Architectures
);
436 for (auto Architectures
: ArchSet
) {
437 ExportSection Section
;
438 Section
.Architectures
= Architectures
;
440 for (const auto &Library
: File
->allowableClients())
441 if (Library
.getArchitectures() == Architectures
)
442 Section
.AllowableClients
.emplace_back(Library
.getInstallName());
444 for (const auto &Library
: File
->reexportedLibraries())
445 if (Library
.getArchitectures() == Architectures
)
446 Section
.ReexportedLibraries
.emplace_back(Library
.getInstallName());
448 for (const auto &SymArch
: SymbolToArchSet
) {
449 if (SymArch
.second
!= Architectures
)
452 const auto *Symbol
= SymArch
.first
;
453 switch (Symbol
->getKind()) {
454 case EncodeKind::GlobalSymbol
:
455 if (Symbol
->isWeakDefined())
456 Section
.WeakDefSymbols
.emplace_back(Symbol
->getName());
457 else if (Symbol
->isThreadLocalValue())
458 Section
.TLVSymbols
.emplace_back(Symbol
->getName());
460 Section
.Symbols
.emplace_back(Symbol
->getName());
462 case EncodeKind::ObjectiveCClass
:
463 if (File
->getFileType() != FileType::TBD_V3
)
464 Section
.Classes
.emplace_back(
465 copyString("_" + Symbol
->getName().str()));
467 Section
.Classes
.emplace_back(Symbol
->getName());
469 case EncodeKind::ObjectiveCClassEHType
:
470 if (File
->getFileType() != FileType::TBD_V3
)
471 Section
.Symbols
.emplace_back(
472 copyString("_OBJC_EHTYPE_$_" + Symbol
->getName().str()));
474 Section
.ClassEHs
.emplace_back(Symbol
->getName());
476 case EncodeKind::ObjectiveCInstanceVariable
:
477 if (File
->getFileType() != FileType::TBD_V3
)
478 Section
.IVars
.emplace_back(
479 copyString("_" + Symbol
->getName().str()));
481 Section
.IVars
.emplace_back(Symbol
->getName());
485 llvm::sort(Section
.Symbols
);
486 llvm::sort(Section
.Classes
);
487 llvm::sort(Section
.ClassEHs
);
488 llvm::sort(Section
.IVars
);
489 llvm::sort(Section
.WeakDefSymbols
);
490 llvm::sort(Section
.TLVSymbols
);
491 Exports
.emplace_back(std::move(Section
));
495 SymbolToArchSet
.clear();
497 for (const auto *Symbol
: File
->undefineds()) {
498 auto Architectures
= Symbol
->getArchitectures();
499 SymbolToArchSet
[Symbol
] = Architectures
;
500 ArchSet
.insert(Architectures
);
503 for (auto Architectures
: ArchSet
) {
504 UndefinedSection Section
;
505 Section
.Architectures
= Architectures
;
507 for (const auto &SymArch
: SymbolToArchSet
) {
508 if (SymArch
.second
!= Architectures
)
511 const auto *Symbol
= SymArch
.first
;
512 switch (Symbol
->getKind()) {
513 case EncodeKind::GlobalSymbol
:
514 if (Symbol
->isWeakReferenced())
515 Section
.WeakRefSymbols
.emplace_back(Symbol
->getName());
517 Section
.Symbols
.emplace_back(Symbol
->getName());
519 case EncodeKind::ObjectiveCClass
:
520 if (File
->getFileType() != FileType::TBD_V3
)
521 Section
.Classes
.emplace_back(
522 copyString("_" + Symbol
->getName().str()));
524 Section
.Classes
.emplace_back(Symbol
->getName());
526 case EncodeKind::ObjectiveCClassEHType
:
527 if (File
->getFileType() != FileType::TBD_V3
)
528 Section
.Symbols
.emplace_back(
529 copyString("_OBJC_EHTYPE_$_" + Symbol
->getName().str()));
531 Section
.ClassEHs
.emplace_back(Symbol
->getName());
533 case EncodeKind::ObjectiveCInstanceVariable
:
534 if (File
->getFileType() != FileType::TBD_V3
)
535 Section
.IVars
.emplace_back(
536 copyString("_" + Symbol
->getName().str()));
538 Section
.IVars
.emplace_back(Symbol
->getName());
542 llvm::sort(Section
.Symbols
);
543 llvm::sort(Section
.Classes
);
544 llvm::sort(Section
.ClassEHs
);
545 llvm::sort(Section
.IVars
);
546 llvm::sort(Section
.WeakRefSymbols
);
547 Undefineds
.emplace_back(std::move(Section
));
551 // TBD v1 - TBD v3 files only support one platform and several
552 // architectures. It is possible to have more than one platform for TBD v3
553 // files, but the architectures don't apply to all
554 // platforms, specifically to filter out the i386 slice from
555 // platform macCatalyst.
556 TargetList
synthesizeTargets(ArchitectureSet Architectures
,
557 const PlatformSet
&Platforms
) {
560 for (auto Platform
: Platforms
) {
561 Platform
= mapToPlatformType(Platform
, Architectures
.hasX86());
563 for (const auto &&Architecture
: Architectures
) {
564 if ((Architecture
== AK_i386
) && (Platform
== PLATFORM_MACCATALYST
))
567 Targets
.emplace_back(Architecture
, Platform
);
573 const InterfaceFile
*denormalize(IO
&IO
) {
574 auto Ctx
= reinterpret_cast<TextAPIContext
*>(IO
.getContext());
577 auto *File
= new InterfaceFile
;
578 File
->setPath(Ctx
->Path
);
579 File
->setFileType(Ctx
->FileKind
);
580 File
->addTargets(synthesizeTargets(Architectures
, Platforms
));
581 File
->setInstallName(InstallName
);
582 File
->setCurrentVersion(CurrentVersion
);
583 File
->setCompatibilityVersion(CompatibilityVersion
);
584 File
->setSwiftABIVersion(SwiftABIVersion
);
585 File
->setObjCConstraint(ObjCConstraint
);
586 for (const auto &Target
: File
->targets())
587 File
->addParentUmbrella(Target
, ParentUmbrella
);
589 if (Ctx
->FileKind
== FileType::TBD_V1
) {
590 File
->setTwoLevelNamespace();
591 File
->setApplicationExtensionSafe();
593 File
->setTwoLevelNamespace(!(Flags
& TBDFlags::FlatNamespace
));
594 File
->setApplicationExtensionSafe(
595 !(Flags
& TBDFlags::NotApplicationExtensionSafe
));
598 // For older file formats, the segment where the symbol
599 // comes from is unknown, treat all symbols as Data
601 const auto Flags
= SymbolFlags::Data
;
603 for (const auto &Section
: Exports
) {
605 synthesizeTargets(Section
.Architectures
, Platforms
);
607 for (const auto &Lib
: Section
.AllowableClients
)
608 for (const auto &Target
: Targets
)
609 File
->addAllowableClient(Lib
, Target
);
611 for (const auto &Lib
: Section
.ReexportedLibraries
)
612 for (const auto &Target
: Targets
)
613 File
->addReexportedLibrary(Lib
, Target
);
615 for (const auto &Symbol
: Section
.Symbols
) {
616 if (Ctx
->FileKind
!= FileType::TBD_V3
&&
617 Symbol
.value
.starts_with(ObjC2EHTypePrefix
))
618 File
->addSymbol(EncodeKind::ObjectiveCClassEHType
,
619 Symbol
.value
.drop_front(15), Targets
, Flags
);
621 File
->addSymbol(EncodeKind::GlobalSymbol
, Symbol
, Targets
, Flags
);
623 for (auto &Symbol
: Section
.Classes
) {
624 auto Name
= Symbol
.value
;
625 if (Ctx
->FileKind
!= FileType::TBD_V3
)
626 Name
= Name
.drop_front();
627 File
->addSymbol(EncodeKind::ObjectiveCClass
, Name
, Targets
, Flags
);
629 for (auto &Symbol
: Section
.ClassEHs
)
630 File
->addSymbol(EncodeKind::ObjectiveCClassEHType
, Symbol
, Targets
,
632 for (auto &Symbol
: Section
.IVars
) {
633 auto Name
= Symbol
.value
;
634 if (Ctx
->FileKind
!= FileType::TBD_V3
)
635 Name
= Name
.drop_front();
636 File
->addSymbol(EncodeKind::ObjectiveCInstanceVariable
, Name
, Targets
,
639 for (auto &Symbol
: Section
.WeakDefSymbols
)
640 File
->addSymbol(EncodeKind::GlobalSymbol
, Symbol
, Targets
,
641 SymbolFlags::WeakDefined
| Flags
);
642 for (auto &Symbol
: Section
.TLVSymbols
)
643 File
->addSymbol(EncodeKind::GlobalSymbol
, Symbol
, Targets
,
644 SymbolFlags::ThreadLocalValue
| Flags
);
647 for (const auto &Section
: Undefineds
) {
649 synthesizeTargets(Section
.Architectures
, Platforms
);
650 for (auto &Symbol
: Section
.Symbols
) {
651 if (Ctx
->FileKind
!= FileType::TBD_V3
&&
652 Symbol
.value
.starts_with(ObjC2EHTypePrefix
))
653 File
->addSymbol(EncodeKind::ObjectiveCClassEHType
,
654 Symbol
.value
.drop_front(15), Targets
,
655 SymbolFlags::Undefined
| Flags
);
657 File
->addSymbol(EncodeKind::GlobalSymbol
, Symbol
, Targets
,
658 SymbolFlags::Undefined
| Flags
);
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(EncodeKind::ObjectiveCClass
, Name
, Targets
,
665 SymbolFlags::Undefined
| Flags
);
667 for (auto &Symbol
: Section
.ClassEHs
)
668 File
->addSymbol(EncodeKind::ObjectiveCClassEHType
, Symbol
, Targets
,
669 SymbolFlags::Undefined
| Flags
);
670 for (auto &Symbol
: Section
.IVars
) {
671 auto Name
= Symbol
.value
;
672 if (Ctx
->FileKind
!= FileType::TBD_V3
)
673 Name
= Name
.drop_front();
674 File
->addSymbol(EncodeKind::ObjectiveCInstanceVariable
, Name
, Targets
,
675 SymbolFlags::Undefined
| Flags
);
677 for (auto &Symbol
: Section
.WeakRefSymbols
)
678 File
->addSymbol(EncodeKind::GlobalSymbol
, Symbol
, Targets
,
679 SymbolFlags::Undefined
| SymbolFlags::WeakReferenced
|
686 llvm::BumpPtrAllocator Allocator
;
687 StringRef
copyString(StringRef String
) {
691 void *Ptr
= Allocator
.Allocate(String
.size(), 1);
692 memcpy(Ptr
, String
.data(), String
.size());
693 return StringRef(reinterpret_cast<const char *>(Ptr
), String
.size());
696 std::vector
<Architecture
> Architectures
;
697 std::vector
<UUID
> UUIDs
;
698 PlatformSet Platforms
;
699 StringRef InstallName
;
700 PackedVersion CurrentVersion
;
701 PackedVersion CompatibilityVersion
;
702 SwiftVersion SwiftABIVersion
{0};
703 ObjCConstraintType ObjCConstraint
{ObjCConstraintType::None
};
704 TBDFlags Flags
{TBDFlags::None
};
705 StringRef ParentUmbrella
;
706 std::vector
<ExportSection
> Exports
;
707 std::vector
<UndefinedSection
> Undefineds
;
710 static void setFileTypeForInput(TextAPIContext
*Ctx
, IO
&IO
) {
711 if (IO
.mapTag("!tapi-tbd", false))
712 Ctx
->FileKind
= FileType::TBD_V4
;
713 else if (IO
.mapTag("!tapi-tbd-v3", false))
714 Ctx
->FileKind
= FileType::TBD_V3
;
715 else if (IO
.mapTag("!tapi-tbd-v2", false))
716 Ctx
->FileKind
= FileType::TBD_V2
;
717 else if (IO
.mapTag("!tapi-tbd-v1", false) ||
718 IO
.mapTag("tag:yaml.org,2002:map", false))
719 Ctx
->FileKind
= FileType::TBD_V1
;
721 Ctx
->FileKind
= FileType::Invalid
;
726 static void mapping(IO
&IO
, const InterfaceFile
*&File
) {
727 auto *Ctx
= reinterpret_cast<TextAPIContext
*>(IO
.getContext());
728 assert((!Ctx
|| !IO
.outputting() ||
729 (Ctx
&& Ctx
->FileKind
!= FileType::Invalid
)) &&
730 "File type is not set in YAML context");
732 if (!IO
.outputting()) {
733 setFileTypeForInput(Ctx
, IO
);
734 switch (Ctx
->FileKind
) {
737 case FileType::TBD_V4
:
738 mapKeysToValuesV4(IO
, File
);
740 case FileType::Invalid
:
741 IO
.setError("unsupported file type");
745 // Set file type when writing.
746 switch (Ctx
->FileKind
) {
748 llvm_unreachable("unexpected file type");
749 case FileType::TBD_V4
:
750 mapKeysToValuesV4(IO
, File
);
752 case FileType::TBD_V3
:
753 IO
.mapTag("!tapi-tbd-v3", true);
755 case FileType::TBD_V2
:
756 IO
.mapTag("!tapi-tbd-v2", true);
758 case FileType::TBD_V1
:
759 // Don't write the tag into the .tbd file for TBD v1
763 mapKeysToValues(Ctx
->FileKind
, IO
, File
);
766 using SectionList
= std::vector
<SymbolSection
>;
767 struct NormalizedTBD_V4
{
768 explicit NormalizedTBD_V4(IO
&IO
) {}
769 NormalizedTBD_V4(IO
&IO
, const InterfaceFile
*&File
) {
770 auto Ctx
= reinterpret_cast<TextAPIContext
*>(IO
.getContext());
772 TBDVersion
= Ctx
->FileKind
>> 4;
773 Targets
.insert(Targets
.begin(), File
->targets().begin(),
774 File
->targets().end());
775 InstallName
= File
->getInstallName();
776 CurrentVersion
= File
->getCurrentVersion();
777 CompatibilityVersion
= File
->getCompatibilityVersion();
778 SwiftABIVersion
= File
->getSwiftABIVersion();
780 Flags
= TBDFlags::None
;
781 if (!File
->isApplicationExtensionSafe())
782 Flags
|= TBDFlags::NotApplicationExtensionSafe
;
784 if (!File
->isTwoLevelNamespace())
785 Flags
|= TBDFlags::FlatNamespace
;
787 if (File
->isOSLibNotForSharedCache())
788 Flags
|= TBDFlags::OSLibNotForSharedCache
;
791 std::map
<std::string
, TargetList
> valueToTargetList
;
792 for (const auto &it
: File
->umbrellas())
793 valueToTargetList
[it
.second
].emplace_back(it
.first
);
795 for (const auto &it
: valueToTargetList
) {
796 UmbrellaSection CurrentSection
;
797 CurrentSection
.Targets
.insert(CurrentSection
.Targets
.begin(),
798 it
.second
.begin(), it
.second
.end());
799 CurrentSection
.Umbrella
= it
.first
;
800 ParentUmbrellas
.emplace_back(std::move(CurrentSection
));
804 assignTargetsToLibrary(File
->allowableClients(), AllowableClients
);
805 assignTargetsToLibrary(File
->reexportedLibraries(), ReexportedLibraries
);
808 [](SectionList
&CurrentSections
,
809 InterfaceFile::const_filtered_symbol_range Symbols
) {
810 std::set
<TargetList
> TargetSet
;
811 std::map
<const Symbol
*, TargetList
> SymbolToTargetList
;
812 for (const auto *Symbol
: Symbols
) {
813 TargetList
Targets(Symbol
->targets());
814 SymbolToTargetList
[Symbol
] = Targets
;
815 TargetSet
.emplace(std::move(Targets
));
817 for (const auto &TargetIDs
: TargetSet
) {
818 SymbolSection CurrentSection
;
819 CurrentSection
.Targets
.insert(CurrentSection
.Targets
.begin(),
820 TargetIDs
.begin(), TargetIDs
.end());
822 for (const auto &IT
: SymbolToTargetList
) {
823 if (IT
.second
!= TargetIDs
)
826 const auto *Symbol
= IT
.first
;
827 switch (Symbol
->getKind()) {
828 case EncodeKind::GlobalSymbol
:
829 if (Symbol
->isWeakDefined())
830 CurrentSection
.WeakSymbols
.emplace_back(Symbol
->getName());
831 else if (Symbol
->isThreadLocalValue())
832 CurrentSection
.TlvSymbols
.emplace_back(Symbol
->getName());
834 CurrentSection
.Symbols
.emplace_back(Symbol
->getName());
836 case EncodeKind::ObjectiveCClass
:
837 CurrentSection
.Classes
.emplace_back(Symbol
->getName());
839 case EncodeKind::ObjectiveCClassEHType
:
840 CurrentSection
.ClassEHs
.emplace_back(Symbol
->getName());
842 case EncodeKind::ObjectiveCInstanceVariable
:
843 CurrentSection
.Ivars
.emplace_back(Symbol
->getName());
847 sort(CurrentSection
.Symbols
);
848 sort(CurrentSection
.Classes
);
849 sort(CurrentSection
.ClassEHs
);
850 sort(CurrentSection
.Ivars
);
851 sort(CurrentSection
.WeakSymbols
);
852 sort(CurrentSection
.TlvSymbols
);
853 CurrentSections
.emplace_back(std::move(CurrentSection
));
857 handleSymbols(Exports
, File
->exports());
858 handleSymbols(Reexports
, File
->reexports());
859 handleSymbols(Undefineds
, File
->undefineds());
862 const InterfaceFile
*denormalize(IO
&IO
) {
863 auto Ctx
= reinterpret_cast<TextAPIContext
*>(IO
.getContext());
866 auto *File
= new InterfaceFile
;
867 File
->setPath(Ctx
->Path
);
868 File
->setFileType(Ctx
->FileKind
);
869 File
->addTargets(Targets
);
870 File
->setInstallName(InstallName
);
871 File
->setCurrentVersion(CurrentVersion
);
872 File
->setCompatibilityVersion(CompatibilityVersion
);
873 File
->setSwiftABIVersion(SwiftABIVersion
);
874 for (const auto &CurrentSection
: ParentUmbrellas
)
875 for (const auto &target
: CurrentSection
.Targets
)
876 File
->addParentUmbrella(target
, CurrentSection
.Umbrella
);
877 File
->setTwoLevelNamespace(!(Flags
& TBDFlags::FlatNamespace
));
878 File
->setApplicationExtensionSafe(
879 !(Flags
& TBDFlags::NotApplicationExtensionSafe
));
880 File
->setOSLibNotForSharedCache(
881 (Flags
& TBDFlags::OSLibNotForSharedCache
));
883 for (const auto &CurrentSection
: AllowableClients
) {
884 for (const auto &lib
: CurrentSection
.Values
)
885 for (const auto &Target
: CurrentSection
.Targets
)
886 File
->addAllowableClient(lib
, Target
);
889 for (const auto &CurrentSection
: ReexportedLibraries
) {
890 for (const auto &Lib
: CurrentSection
.Values
)
891 for (const auto &Target
: CurrentSection
.Targets
)
892 File
->addReexportedLibrary(Lib
, Target
);
895 auto handleSymbols
= [File
](const SectionList
&CurrentSections
,
896 SymbolFlags InputFlag
= SymbolFlags::None
) {
897 // For older file formats, the segment where the symbol
898 // comes from is unknown, treat all symbols as Data
900 const SymbolFlags Flag
= InputFlag
| SymbolFlags::Data
;
902 for (const auto &CurrentSection
: CurrentSections
) {
903 for (auto &sym
: CurrentSection
.Symbols
)
904 File
->addSymbol(EncodeKind::GlobalSymbol
, sym
,
905 CurrentSection
.Targets
, Flag
);
907 for (auto &sym
: CurrentSection
.Classes
)
908 File
->addSymbol(EncodeKind::ObjectiveCClass
, sym
,
909 CurrentSection
.Targets
, Flag
);
911 for (auto &sym
: CurrentSection
.ClassEHs
)
912 File
->addSymbol(EncodeKind::ObjectiveCClassEHType
, sym
,
913 CurrentSection
.Targets
, Flag
);
915 for (auto &sym
: CurrentSection
.Ivars
)
916 File
->addSymbol(EncodeKind::ObjectiveCInstanceVariable
, sym
,
917 CurrentSection
.Targets
, Flag
);
919 SymbolFlags SymFlag
=
920 ((Flag
& SymbolFlags::Undefined
) == SymbolFlags::Undefined
)
921 ? SymbolFlags::WeakReferenced
922 : SymbolFlags::WeakDefined
;
923 for (auto &sym
: CurrentSection
.WeakSymbols
) {
924 File
->addSymbol(EncodeKind::GlobalSymbol
, sym
,
925 CurrentSection
.Targets
, Flag
| SymFlag
);
928 for (auto &sym
: CurrentSection
.TlvSymbols
)
929 File
->addSymbol(EncodeKind::GlobalSymbol
, sym
,
930 CurrentSection
.Targets
,
931 Flag
| SymbolFlags::ThreadLocalValue
);
935 handleSymbols(Exports
);
936 handleSymbols(Reexports
, SymbolFlags::Rexported
);
937 handleSymbols(Undefineds
, SymbolFlags::Undefined
);
943 std::vector
<UUIDv4
> UUIDs
;
945 StringRef InstallName
;
946 PackedVersion CurrentVersion
;
947 PackedVersion CompatibilityVersion
;
948 SwiftVersion SwiftABIVersion
{0};
949 std::vector
<MetadataSection
> AllowableClients
;
950 std::vector
<MetadataSection
> ReexportedLibraries
;
951 TBDFlags Flags
{TBDFlags::None
};
952 std::vector
<UmbrellaSection
> ParentUmbrellas
;
954 SectionList Reexports
;
955 SectionList Undefineds
;
958 void assignTargetsToLibrary(const std::vector
<InterfaceFileRef
> &Libraries
,
959 std::vector
<MetadataSection
> &Section
) {
960 std::set
<TargetList
> targetSet
;
961 std::map
<const InterfaceFileRef
*, TargetList
> valueToTargetList
;
962 for (const auto &library
: Libraries
) {
963 TargetList
targets(library
.targets());
964 valueToTargetList
[&library
] = targets
;
965 targetSet
.emplace(std::move(targets
));
968 for (const auto &targets
: targetSet
) {
969 MetadataSection CurrentSection
;
970 CurrentSection
.Targets
.insert(CurrentSection
.Targets
.begin(),
971 targets
.begin(), targets
.end());
973 for (const auto &it
: valueToTargetList
) {
974 if (it
.second
!= targets
)
977 CurrentSection
.Values
.emplace_back(it
.first
->getInstallName());
979 llvm::sort(CurrentSection
.Values
);
980 Section
.emplace_back(std::move(CurrentSection
));
985 static void mapKeysToValues(FileType FileKind
, IO
&IO
,
986 const InterfaceFile
*&File
) {
987 MappingNormalization
<NormalizedTBD
, const InterfaceFile
*> Keys(IO
, File
);
988 std::vector
<UUID
> EmptyUUID
;
989 IO
.mapRequired("archs", Keys
->Architectures
);
990 if (FileKind
!= FileType::TBD_V1
)
991 IO
.mapOptional("uuids", EmptyUUID
);
992 IO
.mapRequired("platform", Keys
->Platforms
);
993 if (FileKind
!= FileType::TBD_V1
)
994 IO
.mapOptional("flags", Keys
->Flags
, TBDFlags::None
);
995 IO
.mapRequired("install-name", Keys
->InstallName
);
996 IO
.mapOptional("current-version", Keys
->CurrentVersion
,
997 PackedVersion(1, 0, 0));
998 IO
.mapOptional("compatibility-version", Keys
->CompatibilityVersion
,
999 PackedVersion(1, 0, 0));
1000 if (FileKind
!= FileType::TBD_V3
)
1001 IO
.mapOptional("swift-version", Keys
->SwiftABIVersion
, SwiftVersion(0));
1003 IO
.mapOptional("swift-abi-version", Keys
->SwiftABIVersion
,
1005 IO
.mapOptional("objc-constraint", Keys
->ObjCConstraint
,
1006 (FileKind
== FileType::TBD_V1
)
1007 ? ObjCConstraintType::None
1008 : ObjCConstraintType::Retain_Release
);
1009 if (FileKind
!= FileType::TBD_V1
)
1010 IO
.mapOptional("parent-umbrella", Keys
->ParentUmbrella
, StringRef());
1011 IO
.mapOptional("exports", Keys
->Exports
);
1012 if (FileKind
!= FileType::TBD_V1
)
1013 IO
.mapOptional("undefineds", Keys
->Undefineds
);
1016 static void mapKeysToValuesV4(IO
&IO
, const InterfaceFile
*&File
) {
1017 MappingNormalization
<NormalizedTBD_V4
, const InterfaceFile
*> Keys(IO
,
1019 std::vector
<UUIDv4
> EmptyUUID
;
1020 IO
.mapTag("!tapi-tbd", true);
1021 IO
.mapRequired("tbd-version", Keys
->TBDVersion
);
1022 IO
.mapRequired("targets", Keys
->Targets
);
1023 IO
.mapOptional("uuids", EmptyUUID
);
1024 IO
.mapOptional("flags", Keys
->Flags
, TBDFlags::None
);
1025 IO
.mapRequired("install-name", Keys
->InstallName
);
1026 IO
.mapOptional("current-version", Keys
->CurrentVersion
,
1027 PackedVersion(1, 0, 0));
1028 IO
.mapOptional("compatibility-version", Keys
->CompatibilityVersion
,
1029 PackedVersion(1, 0, 0));
1030 IO
.mapOptional("swift-abi-version", Keys
->SwiftABIVersion
, SwiftVersion(0));
1031 IO
.mapOptional("parent-umbrella", Keys
->ParentUmbrellas
);
1032 auto OptionKind
= MetadataSection::Option::Clients
;
1033 IO
.mapOptionalWithContext("allowable-clients", Keys
->AllowableClients
,
1035 OptionKind
= MetadataSection::Option::Libraries
;
1036 IO
.mapOptionalWithContext("reexported-libraries", Keys
->ReexportedLibraries
,
1038 IO
.mapOptional("exports", Keys
->Exports
);
1039 IO
.mapOptional("reexports", Keys
->Reexports
);
1040 IO
.mapOptional("undefineds", Keys
->Undefineds
);
1045 struct DocumentListTraits
<std::vector
<const MachO::InterfaceFile
*>> {
1046 static size_t size(IO
&IO
, std::vector
<const MachO::InterfaceFile
*> &Seq
) {
1049 static const InterfaceFile
*&
1050 element(IO
&IO
, std::vector
<const InterfaceFile
*> &Seq
, size_t Index
) {
1051 if (Index
>= Seq
.size())
1052 Seq
.resize(Index
+ 1);
1057 } // end namespace yaml.
1060 static void DiagHandler(const SMDiagnostic
&Diag
, void *Context
) {
1061 auto *File
= static_cast<TextAPIContext
*>(Context
);
1062 SmallString
<1024> Message
;
1063 raw_svector_ostream
S(Message
);
1065 SMDiagnostic
NewDiag(*Diag
.getSourceMgr(), Diag
.getLoc(), File
->Path
,
1066 Diag
.getLineNo(), Diag
.getColumnNo(), Diag
.getKind(),
1067 Diag
.getMessage(), Diag
.getLineContents(),
1068 Diag
.getRanges(), Diag
.getFixIts());
1070 NewDiag
.print(nullptr, S
);
1071 File
->ErrorMessage
= ("malformed file\n" + Message
).str();
1074 Expected
<FileType
> TextAPIReader::canRead(MemoryBufferRef InputBuffer
) {
1075 auto TAPIFile
= InputBuffer
.getBuffer().trim();
1076 if (TAPIFile
.starts_with("{") && TAPIFile
.ends_with("}"))
1077 return FileType::TBD_V5
;
1079 if (!TAPIFile
.ends_with("..."))
1080 return createStringError(std::errc::not_supported
, "unsupported file type");
1082 if (TAPIFile
.starts_with("--- !tapi-tbd"))
1083 return FileType::TBD_V4
;
1085 if (TAPIFile
.starts_with("--- !tapi-tbd-v3"))
1086 return FileType::TBD_V3
;
1088 if (TAPIFile
.starts_with("--- !tapi-tbd-v2"))
1089 return FileType::TBD_V2
;
1091 if (TAPIFile
.starts_with("--- !tapi-tbd-v1") ||
1092 TAPIFile
.starts_with("---\narchs:"))
1093 return FileType::TBD_V1
;
1095 return createStringError(std::errc::not_supported
, "unsupported file type");
1098 Expected
<std::unique_ptr
<InterfaceFile
>>
1099 TextAPIReader::get(MemoryBufferRef InputBuffer
) {
1101 Ctx
.Path
= std::string(InputBuffer
.getBufferIdentifier());
1102 if (auto FTOrErr
= canRead(InputBuffer
))
1103 Ctx
.FileKind
= *FTOrErr
;
1105 return FTOrErr
.takeError();
1107 // Handle JSON Format.
1108 if (Ctx
.FileKind
>= FileType::TBD_V5
) {
1109 auto FileOrErr
= getInterfaceFileFromJSON(InputBuffer
.getBuffer());
1111 return FileOrErr
.takeError();
1113 (*FileOrErr
)->setPath(Ctx
.Path
);
1114 return std::move(*FileOrErr
);
1116 yaml::Input
YAMLIn(InputBuffer
.getBuffer(), &Ctx
, DiagHandler
, &Ctx
);
1118 // Fill vector with interface file objects created by parsing the YAML file.
1119 std::vector
<const InterfaceFile
*> Files
;
1122 // YAMLIn dynamically allocates for Interface file and in case of error,
1123 // memory leak will occur unless wrapped around unique_ptr
1124 auto File
= std::unique_ptr
<InterfaceFile
>(
1125 const_cast<InterfaceFile
*>(Files
.front()));
1127 for (const InterfaceFile
*FI
: llvm::drop_begin(Files
))
1129 std::shared_ptr
<InterfaceFile
>(const_cast<InterfaceFile
*>(FI
)));
1132 return make_error
<StringError
>(Ctx
.ErrorMessage
, YAMLIn
.error());
1134 return std::move(File
);
1137 Error
TextAPIWriter::writeToStream(raw_ostream
&OS
, const InterfaceFile
&File
,
1138 const FileType FileKind
, bool Compact
) {
1140 Ctx
.Path
= std::string(File
.getPath());
1142 // Prefer parameter for format if passed, otherwise fallback to the File
1145 (FileKind
== FileType::Invalid
) ? File
.getFileType() : FileKind
;
1147 // Write out in JSON format.
1148 if (Ctx
.FileKind
>= FileType::TBD_V5
) {
1149 return serializeInterfaceFileToJSON(OS
, File
, Ctx
.FileKind
, Compact
);
1152 llvm::yaml::Output
YAMLOut(OS
, &Ctx
, /*WrapColumn=*/80);
1154 std::vector
<const InterfaceFile
*> Files
;
1155 Files
.emplace_back(&File
);
1157 for (const auto &Document
: File
.documents())
1158 Files
.emplace_back(Document
.get());
1163 return Error::success();