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