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 262 // clang-format off 263 enum TBDFlags : unsigned { 264 None = 0U, 265 FlatNamespace = 1U << 0, 266 NotApplicationExtensionSafe = 1U << 1, 267 InstallAPI = 1U << 2, 268 LLVM_MARK_AS_BITMASK_ENUM(/*LargestValue=*/InstallAPI), 269 }; 270 // clang-format on 271 } // end anonymous namespace. 272 273 LLVM_YAML_IS_FLOW_SEQUENCE_VECTOR(Architecture) 274 LLVM_YAML_IS_SEQUENCE_VECTOR(ExportSection) 275 LLVM_YAML_IS_SEQUENCE_VECTOR(UndefinedSection) 276 // Specific to TBDv4 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) 282 283 namespace llvm { 284 namespace yaml { 285 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"); 291 292 IO.mapRequired("archs", Section.Architectures); 293 if (Ctx->FileKind == FileType::TBD_V1) 294 IO.mapOptional("allowed-clients", Section.AllowableClients); 295 else 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); 305 } 306 }; 307 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"); 313 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); 321 } 322 }; 323 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); 333 } 334 }; 335 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); 340 } 341 }; 342 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); 347 } 348 }; 349 350 template <> 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); 358 return; 359 case MetadataSection::Option::Libraries: 360 IO.mapRequired("libraries", Section.Values); 361 return; 362 } 363 llvm_unreachable("unexpected option for metadata"); 364 } 365 }; 366 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); 373 } 374 }; 375 376 template <> struct ScalarTraits<Target> { 377 static void output(const Target &Value, void *, raw_ostream &OS) { 378 OS << Value.Arch << "-"; 379 switch (Value.Platform) { 380 default: 381 OS << "unknown"; 382 break; 383 case PlatformKind::macOS: 384 OS << "macos"; 385 break; 386 case PlatformKind::iOS: 387 OS << "ios"; 388 break; 389 case PlatformKind::tvOS: 390 OS << "tvos"; 391 break; 392 case PlatformKind::watchOS: 393 OS << "watchos"; 394 break; 395 case PlatformKind::bridgeOS: 396 OS << "bridgeos"; 397 break; 398 case PlatformKind::macCatalyst: 399 OS << "maccatalyst"; 400 break; 401 case PlatformKind::iOSSimulator: 402 OS << "ios-simulator"; 403 break; 404 case PlatformKind::tvOSSimulator: 405 OS << "tvos-simulator"; 406 break; 407 case PlatformKind::watchOSSimulator: 408 OS << "watchos-simulator"; 409 break; 410 case PlatformKind::driverKit: 411 OS << "driverkit"; 412 break; 413 } 414 } 415 416 static StringRef input(StringRef Scalar, void *, Target &Value) { 417 auto Result = Target::create(Scalar); 418 if (!Result) { 419 consumeError(Result.takeError()); 420 return "unparsable target"; 421 } 422 423 Value = *Result; 424 if (Value.Arch == AK_unknown) 425 return "unknown architecture"; 426 if (Value.Platform == PlatformKind::unknown) 427 return "unknown platform"; 428 429 return {}; 430 } 431 432 static QuotingType mustQuote(StringRef) { return QuotingType::None; } 433 }; 434 435 template <> struct MappingTraits<const InterfaceFile *> { 436 struct NormalizedTBD { 437 explicit NormalizedTBD(IO &IO) {} 438 NormalizedTBD(IO &IO, const InterfaceFile *&File) { 439 Architectures = File->getArchitectures(); 440 UUIDs = File->uuids(); 441 Platforms = File->getPlatforms(); 442 InstallName = File->getInstallName(); 443 CurrentVersion = PackedVersion(File->getCurrentVersion()); 444 CompatibilityVersion = PackedVersion(File->getCompatibilityVersion()); 445 SwiftABIVersion = File->getSwiftABIVersion(); 446 ObjCConstraint = File->getObjCConstraint(); 447 448 Flags = TBDFlags::None; 449 if (!File->isApplicationExtensionSafe()) 450 Flags |= TBDFlags::NotApplicationExtensionSafe; 451 452 if (!File->isTwoLevelNamespace()) 453 Flags |= TBDFlags::FlatNamespace; 454 455 if (File->isInstallAPI()) 456 Flags |= TBDFlags::InstallAPI; 457 458 if (!File->umbrellas().empty()) 459 ParentUmbrella = File->umbrellas().begin()->second; 460 461 std::set<ArchitectureSet> ArchSet; 462 for (const auto &Library : File->allowableClients()) 463 ArchSet.insert(Library.getArchitectures()); 464 465 for (const auto &Library : File->reexportedLibraries()) 466 ArchSet.insert(Library.getArchitectures()); 467 468 std::map<const Symbol *, ArchitectureSet> SymbolToArchSet; 469 for (const auto *Symbol : File->exports()) { 470 auto Architectures = Symbol->getArchitectures(); 471 SymbolToArchSet[Symbol] = Architectures; 472 ArchSet.insert(Architectures); 473 } 474 475 for (auto Architectures : ArchSet) { 476 ExportSection Section; 477 Section.Architectures = Architectures; 478 479 for (const auto &Library : File->allowableClients()) 480 if (Library.getArchitectures() == Architectures) 481 Section.AllowableClients.emplace_back(Library.getInstallName()); 482 483 for (const auto &Library : File->reexportedLibraries()) 484 if (Library.getArchitectures() == Architectures) 485 Section.ReexportedLibraries.emplace_back(Library.getInstallName()); 486 487 for (const auto &SymArch : SymbolToArchSet) { 488 if (SymArch.second != Architectures) 489 continue; 490 491 const auto *Symbol = SymArch.first; 492 switch (Symbol->getKind()) { 493 case SymbolKind::GlobalSymbol: 494 if (Symbol->isWeakDefined()) 495 Section.WeakDefSymbols.emplace_back(Symbol->getName()); 496 else if (Symbol->isThreadLocalValue()) 497 Section.TLVSymbols.emplace_back(Symbol->getName()); 498 else 499 Section.Symbols.emplace_back(Symbol->getName()); 500 break; 501 case SymbolKind::ObjectiveCClass: 502 if (File->getFileType() != FileType::TBD_V3) 503 Section.Classes.emplace_back( 504 copyString("_" + Symbol->getName().str())); 505 else 506 Section.Classes.emplace_back(Symbol->getName()); 507 break; 508 case SymbolKind::ObjectiveCClassEHType: 509 if (File->getFileType() != FileType::TBD_V3) 510 Section.Symbols.emplace_back( 511 copyString("_OBJC_EHTYPE_$_" + Symbol->getName().str())); 512 else 513 Section.ClassEHs.emplace_back(Symbol->getName()); 514 break; 515 case SymbolKind::ObjectiveCInstanceVariable: 516 if (File->getFileType() != FileType::TBD_V3) 517 Section.IVars.emplace_back( 518 copyString("_" + Symbol->getName().str())); 519 else 520 Section.IVars.emplace_back(Symbol->getName()); 521 break; 522 } 523 } 524 llvm::sort(Section.Symbols); 525 llvm::sort(Section.Classes); 526 llvm::sort(Section.ClassEHs); 527 llvm::sort(Section.IVars); 528 llvm::sort(Section.WeakDefSymbols); 529 llvm::sort(Section.TLVSymbols); 530 Exports.emplace_back(std::move(Section)); 531 } 532 533 ArchSet.clear(); 534 SymbolToArchSet.clear(); 535 536 for (const auto *Symbol : File->undefineds()) { 537 auto Architectures = Symbol->getArchitectures(); 538 SymbolToArchSet[Symbol] = Architectures; 539 ArchSet.insert(Architectures); 540 } 541 542 for (auto Architectures : ArchSet) { 543 UndefinedSection Section; 544 Section.Architectures = Architectures; 545 546 for (const auto &SymArch : SymbolToArchSet) { 547 if (SymArch.second != Architectures) 548 continue; 549 550 const auto *Symbol = SymArch.first; 551 switch (Symbol->getKind()) { 552 case SymbolKind::GlobalSymbol: 553 if (Symbol->isWeakReferenced()) 554 Section.WeakRefSymbols.emplace_back(Symbol->getName()); 555 else 556 Section.Symbols.emplace_back(Symbol->getName()); 557 break; 558 case SymbolKind::ObjectiveCClass: 559 if (File->getFileType() != FileType::TBD_V3) 560 Section.Classes.emplace_back( 561 copyString("_" + Symbol->getName().str())); 562 else 563 Section.Classes.emplace_back(Symbol->getName()); 564 break; 565 case SymbolKind::ObjectiveCClassEHType: 566 if (File->getFileType() != FileType::TBD_V3) 567 Section.Symbols.emplace_back( 568 copyString("_OBJC_EHTYPE_$_" + Symbol->getName().str())); 569 else 570 Section.ClassEHs.emplace_back(Symbol->getName()); 571 break; 572 case SymbolKind::ObjectiveCInstanceVariable: 573 if (File->getFileType() != FileType::TBD_V3) 574 Section.IVars.emplace_back( 575 copyString("_" + Symbol->getName().str())); 576 else 577 Section.IVars.emplace_back(Symbol->getName()); 578 break; 579 } 580 } 581 llvm::sort(Section.Symbols); 582 llvm::sort(Section.Classes); 583 llvm::sort(Section.ClassEHs); 584 llvm::sort(Section.IVars); 585 llvm::sort(Section.WeakRefSymbols); 586 Undefineds.emplace_back(std::move(Section)); 587 } 588 } 589 590 // TBD v1 - TBD v3 files only support one platform and several 591 // architectures. It is possible to have more than one platform for TBD v3 592 // files, but the architectures don't apply to all 593 // platforms, specifically to filter out the i386 slice from 594 // platform macCatalyst. 595 TargetList synthesizeTargets(ArchitectureSet Architectures, 596 const PlatformSet &Platforms) { 597 TargetList Targets; 598 599 for (auto Platform : Platforms) { 600 Platform = mapToPlatformKind(Platform, Architectures.hasX86()); 601 602 for (const auto &&Architecture : Architectures) { 603 if ((Architecture == AK_i386) && 604 (Platform == PlatformKind::macCatalyst)) 605 continue; 606 607 Targets.emplace_back(Architecture, Platform); 608 } 609 } 610 return Targets; 611 } 612 613 const InterfaceFile *denormalize(IO &IO) { 614 auto Ctx = reinterpret_cast<TextAPIContext *>(IO.getContext()); 615 assert(Ctx); 616 617 auto *File = new InterfaceFile; 618 File->setPath(Ctx->Path); 619 File->setFileType(Ctx->FileKind); 620 File->addTargets(synthesizeTargets(Architectures, Platforms)); 621 for (auto &ID : UUIDs) 622 File->addUUID(ID.first, ID.second); 623 File->setInstallName(InstallName); 624 File->setCurrentVersion(CurrentVersion); 625 File->setCompatibilityVersion(CompatibilityVersion); 626 File->setSwiftABIVersion(SwiftABIVersion); 627 File->setObjCConstraint(ObjCConstraint); 628 for (const auto &Target : File->targets()) 629 File->addParentUmbrella(Target, ParentUmbrella); 630 631 if (Ctx->FileKind == FileType::TBD_V1) { 632 File->setTwoLevelNamespace(); 633 File->setApplicationExtensionSafe(); 634 } else { 635 File->setTwoLevelNamespace(!(Flags & TBDFlags::FlatNamespace)); 636 File->setApplicationExtensionSafe( 637 !(Flags & TBDFlags::NotApplicationExtensionSafe)); 638 File->setInstallAPI(Flags & TBDFlags::InstallAPI); 639 } 640 641 for (const auto &Section : Exports) { 642 const auto Targets = 643 synthesizeTargets(Section.Architectures, Platforms); 644 645 for (const auto &Lib : Section.AllowableClients) 646 for (const auto &Target : Targets) 647 File->addAllowableClient(Lib, Target); 648 649 for (const auto &Lib : Section.ReexportedLibraries) 650 for (const auto &Target : Targets) 651 File->addReexportedLibrary(Lib, Target); 652 653 for (const auto &Symbol : Section.Symbols) { 654 if (Ctx->FileKind != FileType::TBD_V3 && 655 Symbol.value.startswith("_OBJC_EHTYPE_$_")) 656 File->addSymbol(SymbolKind::ObjectiveCClassEHType, 657 Symbol.value.drop_front(15), Targets); 658 else 659 File->addSymbol(SymbolKind::GlobalSymbol, Symbol, Targets); 660 } 661 for (auto &Symbol : Section.Classes) { 662 auto Name = Symbol.value; 663 if (Ctx->FileKind != FileType::TBD_V3) 664 Name = Name.drop_front(); 665 File->addSymbol(SymbolKind::ObjectiveCClass, Name, Targets); 666 } 667 for (auto &Symbol : Section.ClassEHs) 668 File->addSymbol(SymbolKind::ObjectiveCClassEHType, Symbol, Targets); 669 for (auto &Symbol : Section.IVars) { 670 auto Name = Symbol.value; 671 if (Ctx->FileKind != FileType::TBD_V3) 672 Name = Name.drop_front(); 673 File->addSymbol(SymbolKind::ObjectiveCInstanceVariable, Name, 674 Targets); 675 } 676 for (auto &Symbol : Section.WeakDefSymbols) 677 File->addSymbol(SymbolKind::GlobalSymbol, Symbol, Targets, 678 SymbolFlags::WeakDefined); 679 for (auto &Symbol : Section.TLVSymbols) 680 File->addSymbol(SymbolKind::GlobalSymbol, Symbol, Targets, 681 SymbolFlags::ThreadLocalValue); 682 } 683 684 for (const auto &Section : Undefineds) { 685 const auto Targets = 686 synthesizeTargets(Section.Architectures, Platforms); 687 for (auto &Symbol : Section.Symbols) { 688 if (Ctx->FileKind != FileType::TBD_V3 && 689 Symbol.value.startswith("_OBJC_EHTYPE_$_")) 690 File->addSymbol(SymbolKind::ObjectiveCClassEHType, 691 Symbol.value.drop_front(15), Targets, 692 SymbolFlags::Undefined); 693 else 694 File->addSymbol(SymbolKind::GlobalSymbol, Symbol, Targets, 695 SymbolFlags::Undefined); 696 } 697 for (auto &Symbol : Section.Classes) { 698 auto Name = Symbol.value; 699 if (Ctx->FileKind != FileType::TBD_V3) 700 Name = Name.drop_front(); 701 File->addSymbol(SymbolKind::ObjectiveCClass, Name, Targets, 702 SymbolFlags::Undefined); 703 } 704 for (auto &Symbol : Section.ClassEHs) 705 File->addSymbol(SymbolKind::ObjectiveCClassEHType, Symbol, Targets, 706 SymbolFlags::Undefined); 707 for (auto &Symbol : Section.IVars) { 708 auto Name = Symbol.value; 709 if (Ctx->FileKind != FileType::TBD_V3) 710 Name = Name.drop_front(); 711 File->addSymbol(SymbolKind::ObjectiveCInstanceVariable, Name, Targets, 712 SymbolFlags::Undefined); 713 } 714 for (auto &Symbol : Section.WeakRefSymbols) 715 File->addSymbol(SymbolKind::GlobalSymbol, Symbol, Targets, 716 SymbolFlags::Undefined | SymbolFlags::WeakReferenced); 717 } 718 719 return File; 720 } 721 722 llvm::BumpPtrAllocator Allocator; 723 StringRef copyString(StringRef String) { 724 if (String.empty()) 725 return {}; 726 727 void *Ptr = Allocator.Allocate(String.size(), 1); 728 memcpy(Ptr, String.data(), String.size()); 729 return StringRef(reinterpret_cast<const char *>(Ptr), String.size()); 730 } 731 732 std::vector<Architecture> Architectures; 733 std::vector<UUID> UUIDs; 734 PlatformSet Platforms; 735 StringRef InstallName; 736 PackedVersion CurrentVersion; 737 PackedVersion CompatibilityVersion; 738 SwiftVersion SwiftABIVersion{0}; 739 ObjCConstraintType ObjCConstraint{ObjCConstraintType::None}; 740 TBDFlags Flags{TBDFlags::None}; 741 StringRef ParentUmbrella; 742 std::vector<ExportSection> Exports; 743 std::vector<UndefinedSection> Undefineds; 744 }; 745 746 static void setFileTypeForInput(TextAPIContext *Ctx, IO &IO) { 747 if (IO.mapTag("!tapi-tbd", false)) 748 Ctx->FileKind = FileType::TBD_V4; 749 else if (IO.mapTag("!tapi-tbd-v3", false)) 750 Ctx->FileKind = FileType::TBD_V3; 751 else if (IO.mapTag("!tapi-tbd-v2", false)) 752 Ctx->FileKind = FileType::TBD_V2; 753 else if (IO.mapTag("!tapi-tbd-v1", false) || 754 IO.mapTag("tag:yaml.org,2002:map", false)) 755 Ctx->FileKind = FileType::TBD_V1; 756 else { 757 Ctx->FileKind = FileType::Invalid; 758 return; 759 } 760 } 761 762 static void mapping(IO &IO, const InterfaceFile *&File) { 763 auto *Ctx = reinterpret_cast<TextAPIContext *>(IO.getContext()); 764 assert((!Ctx || !IO.outputting() || 765 (Ctx && Ctx->FileKind != FileType::Invalid)) && 766 "File type is not set in YAML context"); 767 768 if (!IO.outputting()) { 769 setFileTypeForInput(Ctx, IO); 770 switch (Ctx->FileKind) { 771 default: 772 break; 773 case FileType::TBD_V4: 774 mapKeysToValuesV4(IO, File); 775 return; 776 case FileType::Invalid: 777 IO.setError("unsupported file type"); 778 return; 779 } 780 } else { 781 // Set file type when writing. 782 switch (Ctx->FileKind) { 783 default: 784 llvm_unreachable("unexpected file type"); 785 case FileType::TBD_V4: 786 mapKeysToValuesV4(IO, File); 787 return; 788 case FileType::TBD_V3: 789 IO.mapTag("!tapi-tbd-v3", true); 790 break; 791 case FileType::TBD_V2: 792 IO.mapTag("!tapi-tbd-v2", true); 793 break; 794 case FileType::TBD_V1: 795 // Don't write the tag into the .tbd file for TBD v1 796 break; 797 } 798 } 799 mapKeysToValues(Ctx->FileKind, IO, File); 800 } 801 802 using SectionList = std::vector<SymbolSection>; 803 struct NormalizedTBD_V4 { 804 explicit NormalizedTBD_V4(IO &IO) {} 805 NormalizedTBD_V4(IO &IO, const InterfaceFile *&File) { 806 auto Ctx = reinterpret_cast<TextAPIContext *>(IO.getContext()); 807 assert(Ctx); 808 TBDVersion = Ctx->FileKind >> 1; 809 Targets.insert(Targets.begin(), File->targets().begin(), 810 File->targets().end()); 811 for (const auto &IT : File->uuids()) 812 UUIDs.emplace_back(IT.first, IT.second); 813 InstallName = File->getInstallName(); 814 CurrentVersion = File->getCurrentVersion(); 815 CompatibilityVersion = File->getCompatibilityVersion(); 816 SwiftABIVersion = File->getSwiftABIVersion(); 817 818 Flags = TBDFlags::None; 819 if (!File->isApplicationExtensionSafe()) 820 Flags |= TBDFlags::NotApplicationExtensionSafe; 821 822 if (!File->isTwoLevelNamespace()) 823 Flags |= TBDFlags::FlatNamespace; 824 825 if (File->isInstallAPI()) 826 Flags |= TBDFlags::InstallAPI; 827 828 { 829 std::map<std::string, TargetList> valueToTargetList; 830 for (const auto &it : File->umbrellas()) 831 valueToTargetList[it.second].emplace_back(it.first); 832 833 for (const auto &it : valueToTargetList) { 834 UmbrellaSection CurrentSection; 835 CurrentSection.Targets.insert(CurrentSection.Targets.begin(), 836 it.second.begin(), it.second.end()); 837 CurrentSection.Umbrella = it.first; 838 ParentUmbrellas.emplace_back(std::move(CurrentSection)); 839 } 840 } 841 842 assignTargetsToLibrary(File->allowableClients(), AllowableClients); 843 assignTargetsToLibrary(File->reexportedLibraries(), ReexportedLibraries); 844 845 auto handleSymbols = 846 [](SectionList &CurrentSections, 847 InterfaceFile::const_filtered_symbol_range Symbols, 848 std::function<bool(const Symbol *)> Pred) { 849 std::set<TargetList> TargetSet; 850 std::map<const Symbol *, TargetList> SymbolToTargetList; 851 for (const auto *Symbol : Symbols) { 852 if (!Pred(Symbol)) 853 continue; 854 TargetList Targets(Symbol->targets()); 855 SymbolToTargetList[Symbol] = Targets; 856 TargetSet.emplace(std::move(Targets)); 857 } 858 for (const auto &TargetIDs : TargetSet) { 859 SymbolSection CurrentSection; 860 CurrentSection.Targets.insert(CurrentSection.Targets.begin(), 861 TargetIDs.begin(), TargetIDs.end()); 862 863 for (const auto &IT : SymbolToTargetList) { 864 if (IT.second != TargetIDs) 865 continue; 866 867 const auto *Symbol = IT.first; 868 switch (Symbol->getKind()) { 869 case SymbolKind::GlobalSymbol: 870 if (Symbol->isWeakDefined()) 871 CurrentSection.WeakSymbols.emplace_back(Symbol->getName()); 872 else if (Symbol->isThreadLocalValue()) 873 CurrentSection.TlvSymbols.emplace_back(Symbol->getName()); 874 else 875 CurrentSection.Symbols.emplace_back(Symbol->getName()); 876 break; 877 case SymbolKind::ObjectiveCClass: 878 CurrentSection.Classes.emplace_back(Symbol->getName()); 879 break; 880 case SymbolKind::ObjectiveCClassEHType: 881 CurrentSection.ClassEHs.emplace_back(Symbol->getName()); 882 break; 883 case SymbolKind::ObjectiveCInstanceVariable: 884 CurrentSection.Ivars.emplace_back(Symbol->getName()); 885 break; 886 } 887 } 888 sort(CurrentSection.Symbols); 889 sort(CurrentSection.Classes); 890 sort(CurrentSection.ClassEHs); 891 sort(CurrentSection.Ivars); 892 sort(CurrentSection.WeakSymbols); 893 sort(CurrentSection.TlvSymbols); 894 CurrentSections.emplace_back(std::move(CurrentSection)); 895 } 896 }; 897 898 handleSymbols(Exports, File->exports(), [](const Symbol *Symbol) { 899 return !Symbol->isReexported(); 900 }); 901 handleSymbols(Reexports, File->exports(), [](const Symbol *Symbol) { 902 return Symbol->isReexported(); 903 }); 904 handleSymbols(Undefineds, File->undefineds(), 905 [](const Symbol *Symbol) { return true; }); 906 } 907 908 const InterfaceFile *denormalize(IO &IO) { 909 auto Ctx = reinterpret_cast<TextAPIContext *>(IO.getContext()); 910 assert(Ctx); 911 912 auto *File = new InterfaceFile; 913 File->setPath(Ctx->Path); 914 File->setFileType(Ctx->FileKind); 915 for (auto &id : UUIDs) 916 File->addUUID(id.TargetID, id.Value); 917 File->addTargets(Targets); 918 File->setInstallName(InstallName); 919 File->setCurrentVersion(CurrentVersion); 920 File->setCompatibilityVersion(CompatibilityVersion); 921 File->setSwiftABIVersion(SwiftABIVersion); 922 for (const auto &CurrentSection : ParentUmbrellas) 923 for (const auto &target : CurrentSection.Targets) 924 File->addParentUmbrella(target, CurrentSection.Umbrella); 925 File->setTwoLevelNamespace(!(Flags & TBDFlags::FlatNamespace)); 926 File->setApplicationExtensionSafe( 927 !(Flags & TBDFlags::NotApplicationExtensionSafe)); 928 File->setInstallAPI(Flags & TBDFlags::InstallAPI); 929 930 for (const auto &CurrentSection : AllowableClients) { 931 for (const auto &lib : CurrentSection.Values) 932 for (const auto &Target : CurrentSection.Targets) 933 File->addAllowableClient(lib, Target); 934 } 935 936 for (const auto &CurrentSection : ReexportedLibraries) { 937 for (const auto &Lib : CurrentSection.Values) 938 for (const auto &Target : CurrentSection.Targets) 939 File->addReexportedLibrary(Lib, Target); 940 } 941 942 auto handleSymbols = [File](const SectionList &CurrentSections, 943 SymbolFlags Flag = SymbolFlags::None) { 944 for (const auto &CurrentSection : CurrentSections) { 945 for (auto &sym : CurrentSection.Symbols) 946 File->addSymbol(SymbolKind::GlobalSymbol, sym, 947 CurrentSection.Targets, Flag); 948 949 for (auto &sym : CurrentSection.Classes) 950 File->addSymbol(SymbolKind::ObjectiveCClass, sym, 951 CurrentSection.Targets); 952 953 for (auto &sym : CurrentSection.ClassEHs) 954 File->addSymbol(SymbolKind::ObjectiveCClassEHType, sym, 955 CurrentSection.Targets); 956 957 for (auto &sym : CurrentSection.Ivars) 958 File->addSymbol(SymbolKind::ObjectiveCInstanceVariable, sym, 959 CurrentSection.Targets); 960 961 for (auto &sym : CurrentSection.WeakSymbols) 962 File->addSymbol(SymbolKind::GlobalSymbol, sym, 963 CurrentSection.Targets, SymbolFlags::WeakDefined); 964 965 for (auto &sym : CurrentSection.TlvSymbols) 966 File->addSymbol(SymbolKind::GlobalSymbol, sym, 967 CurrentSection.Targets, 968 SymbolFlags::ThreadLocalValue); 969 } 970 }; 971 972 handleSymbols(Exports); 973 handleSymbols(Reexports, SymbolFlags::Rexported); 974 handleSymbols(Undefineds, SymbolFlags::Undefined); 975 976 return File; 977 } 978 979 unsigned TBDVersion; 980 std::vector<UUIDv4> UUIDs; 981 TargetList Targets; 982 StringRef InstallName; 983 PackedVersion CurrentVersion; 984 PackedVersion CompatibilityVersion; 985 SwiftVersion SwiftABIVersion{0}; 986 std::vector<MetadataSection> AllowableClients; 987 std::vector<MetadataSection> ReexportedLibraries; 988 TBDFlags Flags{TBDFlags::None}; 989 std::vector<UmbrellaSection> ParentUmbrellas; 990 SectionList Exports; 991 SectionList Reexports; 992 SectionList Undefineds; 993 994 private: 995 void assignTargetsToLibrary(const std::vector<InterfaceFileRef> &Libraries, 996 std::vector<MetadataSection> &Section) { 997 std::set<TargetList> targetSet; 998 std::map<const InterfaceFileRef *, TargetList> valueToTargetList; 999 for (const auto &library : Libraries) { 1000 TargetList targets(library.targets()); 1001 valueToTargetList[&library] = targets; 1002 targetSet.emplace(std::move(targets)); 1003 } 1004 1005 for (const auto &targets : targetSet) { 1006 MetadataSection CurrentSection; 1007 CurrentSection.Targets.insert(CurrentSection.Targets.begin(), 1008 targets.begin(), targets.end()); 1009 1010 for (const auto &it : valueToTargetList) { 1011 if (it.second != targets) 1012 continue; 1013 1014 CurrentSection.Values.emplace_back(it.first->getInstallName()); 1015 } 1016 llvm::sort(CurrentSection.Values); 1017 Section.emplace_back(std::move(CurrentSection)); 1018 } 1019 } 1020 }; 1021 1022 static void mapKeysToValues(FileType FileKind, IO &IO, 1023 const InterfaceFile *&File) { 1024 MappingNormalization<NormalizedTBD, const InterfaceFile *> Keys(IO, File); 1025 IO.mapRequired("archs", Keys->Architectures); 1026 if (FileKind != FileType::TBD_V1) 1027 IO.mapOptional("uuids", Keys->UUIDs); 1028 IO.mapRequired("platform", Keys->Platforms); 1029 if (FileKind != FileType::TBD_V1) 1030 IO.mapOptional("flags", Keys->Flags, TBDFlags::None); 1031 IO.mapRequired("install-name", Keys->InstallName); 1032 IO.mapOptional("current-version", Keys->CurrentVersion, 1033 PackedVersion(1, 0, 0)); 1034 IO.mapOptional("compatibility-version", Keys->CompatibilityVersion, 1035 PackedVersion(1, 0, 0)); 1036 if (FileKind != FileType::TBD_V3) 1037 IO.mapOptional("swift-version", Keys->SwiftABIVersion, SwiftVersion(0)); 1038 else 1039 IO.mapOptional("swift-abi-version", Keys->SwiftABIVersion, 1040 SwiftVersion(0)); 1041 IO.mapOptional("objc-constraint", Keys->ObjCConstraint, 1042 (FileKind == FileType::TBD_V1) 1043 ? ObjCConstraintType::None 1044 : ObjCConstraintType::Retain_Release); 1045 if (FileKind != FileType::TBD_V1) 1046 IO.mapOptional("parent-umbrella", Keys->ParentUmbrella, StringRef()); 1047 IO.mapOptional("exports", Keys->Exports); 1048 if (FileKind != FileType::TBD_V1) 1049 IO.mapOptional("undefineds", Keys->Undefineds); 1050 } 1051 1052 static void mapKeysToValuesV4(IO &IO, const InterfaceFile *&File) { 1053 MappingNormalization<NormalizedTBD_V4, const InterfaceFile *> Keys(IO, 1054 File); 1055 IO.mapTag("!tapi-tbd", true); 1056 IO.mapRequired("tbd-version", Keys->TBDVersion); 1057 IO.mapRequired("targets", Keys->Targets); 1058 IO.mapOptional("uuids", Keys->UUIDs); 1059 IO.mapOptional("flags", Keys->Flags, TBDFlags::None); 1060 IO.mapRequired("install-name", Keys->InstallName); 1061 IO.mapOptional("current-version", Keys->CurrentVersion, 1062 PackedVersion(1, 0, 0)); 1063 IO.mapOptional("compatibility-version", Keys->CompatibilityVersion, 1064 PackedVersion(1, 0, 0)); 1065 IO.mapOptional("swift-abi-version", Keys->SwiftABIVersion, SwiftVersion(0)); 1066 IO.mapOptional("parent-umbrella", Keys->ParentUmbrellas); 1067 auto OptionKind = MetadataSection::Option::Clients; 1068 IO.mapOptionalWithContext("allowable-clients", Keys->AllowableClients, 1069 OptionKind); 1070 OptionKind = MetadataSection::Option::Libraries; 1071 IO.mapOptionalWithContext("reexported-libraries", Keys->ReexportedLibraries, 1072 OptionKind); 1073 IO.mapOptional("exports", Keys->Exports); 1074 IO.mapOptional("reexports", Keys->Reexports); 1075 IO.mapOptional("undefineds", Keys->Undefineds); 1076 } 1077 }; 1078 1079 template <> 1080 struct DocumentListTraits<std::vector<const MachO::InterfaceFile *>> { 1081 static size_t size(IO &IO, std::vector<const MachO::InterfaceFile *> &Seq) { 1082 return Seq.size(); 1083 } 1084 static const InterfaceFile *& 1085 element(IO &IO, std::vector<const InterfaceFile *> &Seq, size_t Index) { 1086 if (Index >= Seq.size()) 1087 Seq.resize(Index + 1); 1088 return Seq[Index]; 1089 } 1090 }; 1091 1092 } // end namespace yaml. 1093 } // namespace llvm 1094 1095 static void DiagHandler(const SMDiagnostic &Diag, void *Context) { 1096 auto *File = static_cast<TextAPIContext *>(Context); 1097 SmallString<1024> Message; 1098 raw_svector_ostream S(Message); 1099 1100 SMDiagnostic NewDiag(*Diag.getSourceMgr(), Diag.getLoc(), File->Path, 1101 Diag.getLineNo(), Diag.getColumnNo(), Diag.getKind(), 1102 Diag.getMessage(), Diag.getLineContents(), 1103 Diag.getRanges(), Diag.getFixIts()); 1104 1105 NewDiag.print(nullptr, S); 1106 File->ErrorMessage = ("malformed file\n" + Message).str(); 1107 } 1108 1109 Expected<std::unique_ptr<InterfaceFile>> 1110 TextAPIReader::get(MemoryBufferRef InputBuffer) { 1111 TextAPIContext Ctx; 1112 Ctx.Path = std::string(InputBuffer.getBufferIdentifier()); 1113 yaml::Input YAMLIn(InputBuffer.getBuffer(), &Ctx, DiagHandler, &Ctx); 1114 1115 // Fill vector with interface file objects created by parsing the YAML file. 1116 std::vector<const InterfaceFile *> Files; 1117 YAMLIn >> Files; 1118 1119 // YAMLIn dynamically allocates for Interface file and in case of error, 1120 // memory leak will occur unless wrapped around unique_ptr 1121 auto File = std::unique_ptr<InterfaceFile>( 1122 const_cast<InterfaceFile *>(Files.front())); 1123 1124 for (auto Iter = std::next(Files.begin()); Iter != Files.end(); ++Iter) 1125 File->addDocument( 1126 std::shared_ptr<InterfaceFile>(const_cast<InterfaceFile *>(*Iter))); 1127 1128 if (YAMLIn.error()) 1129 return make_error<StringError>(Ctx.ErrorMessage, YAMLIn.error()); 1130 1131 return std::move(File); 1132 } 1133 1134 Error TextAPIWriter::writeToStream(raw_ostream &OS, const InterfaceFile &File) { 1135 TextAPIContext Ctx; 1136 Ctx.Path = std::string(File.getPath()); 1137 Ctx.FileKind = File.getFileType(); 1138 llvm::yaml::Output YAMLOut(OS, &Ctx, /*WrapColumn=*/80); 1139 1140 std::vector<const InterfaceFile *> Files; 1141 Files.emplace_back(&File); 1142 1143 for (auto Document : File.documents()) 1144 Files.emplace_back(Document.get()); 1145 1146 // Stream out yaml. 1147 YAMLOut << Files; 1148 1149 return Error::success(); 1150 } 1151