1 //===- TextStub.cpp -------------------------------------------------------===// 2 // 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 6 // 7 //===----------------------------------------------------------------------===// 8 // 9 // Implements the text stub file reader/writer. 10 // 11 //===----------------------------------------------------------------------===// 12 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" 28 #include <algorithm> 29 #include <set> 30 31 // clang-format off 32 /* 33 34 YAML Format specification. 35 36 The TBD v1 format only support two level address libraries and is per 37 definition application extension safe. 38 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 50 ... 51 52 Each export section is defined as following: 53 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 60 # Variables 61 weak-def-symbols: [] # Optional: List of weak defined symbols 62 thread-local-symbols: [] # Optional: List of thread local symbols 63 */ 64 65 /* 66 67 YAML Format specification. 68 69 --- !tapi-tbd-v2 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) 74 flags: [] # Optional: 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 82 ... 83 undefineds: # List of undefineds sections 84 ... 85 86 Each export section is defined as following: 87 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 94 # Variables 95 weak-def-symbols: [] # Optional: List of weak defined symbols 96 thread-local-symbols: [] # Optional: List of thread local symbols 97 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 104 */ 105 106 /* 107 108 YAML Format specification. 109 110 --- !tapi-tbd-v3 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 123 ... 124 undefineds: # List of undefineds sections 125 ... 126 127 Each export section is defined as following: 128 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 135 # with EH 136 objc-ivars: [] # Optional: List of Objective C Instance 137 # Variables 138 weak-def-symbols: [] # Optional: List of weak defined symbols 139 thread-local-symbols: [] # Optional: List of thread local symbols 140 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 146 # with EH 147 objc-ivars: [] # Optional: List of Objective C Instance Variables 148 weak-ref-symbols: [] # Optional: List of weak defined symbols 149 */ 150 151 /* 152 153 YAML Format specification. 154 155 --- !tapi-tbd 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. 159 - target: armv7-ios 160 value: ... 161 - target: x86_64-maccatalyst 162 value: ... 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: 169 allowable-clients: 170 - targets: [ armv7-ios ] # Optional: 171 clients: [ clientA ] 172 exports: # List of export sections 173 ... 174 re-exports: # List of reexport sections 175 ... 176 undefineds: # List of undefineds sections 177 ... 178 179 Each export and reexport section is defined as following: 180 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 185 # with EH 186 objc-ivars: [] # Optional: List of Objective C Instance 187 # Variables 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 192 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 198 # with EH 199 objc-ivars: [] # Optional: List of Objective C Instance Variables 200 weak-symbols: [] # Optional: List of weak defined symbols 201 */ 202 // clang-format on 203 204 using namespace llvm; 205 using namespace llvm::yaml; 206 using namespace llvm::MachO; 207 208 namespace { 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; 219 }; 220 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; 228 }; 229 230 // Sections for direct target mapping in TBDv4 231 struct SymbolSection { 232 TargetList Targets; 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; 239 }; 240 241 struct MetadataSection { 242 enum Option { Clients, Libraries }; 243 std::vector<Target> Targets; 244 std::vector<FlowStringRef> Values; 245 }; 246 247 struct UmbrellaSection { 248 std::vector<Target> Targets; 249 std::string Umbrella; 250 }; 251 252 // UUID's for TBDv4 are mapped to target not arch 253 struct UUIDv4 { 254 Target TargetID; 255 std::string Value; 256 257 UUIDv4() = default; 258 UUIDv4(const Target &TargetID, const std::string &Value) 259 : TargetID(TargetID), Value(Value) {} 260 }; 261 } // end anonymous namespace. 262 263 LLVM_YAML_IS_FLOW_SEQUENCE_VECTOR(Architecture) 264 LLVM_YAML_IS_SEQUENCE_VECTOR(ExportSection) 265 LLVM_YAML_IS_SEQUENCE_VECTOR(UndefinedSection) 266 // Specific to TBDv4 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) 272 273 namespace llvm { 274 namespace yaml { 275 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"); 281 282 IO.mapRequired("archs", Section.Architectures); 283 if (Ctx->FileKind == FileType::TBD_V1) 284 IO.mapOptional("allowed-clients", Section.AllowableClients); 285 else 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); 295 } 296 }; 297 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"); 303 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); 311 } 312 }; 313 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); 323 } 324 }; 325 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); 330 } 331 }; 332 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); 337 } 338 }; 339 340 template <> 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); 348 return; 349 case MetadataSection::Option::Libraries: 350 IO.mapRequired("libraries", Section.Values); 351 return; 352 } 353 llvm_unreachable("unexpected option for metadata"); 354 } 355 }; 356 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); 365 } 366 }; 367 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, \ 373 marketing) \ 374 case PLATFORM_##platform: \ 375 OS << #tapi_target; \ 376 break; 377 #include "llvm/BinaryFormat/MachO.def" 378 } 379 } 380 381 static StringRef input(StringRef Scalar, void *, Target &Value) { 382 auto Result = Target::create(Scalar); 383 if (!Result) { 384 consumeError(Result.takeError()); 385 return "unparsable target"; 386 } 387 388 Value = *Result; 389 if (Value.Arch == AK_unknown) 390 return "unknown architecture"; 391 if (Value.Platform == PLATFORM_UNKNOWN) 392 return "unknown platform"; 393 394 return {}; 395 } 396 397 static QuotingType mustQuote(StringRef) { return QuotingType::None; } 398 }; 399 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(); 411 412 Flags = TBDFlags::None; 413 if (!File->isApplicationExtensionSafe()) 414 Flags |= TBDFlags::NotApplicationExtensionSafe; 415 416 if (!File->isTwoLevelNamespace()) 417 Flags |= TBDFlags::FlatNamespace; 418 419 if (!File->umbrellas().empty()) 420 ParentUmbrella = File->umbrellas().begin()->second; 421 422 std::set<ArchitectureSet> ArchSet; 423 for (const auto &Library : File->allowableClients()) 424 ArchSet.insert(Library.getArchitectures()); 425 426 for (const auto &Library : File->reexportedLibraries()) 427 ArchSet.insert(Library.getArchitectures()); 428 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); 434 } 435 436 for (auto Architectures : ArchSet) { 437 ExportSection Section; 438 Section.Architectures = Architectures; 439 440 for (const auto &Library : File->allowableClients()) 441 if (Library.getArchitectures() == Architectures) 442 Section.AllowableClients.emplace_back(Library.getInstallName()); 443 444 for (const auto &Library : File->reexportedLibraries()) 445 if (Library.getArchitectures() == Architectures) 446 Section.ReexportedLibraries.emplace_back(Library.getInstallName()); 447 448 for (const auto &SymArch : SymbolToArchSet) { 449 if (SymArch.second != Architectures) 450 continue; 451 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()); 459 else 460 Section.Symbols.emplace_back(Symbol->getName()); 461 break; 462 case EncodeKind::ObjectiveCClass: 463 if (File->getFileType() != FileType::TBD_V3) 464 Section.Classes.emplace_back( 465 copyString("_" + Symbol->getName().str())); 466 else 467 Section.Classes.emplace_back(Symbol->getName()); 468 break; 469 case EncodeKind::ObjectiveCClassEHType: 470 if (File->getFileType() != FileType::TBD_V3) 471 Section.Symbols.emplace_back( 472 copyString("_OBJC_EHTYPE_$_" + Symbol->getName().str())); 473 else 474 Section.ClassEHs.emplace_back(Symbol->getName()); 475 break; 476 case EncodeKind::ObjectiveCInstanceVariable: 477 if (File->getFileType() != FileType::TBD_V3) 478 Section.IVars.emplace_back( 479 copyString("_" + Symbol->getName().str())); 480 else 481 Section.IVars.emplace_back(Symbol->getName()); 482 break; 483 } 484 } 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)); 492 } 493 494 ArchSet.clear(); 495 SymbolToArchSet.clear(); 496 497 for (const auto *Symbol : File->undefineds()) { 498 auto Architectures = Symbol->getArchitectures(); 499 SymbolToArchSet[Symbol] = Architectures; 500 ArchSet.insert(Architectures); 501 } 502 503 for (auto Architectures : ArchSet) { 504 UndefinedSection Section; 505 Section.Architectures = Architectures; 506 507 for (const auto &SymArch : SymbolToArchSet) { 508 if (SymArch.second != Architectures) 509 continue; 510 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()); 516 else 517 Section.Symbols.emplace_back(Symbol->getName()); 518 break; 519 case EncodeKind::ObjectiveCClass: 520 if (File->getFileType() != FileType::TBD_V3) 521 Section.Classes.emplace_back( 522 copyString("_" + Symbol->getName().str())); 523 else 524 Section.Classes.emplace_back(Symbol->getName()); 525 break; 526 case EncodeKind::ObjectiveCClassEHType: 527 if (File->getFileType() != FileType::TBD_V3) 528 Section.Symbols.emplace_back( 529 copyString("_OBJC_EHTYPE_$_" + Symbol->getName().str())); 530 else 531 Section.ClassEHs.emplace_back(Symbol->getName()); 532 break; 533 case EncodeKind::ObjectiveCInstanceVariable: 534 if (File->getFileType() != FileType::TBD_V3) 535 Section.IVars.emplace_back( 536 copyString("_" + Symbol->getName().str())); 537 else 538 Section.IVars.emplace_back(Symbol->getName()); 539 break; 540 } 541 } 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)); 548 } 549 } 550 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) { 558 TargetList Targets; 559 560 for (auto Platform : Platforms) { 561 Platform = mapToPlatformType(Platform, Architectures.hasX86()); 562 563 for (const auto &&Architecture : Architectures) { 564 if ((Architecture == AK_i386) && (Platform == PLATFORM_MACCATALYST)) 565 continue; 566 567 Targets.emplace_back(Architecture, Platform); 568 } 569 } 570 return Targets; 571 } 572 573 const InterfaceFile *denormalize(IO &IO) { 574 auto Ctx = reinterpret_cast<TextAPIContext *>(IO.getContext()); 575 assert(Ctx); 576 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); 588 589 if (Ctx->FileKind == FileType::TBD_V1) { 590 File->setTwoLevelNamespace(); 591 File->setApplicationExtensionSafe(); 592 } else { 593 File->setTwoLevelNamespace(!(Flags & TBDFlags::FlatNamespace)); 594 File->setApplicationExtensionSafe( 595 !(Flags & TBDFlags::NotApplicationExtensionSafe)); 596 } 597 598 // For older file formats, the segment where the symbol 599 // comes from is unknown, treat all symbols as Data 600 // in these cases. 601 const auto Flags = SymbolFlags::Data; 602 603 for (const auto &Section : Exports) { 604 const auto Targets = 605 synthesizeTargets(Section.Architectures, Platforms); 606 607 for (const auto &Lib : Section.AllowableClients) 608 for (const auto &Target : Targets) 609 File->addAllowableClient(Lib, Target); 610 611 for (const auto &Lib : Section.ReexportedLibraries) 612 for (const auto &Target : Targets) 613 File->addReexportedLibrary(Lib, Target); 614 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); 620 else 621 File->addSymbol(EncodeKind::GlobalSymbol, Symbol, Targets, Flags); 622 } 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); 628 } 629 for (auto &Symbol : Section.ClassEHs) 630 File->addSymbol(EncodeKind::ObjectiveCClassEHType, Symbol, Targets, 631 Flags); 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, 637 Flags); 638 } 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); 645 } 646 647 for (const auto &Section : Undefineds) { 648 const auto Targets = 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); 656 else 657 File->addSymbol(EncodeKind::GlobalSymbol, Symbol, Targets, 658 SymbolFlags::Undefined | Flags); 659 } 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); 666 } 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); 676 } 677 for (auto &Symbol : Section.WeakRefSymbols) 678 File->addSymbol(EncodeKind::GlobalSymbol, Symbol, Targets, 679 SymbolFlags::Undefined | SymbolFlags::WeakReferenced | 680 Flags); 681 } 682 683 return File; 684 } 685 686 llvm::BumpPtrAllocator Allocator; 687 StringRef copyString(StringRef String) { 688 if (String.empty()) 689 return {}; 690 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()); 694 } 695 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; 708 }; 709 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; 720 else { 721 Ctx->FileKind = FileType::Invalid; 722 return; 723 } 724 } 725 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"); 731 732 if (!IO.outputting()) { 733 setFileTypeForInput(Ctx, IO); 734 switch (Ctx->FileKind) { 735 default: 736 break; 737 case FileType::TBD_V4: 738 mapKeysToValuesV4(IO, File); 739 return; 740 case FileType::Invalid: 741 IO.setError("unsupported file type"); 742 return; 743 } 744 } else { 745 // Set file type when writing. 746 switch (Ctx->FileKind) { 747 default: 748 llvm_unreachable("unexpected file type"); 749 case FileType::TBD_V4: 750 mapKeysToValuesV4(IO, File); 751 return; 752 case FileType::TBD_V3: 753 IO.mapTag("!tapi-tbd-v3", true); 754 break; 755 case FileType::TBD_V2: 756 IO.mapTag("!tapi-tbd-v2", true); 757 break; 758 case FileType::TBD_V1: 759 // Don't write the tag into the .tbd file for TBD v1 760 break; 761 } 762 } 763 mapKeysToValues(Ctx->FileKind, IO, File); 764 } 765 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()); 771 assert(Ctx); 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(); 779 780 Flags = TBDFlags::None; 781 if (!File->isApplicationExtensionSafe()) 782 Flags |= TBDFlags::NotApplicationExtensionSafe; 783 784 if (!File->isTwoLevelNamespace()) 785 Flags |= TBDFlags::FlatNamespace; 786 787 if (File->isOSLibNotForSharedCache()) 788 Flags |= TBDFlags::OSLibNotForSharedCache; 789 790 { 791 std::map<std::string, TargetList> valueToTargetList; 792 for (const auto &it : File->umbrellas()) 793 valueToTargetList[it.second].emplace_back(it.first); 794 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)); 801 } 802 } 803 804 assignTargetsToLibrary(File->allowableClients(), AllowableClients); 805 assignTargetsToLibrary(File->reexportedLibraries(), ReexportedLibraries); 806 807 auto handleSymbols = 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)); 816 } 817 for (const auto &TargetIDs : TargetSet) { 818 SymbolSection CurrentSection; 819 CurrentSection.Targets.insert(CurrentSection.Targets.begin(), 820 TargetIDs.begin(), TargetIDs.end()); 821 822 for (const auto &IT : SymbolToTargetList) { 823 if (IT.second != TargetIDs) 824 continue; 825 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()); 833 else 834 CurrentSection.Symbols.emplace_back(Symbol->getName()); 835 break; 836 case EncodeKind::ObjectiveCClass: 837 CurrentSection.Classes.emplace_back(Symbol->getName()); 838 break; 839 case EncodeKind::ObjectiveCClassEHType: 840 CurrentSection.ClassEHs.emplace_back(Symbol->getName()); 841 break; 842 case EncodeKind::ObjectiveCInstanceVariable: 843 CurrentSection.Ivars.emplace_back(Symbol->getName()); 844 break; 845 } 846 } 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)); 854 } 855 }; 856 857 handleSymbols(Exports, File->exports()); 858 handleSymbols(Reexports, File->reexports()); 859 handleSymbols(Undefineds, File->undefineds()); 860 } 861 862 const InterfaceFile *denormalize(IO &IO) { 863 auto Ctx = reinterpret_cast<TextAPIContext *>(IO.getContext()); 864 assert(Ctx); 865 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)); 882 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); 887 } 888 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); 893 } 894 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 899 // in these cases. 900 const SymbolFlags Flag = InputFlag | SymbolFlags::Data; 901 902 for (const auto &CurrentSection : CurrentSections) { 903 for (auto &sym : CurrentSection.Symbols) 904 File->addSymbol(EncodeKind::GlobalSymbol, sym, 905 CurrentSection.Targets, Flag); 906 907 for (auto &sym : CurrentSection.Classes) 908 File->addSymbol(EncodeKind::ObjectiveCClass, sym, 909 CurrentSection.Targets, Flag); 910 911 for (auto &sym : CurrentSection.ClassEHs) 912 File->addSymbol(EncodeKind::ObjectiveCClassEHType, sym, 913 CurrentSection.Targets, Flag); 914 915 for (auto &sym : CurrentSection.Ivars) 916 File->addSymbol(EncodeKind::ObjectiveCInstanceVariable, sym, 917 CurrentSection.Targets, Flag); 918 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); 926 } 927 928 for (auto &sym : CurrentSection.TlvSymbols) 929 File->addSymbol(EncodeKind::GlobalSymbol, sym, 930 CurrentSection.Targets, 931 Flag | SymbolFlags::ThreadLocalValue); 932 } 933 }; 934 935 handleSymbols(Exports); 936 handleSymbols(Reexports, SymbolFlags::Rexported); 937 handleSymbols(Undefineds, SymbolFlags::Undefined); 938 939 return File; 940 } 941 942 unsigned TBDVersion; 943 std::vector<UUIDv4> UUIDs; 944 TargetList Targets; 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; 953 SectionList Exports; 954 SectionList Reexports; 955 SectionList Undefineds; 956 957 private: 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)); 966 } 967 968 for (const auto &targets : targetSet) { 969 MetadataSection CurrentSection; 970 CurrentSection.Targets.insert(CurrentSection.Targets.begin(), 971 targets.begin(), targets.end()); 972 973 for (const auto &it : valueToTargetList) { 974 if (it.second != targets) 975 continue; 976 977 CurrentSection.Values.emplace_back(it.first->getInstallName()); 978 } 979 llvm::sort(CurrentSection.Values); 980 Section.emplace_back(std::move(CurrentSection)); 981 } 982 } 983 }; 984 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)); 1002 else 1003 IO.mapOptional("swift-abi-version", Keys->SwiftABIVersion, 1004 SwiftVersion(0)); 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); 1014 } 1015 1016 static void mapKeysToValuesV4(IO &IO, const InterfaceFile *&File) { 1017 MappingNormalization<NormalizedTBD_V4, const InterfaceFile *> Keys(IO, 1018 File); 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, 1034 OptionKind); 1035 OptionKind = MetadataSection::Option::Libraries; 1036 IO.mapOptionalWithContext("reexported-libraries", Keys->ReexportedLibraries, 1037 OptionKind); 1038 IO.mapOptional("exports", Keys->Exports); 1039 IO.mapOptional("reexports", Keys->Reexports); 1040 IO.mapOptional("undefineds", Keys->Undefineds); 1041 } 1042 }; 1043 1044 template <> 1045 struct DocumentListTraits<std::vector<const MachO::InterfaceFile *>> { 1046 static size_t size(IO &IO, std::vector<const MachO::InterfaceFile *> &Seq) { 1047 return Seq.size(); 1048 } 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); 1053 return Seq[Index]; 1054 } 1055 }; 1056 1057 } // end namespace yaml. 1058 } // namespace llvm 1059 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); 1064 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()); 1069 1070 NewDiag.print(nullptr, S); 1071 File->ErrorMessage = ("malformed file\n" + Message).str(); 1072 } 1073 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; 1078 1079 if (!TAPIFile.ends_with("...")) 1080 return createStringError(std::errc::not_supported, "unsupported file type"); 1081 1082 if (TAPIFile.starts_with("--- !tapi-tbd")) 1083 return FileType::TBD_V4; 1084 1085 if (TAPIFile.starts_with("--- !tapi-tbd-v3")) 1086 return FileType::TBD_V3; 1087 1088 if (TAPIFile.starts_with("--- !tapi-tbd-v2")) 1089 return FileType::TBD_V2; 1090 1091 if (TAPIFile.starts_with("--- !tapi-tbd-v1") || 1092 TAPIFile.starts_with("---\narchs:")) 1093 return FileType::TBD_V1; 1094 1095 return createStringError(std::errc::not_supported, "unsupported file type"); 1096 } 1097 1098 Expected<std::unique_ptr<InterfaceFile>> 1099 TextAPIReader::get(MemoryBufferRef InputBuffer) { 1100 TextAPIContext Ctx; 1101 Ctx.Path = std::string(InputBuffer.getBufferIdentifier()); 1102 if (auto FTOrErr = canRead(InputBuffer)) 1103 Ctx.FileKind = *FTOrErr; 1104 else 1105 return FTOrErr.takeError(); 1106 1107 // Handle JSON Format. 1108 if (Ctx.FileKind >= FileType::TBD_V5) { 1109 auto FileOrErr = getInterfaceFileFromJSON(InputBuffer.getBuffer()); 1110 if (!FileOrErr) 1111 return FileOrErr.takeError(); 1112 1113 (*FileOrErr)->setPath(Ctx.Path); 1114 return std::move(*FileOrErr); 1115 } 1116 yaml::Input YAMLIn(InputBuffer.getBuffer(), &Ctx, DiagHandler, &Ctx); 1117 1118 // Fill vector with interface file objects created by parsing the YAML file. 1119 std::vector<const InterfaceFile *> Files; 1120 YAMLIn >> Files; 1121 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())); 1126 1127 for (const InterfaceFile *FI : llvm::drop_begin(Files)) 1128 File->addDocument( 1129 std::shared_ptr<InterfaceFile>(const_cast<InterfaceFile *>(FI))); 1130 1131 if (YAMLIn.error()) 1132 return make_error<StringError>(Ctx.ErrorMessage, YAMLIn.error()); 1133 1134 return std::move(File); 1135 } 1136 1137 Error TextAPIWriter::writeToStream(raw_ostream &OS, const InterfaceFile &File, 1138 const FileType FileKind, bool Compact) { 1139 TextAPIContext Ctx; 1140 Ctx.Path = std::string(File.getPath()); 1141 1142 // Prefer parameter for format if passed, otherwise fallback to the File 1143 // FileType. 1144 Ctx.FileKind = 1145 (FileKind == FileType::Invalid) ? File.getFileType() : FileKind; 1146 1147 // Write out in JSON format. 1148 if (Ctx.FileKind >= FileType::TBD_V5) { 1149 return serializeInterfaceFileToJSON(OS, File, Ctx.FileKind, Compact); 1150 } 1151 1152 llvm::yaml::Output YAMLOut(OS, &Ctx, /*WrapColumn=*/80); 1153 1154 std::vector<const InterfaceFile *> Files; 1155 Files.emplace_back(&File); 1156 1157 for (const auto &Document : File.documents()) 1158 Files.emplace_back(Document.get()); 1159 1160 // Stream out yaml. 1161 YAMLOut << Files; 1162 1163 return Error::success(); 1164 } 1165