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_DARWINSDKINFO_H
10 #define LLVM_CLANG_BASIC_DARWINSDKINFO_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 
36     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.
48     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.
55     static inline constexpr OSEnvPair macCatalystToMacOSPair() {
56       return OSEnvPair(llvm::Triple::IOS, llvm::Triple::MacABI,
57                        llvm::Triple::MacOSX, llvm::Triple::UnknownEnvironment);
58     }
59 
60     /// Returns the os-environment mapping pair that's used to represent the
61     /// iOS -> watchOS version mapping.
62     static inline constexpr OSEnvPair iOStoWatchOSPair() {
63       return OSEnvPair(llvm::Triple::IOS, llvm::Triple::UnknownEnvironment,
64                        llvm::Triple::WatchOS, llvm::Triple::UnknownEnvironment);
65     }
66 
67     /// Returns the os-environment mapping pair that's used to represent the
68     /// iOS -> tvOS version mapping.
69     static inline constexpr OSEnvPair iOStoTvOSPair() {
70       return OSEnvPair(llvm::Triple::IOS, llvm::Triple::UnknownEnvironment,
71                        llvm::Triple::TvOS, llvm::Triple::UnknownEnvironment);
72     }
73 
74   private:
75     StorageType Value;
76 
77     friend class DarwinSDKInfo;
78   };
79 
80   /// Represents a version mapping that maps from a version of one target to a
81   /// version of a related target.
82   ///
83   /// e.g. "macOS_iOSMac":{"10.15":"13.1"} is an example of a macOS -> Mac
84   /// Catalyst version map.
85   class RelatedTargetVersionMapping {
86   public:
87     RelatedTargetVersionMapping(
88         VersionTuple MinimumKeyVersion, VersionTuple MaximumKeyVersion,
89         VersionTuple MinimumValue, VersionTuple MaximumValue,
90         llvm::DenseMap<VersionTuple, VersionTuple> Mapping)
91         : MinimumKeyVersion(MinimumKeyVersion),
92           MaximumKeyVersion(MaximumKeyVersion), MinimumValue(MinimumValue),
93           MaximumValue(MaximumValue), Mapping(Mapping) {
94       assert(!this->Mapping.empty() && "unexpected empty mapping");
95     }
96 
97     /// Returns the value with the lowest version in the mapping.
98     const VersionTuple &getMinimumValue() const { return MinimumValue; }
99 
100     /// Returns the mapped key, or the appropriate Minimum / MaximumValue if
101     /// they key is outside of the mapping bounds. If they key isn't mapped, but
102     /// within the minimum and maximum bounds, None is returned.
103     Optional<VersionTuple> map(const VersionTuple &Key,
104                                const VersionTuple &MinimumValue,
105                                Optional<VersionTuple> MaximumValue) const;
106 
107     static Optional<RelatedTargetVersionMapping>
108     parseJSON(const llvm::json::Object &Obj,
109               VersionTuple MaximumDeploymentTarget);
110 
111   private:
112     VersionTuple MinimumKeyVersion;
113     VersionTuple MaximumKeyVersion;
114     VersionTuple MinimumValue;
115     VersionTuple MaximumValue;
116     llvm::DenseMap<VersionTuple, VersionTuple> Mapping;
117   };
118 
119   DarwinSDKInfo(VersionTuple Version, VersionTuple MaximumDeploymentTarget,
120                 llvm::DenseMap<OSEnvPair::StorageType,
121                                Optional<RelatedTargetVersionMapping>>
122                     VersionMappings =
123                         llvm::DenseMap<OSEnvPair::StorageType,
124                                        Optional<RelatedTargetVersionMapping>>())
125       : Version(Version), MaximumDeploymentTarget(MaximumDeploymentTarget),
126         VersionMappings(std::move(VersionMappings)) {}
127 
128   const llvm::VersionTuple &getVersion() const { return Version; }
129 
130   // Returns the optional, target-specific version mapping that maps from one
131   // target to another target.
132   //
133   // This mapping is constructed from an appropriate mapping in the SDKSettings,
134   // for instance, when building for Mac Catalyst, the mapping would contain the
135   // "macOS_iOSMac" mapping as it maps the macOS versions to the Mac Catalyst
136   // versions.
137   //
138   // This mapping does not exist when the target doesn't have an appropriate
139   // related version mapping, or when there was an error reading the mapping
140   // from the SDKSettings, or when it's missing in the SDKSettings.
141   const RelatedTargetVersionMapping *getVersionMapping(OSEnvPair Kind) const {
142     auto Mapping = VersionMappings.find(Kind.Value);
143     if (Mapping == VersionMappings.end())
144       return nullptr;
145     return Mapping->getSecond() ? Mapping->getSecond().getPointer() : nullptr;
146   }
147 
148   static Optional<DarwinSDKInfo>
149   parseDarwinSDKSettingsJSON(const llvm::json::Object *Obj);
150 
151 private:
152   VersionTuple Version;
153   VersionTuple MaximumDeploymentTarget;
154   // Need to wrap the value in an optional here as the value has to be default
155   // constructible, and std::unique_ptr doesn't like DarwinSDKInfo being
156   // Optional as Optional is trying to copy it in emplace.
157   llvm::DenseMap<OSEnvPair::StorageType, Optional<RelatedTargetVersionMapping>>
158       VersionMappings;
159 };
160 
161 /// Parse the SDK information from the SDKSettings.json file.
162 ///
163 /// \returns an error if the SDKSettings.json file is invalid, None if the
164 /// SDK has no SDKSettings.json, or a valid \c DarwinSDKInfo otherwise.
165 Expected<Optional<DarwinSDKInfo>> parseDarwinSDKInfo(llvm::vfs::FileSystem &VFS,
166                                                      StringRef SDKRootPath);
167 
168 } // end namespace clang
169 
170 #endif // LLVM_CLANG_BASIC_DARWINSDKINFO_H
171