xref: /freebsd-src/contrib/llvm-project/clang/lib/Basic/DarwinSDKInfo.cpp (revision fe6060f10f634930ff71b7c50291ddc610da2475)
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