1 //===- llvm/TextAPI/InterfaceFile.h - TAPI Interface File -------*- 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 // A generic and abstract interface representation for linkable objects. This 10 // could be an MachO executable, bundle, dylib, or text-based stub file. 11 // 12 //===----------------------------------------------------------------------===// 13 14 #ifndef LLVM_TEXTAPI_INTERFACEFILE_H 15 #define LLVM_TEXTAPI_INTERFACEFILE_H 16 17 #include "llvm/ADT/BitmaskEnum.h" 18 #include "llvm/ADT/DenseMap.h" 19 #include "llvm/ADT/Hashing.h" 20 #include "llvm/ADT/StringRef.h" 21 #include "llvm/ADT/iterator.h" 22 #include "llvm/Support/Allocator.h" 23 #include "llvm/TextAPI/ArchitectureSet.h" 24 #include "llvm/TextAPI/PackedVersion.h" 25 #include "llvm/TextAPI/Platform.h" 26 #include "llvm/TextAPI/Symbol.h" 27 #include "llvm/TextAPI/Target.h" 28 29 namespace llvm { 30 namespace MachO { 31 32 /// Defines a list of Objective-C constraints. 33 enum class ObjCConstraintType : unsigned { 34 /// No constraint. 35 None = 0, 36 37 /// Retain/Release. 38 Retain_Release = 1, 39 40 /// Retain/Release for Simulator. 41 Retain_Release_For_Simulator = 2, 42 43 /// Retain/Release or Garbage Collection. 44 Retain_Release_Or_GC = 3, 45 46 /// Garbage Collection. 47 GC = 4, 48 }; 49 50 // clang-format off 51 52 /// Defines the file type this file represents. 53 enum FileType : unsigned { 54 /// Invalid file type. 55 Invalid = 0U, 56 57 /// Text-based stub file (.tbd) version 1.0 58 TBD_V1 = 1U << 0, 59 60 /// Text-based stub file (.tbd) version 2.0 61 TBD_V2 = 1U << 1, 62 63 /// Text-based stub file (.tbd) version 3.0 64 TBD_V3 = 1U << 2, 65 66 /// Text-based stub file (.tbd) version 4.0 67 TBD_V4 = 1U << 3, 68 69 All = ~0U, 70 71 LLVM_MARK_AS_BITMASK_ENUM(/*LargestValue=*/All), 72 }; 73 74 // clang-format on 75 76 /// Reference to an interface file. 77 class InterfaceFileRef { 78 public: 79 InterfaceFileRef() = default; 80 InterfaceFileRef(StringRef InstallName)81 InterfaceFileRef(StringRef InstallName) : InstallName(InstallName) {} 82 InterfaceFileRef(StringRef InstallName,const TargetList Targets)83 InterfaceFileRef(StringRef InstallName, const TargetList Targets) 84 : InstallName(InstallName), Targets(std::move(Targets)) {} 85 getInstallName()86 StringRef getInstallName() const { return InstallName; }; 87 88 void addTarget(const Target &Target); addTargets(RangeT && Targets)89 template <typename RangeT> void addTargets(RangeT &&Targets) { 90 for (const auto &Target : Targets) 91 addTarget(Target(Target)); 92 } 93 94 using const_target_iterator = TargetList::const_iterator; 95 using const_target_range = llvm::iterator_range<const_target_iterator>; targets()96 const_target_range targets() const { return {Targets}; } 97 getArchitectures()98 ArchitectureSet getArchitectures() const { 99 return mapToArchitectureSet(Targets); 100 } 101 getPlatforms()102 PlatformSet getPlatforms() const { return mapToPlatformSet(Targets); } 103 104 bool operator==(const InterfaceFileRef &O) const { 105 return std::tie(InstallName, Targets) == std::tie(O.InstallName, O.Targets); 106 } 107 108 bool operator!=(const InterfaceFileRef &O) const { 109 return std::tie(InstallName, Targets) != std::tie(O.InstallName, O.Targets); 110 } 111 112 bool operator<(const InterfaceFileRef &O) const { 113 return std::tie(InstallName, Targets) < std::tie(O.InstallName, O.Targets); 114 } 115 116 private: 117 std::string InstallName; 118 TargetList Targets; 119 }; 120 121 } // end namespace MachO. 122 123 struct SymbolsMapKey { 124 MachO::SymbolKind Kind; 125 StringRef Name; 126 SymbolsMapKeySymbolsMapKey127 SymbolsMapKey(MachO::SymbolKind Kind, StringRef Name) 128 : Kind(Kind), Name(Name) {} 129 }; 130 template <> struct DenseMapInfo<SymbolsMapKey> { 131 static inline SymbolsMapKey getEmptyKey() { 132 return SymbolsMapKey(MachO::SymbolKind::GlobalSymbol, StringRef{}); 133 } 134 135 static inline SymbolsMapKey getTombstoneKey() { 136 return SymbolsMapKey(MachO::SymbolKind::ObjectiveCInstanceVariable, 137 StringRef{}); 138 } 139 140 static unsigned getHashValue(const SymbolsMapKey &Key) { 141 return hash_combine(hash_value(Key.Kind), hash_value(Key.Name)); 142 } 143 144 static bool isEqual(const SymbolsMapKey &LHS, const SymbolsMapKey &RHS) { 145 return std::tie(LHS.Kind, LHS.Name) == std::tie(RHS.Kind, RHS.Name); 146 } 147 }; 148 149 namespace MachO { 150 151 /// Defines the interface file. 152 class InterfaceFile { 153 public: 154 /// Set the path from which this file was generated (if applicable). 155 /// 156 /// \param Path_ The path to the source file. 157 void setPath(StringRef Path_) { Path = std::string(Path_); } 158 159 /// Get the path from which this file was generated (if applicable). 160 /// 161 /// \return The path to the source file or empty. 162 StringRef getPath() const { return Path; } 163 164 /// Set the file type. 165 /// 166 /// This is used by the YAML writer to identify the specification it should 167 /// use for writing the file. 168 /// 169 /// \param Kind The file type. 170 void setFileType(FileType Kind) { FileKind = Kind; } 171 172 /// Get the file type. 173 /// 174 /// \return The file type. 175 FileType getFileType() const { return FileKind; } 176 177 /// Get the architectures. 178 /// 179 /// \return The applicable architectures. 180 ArchitectureSet getArchitectures() const { 181 return mapToArchitectureSet(Targets); 182 } 183 184 /// Get the platforms. 185 /// 186 /// \return The applicable platforms. 187 PlatformSet getPlatforms() const { return mapToPlatformSet(Targets); } 188 189 /// Set and add target. 190 /// 191 /// \param Target the target to add into. 192 void addTarget(const Target &Target); 193 194 /// Set and add targets. 195 /// 196 /// Add the subset of llvm::triples that is supported by Tapi 197 /// 198 /// \param Targets the collection of targets. 199 template <typename RangeT> void addTargets(RangeT &&Targets) { 200 for (const auto &Target_ : Targets) 201 addTarget(Target(Target_)); 202 } 203 204 using const_target_iterator = TargetList::const_iterator; 205 using const_target_range = llvm::iterator_range<const_target_iterator>; 206 const_target_range targets() const { return {Targets}; } 207 208 using const_filtered_target_iterator = 209 llvm::filter_iterator<const_target_iterator, 210 std::function<bool(const Target &)>>; 211 using const_filtered_target_range = 212 llvm::iterator_range<const_filtered_target_iterator>; 213 const_filtered_target_range targets(ArchitectureSet Archs) const; 214 215 /// Set the install name of the library. 216 void setInstallName(StringRef InstallName_) { 217 InstallName = std::string(InstallName_); 218 } 219 220 /// Get the install name of the library. 221 StringRef getInstallName() const { return InstallName; } 222 223 /// Set the current version of the library. 224 void setCurrentVersion(PackedVersion Version) { CurrentVersion = Version; } 225 226 /// Get the current version of the library. 227 PackedVersion getCurrentVersion() const { return CurrentVersion; } 228 229 /// Set the compatibility version of the library. 230 void setCompatibilityVersion(PackedVersion Version) { 231 CompatibilityVersion = Version; 232 } 233 234 /// Get the compatibility version of the library. 235 PackedVersion getCompatibilityVersion() const { return CompatibilityVersion; } 236 237 /// Set the Swift ABI version of the library. 238 void setSwiftABIVersion(uint8_t Version) { SwiftABIVersion = Version; } 239 240 /// Get the Swift ABI version of the library. 241 uint8_t getSwiftABIVersion() const { return SwiftABIVersion; } 242 243 /// Specify if the library uses two-level namespace (or flat namespace). 244 void setTwoLevelNamespace(bool V = true) { IsTwoLevelNamespace = V; } 245 246 /// Check if the library uses two-level namespace. 247 bool isTwoLevelNamespace() const { return IsTwoLevelNamespace; } 248 249 /// Specify if the library is application extension safe (or not). 250 void setApplicationExtensionSafe(bool V = true) { IsAppExtensionSafe = V; } 251 252 /// Check if the library is application extension safe. 253 bool isApplicationExtensionSafe() const { return IsAppExtensionSafe; } 254 255 /// Set the Objective-C constraint. 256 void setObjCConstraint(ObjCConstraintType Constraint) { 257 ObjcConstraint = Constraint; 258 } 259 260 /// Get the Objective-C constraint. 261 ObjCConstraintType getObjCConstraint() const { return ObjcConstraint; } 262 263 /// Specify if this file was generated during InstallAPI (or not). 264 void setInstallAPI(bool V = true) { IsInstallAPI = V; } 265 266 /// Check if this file was generated during InstallAPI. 267 bool isInstallAPI() const { return IsInstallAPI; } 268 269 /// Set the parent umbrella frameworks. 270 /// \param Target_ The target applicable to Parent 271 /// \param Parent The name of Parent 272 void addParentUmbrella(const Target &Target_, StringRef Parent); 273 274 /// Get the list of Parent Umbrella frameworks. 275 /// 276 /// \return Returns a list of target information and install name of parent 277 /// umbrellas. 278 const std::vector<std::pair<Target, std::string>> &umbrellas() const { 279 return ParentUmbrellas; 280 } 281 282 /// Add an allowable client. 283 /// 284 /// Mach-O Dynamic libraries have the concept of allowable clients that are 285 /// checked during static link time. The name of the application or library 286 /// that is being generated needs to match one of the allowable clients or the 287 /// linker refuses to link this library. 288 /// 289 /// \param InstallName The name of the client that is allowed to link this 290 /// library. 291 /// \param Target The target triple for which this applies. 292 void addAllowableClient(StringRef InstallName, const Target &Target); 293 294 /// Get the list of allowable clients. 295 /// 296 /// \return Returns a list of allowable clients. 297 const std::vector<InterfaceFileRef> &allowableClients() const { 298 return AllowableClients; 299 } 300 301 /// Add a re-exported library. 302 /// 303 /// \param InstallName The name of the library to re-export. 304 /// \param Target The target triple for which this applies. 305 void addReexportedLibrary(StringRef InstallName, const Target &Target); 306 307 /// Get the list of re-exported libraries. 308 /// 309 /// \return Returns a list of re-exported libraries. 310 const std::vector<InterfaceFileRef> &reexportedLibraries() const { 311 return ReexportedLibraries; 312 } 313 314 /// Add an Target/UUID pair. 315 /// 316 /// \param Target The target triple for which this applies. 317 /// \param UUID The UUID of the library for the specified architecture. 318 void addUUID(const Target &Target, StringRef UUID); 319 320 /// Add an Target/UUID pair. 321 /// 322 /// \param Target The target triple for which this applies. 323 /// \param UUID The UUID of the library for the specified architecture. 324 void addUUID(const Target &Target, uint8_t UUID[16]); 325 326 /// Get the list of Target/UUID pairs. 327 /// 328 /// \return Returns a list of Target/UUID pairs. 329 const std::vector<std::pair<Target, std::string>> &uuids() const { 330 return UUIDs; 331 } 332 333 /// Add a library for inlining to top level library. 334 /// 335 ///\param Document The library to inline with top level library. 336 void addDocument(std::shared_ptr<InterfaceFile> &&Document); 337 338 /// Returns the pointer to parent document if exists or nullptr otherwise. 339 InterfaceFile *getParent() const { return Parent; } 340 341 /// Get the list of inlined libraries. 342 /// 343 /// \return Returns a list of the inlined frameworks. 344 const std::vector<std::shared_ptr<InterfaceFile>> &documents() const { 345 return Documents; 346 } 347 348 /// Add a symbol to the symbols list or extend an existing one. 349 void addSymbol(SymbolKind Kind, StringRef Name, const TargetList &Targets, 350 SymbolFlags Flags = SymbolFlags::None); 351 352 using SymbolMapType = DenseMap<SymbolsMapKey, Symbol *>; 353 struct const_symbol_iterator 354 : public iterator_adaptor_base< 355 const_symbol_iterator, SymbolMapType::const_iterator, 356 std::forward_iterator_tag, const Symbol *, ptrdiff_t, 357 const Symbol *, const Symbol *> { 358 const_symbol_iterator() = default; 359 360 template <typename U> 361 const_symbol_iterator(U &&u) 362 : iterator_adaptor_base(std::forward<U &&>(u)) {} 363 364 reference operator*() const { return I->second; } 365 pointer operator->() const { return I->second; } 366 }; 367 368 using const_symbol_range = iterator_range<const_symbol_iterator>; 369 370 using const_filtered_symbol_iterator = 371 filter_iterator<const_symbol_iterator, 372 std::function<bool(const Symbol *)>>; 373 using const_filtered_symbol_range = 374 iterator_range<const_filtered_symbol_iterator>; 375 376 const_symbol_range symbols() const { 377 return {Symbols.begin(), Symbols.end()}; 378 } 379 380 size_t symbolsCount() const { return Symbols.size(); } 381 382 const_filtered_symbol_range exports() const { 383 std::function<bool(const Symbol *)> fn = [](const Symbol *Symbol) { 384 return !Symbol->isUndefined(); 385 }; 386 return make_filter_range( 387 make_range<const_symbol_iterator>({Symbols.begin()}, {Symbols.end()}), 388 fn); 389 } 390 391 const_filtered_symbol_range undefineds() const { 392 std::function<bool(const Symbol *)> fn = [](const Symbol *Symbol) { 393 return Symbol->isUndefined(); 394 }; 395 return make_filter_range( 396 make_range<const_symbol_iterator>({Symbols.begin()}, {Symbols.end()}), 397 fn); 398 } 399 400 /// The equality is determined by attributes that impact linking 401 /// compatibilities. UUIDs, Path, & FileKind are irrelevant since these by 402 /// itself should not impact linking. 403 /// This is an expensive operation. 404 bool operator==(const InterfaceFile &O) const; 405 406 bool operator!=(const InterfaceFile &O) const { return !(*this == O); } 407 408 private: 409 llvm::BumpPtrAllocator Allocator; 410 StringRef copyString(StringRef String) { 411 if (String.empty()) 412 return {}; 413 414 void *Ptr = Allocator.Allocate(String.size(), 1); 415 memcpy(Ptr, String.data(), String.size()); 416 return StringRef(reinterpret_cast<const char *>(Ptr), String.size()); 417 } 418 419 TargetList Targets; 420 std::string Path; 421 FileType FileKind; 422 std::string InstallName; 423 PackedVersion CurrentVersion; 424 PackedVersion CompatibilityVersion; 425 uint8_t SwiftABIVersion{0}; 426 bool IsTwoLevelNamespace{false}; 427 bool IsAppExtensionSafe{false}; 428 bool IsInstallAPI{false}; 429 ObjCConstraintType ObjcConstraint = ObjCConstraintType::None; 430 std::vector<std::pair<Target, std::string>> ParentUmbrellas; 431 std::vector<InterfaceFileRef> AllowableClients; 432 std::vector<InterfaceFileRef> ReexportedLibraries; 433 std::vector<std::shared_ptr<InterfaceFile>> Documents; 434 std::vector<std::pair<Target, std::string>> UUIDs; 435 SymbolMapType Symbols; 436 InterfaceFile *Parent = nullptr; 437 }; 438 439 template <typename DerivedT, typename KeyInfoT, typename BucketT> 440 bool operator==(const DenseMapBase<DerivedT, SymbolsMapKey, MachO::Symbol *, 441 KeyInfoT, BucketT> &LHS, 442 const DenseMapBase<DerivedT, SymbolsMapKey, MachO::Symbol *, 443 KeyInfoT, BucketT> &RHS) { 444 if (LHS.size() != RHS.size()) 445 return false; 446 for (const auto &KV : LHS) { 447 auto I = RHS.find(KV.first); 448 if (I == RHS.end() || *I->second != *KV.second) 449 return false; 450 } 451 return true; 452 } 453 454 } // end namespace MachO. 455 } // end namespace llvm. 456 457 #endif // LLVM_TEXTAPI_INTERFACEFILE_H 458