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