123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150 |
- //===--- 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());
- }
|