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/SymbolSet.h" 28 #include "llvm/TextAPI/Target.h" 29 30 namespace llvm { 31 namespace MachO { 32 33 /// Defines a list of Objective-C constraints. 34 enum class ObjCConstraintType : unsigned { 35 /// No constraint. 36 None = 0, 37 38 /// Retain/Release. 39 Retain_Release = 1, 40 41 /// Retain/Release for Simulator. 42 Retain_Release_For_Simulator = 2, 43 44 /// Retain/Release or Garbage Collection. 45 Retain_Release_Or_GC = 3, 46 47 /// Garbage Collection. 48 GC = 4, 49 }; 50 51 // clang-format off 52 53 /// Defines the file type this file represents. 54 enum FileType : unsigned { 55 /// Invalid file type. 56 Invalid = 0U, 57 58 /// Text-based stub file (.tbd) version 1.0 59 TBD_V1 = 1U << 0, 60 61 /// Text-based stub file (.tbd) version 2.0 62 TBD_V2 = 1U << 1, 63 64 /// Text-based stub file (.tbd) version 3.0 65 TBD_V3 = 1U << 2, 66 67 /// Text-based stub file (.tbd) version 4.0 68 TBD_V4 = 1U << 3, 69 70 /// Text-based stub file (.tbd) version 5.0 71 TBD_V5 = 1U << 4, 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 85 InterfaceFileRef(StringRef InstallName) : InstallName(InstallName) {} 86 87 InterfaceFileRef(StringRef InstallName, const TargetList Targets) 88 : InstallName(InstallName), Targets(std::move(Targets)) {} 89 90 StringRef getInstallName() const { return InstallName; }; 91 92 void addTarget(const Target &Target); 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>; 100 const_target_range targets() const { return {Targets}; } 101 102 ArchitectureSet getArchitectures() const { 103 return mapToArchitectureSet(Targets); 104 } 105 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 namespace MachO { 128 129 /// Defines the interface file. 130 class InterfaceFile { 131 public: 132 InterfaceFile(std::unique_ptr<SymbolSet> &&InputSymbols) 133 : SymbolsSet(std::move(InputSymbols)) {} 134 135 InterfaceFile() : SymbolsSet(std::make_unique<SymbolSet>()){}; 136 /// Set the path from which this file was generated (if applicable). 137 /// 138 /// \param Path_ The path to the source file. 139 void setPath(StringRef Path_) { Path = std::string(Path_); } 140 141 /// Get the path from which this file was generated (if applicable). 142 /// 143 /// \return The path to the source file or empty. 144 StringRef getPath() const { return Path; } 145 146 /// Set the file type. 147 /// 148 /// This is used by the YAML writer to identify the specification it should 149 /// use for writing the file. 150 /// 151 /// \param Kind The file type. 152 void setFileType(FileType Kind) { FileKind = Kind; } 153 154 /// Get the file type. 155 /// 156 /// \return The file type. 157 FileType getFileType() const { return FileKind; } 158 159 /// Get the architectures. 160 /// 161 /// \return The applicable architectures. 162 ArchitectureSet getArchitectures() const { 163 return mapToArchitectureSet(Targets); 164 } 165 166 /// Get the platforms. 167 /// 168 /// \return The applicable platforms. 169 PlatformSet getPlatforms() const { return mapToPlatformSet(Targets); } 170 171 /// Set and add target. 172 /// 173 /// \param Target the target to add into. 174 void addTarget(const Target &Target); 175 176 /// Set and add targets. 177 /// 178 /// Add the subset of llvm::triples that is supported by Tapi 179 /// 180 /// \param Targets the collection of targets. 181 template <typename RangeT> void addTargets(RangeT &&Targets) { 182 for (const auto &Target_ : Targets) 183 addTarget(Target(Target_)); 184 } 185 186 using const_target_iterator = TargetList::const_iterator; 187 using const_target_range = llvm::iterator_range<const_target_iterator>; 188 const_target_range targets() const { return {Targets}; } 189 190 using const_filtered_target_iterator = 191 llvm::filter_iterator<const_target_iterator, 192 std::function<bool(const Target &)>>; 193 using const_filtered_target_range = 194 llvm::iterator_range<const_filtered_target_iterator>; 195 const_filtered_target_range targets(ArchitectureSet Archs) const; 196 197 /// Set the install name of the library. 198 void setInstallName(StringRef InstallName_) { 199 InstallName = std::string(InstallName_); 200 } 201 202 /// Get the install name of the library. 203 StringRef getInstallName() const { return InstallName; } 204 205 /// Set the current version of the library. 206 void setCurrentVersion(PackedVersion Version) { CurrentVersion = Version; } 207 208 /// Get the current version of the library. 209 PackedVersion getCurrentVersion() const { return CurrentVersion; } 210 211 /// Set the compatibility version of the library. 212 void setCompatibilityVersion(PackedVersion Version) { 213 CompatibilityVersion = Version; 214 } 215 216 /// Get the compatibility version of the library. 217 PackedVersion getCompatibilityVersion() const { return CompatibilityVersion; } 218 219 /// Set the Swift ABI version of the library. 220 void setSwiftABIVersion(uint8_t Version) { SwiftABIVersion = Version; } 221 222 /// Get the Swift ABI version of the library. 223 uint8_t getSwiftABIVersion() const { return SwiftABIVersion; } 224 225 /// Specify if the library uses two-level namespace (or flat namespace). 226 void setTwoLevelNamespace(bool V = true) { IsTwoLevelNamespace = V; } 227 228 /// Check if the library uses two-level namespace. 229 bool isTwoLevelNamespace() const { return IsTwoLevelNamespace; } 230 231 /// Specify if the library is application extension safe (or not). 232 void setApplicationExtensionSafe(bool V = true) { IsAppExtensionSafe = V; } 233 234 /// Check if the library is application extension safe. 235 bool isApplicationExtensionSafe() const { return IsAppExtensionSafe; } 236 237 /// Set the Objective-C constraint. 238 void setObjCConstraint(ObjCConstraintType Constraint) { 239 ObjcConstraint = Constraint; 240 } 241 242 /// Get the Objective-C constraint. 243 ObjCConstraintType getObjCConstraint() const { return ObjcConstraint; } 244 245 /// Set the parent umbrella frameworks. 246 /// \param Target_ The target applicable to Parent 247 /// \param Parent The name of Parent 248 void addParentUmbrella(const Target &Target_, StringRef Parent); 249 250 /// Get the list of Parent Umbrella frameworks. 251 /// 252 /// \return Returns a list of target information and install name of parent 253 /// umbrellas. 254 const std::vector<std::pair<Target, std::string>> &umbrellas() const { 255 return ParentUmbrellas; 256 } 257 258 /// Add an allowable client. 259 /// 260 /// Mach-O Dynamic libraries have the concept of allowable clients that are 261 /// checked during static link time. The name of the application or library 262 /// that is being generated needs to match one of the allowable clients or the 263 /// linker refuses to link this library. 264 /// 265 /// \param InstallName The name of the client that is allowed to link this 266 /// library. 267 /// \param Target The target triple for which this applies. 268 void addAllowableClient(StringRef InstallName, const Target &Target); 269 270 /// Get the list of allowable clients. 271 /// 272 /// \return Returns a list of allowable clients. 273 const std::vector<InterfaceFileRef> &allowableClients() const { 274 return AllowableClients; 275 } 276 277 /// Add a re-exported library. 278 /// 279 /// \param InstallName The name of the library to re-export. 280 /// \param Target The target triple for which this applies. 281 void addReexportedLibrary(StringRef InstallName, const Target &Target); 282 283 /// Get the list of re-exported libraries. 284 /// 285 /// \return Returns a list of re-exported libraries. 286 const std::vector<InterfaceFileRef> &reexportedLibraries() const { 287 return ReexportedLibraries; 288 } 289 290 /// Add a library for inlining to top level library. 291 /// 292 ///\param Document The library to inline with top level library. 293 void addDocument(std::shared_ptr<InterfaceFile> &&Document); 294 295 /// Returns the pointer to parent document if exists or nullptr otherwise. 296 InterfaceFile *getParent() const { return Parent; } 297 298 /// Get the list of inlined libraries. 299 /// 300 /// \return Returns a list of the inlined frameworks. 301 const std::vector<std::shared_ptr<InterfaceFile>> &documents() const { 302 return Documents; 303 } 304 305 /// Set the runpath search paths. 306 /// \param InputTarget The target applicable to runpath search path. 307 /// \param RPath The name of runpath. 308 void addRPath(const Target &InputTarget, StringRef RPath); 309 310 /// Get the list of runpath search paths. 311 /// 312 /// \return Returns a list of the rpaths per target. 313 const std::vector<std::pair<Target, std::string>> &rpaths() const { 314 return RPaths; 315 } 316 317 /// Get symbol if exists in file. 318 /// 319 /// \param Kind The kind of global symbol to record. 320 /// \param Name The name of the symbol. 321 std::optional<const Symbol *> getSymbol(SymbolKind Kind, 322 StringRef Name) const { 323 if (auto *Sym = SymbolsSet->findSymbol(Kind, Name)) 324 return Sym; 325 return std::nullopt; 326 } 327 328 /// Add a symbol to the symbols list or extend an existing one. 329 template <typename RangeT, 330 typename ElT = typename std::remove_reference< 331 decltype(*std::begin(std::declval<RangeT>()))>::type> 332 void addSymbol(SymbolKind Kind, StringRef Name, RangeT &&Targets, 333 SymbolFlags Flags = SymbolFlags::None) { 334 SymbolsSet->addGlobal(Kind, Name, Flags, Targets); 335 } 336 337 /// Add Symbol with multiple targets. 338 /// 339 /// \param Kind The kind of global symbol to record. 340 /// \param Name The name of the symbol. 341 /// \param Targets The list of targets the symbol is defined in. 342 /// \param Flags The properties the symbol holds. 343 void addSymbol(SymbolKind Kind, StringRef Name, TargetList &&Targets, 344 SymbolFlags Flags = SymbolFlags::None) { 345 SymbolsSet->addGlobal(Kind, Name, Flags, Targets); 346 } 347 348 /// Add Symbol with single target. 349 /// 350 /// \param Kind The kind of global symbol to record. 351 /// \param Name The name of the symbol. 352 /// \param Target The target the symbol is defined in. 353 /// \param Flags The properties the symbol holds. 354 void addSymbol(SymbolKind Kind, StringRef Name, Target &Target, 355 SymbolFlags Flags = SymbolFlags::None) { 356 SymbolsSet->addGlobal(Kind, Name, Flags, Target); 357 } 358 359 /// Get size of symbol set. 360 /// \return The number of symbols the file holds. 361 size_t symbolsCount() const { return SymbolsSet->size(); } 362 363 using const_symbol_range = SymbolSet::const_symbol_range; 364 using const_filtered_symbol_range = SymbolSet::const_filtered_symbol_range; 365 366 const_symbol_range symbols() const { return SymbolsSet->symbols(); }; 367 const_filtered_symbol_range exports() const { return SymbolsSet->exports(); }; 368 const_filtered_symbol_range reexports() const { 369 return SymbolsSet->reexports(); 370 }; 371 const_filtered_symbol_range undefineds() const { 372 return SymbolsSet->undefineds(); 373 }; 374 375 /// The equality is determined by attributes that impact linking 376 /// compatibilities. Path, & FileKind are irrelevant since these by 377 /// itself should not impact linking. 378 /// This is an expensive operation. 379 bool operator==(const InterfaceFile &O) const; 380 381 bool operator!=(const InterfaceFile &O) const { return !(*this == O); } 382 383 private: 384 llvm::BumpPtrAllocator Allocator; 385 StringRef copyString(StringRef String) { 386 if (String.empty()) 387 return {}; 388 389 void *Ptr = Allocator.Allocate(String.size(), 1); 390 memcpy(Ptr, String.data(), String.size()); 391 return StringRef(reinterpret_cast<const char *>(Ptr), String.size()); 392 } 393 394 TargetList Targets; 395 std::string Path; 396 FileType FileKind{FileType::Invalid}; 397 std::string InstallName; 398 PackedVersion CurrentVersion; 399 PackedVersion CompatibilityVersion; 400 uint8_t SwiftABIVersion{0}; 401 bool IsTwoLevelNamespace{false}; 402 bool IsAppExtensionSafe{false}; 403 ObjCConstraintType ObjcConstraint = ObjCConstraintType::None; 404 std::vector<std::pair<Target, std::string>> ParentUmbrellas; 405 std::vector<InterfaceFileRef> AllowableClients; 406 std::vector<InterfaceFileRef> ReexportedLibraries; 407 std::vector<std::shared_ptr<InterfaceFile>> Documents; 408 std::vector<std::pair<Target, std::string>> RPaths; 409 std::unique_ptr<SymbolSet> SymbolsSet; 410 InterfaceFile *Parent = nullptr; 411 }; 412 413 // Keep containers that hold InterfaceFileRefs in sorted order and uniqued. 414 template <typename C> 415 typename C::iterator addEntry(C &Container, StringRef InstallName) { 416 auto I = partition_point(Container, [=](const InterfaceFileRef &O) { 417 return O.getInstallName() < InstallName; 418 }); 419 if (I != Container.end() && I->getInstallName() == InstallName) 420 return I; 421 422 return Container.emplace(I, InstallName); 423 } 424 425 } // end namespace MachO. 426 } // end namespace llvm. 427 428 #endif // LLVM_TEXTAPI_INTERFACEFILE_H 429