brintos

brintos / llvm-project-archived public Read only

0
0
Text · 6.8 KiB · 6bcfb9d Raw
177 lines · cpp
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-exception6//7//===----------------------------------------------------------------------===//8 9#include "clang/Basic/DarwinSDKInfo.h"10#include "llvm/ADT/StringSwitch.h"11#include "llvm/Support/ErrorOr.h"12#include "llvm/Support/JSON.h"13#include "llvm/Support/MemoryBuffer.h"14#include "llvm/Support/Path.h"15#include <optional>16 17using namespace clang;18 19std::optional<VersionTuple> DarwinSDKInfo::RelatedTargetVersionMapping::map(20    const VersionTuple &Key, const VersionTuple &MinimumValue,21    std::optional<VersionTuple> MaximumValue) const {22  if (Key < MinimumKeyVersion)23    return MinimumValue;24  if (Key > MaximumKeyVersion)25    return MaximumValue;26  auto KV = Mapping.find(Key.normalize());27  if (KV != Mapping.end())28    return KV->getSecond();29  // If no exact entry found, try just the major key version. Only do so when30  // a minor version number is present, to avoid recursing indefinitely into31  // the major-only check.32  if (Key.getMinor())33    return map(VersionTuple(Key.getMajor()), MinimumValue, MaximumValue);34  // If this a major only key, return std::nullopt for a missing entry.35  return std::nullopt;36}37 38std::optional<DarwinSDKInfo::RelatedTargetVersionMapping>39DarwinSDKInfo::RelatedTargetVersionMapping::parseJSON(40    const llvm::json::Object &Obj, VersionTuple MaximumDeploymentTarget) {41  VersionTuple Min = VersionTuple(std::numeric_limits<unsigned>::max());42  VersionTuple Max = VersionTuple(0);43  VersionTuple MinValue = Min;44  llvm::DenseMap<VersionTuple, VersionTuple> Mapping;45  for (const auto &KV : Obj) {46    if (auto Val = KV.getSecond().getAsString()) {47      llvm::VersionTuple KeyVersion;48      llvm::VersionTuple ValueVersion;49      if (KeyVersion.tryParse(KV.getFirst()) || ValueVersion.tryParse(*Val))50        return std::nullopt;51      Mapping[KeyVersion.normalize()] = ValueVersion;52      if (KeyVersion < Min)53        Min = KeyVersion;54      if (KeyVersion > Max)55        Max = KeyVersion;56      if (ValueVersion < MinValue)57        MinValue = ValueVersion;58    }59  }60  if (Mapping.empty())61    return std::nullopt;62  return RelatedTargetVersionMapping(63      Min, Max, MinValue, MaximumDeploymentTarget, std::move(Mapping));64}65 66static llvm::Triple::OSType parseOS(const llvm::json::Object &Obj) {67  // The CanonicalName is the Xcode platform followed by a version, e.g.68  // macosx16.0.69  auto CanonicalName = Obj.getString("CanonicalName");70  if (!CanonicalName)71    return llvm::Triple::UnknownOS;72  size_t VersionStart = CanonicalName->find_first_of("0123456789");73  StringRef XcodePlatform = CanonicalName->slice(0, VersionStart);74  return llvm::StringSwitch<llvm::Triple::OSType>(XcodePlatform)75      .Case("macosx", llvm::Triple::MacOSX)76      .Case("iphoneos", llvm::Triple::IOS)77      .Case("iphonesimulator", llvm::Triple::IOS)78      .Case("appletvos", llvm::Triple::TvOS)79      .Case("appletvsimulator", llvm::Triple::TvOS)80      .Case("watchos", llvm::Triple::WatchOS)81      .Case("watchsimulator", llvm::Triple::WatchOS)82      .Case("xros", llvm::Triple::XROS)83      .Case("xrsimulator", llvm::Triple::XROS)84      .Case("driverkit", llvm::Triple::DriverKit)85      .Default(llvm::Triple::UnknownOS);86}87 88static std::optional<VersionTuple> getVersionKey(const llvm::json::Object &Obj,89                                                 StringRef Key) {90  auto Value = Obj.getString(Key);91  if (!Value)92    return std::nullopt;93  VersionTuple Version;94  if (Version.tryParse(*Value))95    return std::nullopt;96  return Version;97}98 99std::optional<DarwinSDKInfo>100DarwinSDKInfo::parseDarwinSDKSettingsJSON(const llvm::json::Object *Obj) {101  auto Version = getVersionKey(*Obj, "Version");102  if (!Version)103    return std::nullopt;104  auto MaximumDeploymentVersion =105      getVersionKey(*Obj, "MaximumDeploymentTarget");106  if (!MaximumDeploymentVersion)107    return std::nullopt;108  llvm::Triple::OSType OS = parseOS(*Obj);109  llvm::DenseMap<OSEnvPair::StorageType,110                 std::optional<RelatedTargetVersionMapping>>111      VersionMappings;112  if (const auto *VM = Obj->getObject("VersionMap")) {113    // FIXME: Generalize this out beyond iOS-deriving targets.114    // Look for ios_<targetos> version mapping for targets that derive from ios.115    for (const auto &KV : *VM) {116      auto Pair = StringRef(KV.getFirst()).split("_");117      if (Pair.first.compare_insensitive("ios") == 0) {118        llvm::Triple TT(llvm::Twine("--") + Pair.second.lower());119        if (TT.getOS() != llvm::Triple::UnknownOS) {120          auto Mapping = RelatedTargetVersionMapping::parseJSON(121              *KV.getSecond().getAsObject(), *MaximumDeploymentVersion);122          if (Mapping)123            VersionMappings[OSEnvPair(llvm::Triple::IOS,124                                      llvm::Triple::UnknownEnvironment,125                                      TT.getOS(),126                                      llvm::Triple::UnknownEnvironment)127                                .Value] = std::move(Mapping);128        }129      }130    }131 132    if (const auto *Mapping = VM->getObject("macOS_iOSMac")) {133      auto VersionMap = RelatedTargetVersionMapping::parseJSON(134          *Mapping, *MaximumDeploymentVersion);135      if (!VersionMap)136        return std::nullopt;137      VersionMappings[OSEnvPair::macOStoMacCatalystPair().Value] =138          std::move(VersionMap);139    }140    if (const auto *Mapping = VM->getObject("iOSMac_macOS")) {141      auto VersionMap = RelatedTargetVersionMapping::parseJSON(142          *Mapping, *MaximumDeploymentVersion);143      if (!VersionMap)144        return std::nullopt;145      VersionMappings[OSEnvPair::macCatalystToMacOSPair().Value] =146          std::move(VersionMap);147    }148  }149 150  return DarwinSDKInfo(std::move(*Version),151                       std::move(*MaximumDeploymentVersion), OS,152                       std::move(VersionMappings));153}154 155Expected<std::optional<DarwinSDKInfo>>156clang::parseDarwinSDKInfo(llvm::vfs::FileSystem &VFS, StringRef SDKRootPath) {157  llvm::SmallString<256> Filepath = SDKRootPath;158  llvm::sys::path::append(Filepath, "SDKSettings.json");159  llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> File =160      VFS.getBufferForFile(Filepath);161  if (!File) {162    // If the file couldn't be read, assume it just doesn't exist.163    return std::nullopt;164  }165  Expected<llvm::json::Value> Result =166      llvm::json::parse(File.get()->getBuffer());167  if (!Result)168    return Result.takeError();169 170  if (const auto *Obj = Result->getAsObject()) {171    if (auto SDKInfo = DarwinSDKInfo::parseDarwinSDKSettingsJSON(Obj))172      return std::move(SDKInfo);173  }174  return llvm::make_error<llvm::StringError>("invalid SDKSettings.json",175                                             llvm::inconvertibleErrorCode());176}177