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