diff options
Diffstat (limited to 'contrib/llvm-project/clang/lib/Basic/DarwinSDKInfo.cpp')
-rw-r--r-- | contrib/llvm-project/clang/lib/Basic/DarwinSDKInfo.cpp | 150 |
1 files changed, 150 insertions, 0 deletions
diff --git a/contrib/llvm-project/clang/lib/Basic/DarwinSDKInfo.cpp b/contrib/llvm-project/clang/lib/Basic/DarwinSDKInfo.cpp new file mode 100644 index 000000000000..64bcb45a4cd8 --- /dev/null +++ b/contrib/llvm-project/clang/lib/Basic/DarwinSDKInfo.cpp @@ -0,0 +1,150 @@ +//===--- 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")) { + // FIXME: Generalize this out beyond iOS-deriving targets. + // Look for ios_<targetos> version mapping for targets that derive from ios. + for (const auto &KV : *VM) { + auto Pair = StringRef(KV.getFirst()).split("_"); + if (Pair.first.compare_insensitive("ios") == 0) { + llvm::Triple TT(llvm::Twine("--") + Pair.second.lower()); + if (TT.getOS() != llvm::Triple::UnknownOS) { + auto Mapping = RelatedTargetVersionMapping::parseJSON( + *KV.getSecond().getAsObject(), *MaximumDeploymentVersion); + if (Mapping) + VersionMappings[OSEnvPair(llvm::Triple::IOS, + llvm::Triple::UnknownEnvironment, + TT.getOS(), + llvm::Triple::UnknownEnvironment) + .Value] = std::move(Mapping); + } + } + } + + 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()); +} |