1 //===- TextStubV5.cpp -----------------------------------------------------===//
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7 //===----------------------------------------------------------------------===//
9 // Implements Text Stub JSON mappings.
11 //===----------------------------------------------------------------------===//
12 #include "TextStubCommon.h"
13 #include "llvm/ADT/StringSwitch.h"
14 #include "llvm/Support/JSON.h"
20 JSON Format specification.
22 All library level keys, accept target values and are defaulted if not specified.
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
29 "target": "x86_64-macos",
30 "min_deployment": "10.14" # Optional: minOS defaults to 0
33 "target": "arm64-macos",
34 "min_deployment": "10.14"
37 "target": "arm64-maccatalyst",
38 "min_deployment": "12.1"
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:
46 "targets": ["x86_64-macos"], # Optional: defaults to targets in `target-info`
47 "paths": ["@executable_path/.../Frameworks"]
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" ],
59 "data": { ... }, # List of Data segment symbols
61 "reexported_symbols": [{ ... }], # List of reexported symbols section
62 "undefined_symbols": [{ ... }] # List of undefined symbols section
64 "libraries": [ # Optional: Array of inlined libraries
72 using namespace llvm::json
;
73 using namespace llvm::MachO
;
82 using AttrToTargets
= std::map
<std::string
, TargetList
>;
83 using TargetsToSymbols
=
84 SmallVector
<std::pair
<TargetList
, std::vector
<JSONSymbol
>>>;
86 enum TBDKey
: size_t {
124 std::array
<StringRef
, 64> Keys
= {
136 "compatibility_versions",
144 "reexported_libraries",
148 "reexported_symbols",
162 static llvm::SmallString
<128> getParseErrorMsg(TBDKey Key
) {
163 return {"invalid ", Keys
[Key
], " section"};
166 static llvm::SmallString
<128> getSerializeErrorMsg(TBDKey Key
) {
167 return {"missing ", Keys
[Key
], " information"};
170 class JSONStubError
: public llvm::ErrorInfo
<llvm::json::ParseError
> {
172 JSONStubError(Twine ErrMsg
) : Message(ErrMsg
.str()) {}
174 void log(llvm::raw_ostream
&OS
) const override
{ OS
<< Message
<< "\n"; }
175 std::error_code
convertToErrorCode() const override
{
176 return llvm::inconvertibleErrorCode();
183 template <typename JsonT
, typename StubT
= JsonT
>
184 Expected
<StubT
> getRequiredValue(
185 TBDKey Key
, const Object
*Obj
,
186 std::function
<std::optional
<JsonT
>(const Object
*, StringRef
)> GetValue
,
187 std::function
<std::optional
<StubT
>(JsonT
)> Validate
= nullptr) {
188 std::optional
<JsonT
> Val
= GetValue(Obj
, Keys
[Key
]);
190 return make_error
<JSONStubError
>(getParseErrorMsg(Key
));
192 if (Validate
== nullptr)
193 return static_cast<StubT
>(*Val
);
195 std::optional
<StubT
> Result
= Validate(*Val
);
196 if (!Result
.has_value())
197 return make_error
<JSONStubError
>(getParseErrorMsg(Key
));
198 return Result
.value();
201 template <typename JsonT
, typename StubT
= JsonT
>
202 Expected
<StubT
> getRequiredValue(
203 TBDKey Key
, const Object
*Obj
,
204 std::function
<std::optional
<JsonT
>(const Object
*, StringRef
)> GetValue
,
205 StubT DefaultValue
, std::function
<std::optional
<StubT
>(JsonT
)> Validate
) {
206 std::optional
<JsonT
> Val
= GetValue(Obj
, Keys
[Key
]);
210 std::optional
<StubT
> Result
;
211 Result
= Validate(*Val
);
212 if (!Result
.has_value())
213 return make_error
<JSONStubError
>(getParseErrorMsg(Key
));
214 return Result
.value();
217 Error
collectFromArray(TBDKey Key
, const Object
*Obj
,
218 std::function
<void(StringRef
)> Append
,
219 bool IsRequired
= false) {
220 const auto *Values
= Obj
->getArray(Keys
[Key
]);
223 return make_error
<JSONStubError
>(getParseErrorMsg(Key
));
224 return Error::success();
227 for (const Value
&Val
: *Values
) {
228 auto ValStr
= Val
.getAsString();
229 if (!ValStr
.has_value())
230 return make_error
<JSONStubError
>(getParseErrorMsg(Key
));
231 Append(ValStr
.value());
234 return Error::success();
237 namespace StubParser
{
239 Expected
<FileType
> getVersion(const Object
*File
) {
240 auto VersionOrErr
= getRequiredValue
<int64_t, FileType
>(
241 TBDKey::TBDVersion
, File
, &Object::getInteger
,
242 [](int64_t Val
) -> std::optional
<FileType
> {
243 unsigned Result
= Val
;
246 return FileType::TBD_V5
;
250 return VersionOrErr
.takeError();
251 return *VersionOrErr
;
254 Expected
<TargetList
> getTargets(const Object
*Section
) {
255 const auto *Targets
= Section
->getArray(Keys
[TBDKey::Targets
]);
257 return make_error
<JSONStubError
>(getParseErrorMsg(TBDKey::Targets
));
259 TargetList IFTargets
;
260 for (const Value
&JSONTarget
: *Targets
) {
261 auto TargetStr
= JSONTarget
.getAsString();
262 if (!TargetStr
.has_value())
263 return make_error
<JSONStubError
>(getParseErrorMsg(TBDKey::Target
));
264 auto TargetOrErr
= Target::create(TargetStr
.value());
266 return make_error
<JSONStubError
>(getParseErrorMsg(TBDKey::Target
));
267 IFTargets
.push_back(*TargetOrErr
);
269 return std::move(IFTargets
);
272 Expected
<TargetList
> getTargetsSection(const Object
*Section
) {
273 const Array
*Targets
= Section
->getArray(Keys
[TBDKey::TargetInfo
]);
275 return make_error
<JSONStubError
>(getParseErrorMsg(TBDKey::Targets
));
277 TargetList IFTargets
;
278 for (const Value
&JSONTarget
: *Targets
) {
279 const auto *Obj
= JSONTarget
.getAsObject();
281 return make_error
<JSONStubError
>(getParseErrorMsg(TBDKey::Target
));
283 getRequiredValue
<StringRef
>(TBDKey::Target
, Obj
, &Object::getString
);
285 return make_error
<JSONStubError
>(getParseErrorMsg(TBDKey::Target
));
286 auto TargetOrErr
= Target::create(*TargetStr
);
288 return make_error
<JSONStubError
>(getParseErrorMsg(TBDKey::Target
));
290 auto VersionStr
= Obj
->getString(Keys
[TBDKey::Deployment
]);
291 VersionTuple Version
;
292 if (VersionStr
&& Version
.tryParse(*VersionStr
))
293 return make_error
<JSONStubError
>(getParseErrorMsg(TBDKey::Deployment
));
294 TargetOrErr
->MinDeployment
= Version
;
296 // Convert to LLVM::Triple to accurately compute minOS + platform + arch
299 MachO::Target(Triple(getTargetTripleName(*TargetOrErr
))));
301 return std::move(IFTargets
);
304 Error
collectSymbolsFromSegment(const Object
*Segment
, TargetsToSymbols
&Result
,
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
);
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
);
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
);
331 Err
= collectFromArray(
332 TBDKey::ObjCIvar
, Segment
, [&Result
, &SectionFlag
](StringRef Name
) {
333 JSONSymbol Sym
= {SymbolKind::ObjectiveCInstanceVariable
, Name
.str(),
335 Result
.back().second
.emplace_back(Sym
);
340 SymbolFlags WeakFlag
=
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
);
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
);
362 return Error::success();
365 Expected
<StringRef
> getNameSection(const Object
*File
) {
366 const Array
*Section
= File
->getArray(Keys
[TBDKey::InstallName
]);
368 return make_error
<JSONStubError
>(getParseErrorMsg(TBDKey::InstallName
));
370 assert(!Section
->empty() && "unexpected missing install name");
371 // TODO: Just take first for now.
372 const auto *Obj
= Section
->front().getAsObject();
374 return make_error
<JSONStubError
>(getParseErrorMsg(TBDKey::InstallName
));
376 return getRequiredValue
<StringRef
>(TBDKey::Name
, Obj
, &Object::getString
);
379 Expected
<TargetsToSymbols
> getSymbolSection(const Object
*File
, TBDKey Key
,
380 TargetList
&Targets
) {
382 const Array
*Section
= File
->getArray(Keys
[Key
]);
384 return TargetsToSymbols();
386 SymbolFlags SectionFlag
;
388 case TBDKey::Reexports
:
389 SectionFlag
= SymbolFlags::Rexported
;
391 case TBDKey::Undefineds
:
392 SectionFlag
= SymbolFlags::Undefined
;
395 SectionFlag
= SymbolFlags::None
;
399 TargetsToSymbols Result
;
400 TargetList MappedTargets
;
401 for (auto Val
: *Section
) {
402 auto *Obj
= Val
.getAsObject();
406 auto TargetsOrErr
= getTargets(Obj
);
408 MappedTargets
= Targets
;
409 consumeError(TargetsOrErr
.takeError());
411 MappedTargets
= *TargetsOrErr
;
414 std::make_pair(std::move(MappedTargets
), std::vector
<JSONSymbol
>()));
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
));
423 auto Err
= collectSymbolsFromSegment(DataSection
, Result
,
424 SectionFlag
| SymbolFlags::Data
);
426 return std::move(Err
);
429 auto Err
= collectSymbolsFromSegment(TextSection
, Result
,
430 SectionFlag
| SymbolFlags::Text
);
432 return std::move(Err
);
436 return std::move(Result
);
439 Expected
<AttrToTargets
> getLibSection(const Object
*File
, TBDKey Key
,
441 const TargetList
&Targets
) {
442 auto *Section
= File
->getArray(Keys
[Key
]);
444 return AttrToTargets();
446 AttrToTargets Result
;
447 TargetList MappedTargets
;
448 for (auto Val
: *Section
) {
449 auto *Obj
= Val
.getAsObject();
453 auto TargetsOrErr
= getTargets(Obj
);
455 MappedTargets
= Targets
;
456 consumeError(TargetsOrErr
.takeError());
458 MappedTargets
= *TargetsOrErr
;
461 collectFromArray(SubKey
, Obj
, [&Result
, &MappedTargets
](StringRef Key
) {
462 Result
[Key
.str()] = MappedTargets
;
465 return std::move(Err
);
468 return std::move(Result
);
471 Expected
<AttrToTargets
> getUmbrellaSection(const Object
*File
,
472 const TargetList
&Targets
) {
473 const auto *Umbrella
= File
->getArray(Keys
[TBDKey::ParentUmbrella
]);
475 return AttrToTargets();
477 AttrToTargets Result
;
478 TargetList MappedTargets
;
479 for (auto Val
: *Umbrella
) {
480 auto *Obj
= Val
.getAsObject();
482 return make_error
<JSONStubError
>(
483 getParseErrorMsg(TBDKey::ParentUmbrella
));
485 // Get Targets section.
486 auto TargetsOrErr
= getTargets(Obj
);
488 MappedTargets
= Targets
;
489 consumeError(TargetsOrErr
.takeError());
491 MappedTargets
= *TargetsOrErr
;
495 getRequiredValue
<StringRef
>(TBDKey::Umbrella
, Obj
, &Object::getString
);
497 return UmbrellaOrErr
.takeError();
498 Result
[UmbrellaOrErr
->str()] = Targets
;
500 return std::move(Result
);
503 Expected
<uint8_t> getSwiftVersion(const Object
*File
) {
504 const Array
*Versions
= File
->getArray(Keys
[TBDKey::SwiftABI
]);
508 for (const auto &Val
: *Versions
) {
509 const auto *Obj
= Val
.getAsObject();
511 return make_error
<JSONStubError
>(getParseErrorMsg(TBDKey::SwiftABI
));
513 // TODO: Take first for now.
514 return getRequiredValue
<int64_t, uint8_t>(TBDKey::ABI
, Obj
,
515 &Object::getInteger
);
521 Expected
<PackedVersion
> getPackedVersion(const Object
*File
, TBDKey Key
) {
522 const Array
*Versions
= File
->getArray(Keys
[Key
]);
524 return PackedVersion(1, 0, 0);
526 for (const auto &Val
: *Versions
) {
527 const auto *Obj
= Val
.getAsObject();
529 return make_error
<JSONStubError
>(getParseErrorMsg(Key
));
531 auto ValidatePV
= [](StringRef Version
) -> std::optional
<PackedVersion
> {
533 auto [success
, truncated
] = PV
.parse64(Version
);
534 if (!success
|| truncated
)
538 // TODO: Take first for now.
539 return getRequiredValue
<StringRef
, PackedVersion
>(
540 TBDKey::Version
, Obj
, &Object::getString
, PackedVersion(1, 0, 0),
544 return PackedVersion(1, 0, 0);
547 Expected
<TBDFlags
> getFlags(const Object
*File
) {
548 TBDFlags Flags
= TBDFlags::None
;
549 const Array
*Section
= File
->getArray(Keys
[TBDKey::Flags
]);
550 if (!Section
|| Section
->empty())
553 for (auto &Val
: *Section
) {
554 // FIXME: Flags currently apply to all target triples.
555 const auto *Obj
= Val
.getAsObject();
557 return make_error
<JSONStubError
>(getParseErrorMsg(TBDKey::Flags
));
560 collectFromArray(TBDKey::Attributes
, Obj
, [&Flags
](StringRef Flag
) {
562 StringSwitch
<TBDFlags
>(Flag
)
563 .Case("flat_namespace", TBDFlags::FlatNamespace
)
564 .Case("not_app_extension_safe",
565 TBDFlags::NotApplicationExtensionSafe
)
566 .Case("sim_support", TBDFlags::SimulatorSupport
)
567 .Default(TBDFlags::None
);
572 return std::move(FlagsOrErr
);
580 using IFPtr
= std::unique_ptr
<InterfaceFile
>;
581 Expected
<IFPtr
> parseToInterfaceFile(const Object
*File
) {
582 auto TargetsOrErr
= getTargetsSection(File
);
584 return TargetsOrErr
.takeError();
585 TargetList Targets
= *TargetsOrErr
;
587 auto NameOrErr
= getNameSection(File
);
589 return NameOrErr
.takeError();
590 StringRef Name
= *NameOrErr
;
592 auto CurrVersionOrErr
= getPackedVersion(File
, TBDKey::CurrentVersion
);
593 if (!CurrVersionOrErr
)
594 return CurrVersionOrErr
.takeError();
595 PackedVersion CurrVersion
= *CurrVersionOrErr
;
597 auto CompVersionOrErr
= getPackedVersion(File
, TBDKey::CompatibilityVersion
);
598 if (!CompVersionOrErr
)
599 return CompVersionOrErr
.takeError();
600 PackedVersion CompVersion
= *CompVersionOrErr
;
602 auto SwiftABIOrErr
= getSwiftVersion(File
);
604 return SwiftABIOrErr
.takeError();
605 uint8_t SwiftABI
= *SwiftABIOrErr
;
607 auto FlagsOrErr
= getFlags(File
);
609 return FlagsOrErr
.takeError();
610 TBDFlags Flags
= *FlagsOrErr
;
612 auto UmbrellasOrErr
= getUmbrellaSection(File
, Targets
);
614 return UmbrellasOrErr
.takeError();
615 AttrToTargets Umbrellas
= *UmbrellasOrErr
;
618 getLibSection(File
, TBDKey::AllowableClients
, TBDKey::Clients
, Targets
);
620 return ClientsOrErr
.takeError();
621 AttrToTargets Clients
= *ClientsOrErr
;
624 getLibSection(File
, TBDKey::ReexportLibs
, TBDKey::Names
, Targets
);
626 return RLOrErr
.takeError();
627 AttrToTargets ReexportLibs
= std::move(*RLOrErr
);
629 auto RPathsOrErr
= getLibSection(File
, TBDKey::RPath
, TBDKey::Paths
, Targets
);
631 return RPathsOrErr
.takeError();
632 AttrToTargets RPaths
= std::move(*RPathsOrErr
);
634 auto ExportsOrErr
= getSymbolSection(File
, TBDKey::Exports
, Targets
);
636 return ExportsOrErr
.takeError();
637 TargetsToSymbols Exports
= std::move(*ExportsOrErr
);
639 auto ReexportsOrErr
= getSymbolSection(File
, TBDKey::Reexports
, Targets
);
641 return ReexportsOrErr
.takeError();
642 TargetsToSymbols Reexports
= std::move(*ReexportsOrErr
);
644 auto UndefinedsOrErr
= getSymbolSection(File
, TBDKey::Undefineds
, Targets
);
645 if (!UndefinedsOrErr
)
646 return UndefinedsOrErr
.takeError();
647 TargetsToSymbols Undefineds
= std::move(*UndefinedsOrErr
);
649 IFPtr
F(new InterfaceFile
);
650 F
->setInstallName(Name
);
651 F
->setCurrentVersion(CurrVersion
);
652 F
->setCompatibilityVersion(CompVersion
);
653 F
->setSwiftABIVersion(SwiftABI
);
654 F
->setTwoLevelNamespace(!(Flags
& TBDFlags::FlatNamespace
));
655 F
->setApplicationExtensionSafe(
656 !(Flags
& TBDFlags::NotApplicationExtensionSafe
));
657 F
->setSimulatorSupport((Flags
& TBDFlags::SimulatorSupport
));
658 for (auto &T
: Targets
)
660 for (auto &[Lib
, Targets
] : Clients
)
661 for (auto Target
: Targets
)
662 F
->addAllowableClient(Lib
, Target
);
663 for (auto &[Lib
, Targets
] : ReexportLibs
)
664 for (auto Target
: Targets
)
665 F
->addReexportedLibrary(Lib
, Target
);
666 for (auto &[Lib
, Targets
] : Umbrellas
)
667 for (auto Target
: Targets
)
668 F
->addParentUmbrella(Target
, Lib
);
669 for (auto &[Path
, Targets
] : RPaths
)
670 for (auto Target
: Targets
)
671 F
->addRPath(Target
, Path
);
672 for (auto &[Targets
, Symbols
] : Exports
)
673 for (auto &Sym
: Symbols
)
674 F
->addSymbol(Sym
.Kind
, Sym
.Name
, Targets
, Sym
.Flags
);
675 for (auto &[Targets
, Symbols
] : Reexports
)
676 for (auto &Sym
: Symbols
)
677 F
->addSymbol(Sym
.Kind
, Sym
.Name
, Targets
, Sym
.Flags
);
678 for (auto &[Targets
, Symbols
] : Undefineds
)
679 for (auto &Sym
: Symbols
)
680 F
->addSymbol(Sym
.Kind
, Sym
.Name
, Targets
, Sym
.Flags
);
685 Expected
<std::vector
<IFPtr
>> getInlinedLibs(const Object
*File
) {
686 std::vector
<IFPtr
> IFs
;
687 const Array
*Files
= File
->getArray(Keys
[TBDKey::Documents
]);
689 return std::move(IFs
);
691 for (auto Lib
: *Files
) {
692 auto IFOrErr
= parseToInterfaceFile(Lib
.getAsObject());
694 return IFOrErr
.takeError();
695 auto IF
= std::move(*IFOrErr
);
696 IFs
.emplace_back(std::move(IF
));
698 return std::move(IFs
);
701 } // namespace StubParser
704 Expected
<std::unique_ptr
<InterfaceFile
>>
705 MachO::getInterfaceFileFromJSON(StringRef JSON
) {
706 auto ValOrErr
= parse(JSON
);
708 return ValOrErr
.takeError();
710 auto *Root
= ValOrErr
->getAsObject();
711 auto VersionOrErr
= StubParser::getVersion(Root
);
713 return VersionOrErr
.takeError();
714 FileType Version
= *VersionOrErr
;
716 Object
*MainLib
= Root
->getObject(Keys
[TBDKey::MainLibrary
]);
717 auto IFOrErr
= StubParser::parseToInterfaceFile(MainLib
);
719 return IFOrErr
.takeError();
720 (*IFOrErr
)->setFileType(Version
);
721 std::unique_ptr
<InterfaceFile
> IF(std::move(*IFOrErr
));
723 auto IFsOrErr
= StubParser::getInlinedLibs(Root
);
725 return IFsOrErr
.takeError();
726 for (auto &File
: *IFsOrErr
) {
727 File
->setFileType(Version
);
728 IF
->addDocument(std::shared_ptr
<InterfaceFile
>(std::move(File
)));
730 return std::move(IF
);
735 template <typename ContainerT
= Array
>
736 bool insertNonEmptyValues(Object
&Obj
, TBDKey Key
, ContainerT
&&Contents
) {
737 if (Contents
.empty())
739 Obj
[Keys
[Key
]] = std::move(Contents
);
743 std::string
getFormattedStr(const MachO::Target
&Targ
) {
744 std::string PlatformStr
= Targ
.Platform
== PLATFORM_MACCATALYST
746 : getOSAndEnvironmentName(Targ
.Platform
);
747 return (getArchitectureName(Targ
.Arch
) + "-" + PlatformStr
).str();
750 template <typename AggregateT
>
751 std::vector
<std::string
> serializeTargets(const AggregateT Targets
,
752 const TargetList
&ActiveTargets
) {
753 std::vector
<std::string
> TargetsStr
;
754 if (Targets
.size() == ActiveTargets
.size())
757 for (const MachO::Target
&Target
: Targets
)
758 TargetsStr
.emplace_back(getFormattedStr(Target
));
763 Array
serializeTargetInfo(const TargetList
&ActiveTargets
) {
765 for (const auto Targ
: ActiveTargets
) {
767 TargetInfo
[Keys
[TBDKey::Deployment
]] = Targ
.MinDeployment
.getAsString();
768 TargetInfo
[Keys
[TBDKey::Target
]] = getFormattedStr(Targ
);
769 Targets
.emplace_back(std::move(TargetInfo
));
774 template <typename ValueT
, typename EntryT
= ValueT
>
775 Array
serializeScalar(TBDKey Key
, ValueT Value
, ValueT Default
= ValueT()) {
776 if (Value
== Default
)
779 Object
ScalarObj({Object::KV({Keys
[Key
], EntryT(Value
)})});
781 Container
.emplace_back(std::move(ScalarObj
));
785 using TargetsToValuesMap
=
786 std::map
<std::vector
<std::string
>, std::vector
<std::string
>>;
788 template <typename AggregateT
= TargetsToValuesMap
>
789 Array
serializeAttrToTargets(AggregateT
&Entries
, TBDKey Key
) {
791 for (const auto &[Targets
, Values
] : Entries
) {
793 insertNonEmptyValues(Obj
, TBDKey::Targets
, std::move(Targets
));
794 Obj
[Keys
[Key
]] = Values
;
795 Container
.emplace_back(std::move(Obj
));
800 template <typename ValueT
= std::string
,
801 typename AggregateT
= std::vector
<std::pair
<MachO::Target
, ValueT
>>>
802 Array
serializeField(TBDKey Key
, const AggregateT
&Values
,
803 const TargetList
&ActiveTargets
, bool IsArray
= true) {
804 std::map
<ValueT
, std::set
<MachO::Target
>> Entries
;
805 for (const auto &[Target
, Val
] : Values
)
806 Entries
[Val
].insert(Target
);
809 std::map
<std::vector
<std::string
>, std::string
> FinalEntries
;
810 for (const auto &[Val
, Targets
] : Entries
)
811 FinalEntries
[serializeTargets(Targets
, ActiveTargets
)] = Val
;
812 return serializeAttrToTargets(FinalEntries
, Key
);
815 TargetsToValuesMap FinalEntries
;
816 for (const auto &[Val
, Targets
] : Entries
)
817 FinalEntries
[serializeTargets(Targets
, ActiveTargets
)].emplace_back(Val
);
818 return serializeAttrToTargets(FinalEntries
, Key
);
821 Array
serializeField(TBDKey Key
, const std::vector
<InterfaceFileRef
> &Values
,
822 const TargetList
&ActiveTargets
) {
823 TargetsToValuesMap FinalEntries
;
824 for (const auto &Ref
: Values
) {
825 TargetList Targets
{Ref
.targets().begin(), Ref
.targets().end()};
826 FinalEntries
[serializeTargets(Targets
, ActiveTargets
)].emplace_back(
827 Ref
.getInstallName());
829 return serializeAttrToTargets(FinalEntries
, Key
);
832 struct SymbolFields
{
834 std::vector
<StringRef
> Weaks
;
835 std::vector
<StringRef
> Globals
;
836 std::vector
<StringRef
> TLV
;
837 std::vector
<StringRef
> ObjCClasses
;
838 std::vector
<StringRef
> IVars
;
839 std::vector
<StringRef
> EHTypes
;
842 return Weaks
.empty() && Globals
.empty() && TLV
.empty() &&
843 ObjCClasses
.empty() && IVars
.empty() && EHTypes
.empty();
850 Array
serializeSymbols(InterfaceFile::const_filtered_symbol_range Symbols
,
851 const TargetList
&ActiveTargets
) {
852 auto AssignForSymbolType
= [](SymbolFields::SymbolTypes
&Assignment
,
854 switch (Sym
->getKind()) {
855 case SymbolKind::ObjectiveCClass
:
856 Assignment
.ObjCClasses
.emplace_back(Sym
->getName());
858 case SymbolKind::ObjectiveCClassEHType
:
859 Assignment
.EHTypes
.emplace_back(Sym
->getName());
861 case SymbolKind::ObjectiveCInstanceVariable
:
862 Assignment
.IVars
.emplace_back(Sym
->getName());
864 case SymbolKind::GlobalSymbol
: {
865 if (Sym
->isWeakReferenced() || Sym
->isWeakDefined())
866 Assignment
.Weaks
.emplace_back(Sym
->getName());
867 else if (Sym
->isThreadLocalValue())
868 Assignment
.TLV
.emplace_back(Sym
->getName());
870 Assignment
.Globals
.emplace_back(Sym
->getName());
876 std::map
<std::vector
<std::string
>, SymbolFields
> Entries
;
877 for (const auto *Sym
: Symbols
) {
878 std::set
<MachO::Target
> Targets
{Sym
->targets().begin(),
879 Sym
->targets().end()};
880 auto JSONTargets
= serializeTargets(Targets
, ActiveTargets
);
882 AssignForSymbolType(Entries
[std::move(JSONTargets
)].Data
, Sym
);
883 else if (Sym
->isText())
884 AssignForSymbolType(Entries
[std::move(JSONTargets
)].Text
, Sym
);
886 llvm_unreachable("unexpected symbol type");
889 auto InsertSymbolsToJSON
= [](Object
&SymSection
, TBDKey SegmentKey
,
890 SymbolFields::SymbolTypes
&SymField
) {
891 if (SymField
.empty())
894 insertNonEmptyValues(Segment
, TBDKey::Globals
, std::move(SymField
.Globals
));
895 insertNonEmptyValues(Segment
, TBDKey::ThreadLocal
, std::move(SymField
.TLV
));
896 insertNonEmptyValues(Segment
, TBDKey::Weak
, std::move(SymField
.Weaks
));
897 insertNonEmptyValues(Segment
, TBDKey::ObjCClass
,
898 std::move(SymField
.ObjCClasses
));
899 insertNonEmptyValues(Segment
, TBDKey::ObjCEHType
,
900 std::move(SymField
.EHTypes
));
901 insertNonEmptyValues(Segment
, TBDKey::ObjCIvar
, std::move(SymField
.IVars
));
902 insertNonEmptyValues(SymSection
, SegmentKey
, std::move(Segment
));
906 for (auto &[Targets
, Fields
] : Entries
) {
908 insertNonEmptyValues(AllSyms
, TBDKey::Targets
, std::move(Targets
));
909 InsertSymbolsToJSON(AllSyms
, TBDKey::Data
, Fields
.Data
);
910 InsertSymbolsToJSON(AllSyms
, TBDKey::Text
, Fields
.Text
);
911 SymbolSection
.emplace_back(std::move(AllSyms
));
914 return SymbolSection
;
917 Array
serializeFlags(const InterfaceFile
*File
) {
918 // TODO: Give all Targets the same flags for now.
920 if (!File
->isTwoLevelNamespace())
921 Flags
.emplace_back("flat_namespace");
922 if (!File
->isApplicationExtensionSafe())
923 Flags
.emplace_back("not_app_extension_safe");
924 if (File
->hasSimulatorSupport())
925 Flags
.emplace_back("sim_support");
926 return serializeScalar(TBDKey::Attributes
, std::move(Flags
));
929 Expected
<Object
> serializeIF(const InterfaceFile
*File
) {
932 // Handle required keys.
933 TargetList ActiveTargets
{File
->targets().begin(), File
->targets().end()};
934 if (!insertNonEmptyValues(Library
, TBDKey::TargetInfo
,
935 serializeTargetInfo(ActiveTargets
)))
936 return make_error
<JSONStubError
>(getSerializeErrorMsg(TBDKey::TargetInfo
));
938 Array Name
= serializeScalar
<StringRef
>(TBDKey::Name
, File
->getInstallName());
939 if (!insertNonEmptyValues(Library
, TBDKey::InstallName
, std::move(Name
)))
940 return make_error
<JSONStubError
>(getSerializeErrorMsg(TBDKey::InstallName
));
942 // Handle optional keys.
943 Array Flags
= serializeFlags(File
);
944 insertNonEmptyValues(Library
, TBDKey::Flags
, std::move(Flags
));
946 Array CurrentV
= serializeScalar
<PackedVersion
, std::string
>(
947 TBDKey::Version
, File
->getCurrentVersion(), PackedVersion(1, 0, 0));
948 insertNonEmptyValues(Library
, TBDKey::CurrentVersion
, std::move(CurrentV
));
950 Array CompatV
= serializeScalar
<PackedVersion
, std::string
>(
951 TBDKey::Version
, File
->getCompatibilityVersion(), PackedVersion(1, 0, 0));
952 insertNonEmptyValues(Library
, TBDKey::CompatibilityVersion
,
955 Array SwiftABI
= serializeScalar
<uint8_t, int64_t>(
956 TBDKey::ABI
, File
->getSwiftABIVersion(), 0u);
957 insertNonEmptyValues(Library
, TBDKey::SwiftABI
, std::move(SwiftABI
));
959 Array RPaths
= serializeField(TBDKey::Paths
, File
->rpaths(), ActiveTargets
);
960 insertNonEmptyValues(Library
, TBDKey::RPath
, std::move(RPaths
));
962 Array Umbrellas
= serializeField(TBDKey::Umbrella
, File
->umbrellas(),
963 ActiveTargets
, /*IsArray=*/false);
964 insertNonEmptyValues(Library
, TBDKey::ParentUmbrella
, std::move(Umbrellas
));
967 serializeField(TBDKey::Clients
, File
->allowableClients(), ActiveTargets
);
968 insertNonEmptyValues(Library
, TBDKey::AllowableClients
, std::move(Clients
));
971 serializeField(TBDKey::Names
, File
->reexportedLibraries(), ActiveTargets
);
972 insertNonEmptyValues(Library
, TBDKey::ReexportLibs
, std::move(ReexportLibs
));
975 Array Exports
= serializeSymbols(File
->exports(), ActiveTargets
);
976 insertNonEmptyValues(Library
, TBDKey::Exports
, std::move(Exports
));
978 Array Reexports
= serializeSymbols(File
->reexports(), ActiveTargets
);
979 insertNonEmptyValues(Library
, TBDKey::Reexports
, std::move(Reexports
));
981 if (!File
->isTwoLevelNamespace()) {
982 Array Undefineds
= serializeSymbols(File
->undefineds(), ActiveTargets
);
983 insertNonEmptyValues(Library
, TBDKey::Undefineds
, std::move(Undefineds
));
986 return std::move(Library
);
989 Expected
<Object
> getJSON(const InterfaceFile
*File
, const FileType FileKind
) {
990 assert(FileKind
== FileType::TBD_V5
&& "unexpected json file format version");
993 auto MainLibOrErr
= serializeIF(File
);
996 Root
[Keys
[TBDKey::MainLibrary
]] = std::move(*MainLibOrErr
);
998 for (const auto &Doc
: File
->documents()) {
999 auto LibOrErr
= serializeIF(Doc
.get());
1002 Documents
.emplace_back(std::move(*LibOrErr
));
1005 Root
[Keys
[TBDKey::TBDVersion
]] = 5;
1006 insertNonEmptyValues(Root
, TBDKey::Documents
, std::move(Documents
));
1007 return std::move(Root
);
1012 Error
MachO::serializeInterfaceFileToJSON(raw_ostream
&OS
,
1013 const InterfaceFile
&File
,
1014 const FileType FileKind
,
1016 auto TextFile
= getJSON(&File
, FileKind
);
1018 return TextFile
.takeError();
1020 OS
<< formatv("{0}", Value(std::move(*TextFile
))) << "\n";
1022 OS
<< formatv("{0:2}", Value(std::move(*TextFile
))) << "\n";
1023 return Error::success();