DarwinSDKInfo.cpp 5.7 KB

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