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/Support/Error.h" 15 #include "llvm/Support/VersionTuple.h" 16 #include "llvm/Support/VirtualFileSystem.h" 17 #include "llvm/TargetParser/Triple.h" 18 #include <optional> 19 20 namespace llvm { 21 namespace json { 22 class Object; 23 } // end namespace json 24 } // end namespace llvm 25 26 namespace clang { 27 28 /// The information about the darwin SDK that was used during this compilation. 29 class DarwinSDKInfo { 30 public: 31 /// A value that describes two os-environment pairs that can be used as a key 32 /// to the version map in the SDK. 33 struct OSEnvPair { 34 public: 35 using StorageType = uint64_t; 36 OSEnvPairOSEnvPair37 constexpr OSEnvPair(llvm::Triple::OSType FromOS, 38 llvm::Triple::EnvironmentType FromEnv, 39 llvm::Triple::OSType ToOS, 40 llvm::Triple::EnvironmentType ToEnv) 41 : Value(((StorageType(FromOS) * StorageType(llvm::Triple::LastOSType) + 42 StorageType(FromEnv)) 43 << 32ull) | 44 (StorageType(ToOS) * StorageType(llvm::Triple::LastOSType) + 45 StorageType(ToEnv))) {} 46 47 /// Returns the os-environment mapping pair that's used to represent the 48 /// macOS -> Mac Catalyst version mapping. macOStoMacCatalystPairOSEnvPair49 static inline constexpr OSEnvPair macOStoMacCatalystPair() { 50 return OSEnvPair(llvm::Triple::MacOSX, llvm::Triple::UnknownEnvironment, 51 llvm::Triple::IOS, llvm::Triple::MacABI); 52 } 53 54 /// Returns the os-environment mapping pair that's used to represent the 55 /// Mac Catalyst -> macOS version mapping. macCatalystToMacOSPairOSEnvPair56 static inline constexpr OSEnvPair macCatalystToMacOSPair() { 57 return OSEnvPair(llvm::Triple::IOS, llvm::Triple::MacABI, 58 llvm::Triple::MacOSX, llvm::Triple::UnknownEnvironment); 59 } 60 61 /// Returns the os-environment mapping pair that's used to represent the 62 /// iOS -> watchOS version mapping. iOStoWatchOSPairOSEnvPair63 static inline constexpr OSEnvPair iOStoWatchOSPair() { 64 return OSEnvPair(llvm::Triple::IOS, llvm::Triple::UnknownEnvironment, 65 llvm::Triple::WatchOS, llvm::Triple::UnknownEnvironment); 66 } 67 68 /// Returns the os-environment mapping pair that's used to represent the 69 /// iOS -> tvOS version mapping. iOStoTvOSPairOSEnvPair70 static inline constexpr OSEnvPair iOStoTvOSPair() { 71 return OSEnvPair(llvm::Triple::IOS, llvm::Triple::UnknownEnvironment, 72 llvm::Triple::TvOS, llvm::Triple::UnknownEnvironment); 73 } 74 75 private: 76 StorageType Value; 77 78 friend class DarwinSDKInfo; 79 }; 80 81 /// Represents a version mapping that maps from a version of one target to a 82 /// version of a related target. 83 /// 84 /// e.g. "macOS_iOSMac":{"10.15":"13.1"} is an example of a macOS -> Mac 85 /// Catalyst version map. 86 class RelatedTargetVersionMapping { 87 public: RelatedTargetVersionMapping(VersionTuple MinimumKeyVersion,VersionTuple MaximumKeyVersion,VersionTuple MinimumValue,VersionTuple MaximumValue,llvm::DenseMap<VersionTuple,VersionTuple> Mapping)88 RelatedTargetVersionMapping( 89 VersionTuple MinimumKeyVersion, VersionTuple MaximumKeyVersion, 90 VersionTuple MinimumValue, VersionTuple MaximumValue, 91 llvm::DenseMap<VersionTuple, VersionTuple> Mapping) 92 : MinimumKeyVersion(MinimumKeyVersion), 93 MaximumKeyVersion(MaximumKeyVersion), MinimumValue(MinimumValue), 94 MaximumValue(MaximumValue), Mapping(Mapping) { 95 assert(!this->Mapping.empty() && "unexpected empty mapping"); 96 } 97 98 /// Returns the value with the lowest version in the mapping. getMinimumValue()99 const VersionTuple &getMinimumValue() const { return MinimumValue; } 100 101 /// Returns the mapped key, or the appropriate Minimum / MaximumValue if 102 /// they key is outside of the mapping bounds. If they key isn't mapped, but 103 /// within the minimum and maximum bounds, std::nullopt is returned. 104 std::optional<VersionTuple> 105 map(const VersionTuple &Key, const VersionTuple &MinimumValue, 106 std::optional<VersionTuple> MaximumValue) const; 107 108 /// Remap the 'introduced' availability version. 109 /// If None is returned, the 'unavailable' availability should be used 110 /// instead. 111 std::optional<VersionTuple> mapIntroducedAvailabilityVersion(const VersionTuple & Key)112 mapIntroducedAvailabilityVersion(const VersionTuple &Key) const { 113 // API_TO_BE_DEPRECATED is 100000. 114 if (Key.getMajor() == 100000) 115 return VersionTuple(100000); 116 // Use None for maximum to force unavailable behavior for 117 return map(Key, MinimumValue, std::nullopt); 118 } 119 120 /// Remap the 'deprecated' and 'obsoleted' availability version. 121 /// If None is returned for 'obsoleted', the 'unavailable' availability 122 /// should be used instead. If None is returned for 'deprecated', the 123 /// 'deprecated' version should be dropped. 124 std::optional<VersionTuple> mapDeprecatedObsoletedAvailabilityVersion(const VersionTuple & Key)125 mapDeprecatedObsoletedAvailabilityVersion(const VersionTuple &Key) const { 126 // API_TO_BE_DEPRECATED is 100000. 127 if (Key.getMajor() == 100000) 128 return VersionTuple(100000); 129 return map(Key, MinimumValue, MaximumValue); 130 } 131 132 static std::optional<RelatedTargetVersionMapping> 133 parseJSON(const llvm::json::Object &Obj, 134 VersionTuple MaximumDeploymentTarget); 135 136 private: 137 VersionTuple MinimumKeyVersion; 138 VersionTuple MaximumKeyVersion; 139 VersionTuple MinimumValue; 140 VersionTuple MaximumValue; 141 llvm::DenseMap<VersionTuple, VersionTuple> Mapping; 142 }; 143 144 DarwinSDKInfo( 145 VersionTuple Version, VersionTuple MaximumDeploymentTarget, 146 llvm::DenseMap<OSEnvPair::StorageType, 147 std::optional<RelatedTargetVersionMapping>> 148 VersionMappings = 149 llvm::DenseMap<OSEnvPair::StorageType, 150 std::optional<RelatedTargetVersionMapping>>()) Version(Version)151 : Version(Version), MaximumDeploymentTarget(MaximumDeploymentTarget), 152 VersionMappings(std::move(VersionMappings)) {} 153 getVersion()154 const llvm::VersionTuple &getVersion() const { return Version; } 155 156 // Returns the optional, target-specific version mapping that maps from one 157 // target to another target. 158 // 159 // This mapping is constructed from an appropriate mapping in the SDKSettings, 160 // for instance, when building for Mac Catalyst, the mapping would contain the 161 // "macOS_iOSMac" mapping as it maps the macOS versions to the Mac Catalyst 162 // versions. 163 // 164 // This mapping does not exist when the target doesn't have an appropriate 165 // related version mapping, or when there was an error reading the mapping 166 // from the SDKSettings, or when it's missing in the SDKSettings. getVersionMapping(OSEnvPair Kind)167 const RelatedTargetVersionMapping *getVersionMapping(OSEnvPair Kind) const { 168 auto Mapping = VersionMappings.find(Kind.Value); 169 if (Mapping == VersionMappings.end()) 170 return nullptr; 171 return Mapping->getSecond() ? &*Mapping->getSecond() : nullptr; 172 } 173 174 static std::optional<DarwinSDKInfo> 175 parseDarwinSDKSettingsJSON(const llvm::json::Object *Obj); 176 177 private: 178 VersionTuple Version; 179 VersionTuple MaximumDeploymentTarget; 180 // Need to wrap the value in an optional here as the value has to be default 181 // constructible, and std::unique_ptr doesn't like DarwinSDKInfo being 182 // Optional as Optional is trying to copy it in emplace. 183 llvm::DenseMap<OSEnvPair::StorageType, 184 std::optional<RelatedTargetVersionMapping>> 185 VersionMappings; 186 }; 187 188 /// Parse the SDK information from the SDKSettings.json file. 189 /// 190 /// \returns an error if the SDKSettings.json file is invalid, std::nullopt if 191 /// the SDK has no SDKSettings.json, or a valid \c DarwinSDKInfo otherwise. 192 Expected<std::optional<DarwinSDKInfo>> 193 parseDarwinSDKInfo(llvm::vfs::FileSystem &VFS, StringRef SDKRootPath); 194 195 } // end namespace clang 196 197 #endif // LLVM_CLANG_BASIC_DARWINSDKINFO_H 198