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/Hashing.h" 18 #include "llvm/ADT/StringRef.h" 19 #include "llvm/ADT/iterator.h" 20 #include "llvm/Support/Allocator.h" 21 #include "llvm/TextAPI/ArchitectureSet.h" 22 #include "llvm/TextAPI/FileTypes.h" 23 #include "llvm/TextAPI/PackedVersion.h" 24 #include "llvm/TextAPI/Platform.h" 25 #include "llvm/TextAPI/RecordsSlice.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 /// Reference to an interface file. 52 class InterfaceFileRef { 53 public: 54 InterfaceFileRef() = default; 55 56 InterfaceFileRef(StringRef InstallName) : InstallName(InstallName) {} 57 58 InterfaceFileRef(StringRef InstallName, const TargetList Targets) 59 : InstallName(InstallName), Targets(std::move(Targets)) {} 60 61 StringRef getInstallName() const { return InstallName; }; 62 63 void addTarget(const Target &Target); 64 template <typename RangeT> void addTargets(RangeT &&Targets) { 65 for (const auto &Target : Targets) 66 addTarget(Target(Target)); 67 } 68 69 bool hasTarget(Target &Targ) const { 70 return llvm::is_contained(Targets, Targ); 71 } 72 73 using const_target_iterator = TargetList::const_iterator; 74 using const_target_range = llvm::iterator_range<const_target_iterator>; 75 const_target_range targets() const { return {Targets}; } 76 77 ArchitectureSet getArchitectures() const { 78 return mapToArchitectureSet(Targets); 79 } 80 81 PlatformSet getPlatforms() const { return mapToPlatformSet(Targets); } 82 83 bool operator==(const InterfaceFileRef &O) const { 84 return std::tie(InstallName, Targets) == std::tie(O.InstallName, O.Targets); 85 } 86 87 bool operator!=(const InterfaceFileRef &O) const { 88 return std::tie(InstallName, Targets) != std::tie(O.InstallName, O.Targets); 89 } 90 91 bool operator<(const InterfaceFileRef &O) const { 92 return std::tie(InstallName, Targets) < std::tie(O.InstallName, O.Targets); 93 } 94 95 private: 96 std::string InstallName; 97 TargetList Targets; 98 }; 99 100 } // end namespace MachO. 101 102 namespace MachO { 103 104 /// Defines the interface file. 105 class InterfaceFile { 106 public: 107 InterfaceFile(std::unique_ptr<SymbolSet> &&InputSymbols) 108 : SymbolsSet(std::move(InputSymbols)) {} 109 110 InterfaceFile() : SymbolsSet(std::make_unique<SymbolSet>()){}; 111 /// Set the path from which this file was generated (if applicable). 112 /// 113 /// \param Path_ The path to the source file. 114 void setPath(StringRef Path_) { Path = std::string(Path_); } 115 116 /// Get the path from which this file was generated (if applicable). 117 /// 118 /// \return The path to the source file or empty. 119 StringRef getPath() const { return Path; } 120 121 /// Set the file type. 122 /// 123 /// This is used by the YAML writer to identify the specification it should 124 /// use for writing the file. 125 /// 126 /// \param Kind The file type. 127 void setFileType(FileType Kind) { FileKind = Kind; } 128 129 /// Get the file type. 130 /// 131 /// \return The file type. 132 FileType getFileType() const { return FileKind; } 133 134 /// Get the architectures. 135 /// 136 /// \return The applicable architectures. 137 ArchitectureSet getArchitectures() const { 138 return mapToArchitectureSet(Targets); 139 } 140 141 /// Get the platforms. 142 /// 143 /// \return The applicable platforms. 144 PlatformSet getPlatforms() const { return mapToPlatformSet(Targets); } 145 146 /// Set and add target. 147 /// 148 /// \param Target the target to add into. 149 void addTarget(const Target &Target); 150 151 /// Determine if target triple slice exists in file. 152 /// 153 /// \param Targ the value to find. 154 bool hasTarget(const Target &Targ) const { 155 return llvm::is_contained(Targets, Targ); 156 } 157 158 /// Set and add targets. 159 /// 160 /// Add the subset of llvm::triples that is supported by Tapi 161 /// 162 /// \param Targets the collection of targets. 163 template <typename RangeT> void addTargets(RangeT &&Targets) { 164 for (const auto &Target_ : Targets) 165 addTarget(Target(Target_)); 166 } 167 168 using const_target_iterator = TargetList::const_iterator; 169 using const_target_range = llvm::iterator_range<const_target_iterator>; 170 const_target_range targets() const { return {Targets}; } 171 172 using const_filtered_target_iterator = 173 llvm::filter_iterator<const_target_iterator, 174 std::function<bool(const Target &)>>; 175 using const_filtered_target_range = 176 llvm::iterator_range<const_filtered_target_iterator>; 177 const_filtered_target_range targets(ArchitectureSet Archs) const; 178 179 /// Set the install name of the library. 180 void setInstallName(StringRef InstallName_) { 181 InstallName = std::string(InstallName_); 182 } 183 184 /// Get the install name of the library. 185 StringRef getInstallName() const { return InstallName; } 186 187 /// Set the current version of the library. 188 void setCurrentVersion(PackedVersion Version) { CurrentVersion = Version; } 189 190 /// Get the current version of the library. 191 PackedVersion getCurrentVersion() const { return CurrentVersion; } 192 193 /// Set the compatibility version of the library. 194 void setCompatibilityVersion(PackedVersion Version) { 195 CompatibilityVersion = Version; 196 } 197 198 /// Get the compatibility version of the library. 199 PackedVersion getCompatibilityVersion() const { return CompatibilityVersion; } 200 201 /// Set the Swift ABI version of the library. 202 void setSwiftABIVersion(uint8_t Version) { SwiftABIVersion = Version; } 203 204 /// Get the Swift ABI version of the library. 205 uint8_t getSwiftABIVersion() const { return SwiftABIVersion; } 206 207 /// Specify if the library uses two-level namespace (or flat namespace). 208 void setTwoLevelNamespace(bool V = true) { IsTwoLevelNamespace = V; } 209 210 /// Check if the library uses two-level namespace. 211 bool isTwoLevelNamespace() const { return IsTwoLevelNamespace; } 212 213 /// Specify if the library is an OS library but not shared cache eligible. 214 void setOSLibNotForSharedCache(bool V = true) { 215 IsOSLibNotForSharedCache = V; 216 } 217 218 /// Check if the library is an OS library that is not shared cache eligible. 219 bool isOSLibNotForSharedCache() const { return IsOSLibNotForSharedCache; } 220 221 /// Specify if the library is application extension safe (or not). 222 void setApplicationExtensionSafe(bool V = true) { IsAppExtensionSafe = V; } 223 224 /// Check if the library is application extension safe. 225 bool isApplicationExtensionSafe() const { return IsAppExtensionSafe; } 226 227 /// Check if the library has simulator support. 228 bool hasSimulatorSupport() const { return HasSimSupport; } 229 230 /// Specify if the library has simulator support. 231 void setSimulatorSupport(bool V = true) { HasSimSupport = V; } 232 233 /// Set the Objective-C constraint. 234 void setObjCConstraint(ObjCConstraintType Constraint) { 235 ObjcConstraint = Constraint; 236 } 237 238 /// Get the Objective-C constraint. 239 ObjCConstraintType getObjCConstraint() const { return ObjcConstraint; } 240 241 /// Set the parent umbrella frameworks. 242 /// \param Target_ The target applicable to Parent 243 /// \param Parent The name of Parent 244 void addParentUmbrella(const Target &Target_, StringRef Parent); 245 246 /// Get the list of Parent Umbrella frameworks. 247 /// 248 /// \return Returns a list of target information and install name of parent 249 /// umbrellas. 250 const std::vector<std::pair<Target, std::string>> &umbrellas() const { 251 return ParentUmbrellas; 252 } 253 254 /// Add an allowable client. 255 /// 256 /// Mach-O Dynamic libraries have the concept of allowable clients that are 257 /// checked during static link time. The name of the application or library 258 /// that is being generated needs to match one of the allowable clients or the 259 /// linker refuses to link this library. 260 /// 261 /// \param InstallName The name of the client that is allowed to link this 262 /// library. 263 /// \param Target The target triple for which this applies. 264 void addAllowableClient(StringRef InstallName, const Target &Target); 265 266 /// Get the list of allowable clients. 267 /// 268 /// \return Returns a list of allowable clients. 269 const std::vector<InterfaceFileRef> &allowableClients() const { 270 return AllowableClients; 271 } 272 273 /// Add a re-exported library. 274 /// 275 /// \param InstallName The name of the library to re-export. 276 /// \param Target The target triple for which this applies. 277 void addReexportedLibrary(StringRef InstallName, const Target &Target); 278 279 /// Get the list of re-exported libraries. 280 /// 281 /// \return Returns a list of re-exported libraries. 282 const std::vector<InterfaceFileRef> &reexportedLibraries() const { 283 return ReexportedLibraries; 284 } 285 286 /// Add a library for inlining to top level library. 287 /// 288 ///\param Document The library to inline with top level library. 289 void addDocument(std::shared_ptr<InterfaceFile> &&Document); 290 291 /// Returns the pointer to parent document if exists or nullptr otherwise. 292 InterfaceFile *getParent() const { return Parent; } 293 294 /// Get the list of inlined libraries. 295 /// 296 /// \return Returns a list of the inlined frameworks. 297 const std::vector<std::shared_ptr<InterfaceFile>> &documents() const { 298 return Documents; 299 } 300 301 /// Set the runpath search paths. 302 /// \param RPath The name of runpath. 303 /// \param InputTarget The target applicable to runpath search path. 304 void addRPath(StringRef RPath, const Target &InputTarget); 305 306 /// Get the list of runpath search paths. 307 /// 308 /// \return Returns a list of the rpaths per target. 309 const std::vector<std::pair<Target, std::string>> &rpaths() const { 310 return RPaths; 311 } 312 313 /// Get symbol if exists in file. 314 /// 315 /// \param Kind The kind of global symbol to record. 316 /// \param Name The name of the symbol. 317 /// \param ObjCIF The ObjCInterface symbol type, if applicable. 318 std::optional<const Symbol *> 319 getSymbol(EncodeKind Kind, StringRef Name, 320 ObjCIFSymbolKind ObjCIF = ObjCIFSymbolKind::None) const { 321 if (auto *Sym = SymbolsSet->findSymbol(Kind, Name, ObjCIF)) 322 return Sym; 323 return std::nullopt; 324 } 325 326 /// Add a symbol to the symbols list or extend an existing one. 327 template <typename RangeT, typename ElT = std::remove_reference_t< 328 decltype(*std::begin(std::declval<RangeT>()))>> 329 void addSymbol(EncodeKind Kind, StringRef Name, RangeT &&Targets, 330 SymbolFlags Flags = SymbolFlags::None) { 331 SymbolsSet->addGlobal(Kind, Name, Flags, Targets); 332 } 333 334 /// Add Symbol with multiple targets. 335 /// 336 /// \param Kind The kind of global symbol to record. 337 /// \param Name The name of the symbol. 338 /// \param Targets The list of targets the symbol is defined in. 339 /// \param Flags The properties the symbol holds. 340 void addSymbol(EncodeKind Kind, StringRef Name, TargetList &&Targets, 341 SymbolFlags Flags = SymbolFlags::None) { 342 SymbolsSet->addGlobal(Kind, Name, Flags, Targets); 343 } 344 345 /// Add Symbol with single target. 346 /// 347 /// \param Kind The kind of global symbol to record. 348 /// \param Name The name of the symbol. 349 /// \param Target The target the symbol is defined in. 350 /// \param Flags The properties the symbol holds. 351 void addSymbol(EncodeKind Kind, StringRef Name, Target &Target, 352 SymbolFlags Flags = SymbolFlags::None) { 353 SymbolsSet->addGlobal(Kind, Name, Flags, Target); 354 } 355 356 /// Get size of symbol set. 357 /// \return The number of symbols the file holds. 358 size_t symbolsCount() const { return SymbolsSet->size(); } 359 360 using const_symbol_range = SymbolSet::const_symbol_range; 361 using const_filtered_symbol_range = SymbolSet::const_filtered_symbol_range; 362 363 const_symbol_range symbols() const { return SymbolsSet->symbols(); }; 364 const_filtered_symbol_range exports() const { return SymbolsSet->exports(); }; 365 const_filtered_symbol_range reexports() const { 366 return SymbolsSet->reexports(); 367 }; 368 const_filtered_symbol_range undefineds() const { 369 return SymbolsSet->undefineds(); 370 }; 371 372 /// Extract architecture slice from Interface. 373 /// 374 /// \param Arch architecture to extract from. 375 /// \return New InterfaceFile with extracted architecture slice. 376 llvm::Expected<std::unique_ptr<InterfaceFile>> 377 extract(Architecture Arch) const; 378 379 /// Remove architecture slice from Interface. 380 /// 381 /// \param Arch architecture to remove. 382 /// \return New Interface File with removed architecture slice. 383 llvm::Expected<std::unique_ptr<InterfaceFile>> 384 remove(Architecture Arch) const; 385 386 /// Merge Interfaces for the same library. The following library attributes 387 /// must match. 388 /// * Install name, Current & Compatibility version, 389 /// * Two-level namespace enablement, and App extension enablement. 390 /// 391 /// \param O The Interface to merge. 392 /// \return New Interface File that was merged. 393 llvm::Expected<std::unique_ptr<InterfaceFile>> 394 merge(const InterfaceFile *O) const; 395 396 /// Inline reexported library into Interface. 397 /// 398 /// \param Library Interface of reexported library. 399 /// \param Overwrite Whether to overwrite preexisting inlined library. 400 void inlineLibrary(std::shared_ptr<InterfaceFile> Library, 401 bool Overwrite = false); 402 403 /// Set InterfaceFile properties from pre-gathered binary attributes, 404 /// if they are not set already. 405 /// 406 /// \param BA Attributes typically represented in load commands. 407 /// \param Targ MachO Target slice to add attributes to. 408 void setFromBinaryAttrs(const RecordsSlice::BinaryAttrs &BA, 409 const Target &Targ); 410 411 /// The equality is determined by attributes that impact linking 412 /// compatibilities. Path, & FileKind are irrelevant since these by 413 /// itself should not impact linking. 414 /// This is an expensive operation. 415 bool operator==(const InterfaceFile &O) const; 416 417 bool operator!=(const InterfaceFile &O) const { return !(*this == O); } 418 419 private: 420 llvm::BumpPtrAllocator Allocator; 421 StringRef copyString(StringRef String) { 422 if (String.empty()) 423 return {}; 424 425 void *Ptr = Allocator.Allocate(String.size(), 1); 426 memcpy(Ptr, String.data(), String.size()); 427 return StringRef(reinterpret_cast<const char *>(Ptr), String.size()); 428 } 429 430 TargetList Targets; 431 std::string Path; 432 FileType FileKind{FileType::Invalid}; 433 std::string InstallName; 434 PackedVersion CurrentVersion; 435 PackedVersion CompatibilityVersion; 436 uint8_t SwiftABIVersion{0}; 437 bool IsTwoLevelNamespace{false}; 438 bool IsOSLibNotForSharedCache{false}; 439 bool IsAppExtensionSafe{false}; 440 bool HasSimSupport{false}; 441 ObjCConstraintType ObjcConstraint = ObjCConstraintType::None; 442 std::vector<std::pair<Target, std::string>> ParentUmbrellas; 443 std::vector<InterfaceFileRef> AllowableClients; 444 std::vector<InterfaceFileRef> ReexportedLibraries; 445 std::vector<std::shared_ptr<InterfaceFile>> Documents; 446 std::vector<std::pair<Target, std::string>> RPaths; 447 std::unique_ptr<SymbolSet> SymbolsSet; 448 InterfaceFile *Parent = nullptr; 449 }; 450 451 // Keep containers that hold InterfaceFileRefs in sorted order and uniqued. 452 template <typename C> 453 typename C::iterator addEntry(C &Container, StringRef InstallName) { 454 auto I = partition_point(Container, [=](const InterfaceFileRef &O) { 455 return O.getInstallName() < InstallName; 456 }); 457 if (I != Container.end() && I->getInstallName() == InstallName) 458 return I; 459 460 return Container.emplace(I, InstallName); 461 } 462 463 } // end namespace MachO. 464 } // end namespace llvm. 465 466 #endif // LLVM_TEXTAPI_INTERFACEFILE_H 467