DarwinSDKInfo.cpp 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150
  1. //===--- DarwinSDKInfo.cpp - SDK Information parser for darwin - ----------===//
  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. #include "clang/Basic/DarwinSDKInfo.h"
  9. #include "llvm/Support/ErrorOr.h"
  10. #include "llvm/Support/JSON.h"
  11. #include "llvm/Support/MemoryBuffer.h"
  12. #include "llvm/Support/Path.h"
  13. using namespace clang;
  14. Optional<VersionTuple> DarwinSDKInfo::RelatedTargetVersionMapping::map(
  15. const VersionTuple &Key, const VersionTuple &MinimumValue,
  16. Optional<VersionTuple> MaximumValue) const {
  17. if (Key < MinimumKeyVersion)
  18. return MinimumValue;
  19. if (Key > MaximumKeyVersion)
  20. return MaximumValue;
  21. auto KV = Mapping.find(Key.normalize());
  22. if (KV != Mapping.end())
  23. return KV->getSecond();
  24. // If no exact entry found, try just the major key version. Only do so when
  25. // a minor version number is present, to avoid recursing indefinitely into
  26. // the major-only check.
  27. if (Key.getMinor())
  28. return map(VersionTuple(Key.getMajor()), MinimumValue, MaximumValue);
  29. // If this a major only key, return None for a missing entry.
  30. return None;
  31. }
  32. Optional<DarwinSDKInfo::RelatedTargetVersionMapping>
  33. DarwinSDKInfo::RelatedTargetVersionMapping::parseJSON(
  34. const llvm::json::Object &Obj, VersionTuple MaximumDeploymentTarget) {
  35. VersionTuple Min = VersionTuple(std::numeric_limits<unsigned>::max());
  36. VersionTuple Max = VersionTuple(0);
  37. VersionTuple MinValue = Min;
  38. llvm::DenseMap<VersionTuple, VersionTuple> Mapping;
  39. for (const auto &KV : Obj) {
  40. if (auto Val = KV.getSecond().getAsString()) {
  41. llvm::VersionTuple KeyVersion;
  42. llvm::VersionTuple ValueVersion;
  43. if (KeyVersion.tryParse(KV.getFirst()) || ValueVersion.tryParse(*Val))
  44. return None;
  45. Mapping[KeyVersion.normalize()] = ValueVersion;
  46. if (KeyVersion < Min)
  47. Min = KeyVersion;
  48. if (KeyVersion > Max)
  49. Max = KeyVersion;
  50. if (ValueVersion < MinValue)
  51. MinValue = ValueVersion;
  52. }
  53. }
  54. if (Mapping.empty())
  55. return None;
  56. return RelatedTargetVersionMapping(
  57. Min, Max, MinValue, MaximumDeploymentTarget, std::move(Mapping));
  58. }
  59. static Optional<VersionTuple> getVersionKey(const llvm::json::Object &Obj,
  60. StringRef Key) {
  61. auto Value = Obj.getString(Key);
  62. if (!Value)
  63. return None;
  64. VersionTuple Version;
  65. if (Version.tryParse(*Value))
  66. return None;
  67. return Version;
  68. }
  69. Optional<DarwinSDKInfo>
  70. DarwinSDKInfo::parseDarwinSDKSettingsJSON(const llvm::json::Object *Obj) {
  71. auto Version = getVersionKey(*Obj, "Version");
  72. if (!Version)
  73. return None;
  74. auto MaximumDeploymentVersion =
  75. getVersionKey(*Obj, "MaximumDeploymentTarget");
  76. if (!MaximumDeploymentVersion)
  77. return None;
  78. llvm::DenseMap<OSEnvPair::StorageType, Optional<RelatedTargetVersionMapping>>
  79. VersionMappings;
  80. if (const auto *VM = Obj->getObject("VersionMap")) {
  81. // FIXME: Generalize this out beyond iOS-deriving targets.
  82. // Look for ios_<targetos> version mapping for targets that derive from ios.
  83. for (const auto &KV : *VM) {
  84. auto Pair = StringRef(KV.getFirst()).split("_");
  85. if (Pair.first.compare_insensitive("ios") == 0) {
  86. llvm::Triple TT(llvm::Twine("--") + Pair.second.lower());
  87. if (TT.getOS() != llvm::Triple::UnknownOS) {
  88. auto Mapping = RelatedTargetVersionMapping::parseJSON(
  89. *KV.getSecond().getAsObject(), *MaximumDeploymentVersion);
  90. if (Mapping)
  91. VersionMappings[OSEnvPair(llvm::Triple::IOS,
  92. llvm::Triple::UnknownEnvironment,
  93. TT.getOS(),
  94. llvm::Triple::UnknownEnvironment)
  95. .Value] = std::move(Mapping);
  96. }
  97. }
  98. }
  99. if (const auto *Mapping = VM->getObject("macOS_iOSMac")) {
  100. auto VersionMap = RelatedTargetVersionMapping::parseJSON(
  101. *Mapping, *MaximumDeploymentVersion);
  102. if (!VersionMap)
  103. return None;
  104. VersionMappings[OSEnvPair::macOStoMacCatalystPair().Value] =
  105. std::move(VersionMap);
  106. }
  107. if (const auto *Mapping = VM->getObject("iOSMac_macOS")) {
  108. auto VersionMap = RelatedTargetVersionMapping::parseJSON(
  109. *Mapping, *MaximumDeploymentVersion);
  110. if (!VersionMap)
  111. return None;
  112. VersionMappings[OSEnvPair::macCatalystToMacOSPair().Value] =
  113. std::move(VersionMap);
  114. }
  115. }
  116. return DarwinSDKInfo(std::move(*Version),
  117. std::move(*MaximumDeploymentVersion),
  118. std::move(VersionMappings));
  119. }
  120. Expected<Optional<DarwinSDKInfo>>
  121. clang::parseDarwinSDKInfo(llvm::vfs::FileSystem &VFS, StringRef SDKRootPath) {
  122. llvm::SmallString<256> Filepath = SDKRootPath;
  123. llvm::sys::path::append(Filepath, "SDKSettings.json");
  124. llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> File =
  125. VFS.getBufferForFile(Filepath);
  126. if (!File) {
  127. // If the file couldn't be read, assume it just doesn't exist.
  128. return None;
  129. }
  130. Expected<llvm::json::Value> Result =
  131. llvm::json::parse(File.get()->getBuffer());
  132. if (!Result)
  133. return Result.takeError();
  134. if (const auto *Obj = Result->getAsObject()) {
  135. if (auto SDKInfo = DarwinSDKInfo::parseDarwinSDKSettingsJSON(Obj))
  136. return std::move(SDKInfo);
  137. }
  138. return llvm::make_error<llvm::StringError>("invalid SDKSettings.json",
  139. llvm::inconvertibleErrorCode());
  140. }