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