forked from OSchip/llvm-project
132 lines
4.7 KiB
C++
132 lines
4.7 KiB
C++
//===--- DarwinSDKInfo.cpp - SDK Information parser for darwin - ----------===//
|
|
//
|
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
|
// See https://llvm.org/LICENSE.txt for license information.
|
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#include "clang/Basic/DarwinSDKInfo.h"
|
|
#include "llvm/Support/ErrorOr.h"
|
|
#include "llvm/Support/JSON.h"
|
|
#include "llvm/Support/MemoryBuffer.h"
|
|
#include "llvm/Support/Path.h"
|
|
|
|
using namespace clang;
|
|
|
|
Optional<VersionTuple> DarwinSDKInfo::RelatedTargetVersionMapping::map(
|
|
const VersionTuple &Key, const VersionTuple &MinimumValue,
|
|
Optional<VersionTuple> MaximumValue) const {
|
|
if (Key < MinimumKeyVersion)
|
|
return MinimumValue;
|
|
if (Key > MaximumKeyVersion)
|
|
return MaximumValue;
|
|
auto KV = Mapping.find(Key.normalize());
|
|
if (KV != Mapping.end())
|
|
return KV->getSecond();
|
|
// If no exact entry found, try just the major key version. Only do so when
|
|
// a minor version number is present, to avoid recursing indefinitely into
|
|
// the major-only check.
|
|
if (Key.getMinor())
|
|
return map(VersionTuple(Key.getMajor()), MinimumValue, MaximumValue);
|
|
// If this a major only key, return None for a missing entry.
|
|
return None;
|
|
}
|
|
|
|
Optional<DarwinSDKInfo::RelatedTargetVersionMapping>
|
|
DarwinSDKInfo::RelatedTargetVersionMapping::parseJSON(
|
|
const llvm::json::Object &Obj, VersionTuple MaximumDeploymentTarget) {
|
|
VersionTuple Min = VersionTuple(std::numeric_limits<unsigned>::max());
|
|
VersionTuple Max = VersionTuple(0);
|
|
VersionTuple MinValue = Min;
|
|
llvm::DenseMap<VersionTuple, VersionTuple> Mapping;
|
|
for (const auto &KV : Obj) {
|
|
if (auto Val = KV.getSecond().getAsString()) {
|
|
llvm::VersionTuple KeyVersion;
|
|
llvm::VersionTuple ValueVersion;
|
|
if (KeyVersion.tryParse(KV.getFirst()) || ValueVersion.tryParse(*Val))
|
|
return None;
|
|
Mapping[KeyVersion.normalize()] = ValueVersion;
|
|
if (KeyVersion < Min)
|
|
Min = KeyVersion;
|
|
if (KeyVersion > Max)
|
|
Max = KeyVersion;
|
|
if (ValueVersion < MinValue)
|
|
MinValue = ValueVersion;
|
|
}
|
|
}
|
|
if (Mapping.empty())
|
|
return None;
|
|
return RelatedTargetVersionMapping(
|
|
Min, Max, MinValue, MaximumDeploymentTarget, std::move(Mapping));
|
|
}
|
|
|
|
static Optional<VersionTuple> getVersionKey(const llvm::json::Object &Obj,
|
|
StringRef Key) {
|
|
auto Value = Obj.getString(Key);
|
|
if (!Value)
|
|
return None;
|
|
VersionTuple Version;
|
|
if (Version.tryParse(*Value))
|
|
return None;
|
|
return Version;
|
|
}
|
|
|
|
Optional<DarwinSDKInfo>
|
|
DarwinSDKInfo::parseDarwinSDKSettingsJSON(const llvm::json::Object *Obj) {
|
|
auto Version = getVersionKey(*Obj, "Version");
|
|
if (!Version)
|
|
return None;
|
|
auto MaximumDeploymentVersion =
|
|
getVersionKey(*Obj, "MaximumDeploymentTarget");
|
|
if (!MaximumDeploymentVersion)
|
|
return None;
|
|
llvm::DenseMap<OSEnvPair::StorageType, Optional<RelatedTargetVersionMapping>>
|
|
VersionMappings;
|
|
if (const auto *VM = Obj->getObject("VersionMap")) {
|
|
if (const auto *Mapping = VM->getObject("macOS_iOSMac")) {
|
|
auto VersionMap = RelatedTargetVersionMapping::parseJSON(
|
|
*Mapping, *MaximumDeploymentVersion);
|
|
if (!VersionMap)
|
|
return None;
|
|
VersionMappings[OSEnvPair::macOStoMacCatalystPair().Value] =
|
|
std::move(VersionMap);
|
|
}
|
|
if (const auto *Mapping = VM->getObject("iOSMac_macOS")) {
|
|
auto VersionMap = RelatedTargetVersionMapping::parseJSON(
|
|
*Mapping, *MaximumDeploymentVersion);
|
|
if (!VersionMap)
|
|
return None;
|
|
VersionMappings[OSEnvPair::macCatalystToMacOSPair().Value] =
|
|
std::move(VersionMap);
|
|
}
|
|
}
|
|
|
|
return DarwinSDKInfo(std::move(*Version),
|
|
std::move(*MaximumDeploymentVersion),
|
|
std::move(VersionMappings));
|
|
}
|
|
|
|
Expected<Optional<DarwinSDKInfo>>
|
|
clang::parseDarwinSDKInfo(llvm::vfs::FileSystem &VFS, StringRef SDKRootPath) {
|
|
llvm::SmallString<256> Filepath = SDKRootPath;
|
|
llvm::sys::path::append(Filepath, "SDKSettings.json");
|
|
llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> File =
|
|
VFS.getBufferForFile(Filepath);
|
|
if (!File) {
|
|
// If the file couldn't be read, assume it just doesn't exist.
|
|
return None;
|
|
}
|
|
Expected<llvm::json::Value> Result =
|
|
llvm::json::parse(File.get()->getBuffer());
|
|
if (!Result)
|
|
return Result.takeError();
|
|
|
|
if (const auto *Obj = Result->getAsObject()) {
|
|
if (auto SDKInfo = DarwinSDKInfo::parseDarwinSDKSettingsJSON(Obj))
|
|
return std::move(SDKInfo);
|
|
}
|
|
return llvm::make_error<llvm::StringError>("invalid SDKSettings.json",
|
|
llvm::inconvertibleErrorCode());
|
|
}
|