1 //===--- DarwinSDKInfo.h - SDK Information parser for darwin ----*- C++ -*-===//
2 //
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
6 //
7 //===----------------------------------------------------------------------===//
8 
9 #ifndef LLVM_CLANG_BASIC_DARWIN_SDK_INFO_H
10 #define LLVM_CLANG_BASIC_DARWIN_SDK_INFO_H
11 
12 #include "clang/Basic/LLVM.h"
13 #include "llvm/ADT/DenseMap.h"
14 #include "llvm/ADT/Triple.h"
15 #include "llvm/Support/Error.h"
16 #include "llvm/Support/VersionTuple.h"
17 #include "llvm/Support/VirtualFileSystem.h"
18 
19 namespace llvm {
20 namespace json {
21 class Object;
22 } // end namespace json
23 } // end namespace llvm
24 
25 namespace clang {
26 
27 /// The information about the darwin SDK that was used during this compilation.
28 class DarwinSDKInfo {
29 public:
30   /// A value that describes two os-environment pairs that can be used as a key
31   /// to the version map in the SDK.
32   struct OSEnvPair {
33   public:
34     using StorageType = uint64_t;
35 
OSEnvPairOSEnvPair36     constexpr OSEnvPair(llvm::Triple::OSType FromOS,
37                         llvm::Triple::EnvironmentType FromEnv,
38                         llvm::Triple::OSType ToOS,
39                         llvm::Triple::EnvironmentType ToEnv)
40         : Value(((StorageType(FromOS) * StorageType(llvm::Triple::LastOSType) +
41                   StorageType(FromEnv))
42                  << 32ull) |
43                 (StorageType(ToOS) * StorageType(llvm::Triple::LastOSType) +
44                  StorageType(ToEnv))) {}
45 
46     /// Returns the os-environment mapping pair that's used to represent the
47     /// macOS -> Mac Catalyst version mapping.
macOStoMacCatalystPairOSEnvPair48     static inline constexpr OSEnvPair macOStoMacCatalystPair() {
49       return OSEnvPair(llvm::Triple::MacOSX, llvm::Triple::UnknownEnvironment,
50                        llvm::Triple::IOS, llvm::Triple::MacABI);
51     }
52 
53     /// Returns the os-environment mapping pair that's used to represent the
54     /// Mac Catalyst -> macOS version mapping.
macCatalystToMacOSPairOSEnvPair55     static inline constexpr OSEnvPair macCatalystToMacOSPair() {
56       return OSEnvPair(llvm::Triple::IOS, llvm::Triple::MacABI,
57                        llvm::Triple::MacOSX, llvm::Triple::UnknownEnvironment);
58     }
59 
60   private:
61     StorageType Value;
62 
63     friend class DarwinSDKInfo;
64   };
65 
66   /// Represents a version mapping that maps from a version of one target to a
67   /// version of a related target.
68   ///
69   /// e.g. "macOS_iOSMac":{"10.15":"13.1"} is an example of a macOS -> Mac
70   /// Catalyst version map.
71   class RelatedTargetVersionMapping {
72   public:
RelatedTargetVersionMapping(VersionTuple MinimumKeyVersion,VersionTuple MaximumKeyVersion,VersionTuple MinimumValue,VersionTuple MaximumValue,llvm::DenseMap<VersionTuple,VersionTuple> Mapping)73     RelatedTargetVersionMapping(
74         VersionTuple MinimumKeyVersion, VersionTuple MaximumKeyVersion,
75         VersionTuple MinimumValue, VersionTuple MaximumValue,
76         llvm::DenseMap<VersionTuple, VersionTuple> Mapping)
77         : MinimumKeyVersion(MinimumKeyVersion),
78           MaximumKeyVersion(MaximumKeyVersion), MinimumValue(MinimumValue),
79           MaximumValue(MaximumValue), Mapping(Mapping) {
80       assert(!this->Mapping.empty() && "unexpected empty mapping");
81     }
82 
83     /// Returns the value with the lowest version in the mapping.
getMinimumValue()84     const VersionTuple &getMinimumValue() const { return MinimumValue; }
85 
86     /// Returns the mapped key, or the appropriate Minimum / MaximumValue if
87     /// they key is outside of the mapping bounds. If they key isn't mapped, but
88     /// within the minimum and maximum bounds, None is returned.
89     Optional<VersionTuple> map(const VersionTuple &Key,
90                                const VersionTuple &MinimumValue,
91                                Optional<VersionTuple> MaximumValue) const;
92 
93     static Optional<RelatedTargetVersionMapping>
94     parseJSON(const llvm::json::Object &Obj,
95               VersionTuple MaximumDeploymentTarget);
96 
97   private:
98     VersionTuple MinimumKeyVersion;
99     VersionTuple MaximumKeyVersion;
100     VersionTuple MinimumValue;
101     VersionTuple MaximumValue;
102     llvm::DenseMap<VersionTuple, VersionTuple> Mapping;
103   };
104 
105   DarwinSDKInfo(VersionTuple Version, VersionTuple MaximumDeploymentTarget,
106                 llvm::DenseMap<OSEnvPair::StorageType,
107                                Optional<RelatedTargetVersionMapping>>
108                     VersionMappings =
109                         llvm::DenseMap<OSEnvPair::StorageType,
110                                        Optional<RelatedTargetVersionMapping>>())
Version(Version)111       : Version(Version), MaximumDeploymentTarget(MaximumDeploymentTarget),
112         VersionMappings(std::move(VersionMappings)) {}
113 
getVersion()114   const llvm::VersionTuple &getVersion() const { return Version; }
115 
116   // Returns the optional, target-specific version mapping that maps from one
117   // target to another target.
118   //
119   // This mapping is constructed from an appropriate mapping in the SDKSettings,
120   // for instance, when building for Mac Catalyst, the mapping would contain the
121   // "macOS_iOSMac" mapping as it maps the macOS versions to the Mac Catalyst
122   // versions.
123   //
124   // This mapping does not exist when the target doesn't have an appropriate
125   // related version mapping, or when there was an error reading the mapping
126   // from the SDKSettings, or when it's missing in the SDKSettings.
getVersionMapping(OSEnvPair Kind)127   const RelatedTargetVersionMapping *getVersionMapping(OSEnvPair Kind) const {
128     auto Mapping = VersionMappings.find(Kind.Value);
129     if (Mapping == VersionMappings.end())
130       return nullptr;
131     return Mapping->getSecond().hasValue() ? Mapping->getSecond().getPointer()
132                                            : nullptr;
133   }
134 
135   static Optional<DarwinSDKInfo>
136   parseDarwinSDKSettingsJSON(const llvm::json::Object *Obj);
137 
138 private:
139   VersionTuple Version;
140   VersionTuple MaximumDeploymentTarget;
141   // Need to wrap the value in an optional here as the value has to be default
142   // constructible, and std::unique_ptr doesn't like DarwinSDKInfo being
143   // Optional as Optional is trying to copy it in emplace.
144   llvm::DenseMap<OSEnvPair::StorageType, Optional<RelatedTargetVersionMapping>>
145       VersionMappings;
146 };
147 
148 /// Parse the SDK information from the SDKSettings.json file.
149 ///
150 /// \returns an error if the SDKSettings.json file is invalid, None if the
151 /// SDK has no SDKSettings.json, or a valid \c DarwinSDKInfo otherwise.
152 Expected<Optional<DarwinSDKInfo>> parseDarwinSDKInfo(llvm::vfs::FileSystem &VFS,
153                                                      StringRef SDKRootPath);
154 
155 } // end namespace clang
156 
157 #endif // LLVM_CLANG_BASIC_DARWIN_SDK_INFO_H
158