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