LLVM 17.0.0git
TextStubV5.cpp
Go to the documentation of this file.
1//===- TextStubV5.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 Text Stub JSON mappings.
10//
11//===----------------------------------------------------------------------===//
12#include "TextStubCommon.h"
14#include "llvm/Support/JSON.h"
15#include <utility>
16
17// clang-format off
18/*
19
20JSON Format specification.
21
22All library level keys, accept target values and are defaulted if not specified.
23
24{
25"tapi_tbd_version": 5, # Required: TBD version for all documents in file
26"main_library": { # Required: top level library
27 "target_info": [ # Required: target information
28 {
29 "target": "x86_64-macos",
30 "min_deployment": "10.14" # Required: minimum OS deployment version
31 },
32 {
33 "target": "arm64-macos",
34 "min_deployment": "10.14"
35 },
36 {
37 "target": "arm64-maccatalyst",
38 "min_deployment": "12.1"
39 }],
40 "flags":[{"attributes": ["flat_namespace"]}], # Optional:
41 "install_names":[{"name":"/S/L/F/Foo.fwk/Foo"}], # Required: library install name
42 "current_versions":[{"version": "1.2"}], # Optional: defaults to 1
43 "compatibility_versions":[{ "version": "1.1"}], # Optional: defaults to 1
44 "rpaths": [ # Optional:
45 {
46 "targets": ["x86_64-macos"], # Optional: defaults to targets in `target-info`
47 "paths": ["@executable_path/.../Frameworks"]
48 }],
49 "parent_umbrellas": [{"umbrella": "System"}],
50 "allowable_clients": [{"clients": ["ClientA"]}],
51 "reexported_libraries": [{"names": ["/u/l/l/foo.dylib"]}],
52 "exported_symbols": [{ # List of export symbols section
53 "targets": ["x86_64-macos", "arm64-macos"], # Optional: defaults to targets in `target-info`
54 "text": { # List of Text segment symbols
55 "global": [ "_func" ],
56 "weak": [],
57 "thread_local": []
58 },
59 "data": { ... }, # List of Data segment symbols
60 }],
61 "reexported_symbols": [{ ... }], # List of reexported symbols section
62 "undefined_symbols": [{ ... }] # List of undefined symbols section
63},
64"libraries": [ # Optional: Array of inlined libraries
65 {...}, {...}, {...}
66]
67}
68*/
69// clang-format on
70
71using namespace llvm;
72using namespace llvm::json;
73using namespace llvm::MachO;
74
75struct JSONSymbol {
77 std::string Name;
79};
80
81using AttrToTargets = std::map<std::string, TargetList>;
84
85enum TBDKey : size_t {
121};
122
123std::array<StringRef, 64> Keys = {
124 "tapi_tbd_version",
125 "main_library",
126 "libraries",
127 "target_info",
128 "targets",
129 "target",
130 "min_deployment",
131 "flags",
132 "attributes",
133 "install_names",
134 "current_versions",
135 "compatibility_versions",
136 "version",
137 "swift_abi",
138 "abi",
139 "parent_umbrellas",
140 "umbrella",
141 "allowable_clients",
142 "clients",
143 "reexported_libraries",
144 "names",
145 "name",
146 "exported_symbols",
147 "reexported_symbols",
148 "undefined_symbols",
149 "data",
150 "text",
151 "weak",
152 "thread_local",
153 "global",
154 "objc_class",
155 "objc_eh_type",
156 "objc_ivar",
157 "rpaths",
158 "paths",
159};
160
162 return {"invalid ", Keys[Key], " section"};
163}
164
166 return {"missing ", Keys[Key], " information"};
167}
168
169class JSONStubError : public llvm::ErrorInfo<llvm::json::ParseError> {
170public:
171 JSONStubError(Twine ErrMsg) : Message(ErrMsg.str()) {}
172
173 void log(llvm::raw_ostream &OS) const override { OS << Message << "\n"; }
174 std::error_code convertToErrorCode() const override {
176 }
177
178private:
179 std::string Message;
180};
181
182template <typename JsonT, typename StubT = JsonT>
184 TBDKey Key, const Object *Obj,
185 std::function<std::optional<JsonT>(const Object *, StringRef)> GetValue,
186 std::function<std::optional<StubT>(JsonT)> Validate = nullptr) {
187 std::optional<JsonT> Val = GetValue(Obj, Keys[Key]);
188 if (!Val)
189 return make_error<JSONStubError>(getParseErrorMsg(Key));
190
191 if (Validate == nullptr)
192 return static_cast<StubT>(*Val);
193
194 std::optional<StubT> Result = Validate(*Val);
195 if (!Result.has_value())
196 return make_error<JSONStubError>(getParseErrorMsg(Key));
197 return Result.value();
198}
199
200template <typename JsonT, typename StubT = JsonT>
202 TBDKey Key, const Object *Obj,
203 std::function<std::optional<JsonT>(const Object *, StringRef)> GetValue,
204 StubT DefaultValue, std::function<std::optional<StubT>(JsonT)> Validate) {
205 std::optional<JsonT> Val = GetValue(Obj, Keys[Key]);
206 if (!Val)
207 return DefaultValue;
208
209 std::optional<StubT> Result;
210 Result = Validate(*Val);
211 if (!Result.has_value())
212 return make_error<JSONStubError>(getParseErrorMsg(Key));
213 return Result.value();
214}
215
217 std::function<void(StringRef)> Append,
218 bool IsRequired = false) {
219 const auto *Values = Obj->getArray(Keys[Key]);
220 if (!Values) {
221 if (IsRequired)
222 return make_error<JSONStubError>(getParseErrorMsg(Key));
223 return Error::success();
224 }
225
226 for (const Value &Val : *Values) {
227 auto ValStr = Val.getAsString();
228 if (!ValStr.has_value())
229 return make_error<JSONStubError>(getParseErrorMsg(Key));
230 Append(ValStr.value());
231 }
232
233 return Error::success();
234}
235
236namespace StubParser {
237
239 auto VersionOrErr = getRequiredValue<int64_t, FileType>(
240 TBDKey::TBDVersion, File, &Object::getInteger,
241 [](int64_t Val) -> std::optional<FileType> {
242 unsigned Result = Val;
243 if (Result != 5)
244 return std::nullopt;
245 return FileType::TBD_V5;
246 });
247
248 if (!VersionOrErr)
249 return VersionOrErr.takeError();
250 return *VersionOrErr;
251}
252
254 const auto *Targets = Section->getArray(Keys[TBDKey::Targets]);
255 if (!Targets)
256 return make_error<JSONStubError>(getParseErrorMsg(TBDKey::Targets));
257
258 TargetList IFTargets;
259 for (const Value &JSONTarget : *Targets) {
260 auto TargetStr = JSONTarget.getAsString();
261 if (!TargetStr.has_value())
262 return make_error<JSONStubError>(getParseErrorMsg(TBDKey::Target));
263 auto TargetOrErr = Target::create(TargetStr.value());
264 if (!TargetOrErr)
265 return make_error<JSONStubError>(getParseErrorMsg(TBDKey::Target));
266 IFTargets.push_back(*TargetOrErr);
267 }
268 return std::move(IFTargets);
269}
270
272 const Array *Targets = Section->getArray(Keys[TBDKey::TargetInfo]);
273 if (!Targets)
274 return make_error<JSONStubError>(getParseErrorMsg(TBDKey::Targets));
275
276 TargetList IFTargets;
277 for (const Value &JSONTarget : *Targets) {
278 const auto *Obj = JSONTarget.getAsObject();
279 if (!Obj)
280 return make_error<JSONStubError>(getParseErrorMsg(TBDKey::Target));
281 auto TargetStr =
282 getRequiredValue<StringRef>(TBDKey::Target, Obj, &Object::getString);
283 if (!TargetStr)
284 return make_error<JSONStubError>(getParseErrorMsg(TBDKey::Target));
285 auto VersionStr = getRequiredValue<StringRef>(TBDKey::Deployment, Obj,
287 if (!VersionStr)
288 return make_error<JSONStubError>(getParseErrorMsg(TBDKey::Deployment));
289 VersionTuple Version;
290 if (Version.tryParse(*VersionStr))
291 return make_error<JSONStubError>(getParseErrorMsg(TBDKey::Deployment));
292 auto TargetOrErr = Target::create(*TargetStr);
293 if (!TargetOrErr)
294 return make_error<JSONStubError>(getParseErrorMsg(TBDKey::Target));
295 TargetOrErr->MinDeployment = Version;
296 // Convert to LLVM::Triple to accurately compute minOS + platform + arch
297 // pairing.
298 IFTargets.push_back(
300 }
301 return std::move(IFTargets);
302}
303
305 SymbolFlags SectionFlag) {
306 auto Err = collectFromArray(
307 TBDKey::Globals, Segment, [&Result, &SectionFlag](StringRef Name) {
308 JSONSymbol Sym = {SymbolKind::GlobalSymbol, Name.str(), SectionFlag};
309 Result.back().second.emplace_back(Sym);
310 });
311 if (Err)
312 return Err;
313
314 Err = collectFromArray(
315 TBDKey::ObjCClass, Segment, [&Result, &SectionFlag](StringRef Name) {
316 JSONSymbol Sym = {SymbolKind::ObjectiveCClass, Name.str(), SectionFlag};
317 Result.back().second.emplace_back(Sym);
318 });
319 if (Err)
320 return Err;
321
322 Err = collectFromArray(TBDKey::ObjCEHType, Segment,
323 [&Result, &SectionFlag](StringRef Name) {
324 JSONSymbol Sym = {SymbolKind::ObjectiveCClassEHType,
325 Name.str(), SectionFlag};
326 Result.back().second.emplace_back(Sym);
327 });
328 if (Err)
329 return Err;
330
331 Err = collectFromArray(
332 TBDKey::ObjCIvar, Segment, [&Result, &SectionFlag](StringRef Name) {
333 JSONSymbol Sym = {SymbolKind::ObjectiveCInstanceVariable, Name.str(),
334 SectionFlag};
335 Result.back().second.emplace_back(Sym);
336 });
337 if (Err)
338 return Err;
339
340 SymbolFlags WeakFlag =
341 SectionFlag |
342 (((SectionFlag & SymbolFlags::Undefined) == SymbolFlags::Undefined)
343 ? SymbolFlags::WeakReferenced
344 : SymbolFlags::WeakDefined);
345 Err = collectFromArray(
346 TBDKey::Weak, Segment, [&Result, WeakFlag](StringRef Name) {
347 JSONSymbol Sym = {SymbolKind::GlobalSymbol, Name.str(), WeakFlag};
348 Result.back().second.emplace_back(Sym);
349 });
350 if (Err)
351 return Err;
352
353 Err = collectFromArray(
354 TBDKey::ThreadLocal, Segment, [&Result, SectionFlag](StringRef Name) {
355 JSONSymbol Sym = {SymbolKind::GlobalSymbol, Name.str(),
356 SymbolFlags::ThreadLocalValue | SectionFlag};
357 Result.back().second.emplace_back(Sym);
358 });
359 if (Err)
360 return Err;
361
362 return Error::success();
363}
364
366 const Array *Section = File->getArray(Keys[TBDKey::InstallName]);
367 if (!Section)
368 return make_error<JSONStubError>(getParseErrorMsg(TBDKey::InstallName));
369
370 assert(!Section->empty() && "unexpected missing install name");
371 // TODO: Just take first for now.
372 const auto *Obj = Section->front().getAsObject();
373 if (!Obj)
374 return make_error<JSONStubError>(getParseErrorMsg(TBDKey::InstallName));
375
376 return getRequiredValue<StringRef>(TBDKey::Name, Obj, &Object::getString);
377}
378
381
382 const Array *Section = File->getArray(Keys[Key]);
383 if (!Section)
384 return TargetsToSymbols();
385
386 SymbolFlags SectionFlag;
387 switch (Key) {
388 case TBDKey::Reexports:
389 SectionFlag = SymbolFlags::Rexported;
390 break;
391 case TBDKey::Undefineds:
392 SectionFlag = SymbolFlags::Undefined;
393 break;
394 default:
395 SectionFlag = SymbolFlags::None;
396 break;
397 };
398
399 TargetsToSymbols Result;
400 TargetList MappedTargets;
401 for (auto Val : *Section) {
402 auto *Obj = Val.getAsObject();
403 if (!Obj)
404 continue;
405
406 auto TargetsOrErr = getTargets(Obj);
407 if (!TargetsOrErr) {
408 MappedTargets = Targets;
409 consumeError(TargetsOrErr.takeError());
410 } else {
411 MappedTargets = *TargetsOrErr;
412 }
413 Result.emplace_back(
414 std::make_pair(std::move(MappedTargets), std::vector<JSONSymbol>()));
415
416 auto *DataSection = Obj->getObject(Keys[TBDKey::Data]);
417 auto *TextSection = Obj->getObject(Keys[TBDKey::Text]);
418 // There should be at least one valid section.
419 if (!DataSection && !TextSection)
420 return make_error<JSONStubError>(getParseErrorMsg(Key));
421
422 if (DataSection) {
423 auto Err = collectSymbolsFromSegment(DataSection, Result,
424 SectionFlag | SymbolFlags::Data);
425 if (Err)
426 return std::move(Err);
427 }
428 if (TextSection) {
429 auto Err = collectSymbolsFromSegment(TextSection, Result,
430 SectionFlag | SymbolFlags::Text);
431 if (Err)
432 return std::move(Err);
433 }
434 }
435
436 return std::move(Result);
437}
438
440 TBDKey SubKey,
441 const TargetList &Targets) {
442 auto *Section = File->getArray(Keys[Key]);
443 if (!Section)
444 return AttrToTargets();
445
446 AttrToTargets Result;
447 TargetList MappedTargets;
448 for (auto Val : *Section) {
449 auto *Obj = Val.getAsObject();
450 if (!Obj)
451 continue;
452
453 auto TargetsOrErr = getTargets(Obj);
454 if (!TargetsOrErr) {
455 MappedTargets = Targets;
456 consumeError(TargetsOrErr.takeError());
457 } else {
458 MappedTargets = *TargetsOrErr;
459 }
460 auto Err =
461 collectFromArray(SubKey, Obj, [&Result, &MappedTargets](StringRef Key) {
462 Result[Key.str()] = MappedTargets;
463 });
464 if (Err)
465 return std::move(Err);
466 }
467
468 return std::move(Result);
469}
470
472 const TargetList &Targets) {
473 const auto *Umbrella = File->getArray(Keys[TBDKey::ParentUmbrella]);
474 if (!Umbrella)
475 return AttrToTargets();
476
477 AttrToTargets Result;
478 TargetList MappedTargets;
479 for (auto Val : *Umbrella) {
480 auto *Obj = Val.getAsObject();
481 if (!Obj)
482 return make_error<JSONStubError>(
483 getParseErrorMsg(TBDKey::ParentUmbrella));
484
485 // Get Targets section.
486 auto TargetsOrErr = getTargets(Obj);
487 if (!TargetsOrErr) {
488 MappedTargets = Targets;
489 consumeError(TargetsOrErr.takeError());
490 } else {
491 MappedTargets = *TargetsOrErr;
492 }
493
494 auto UmbrellaOrErr =
495 getRequiredValue<StringRef>(TBDKey::Umbrella, Obj, &Object::getString);
496 if (!UmbrellaOrErr)
497 return UmbrellaOrErr.takeError();
498 Result[UmbrellaOrErr->str()] = Targets;
499 }
500 return std::move(Result);
501}
502
504 const Array *Versions = File->getArray(Keys[TBDKey::SwiftABI]);
505 if (!Versions)
506 return 0;
507
508 for (const auto &Val : *Versions) {
509 const auto *Obj = Val.getAsObject();
510 if (!Obj)
511 return make_error<JSONStubError>(getParseErrorMsg(TBDKey::SwiftABI));
512
513 // TODO: Take first for now.
514 return getRequiredValue<int64_t, uint8_t>(TBDKey::ABI, Obj,
516 }
517
518 return 0;
519}
520
522 const Array *Versions = File->getArray(Keys[Key]);
523 if (!Versions)
524 return PackedVersion(1, 0, 0);
525
526 for (const auto &Val : *Versions) {
527 const auto *Obj = Val.getAsObject();
528 if (!Obj)
529 return make_error<JSONStubError>(getParseErrorMsg(Key));
530
531 auto ValidatePV = [](StringRef Version) -> std::optional<PackedVersion> {
532 PackedVersion PV;
533 auto [success, truncated] = PV.parse64(Version);
534 if (!success || truncated)
535 return std::nullopt;
536 return PV;
537 };
538 // TODO: Take first for now.
539 return getRequiredValue<StringRef, PackedVersion>(
540 TBDKey::Version, Obj, &Object::getString, PackedVersion(1, 0, 0),
541 ValidatePV);
542 }
543
544 return PackedVersion(1, 0, 0);
545}
546
548 TBDFlags Flags = TBDFlags::None;
549 const Array *Section = File->getArray(Keys[TBDKey::Flags]);
550 if (!Section)
551 return Flags;
552
553 for (auto &Val : *Section) {
554 // TODO: Just take first for now.
555 const auto *Obj = Val.getAsObject();
556 if (!Obj)
557 return make_error<JSONStubError>(getParseErrorMsg(TBDKey::Flags));
558
559 auto FlagsOrErr =
560 collectFromArray(TBDKey::Attributes, Obj, [&Flags](StringRef Flag) {
561 TBDFlags TBDFlag =
563 .Case("flat_namespace", TBDFlags::FlatNamespace)
564 .Case("not_app_extension_safe",
565 TBDFlags::NotApplicationExtensionSafe)
566 .Default(TBDFlags::None);
567 Flags |= TBDFlag;
568 });
569
570 if (FlagsOrErr)
571 return std::move(FlagsOrErr);
572
573 return Flags;
574 }
575
576 return Flags;
577}
578
579using IFPtr = std::unique_ptr<InterfaceFile>;
581 auto TargetsOrErr = getTargetsSection(File);
582 if (!TargetsOrErr)
583 return TargetsOrErr.takeError();
584 TargetList Targets = *TargetsOrErr;
585
586 auto NameOrErr = getNameSection(File);
587 if (!NameOrErr)
588 return NameOrErr.takeError();
589 StringRef Name = *NameOrErr;
590
591 auto CurrVersionOrErr = getPackedVersion(File, TBDKey::CurrentVersion);
592 if (!CurrVersionOrErr)
593 return CurrVersionOrErr.takeError();
594 PackedVersion CurrVersion = *CurrVersionOrErr;
595
596 auto CompVersionOrErr = getPackedVersion(File, TBDKey::CompatibilityVersion);
597 if (!CompVersionOrErr)
598 return CompVersionOrErr.takeError();
599 PackedVersion CompVersion = *CompVersionOrErr;
600
601 auto SwiftABIOrErr = getSwiftVersion(File);
602 if (!SwiftABIOrErr)
603 return SwiftABIOrErr.takeError();
604 uint8_t SwiftABI = *SwiftABIOrErr;
605
606 auto FlagsOrErr = getFlags(File);
607 if (!FlagsOrErr)
608 return FlagsOrErr.takeError();
609 TBDFlags Flags = *FlagsOrErr;
610
611 auto UmbrellasOrErr = getUmbrellaSection(File, Targets);
612 if (!UmbrellasOrErr)
613 return UmbrellasOrErr.takeError();
614 AttrToTargets Umbrellas = *UmbrellasOrErr;
615
616 auto ClientsOrErr =
617 getLibSection(File, TBDKey::AllowableClients, TBDKey::Clients, Targets);
618 if (!ClientsOrErr)
619 return ClientsOrErr.takeError();
620 AttrToTargets Clients = *ClientsOrErr;
621
622 auto RLOrErr =
623 getLibSection(File, TBDKey::ReexportLibs, TBDKey::Names, Targets);
624 if (!RLOrErr)
625 return RLOrErr.takeError();
626 AttrToTargets ReexportLibs = std::move(*RLOrErr);
627
628 auto RPathsOrErr = getLibSection(File, TBDKey::RPath, TBDKey::Paths, Targets);
629 if (!RPathsOrErr)
630 return RPathsOrErr.takeError();
631 AttrToTargets RPaths = std::move(*RPathsOrErr);
632
633 auto ExportsOrErr = getSymbolSection(File, TBDKey::Exports, Targets);
634 if (!ExportsOrErr)
635 return ExportsOrErr.takeError();
636 TargetsToSymbols Exports = std::move(*ExportsOrErr);
637
638 auto ReexportsOrErr = getSymbolSection(File, TBDKey::Reexports, Targets);
639 if (!ReexportsOrErr)
640 return ReexportsOrErr.takeError();
641 TargetsToSymbols Reexports = std::move(*ReexportsOrErr);
642
643 auto UndefinedsOrErr = getSymbolSection(File, TBDKey::Undefineds, Targets);
644 if (!UndefinedsOrErr)
645 return UndefinedsOrErr.takeError();
646 TargetsToSymbols Undefineds = std::move(*UndefinedsOrErr);
647
648 IFPtr F(new InterfaceFile);
649 F->setInstallName(Name);
650 F->setCurrentVersion(CurrVersion);
651 F->setCompatibilityVersion(CompVersion);
652 F->setSwiftABIVersion(SwiftABI);
653 F->setTwoLevelNamespace(!(Flags & TBDFlags::FlatNamespace));
654 F->setApplicationExtensionSafe(
655 !(Flags & TBDFlags::NotApplicationExtensionSafe));
656 for (auto &T : Targets)
657 F->addTarget(T);
658 for (auto &[Lib, Targets] : Clients)
659 for (auto Target : Targets)
660 F->addAllowableClient(Lib, Target);
661 for (auto &[Lib, Targets] : ReexportLibs)
662 for (auto Target : Targets)
663 F->addReexportedLibrary(Lib, Target);
664 for (auto &[Lib, Targets] : Umbrellas)
665 for (auto Target : Targets)
666 F->addParentUmbrella(Target, Lib);
667 for (auto &[Path, Targets] : RPaths)
668 for (auto Target : Targets)
669 F->addRPath(Target, Path);
670 for (auto &[Targets, Symbols] : Exports)
671 for (auto &Sym : Symbols)
672 F->addSymbol(Sym.Kind, Sym.Name, Targets, Sym.Flags);
673 for (auto &[Targets, Symbols] : Reexports)
674 for (auto &Sym : Symbols)
675 F->addSymbol(Sym.Kind, Sym.Name, Targets, Sym.Flags);
676 for (auto &[Targets, Symbols] : Undefineds)
677 for (auto &Sym : Symbols)
678 F->addSymbol(Sym.Kind, Sym.Name, Targets, Sym.Flags);
679
680 return std::move(F);
681}
682
684 std::vector<IFPtr> IFs;
685 const Array *Files = File->getArray(Keys[TBDKey::Documents]);
686 if (!Files)
687 return std::move(IFs);
688
689 for (auto Lib : *Files) {
690 auto IFOrErr = parseToInterfaceFile(Lib.getAsObject());
691 if (!IFOrErr)
692 return IFOrErr.takeError();
693 auto IF = std::move(*IFOrErr);
694 IFs.emplace_back(std::move(IF));
695 }
696 return std::move(IFs);
697}
698
699} // namespace StubParser
700
703 auto ValOrErr = parse(JSON);
704 if (!ValOrErr)
705 return ValOrErr.takeError();
706
707 auto *Root = ValOrErr->getAsObject();
708 auto VersionOrErr = StubParser::getVersion(Root);
709 if (!VersionOrErr)
710 return VersionOrErr.takeError();
711 FileType Version = *VersionOrErr;
712
713 Object *MainLib = Root->getObject(Keys[TBDKey::MainLibrary]);
714 auto IFOrErr = StubParser::parseToInterfaceFile(MainLib);
715 if (!IFOrErr)
716 return IFOrErr.takeError();
717 (*IFOrErr)->setFileType(Version);
718 std::unique_ptr<InterfaceFile> IF(std::move(*IFOrErr));
719
720 auto IFsOrErr = StubParser::getInlinedLibs(Root);
721 if (!IFsOrErr)
722 return IFsOrErr.takeError();
723 for (auto &File : *IFsOrErr) {
724 File->setFileType(Version);
725 IF->addDocument(std::shared_ptr<InterfaceFile>(std::move(File)));
726 }
727 return std::move(IF);
728}
729
730namespace {
731
732template <typename ContainerT = Array>
733bool insertNonEmptyValues(Object &Obj, TBDKey Key, ContainerT &&Contents) {
734 if (Contents.empty())
735 return false;
736 Obj[Keys[Key]] = std::move(Contents);
737 return true;
738}
739
740std::string getFormattedStr(const MachO::Target &Targ) {
741 std::string PlatformStr = Targ.Platform == PLATFORM_MACCATALYST
742 ? "maccatalyst"
744 return (getArchitectureName(Targ.Arch) + "-" + PlatformStr).str();
745}
746
747template <typename AggregateT>
748std::vector<std::string> serializeTargets(const AggregateT Targets,
749 const TargetList &ActiveTargets) {
750 std::vector<std::string> TargetsStr;
751 if (Targets.size() == ActiveTargets.size())
752 return TargetsStr;
753
754 llvm::for_each(Targets, [&TargetsStr](const MachO::Target &Target) {
755 TargetsStr.emplace_back(getFormattedStr(Target));
756 });
757 return TargetsStr;
758}
759
760Array serializeTargetInfo(const TargetList &ActiveTargets) {
762 for (const auto Targ : ActiveTargets) {
765 TargetInfo[Keys[TBDKey::Target]] = getFormattedStr(Targ);
766 Targets.emplace_back(std::move(TargetInfo));
767 }
768 return Targets;
769}
770
771template <typename ValueT, typename EntryT = ValueT>
772Array serializeScalar(TBDKey Key, ValueT Value, ValueT Default = ValueT()) {
773 if (Value == Default)
774 return {};
775 Array Container;
776 Object ScalarObj({Object::KV({Keys[Key], EntryT(Value)})});
777
778 Container.emplace_back(std::move(ScalarObj));
779 return Container;
780}
781
782using TargetsToValuesMap =
783 std::map<std::vector<std::string>, std::vector<std::string>>;
784
785template <typename AggregateT = TargetsToValuesMap>
786Array serializeAttrToTargets(AggregateT &Entries, TBDKey Key) {
787 Array Container;
788 for (const auto &[Targets, Values] : Entries) {
789 Object Obj;
790 insertNonEmptyValues(Obj, TBDKey::Targets, std::move(Targets));
791 Obj[Keys[Key]] = Values;
792 Container.emplace_back(std::move(Obj));
793 }
794 return Container;
795}
796
797template <typename ValueT = std::string,
798 typename AggregateT = std::vector<std::pair<MachO::Target, ValueT>>>
799Array serializeField(TBDKey Key, const AggregateT &Values,
800 const TargetList &ActiveTargets, bool IsArray = true) {
801 std::map<ValueT, std::set<MachO::Target>> Entries;
802 for (const auto &[Target, Val] : Values)
803 Entries[Val].insert(Target);
804
805 if (!IsArray) {
806 std::map<std::vector<std::string>, std::string> FinalEntries;
807 for (const auto &[Val, Targets] : Entries)
808 FinalEntries[serializeTargets(Targets, ActiveTargets)] = Val;
809 return serializeAttrToTargets(FinalEntries, Key);
810 }
811
812 TargetsToValuesMap FinalEntries;
813 for (const auto &[Val, Targets] : Entries)
814 FinalEntries[serializeTargets(Targets, ActiveTargets)].emplace_back(Val);
815 return serializeAttrToTargets(FinalEntries, Key);
816}
817
818Array serializeField(TBDKey Key, const std::vector<InterfaceFileRef> &Values,
819 const TargetList &ActiveTargets) {
820 TargetsToValuesMap FinalEntries;
821 for (const auto &Ref : Values) {
822 TargetList Targets{Ref.targets().begin(), Ref.targets().end()};
823 FinalEntries[serializeTargets(Targets, ActiveTargets)].emplace_back(
824 Ref.getInstallName());
825 }
826 return serializeAttrToTargets(FinalEntries, Key);
827}
828
829struct SymbolFields {
830 struct SymbolTypes {
831 std::vector<StringRef> Weaks;
832 std::vector<StringRef> Globals;
833 std::vector<StringRef> TLV;
834 std::vector<StringRef> ObjCClasses;
835 std::vector<StringRef> IVars;
836 std::vector<StringRef> EHTypes;
837
838 bool empty() const {
839 return Weaks.empty() && Globals.empty() && TLV.empty() &&
840 ObjCClasses.empty() && IVars.empty() && EHTypes.empty();
841 }
842 };
843 SymbolTypes Data;
844 SymbolTypes Text;
845};
846
848 const TargetList &ActiveTargets) {
849 auto AssignForSymbolType = [](SymbolFields::SymbolTypes &Assignment,
850 const Symbol *Sym) {
851 switch (Sym->getKind()) {
852 case SymbolKind::ObjectiveCClass:
853 Assignment.ObjCClasses.emplace_back(Sym->getName());
854 return;
855 case SymbolKind::ObjectiveCClassEHType:
856 Assignment.EHTypes.emplace_back(Sym->getName());
857 return;
858 case SymbolKind::ObjectiveCInstanceVariable:
859 Assignment.IVars.emplace_back(Sym->getName());
860 return;
861 case SymbolKind::GlobalSymbol: {
863 Assignment.Weaks.emplace_back(Sym->getName());
864 else if (Sym->isThreadLocalValue())
865 Assignment.TLV.emplace_back(Sym->getName());
866 else
867 Assignment.Globals.emplace_back(Sym->getName());
868 return;
869 }
870 }
871 };
872
873 std::map<std::vector<std::string>, SymbolFields> Entries;
874 for (const auto *Sym : Symbols) {
875 std::set<MachO::Target> Targets{Sym->targets().begin(),
876 Sym->targets().end()};
877 auto JSONTargets = serializeTargets(Targets, ActiveTargets);
878 if (Sym->isData())
879 AssignForSymbolType(Entries[std::move(JSONTargets)].Data, Sym);
880 else if (Sym->isText())
881 AssignForSymbolType(Entries[std::move(JSONTargets)].Text, Sym);
882 else
883 llvm_unreachable("unexpected symbol type");
884 }
885
886 auto InsertSymbolsToJSON = [](Object &SymSection, TBDKey SegmentKey,
887 SymbolFields::SymbolTypes &SymField) {
888 if (SymField.empty())
889 return;
890 Object Segment;
891 insertNonEmptyValues(Segment, TBDKey::Globals, std::move(SymField.Globals));
892 insertNonEmptyValues(Segment, TBDKey::ThreadLocal, std::move(SymField.TLV));
893 insertNonEmptyValues(Segment, TBDKey::Weak, std::move(SymField.Weaks));
894 insertNonEmptyValues(Segment, TBDKey::ObjCClass,
895 std::move(SymField.ObjCClasses));
896 insertNonEmptyValues(Segment, TBDKey::ObjCEHType,
897 std::move(SymField.EHTypes));
898 insertNonEmptyValues(Segment, TBDKey::ObjCIvar, std::move(SymField.IVars));
899 insertNonEmptyValues(SymSection, SegmentKey, std::move(Segment));
900 };
901
902 Array SymbolSection;
903 for (auto &[Targets, Fields] : Entries) {
904 Object AllSyms;
905 insertNonEmptyValues(AllSyms, TBDKey::Targets, std::move(Targets));
906 InsertSymbolsToJSON(AllSyms, TBDKey::Data, Fields.Data);
907 InsertSymbolsToJSON(AllSyms, TBDKey::Text, Fields.Text);
908 SymbolSection.emplace_back(std::move(AllSyms));
909 }
910
911 return SymbolSection;
912}
913
914Array serializeFlags(const InterfaceFile *File) {
915 // TODO: Give all Targets the same flags for now.
916 Array Flags;
917 if (!File->isTwoLevelNamespace())
918 Flags.emplace_back("flat_namespace");
919 if (!File->isApplicationExtensionSafe())
920 Flags.emplace_back("not_app_extension_safe");
921 return serializeScalar(TBDKey::Attributes, std::move(Flags));
922}
923
924Expected<Object> serializeIF(const InterfaceFile *File) {
925 Object Library;
926
927 // Handle required keys.
928 TargetList ActiveTargets{File->targets().begin(), File->targets().end()};
929 if (!insertNonEmptyValues(Library, TBDKey::TargetInfo,
930 serializeTargetInfo(ActiveTargets)))
931 return make_error<JSONStubError>(getSerializeErrorMsg(TBDKey::TargetInfo));
932
933 Array Name = serializeScalar<StringRef>(TBDKey::Name, File->getInstallName());
934 if (!insertNonEmptyValues(Library, TBDKey::InstallName, std::move(Name)))
935 return make_error<JSONStubError>(getSerializeErrorMsg(TBDKey::InstallName));
936
937 // Handle optional keys.
938 Array Flags = serializeFlags(File);
939 insertNonEmptyValues(Library, TBDKey::Flags, std::move(Flags));
940
941 Array CurrentV = serializeScalar<PackedVersion, std::string>(
942 TBDKey::Version, File->getCurrentVersion(), PackedVersion(1, 0, 0));
943 insertNonEmptyValues(Library, TBDKey::CurrentVersion, std::move(CurrentV));
944
945 Array CompatV = serializeScalar<PackedVersion, std::string>(
946 TBDKey::Version, File->getCompatibilityVersion(), PackedVersion(1, 0, 0));
947 insertNonEmptyValues(Library, TBDKey::CompatibilityVersion,
948 std::move(CompatV));
949
950 Array SwiftABI = serializeScalar<uint8_t, int64_t>(
951 TBDKey::ABI, File->getSwiftABIVersion(), 0u);
952 insertNonEmptyValues(Library, TBDKey::SwiftABI, std::move(SwiftABI));
953
954 Array RPaths = serializeField(TBDKey::Paths, File->rpaths(), ActiveTargets);
955 insertNonEmptyValues(Library, TBDKey::RPath, std::move(RPaths));
956
957 Array Umbrellas = serializeField(TBDKey::Umbrella, File->umbrellas(),
958 ActiveTargets, /*IsArray=*/false);
959 insertNonEmptyValues(Library, TBDKey::ParentUmbrella, std::move(Umbrellas));
960
961 Array Clients =
962 serializeField(TBDKey::Clients, File->allowableClients(), ActiveTargets);
963 insertNonEmptyValues(Library, TBDKey::AllowableClients, std::move(Clients));
964
966 serializeField(TBDKey::Names, File->reexportedLibraries(), ActiveTargets);
967 insertNonEmptyValues(Library, TBDKey::ReexportLibs, std::move(ReexportLibs));
968
969 // Handle symbols.
970 Array Exports = serializeSymbols(File->exports(), ActiveTargets);
971 insertNonEmptyValues(Library, TBDKey::Exports, std::move(Exports));
972
973 Array Reexports = serializeSymbols(File->reexports(), ActiveTargets);
974 insertNonEmptyValues(Library, TBDKey::Reexports, std::move(Reexports));
975
976 if (!File->isTwoLevelNamespace()) {
977 Array Undefineds = serializeSymbols(File->undefineds(), ActiveTargets);
978 insertNonEmptyValues(Library, TBDKey::Undefineds, std::move(Undefineds));
979 }
980
981 return std::move(Library);
982}
983
984Expected<Object> getJSON(const InterfaceFile *File) {
985 assert(File->getFileType() == FileType::TBD_V5 &&
986 "unexpected json file format version");
987 Object Root;
988
989 auto MainLibOrErr = serializeIF(File);
990 if (!MainLibOrErr)
991 return MainLibOrErr;
992 Root[Keys[TBDKey::MainLibrary]] = std::move(*MainLibOrErr);
994 for (const auto &Doc : File->documents()) {
995 auto LibOrErr = serializeIF(Doc.get());
996 if (!LibOrErr)
997 return LibOrErr;
998 Documents.emplace_back(std::move(*LibOrErr));
999 }
1000
1001 Root[Keys[TBDKey::TBDVersion]] = 5;
1002 insertNonEmptyValues(Root, TBDKey::Documents, std::move(Documents));
1003 return std::move(Root);
1004}
1005
1006} // namespace
1007
1009 const InterfaceFile &File,
1010 bool Compact) {
1011 auto TextFile = getJSON(&File);
1012 if (!TextFile)
1013 return TextFile.takeError();
1014 if (Compact)
1015 OS << formatv("{0}", Value(std::move(*TextFile))) << "\n";
1016 else
1017 OS << formatv("{0:2}", Value(std::move(*TextFile))) << "\n";
1018 return Error::success();
1019}
@ Default
Definition: DwarfDebug.cpp:86
std::string Name
Symbol * Sym
Definition: ELF_riscv.cpp:463
This file supports working with JSON data.
#define F(x, y, z)
Definition: MD5.cpp:55
assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())
raw_pwrite_stream & OS
This file implements the StringSwitch template, which mimics a switch() statement whose cases are str...
TBDFlags
static llvm::SmallString< 128 > getSerializeErrorMsg(TBDKey Key)
Definition: TextStubV5.cpp:165
Error collectFromArray(TBDKey Key, const Object *Obj, std::function< void(StringRef)> Append, bool IsRequired=false)
Definition: TextStubV5.cpp:216
std::map< std::string, TargetList > AttrToTargets
Definition: TextStubV5.cpp:81
static llvm::SmallString< 128 > getParseErrorMsg(TBDKey Key)
Definition: TextStubV5.cpp:161
std::array< StringRef, 64 > Keys
Definition: TextStubV5.cpp:123
SmallVector< std::pair< TargetList, std::vector< JSONSymbol > > > TargetsToSymbols
Definition: TextStubV5.cpp:83
Expected< StubT > getRequiredValue(TBDKey Key, const Object *Obj, std::function< std::optional< JsonT >(const Object *, StringRef)> GetValue, std::function< std::optional< StubT >(JsonT)> Validate=nullptr)
Definition: TextStubV5.cpp:183
TBDKey
Definition: TextStubV5.cpp:85
@ Targets
Definition: TextStubV5.cpp:90
@ CurrentVersion
Definition: TextStubV5.cpp:96
@ Undefineds
Definition: TextStubV5.cpp:110
@ Globals
Definition: TextStubV5.cpp:115
@ ObjCClass
Definition: TextStubV5.cpp:116
@ InstallName
Definition: TextStubV5.cpp:95
@ AllowableClients
Definition: TextStubV5.cpp:103
@ Paths
Definition: TextStubV5.cpp:120
@ ObjCEHType
Definition: TextStubV5.cpp:117
@ Text
Definition: TextStubV5.cpp:112
@ TargetInfo
Definition: TextStubV5.cpp:89
@ Umbrella
Definition: TextStubV5.cpp:102
@ SwiftABI
Definition: TextStubV5.cpp:99
@ Target
Definition: TextStubV5.cpp:91
@ MainLibrary
Definition: TextStubV5.cpp:87
@ ObjCIvar
Definition: TextStubV5.cpp:118
@ Attributes
Definition: TextStubV5.cpp:94
@ TBDVersion
Definition: TextStubV5.cpp:86
@ CompatibilityVersion
Definition: TextStubV5.cpp:97
@ Exports
Definition: TextStubV5.cpp:108
@ Name
Definition: TextStubV5.cpp:107
@ Reexports
Definition: TextStubV5.cpp:109
@ Flags
Definition: TextStubV5.cpp:93
@ ReexportLibs
Definition: TextStubV5.cpp:105
@ Data
Definition: TextStubV5.cpp:111
@ RPath
Definition: TextStubV5.cpp:119
@ Version
Definition: TextStubV5.cpp:98
@ Weak
Definition: TextStubV5.cpp:113
@ Clients
Definition: TextStubV5.cpp:104
@ Deployment
Definition: TextStubV5.cpp:92
@ ParentUmbrella
Definition: TextStubV5.cpp:101
@ Documents
Definition: TextStubV5.cpp:88
@ ABI
Definition: TextStubV5.cpp:100
@ Names
Definition: TextStubV5.cpp:106
@ ThreadLocal
Definition: TextStubV5.cpp:114
std::error_code convertToErrorCode() const override
Convert this error to a std::error_code.
Definition: TextStubV5.cpp:174
void log(llvm::raw_ostream &OS) const override
Print an error message to an output stream.
Definition: TextStubV5.cpp:173
JSONStubError(Twine ErrMsg)
Definition: TextStubV5.cpp:171
Base class for user error types.
Definition: Error.h:348
Lightweight error class with error context and mandatory checking.
Definition: Error.h:156
static ErrorSuccess success()
Create a success value.
Definition: Error.h:330
Tagged union holding either a T or a Error.
Definition: Error.h:470
Defines the interface file.
std::pair< bool, bool > parse64(StringRef Str)
bool isData() const
Definition: Symbol.h:102
bool isWeakDefined() const
Definition: Symbol.h:81
const_target_range targets() const
Definition: Symbol.h:112
bool isThreadLocalValue() const
Definition: Symbol.h:89
SymbolKind getKind() const
Definition: Symbol.h:74
StringRef getName() const
Definition: Symbol.h:75
bool isText() const
Definition: Symbol.h:106
bool isWeakReferenced() const
Definition: Symbol.h:85
PlatformType Platform
Definition: Target.h:43
static llvm::Expected< Target > create(StringRef Target)
Definition: Target.cpp:17
Architecture Arch
Definition: Target.h:42
VersionTuple MinDeployment
Definition: Target.h:44
SmallString - A SmallString is just a SmallVector with methods and accessors that make it work better...
Definition: SmallString.h:26
size_t size() const
Definition: SmallVector.h:91
void push_back(const T &Elt)
Definition: SmallVector.h:416
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
Definition: SmallVector.h:1200
StringRef - Represent a constant reference to a string, i.e.
Definition: StringRef.h:50
A switch()-like statement whose cases are string literals.
Definition: StringSwitch.h:44
StringSwitch & Case(StringLiteral S, T Value)
Definition: StringSwitch.h:69
R Default(T Value)
Definition: StringSwitch.h:182
Target - Wrapper for Target specific information.
Triple - Helper class for working with autoconf configuration names.
Definition: Triple.h:44
Twine - A lightweight data structure for efficiently representing the concatenation of temporary valu...
Definition: Twine.h:81
LLVM Value Representation.
Definition: Value.h:74
Represents a version number in the form major[.minor[.subminor[.build]]].
Definition: VersionTuple.h:31
std::string getAsString() const
Retrieve a string representation of the version number.
A range adaptor for a pair of iterators.
IteratorT end() const
IteratorT begin() const
An Array is a JSON array, which contains heterogeneous JSON values.
Definition: JSON.h:163
void emplace_back(Args &&...A)
Definition: JSON.h:541
An Object is a JSON object, which maps strings to heterogenous JSON values.
Definition: JSON.h:97
const json::Object * getObject(StringRef K) const
Definition: JSON.cpp:66
std::optional< llvm::StringRef > getString(StringRef K) const
Definition: JSON.cpp:61
std::optional< int64_t > getInteger(StringRef K) const
Definition: JSON.cpp:56
const json::Array * getArray(StringRef K) const
Definition: JSON.cpp:76
A "cursor" marking a position within a Value.
Definition: JSON.h:640
This class implements an extremely fast bulk output stream that can only output to a stream.
Definition: raw_ostream.h:52
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
Expected< TargetsToSymbols > getSymbolSection(const Object *File, TBDKey Key, TargetList &Targets)
Definition: TextStubV5.cpp:379
std::unique_ptr< InterfaceFile > IFPtr
Definition: TextStubV5.cpp:579
Expected< TargetList > getTargetsSection(const Object *Section)
Definition: TextStubV5.cpp:271
Expected< IFPtr > parseToInterfaceFile(const Object *File)
Definition: TextStubV5.cpp:580
Expected< TBDFlags > getFlags(const Object *File)
Definition: TextStubV5.cpp:547
Expected< std::vector< IFPtr > > getInlinedLibs(const Object *File)
Definition: TextStubV5.cpp:683
Expected< FileType > getVersion(const Object *File)
Definition: TextStubV5.cpp:238
Error collectSymbolsFromSegment(const Object *Segment, TargetsToSymbols &Result, SymbolFlags SectionFlag)
Definition: TextStubV5.cpp:304
Expected< uint8_t > getSwiftVersion(const Object *File)
Definition: TextStubV5.cpp:503
Expected< TargetList > getTargets(const Object *Section)
Definition: TextStubV5.cpp:253
Expected< AttrToTargets > getUmbrellaSection(const Object *File, const TargetList &Targets)
Definition: TextStubV5.cpp:471
Expected< AttrToTargets > getLibSection(const Object *File, TBDKey Key, TBDKey SubKey, const TargetList &Targets)
Definition: TextStubV5.cpp:439
Expected< PackedVersion > getPackedVersion(const Object *File, TBDKey Key)
Definition: TextStubV5.cpp:521
Expected< StringRef > getNameSection(const Object *File)
Definition: TextStubV5.cpp:365
Key
PAL metadata keys.
std::string getTargetTripleName(const Target &Targ)
Definition: Target.cpp:82
FileType
Defines the file type this file represents.
Definition: InterfaceFile.h:53
StringRef getArchitectureName(Architecture Arch)
Convert an architecture slice to a string.
std::string getOSAndEnvironmentName(PlatformType Platform, std::string Version="")
Definition: Platform.cpp:106
@ PLATFORM_MACCATALYST
Definition: MachO.h:506
Error serializeInterfaceFileToJSON(raw_ostream &OS, const InterfaceFile &File, bool Compact)
Expected< std::unique_ptr< InterfaceFile > > getInterfaceFileFromJSON(StringRef JSON)
Definition: TextStubV5.cpp:702
SymbolFlags
Symbol flags.
Definition: Symbol.h:24
This is an optimization pass for GlobalISel generic memory operations.
Definition: AddressRanges.h:18
auto formatv(const char *Fmt, Ts &&... Vals) -> formatv_object< decltype(std::make_tuple(detail::build_format_adapter(std::forward< Ts >(Vals))...))>
UnaryFunction for_each(R &&Range, UnaryFunction F)
Provide wrappers to std::for_each which take ranges instead of having to pass begin/end explicitly.
Definition: STLExtras.h:1812
std::error_code inconvertibleErrorCode()
The value returned by this function can be returned from convertToErrorCode for Error values where no...
Definition: Error.cpp:79
@ Ref
The access may reference the value stored in memory.
void consumeError(Error Err)
Consume a Error without doing anything.
Definition: Error.h:1043
SymbolFlags Flags
Definition: TextStubV5.cpp:78
SymbolKind Kind
Definition: TextStubV5.cpp:76
std::string Name
Definition: TextStubV5.cpp:77
Definition: regcomp.c:192