//===--- ModuleDependencies.h - Module Dependencies -------------*- C++ -*-===// // // This source file is part of the Swift.org open source project // // Copyright (c) 2014 - 2020 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See https://swift.org/LICENSE.txt for license information // See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors // //===----------------------------------------------------------------------===// // // This file defines data structures for capturing all of the source files // and modules on which a given module depends, forming a graph of all of the // modules that need to be present for a given module to be built. // //===----------------------------------------------------------------------===// #ifndef SWIFT_AST_MODULE_DEPENDENCIES_H #define SWIFT_AST_MODULE_DEPENDENCIES_H #include "swift/Basic/LLVM.h" #include "swift/AST/Import.h" #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/Optional.h" #include "llvm/ADT/StringSet.h" #include #include namespace swift { class ClangModuleDependenciesCacheImpl; class SourceFile; class ASTContext; class Identifier; /// Which kind of module dependencies we are looking for. enum class ModuleDependenciesKind : int8_t { SwiftTextual, SwiftBinary, // Placeholder dependencies are a kind of dependencies used only by the // dependency scanner. They are swift modules that the scanner will not be // able to locate in its search paths and which are the responsibility of the // scanner's client to ensure are provided. // // Placeholder dependencies will be specified in the scanner's output // dependency graph where it is the responsibility of the scanner's client to // ensure required post-processing takes place to "resolve" them. In order to // do so, the client (swift driver, or any other client build system) is // expected to have access to a full dependency graph of all placeholder // dependencies and be able to replace placeholder nodes in the dependency // graph with their full dependency trees, `uniquing` common dependency module // nodes in the process. // // One example where placeholder dependencies are employed is when using // SwiftPM in Explicit Module Build mode. SwiftPM constructs a build plan for // all targets ahead-of-time. When planning a build for a target that depends // on other targets, the dependency scanning action is not able to locate // dependency target modules, because they have not yet been built. Instead, // the build system treats them as placeholder dependencies and resolves them // with `actual` dependencies in a post-processing step once dependency graphs // of all targets, individually, have been computed. SwiftPlaceholder, Clang, }; /// Base class for the variant storage of ModuleDependencies. /// /// This class is mostly an implementation detail for \c ModuleDependencies. class ModuleDependenciesStorageBase { public: const ModuleDependenciesKind dependencyKind; ModuleDependenciesStorageBase(ModuleDependenciesKind dependencyKind) : dependencyKind(dependencyKind) { } virtual ModuleDependenciesStorageBase *clone() const = 0; virtual ~ModuleDependenciesStorageBase(); /// The set of modules on which this module depends. std::vector moduleDependencies; }; /// Describes the dependencies of a Swift module. /// /// This class is mostly an implementation detail for \c ModuleDependencies. class SwiftTextualModuleDependenciesStorage : public ModuleDependenciesStorageBase { public: /// The Swift interface file, if it can be used to generate the module file. const Optional swiftInterfaceFile; /// Potentially ready-to-use compiled modules for the interface file. const std::vector compiledModuleCandidates; /// The Swift frontend invocation arguments to build the Swift module from the /// interface. const std::vector buildCommandLine; /// To build a PCM to be used by this Swift module, we need to append these /// arguments to the generic PCM build arguments reported from the dependency /// graph. const std::vector extraPCMArgs; /// The hash value that will be used for the generated module const std::string contextHash; /// A flag that indicates this dependency is a framework const bool isFramework; /// Bridging header file, if there is one. Optional bridgingHeaderFile; /// Swift source files that are part of the Swift module, when known. std::vector sourceFiles; /// Source files on which the bridging header depends. std::vector bridgingSourceFiles; /// (Clang) modules on which the bridging header depends. std::vector bridgingModuleDependencies; SwiftTextualModuleDependenciesStorage( const Optional &swiftInterfaceFile, ArrayRef compiledModuleCandidates, ArrayRef buildCommandLine, ArrayRef extraPCMArgs, StringRef contextHash, bool isFramework ) : ModuleDependenciesStorageBase(ModuleDependenciesKind::SwiftTextual), swiftInterfaceFile(swiftInterfaceFile), compiledModuleCandidates(compiledModuleCandidates.begin(), compiledModuleCandidates.end()), buildCommandLine(buildCommandLine.begin(), buildCommandLine.end()), extraPCMArgs(extraPCMArgs.begin(), extraPCMArgs.end()), contextHash(contextHash), isFramework(isFramework) { } ModuleDependenciesStorageBase *clone() const override { return new SwiftTextualModuleDependenciesStorage(*this); } static bool classof(const ModuleDependenciesStorageBase *base) { return base->dependencyKind == ModuleDependenciesKind::SwiftTextual; } }; /// Describes the dependencies of a pre-built Swift module (with no .swiftinterface). /// /// This class is mostly an implementation detail for \c ModuleDependencies. class SwiftBinaryModuleDependencyStorage : public ModuleDependenciesStorageBase { public: SwiftBinaryModuleDependencyStorage(const std::string &compiledModulePath, const std::string &moduleDocPath, const std::string &sourceInfoPath, const bool isFramework) : ModuleDependenciesStorageBase(ModuleDependenciesKind::SwiftBinary), compiledModulePath(compiledModulePath), moduleDocPath(moduleDocPath), sourceInfoPath(sourceInfoPath), isFramework(isFramework) {} ModuleDependenciesStorageBase *clone() const override { return new SwiftBinaryModuleDependencyStorage(*this); } /// The path to the .swiftmodule file. const std::string compiledModulePath; /// The path to the .swiftModuleDoc file. const std::string moduleDocPath; /// The path to the .swiftSourceInfo file. const std::string sourceInfoPath; /// A flag that indicates this dependency is a framework const bool isFramework; static bool classof(const ModuleDependenciesStorageBase *base) { return base->dependencyKind == ModuleDependenciesKind::SwiftBinary; } }; /// Describes the dependencies of a Clang module. /// /// This class is mostly an implementation detail for \c ModuleDependencies. class ClangModuleDependenciesStorage : public ModuleDependenciesStorageBase { public: /// The module map file used to generate the Clang module. const std::string moduleMapFile; /// The context hash describing the configuration options for this module. const std::string contextHash; /// Partial (Clang) command line that can be used to build this module. const std::vector nonPathCommandLine; /// The file dependencies const std::vector fileDependencies; ClangModuleDependenciesStorage( const std::string &moduleMapFile, const std::string &contextHash, const std::vector &nonPathCommandLine, const std::vector &fileDependencies ) : ModuleDependenciesStorageBase(ModuleDependenciesKind::Clang), moduleMapFile(moduleMapFile), contextHash(contextHash), nonPathCommandLine(nonPathCommandLine), fileDependencies(fileDependencies) { } ModuleDependenciesStorageBase *clone() const override { return new ClangModuleDependenciesStorage(*this); } static bool classof(const ModuleDependenciesStorageBase *base) { return base->dependencyKind == ModuleDependenciesKind::Clang; } }; /// Describes an placeholder Swift module dependency module stub. /// /// This class is mostly an implementation detail for \c ModuleDependencies. class SwiftPlaceholderModuleDependencyStorage : public ModuleDependenciesStorageBase { public: SwiftPlaceholderModuleDependencyStorage(const std::string &compiledModulePath, const std::string &moduleDocPath, const std::string &sourceInfoPath) : ModuleDependenciesStorageBase(ModuleDependenciesKind::SwiftPlaceholder), compiledModulePath(compiledModulePath), moduleDocPath(moduleDocPath), sourceInfoPath(sourceInfoPath) {} ModuleDependenciesStorageBase *clone() const override { return new SwiftPlaceholderModuleDependencyStorage(*this); } /// The path to the .swiftmodule file. const std::string compiledModulePath; /// The path to the .swiftModuleDoc file. const std::string moduleDocPath; /// The path to the .swiftSourceInfo file. const std::string sourceInfoPath; static bool classof(const ModuleDependenciesStorageBase *base) { return base->dependencyKind == ModuleDependenciesKind::SwiftPlaceholder; } }; /// Describes the dependencies of a given module. /// /// The dependencies of a module include all of the source files that go /// into that module, as well as any modules that are directly imported /// into the module. class ModuleDependencies { private: std::unique_ptr storage; ModuleDependencies(std::unique_ptr &&storage) : storage(std::move(storage)) { } public: ModuleDependencies(const ModuleDependencies &other) : storage(other.storage->clone()) { } ModuleDependencies(ModuleDependencies &&other) = default; ModuleDependencies &operator=(const ModuleDependencies &other) { storage.reset(other.storage->clone()); return *this; } ModuleDependencies &operator=(ModuleDependencies &&other) = default; /// Describe the module dependencies for a Swift module that can be /// built from a Swift interface file (\c .swiftinterface). static ModuleDependencies forSwiftInterface( const std::string &swiftInterfaceFile, ArrayRef compiledCandidates, ArrayRef buildCommands, ArrayRef extraPCMArgs, StringRef contextHash, bool isFramework) { return ModuleDependencies( std::make_unique( swiftInterfaceFile, compiledCandidates, buildCommands, extraPCMArgs, contextHash, isFramework)); } /// Describe the module dependencies for a serialized or parsed Swift module. static ModuleDependencies forSwiftBinaryModule( const std::string &compiledModulePath, const std::string &moduleDocPath, const std::string &sourceInfoPath, bool isFramework) { return ModuleDependencies( std::make_unique( compiledModulePath, moduleDocPath, sourceInfoPath, isFramework)); } /// Describe the main Swift module. static ModuleDependencies forMainSwiftModule(ArrayRef extraPCMArgs) { return ModuleDependencies( std::make_unique( None, ArrayRef(), ArrayRef(), extraPCMArgs, StringRef(), false)); } /// Describe the module dependencies for a Clang module that can be /// built from a module map and headers. static ModuleDependencies forClangModule( const std::string &moduleMapFile, const std::string &contextHash, const std::vector &nonPathCommandLine, const std::vector &fileDependencies) { return ModuleDependencies( std::make_unique( moduleMapFile, contextHash, nonPathCommandLine, fileDependencies)); } /// Describe a placeholder dependency swift module. static ModuleDependencies forPlaceholderSwiftModuleStub( const std::string &compiledModulePath, const std::string &moduleDocPath, const std::string &sourceInfoPath) { return ModuleDependencies( std::make_unique( compiledModulePath, moduleDocPath, sourceInfoPath)); } /// Retrieve the module-level dependencies. ArrayRef getModuleDependencies() const { return storage->moduleDependencies; } /// Whether the dependencies are for a Swift module: either Textual, Binary, or Placeholder. bool isSwiftModule() const; /// Whether the dependencies are for a textual Swift module. bool isSwiftTextualModule() const; /// Whether the dependencies are for a binary Swift module. bool isSwiftBinaryModule() const; /// Whether this represents a placeholder module stub bool isSwiftPlaceholderModule() const; /// Whether the dependencies are for a Clang module. bool isClangModule() const; ModuleDependenciesKind getKind() const { return storage->dependencyKind; } /// Retrieve the dependencies for a Swift module. const SwiftTextualModuleDependenciesStorage *getAsSwiftTextualModule() const; /// Retrieve the dependencies for a binary Swift module. const SwiftBinaryModuleDependencyStorage *getAsSwiftBinaryModule() const; /// Retrieve the dependencies for a Clang module. const ClangModuleDependenciesStorage *getAsClangModule() const; /// Retrieve the dependencies for a placeholder dependency module stub. const SwiftPlaceholderModuleDependencyStorage * getAsPlaceholderDependencyModule() const; /// Add a dependency on the given module, if it was not already in the set. void addModuleDependency(StringRef module, llvm::StringSet<> *alreadyAddedModules = nullptr); /// Add a dependency on the given module, if it was not already in the set. void addModuleDependency(ImportPath::Module module, llvm::StringSet<> *alreadyAddedModules = nullptr) { addModuleDependency(module.front().Item.str(), alreadyAddedModules); } /// Add all of the module dependencies for the imports in the given source /// file to the set of module dependencies. void addModuleDependencies(const SourceFile &sf, llvm::StringSet<> &alreadyAddedModules); /// Get the bridging header. Optional getBridgingHeader() const; /// Add a bridging header to a Swift module's dependencies. void addBridgingHeader(StringRef bridgingHeader); /// Add source files that the bridging header depends on. void addBridgingSourceFile(StringRef bridgingSourceFile); /// Add (Clang) module on which the bridging header depends. void addBridgingModuleDependency(StringRef module, llvm::StringSet<> &alreadyAddedModules); /// Collect a map from a secondary module name to a list of cross-import /// overlays, when this current module serves as the primary module. llvm::StringMap> collectCrossImportOverlayNames(ASTContext &ctx, StringRef moduleName); }; using ModuleDependencyID = std::pair; /// A cache describing the set of module dependencies that has been queried /// thus far. class ModuleDependenciesCache { /// All cached module dependencies, in the order in which they were /// encountered. std::vector AllModules; /// Dependencies for Textual Swift modules that have already been computed. llvm::StringMap SwiftTextualModuleDependencies; /// Dependencies for Binary Swift modules that have already been computed. llvm::StringMap SwiftBinaryModuleDependencies; /// Dependencies for Swift placeholder dependency modules that have already been computed. llvm::StringMap SwiftPlaceholderModuleDependencies; /// Dependencies for Clang modules that have already been computed. llvm::StringMap ClangModuleDependencies; /// Additional information needed for Clang dependency scanning. ClangModuleDependenciesCacheImpl *clangImpl = nullptr; /// Function that will delete \c clangImpl properly. void (*clangImplDeleter)(ClangModuleDependenciesCacheImpl *) = nullptr; /// Free up the storage associated with the Clang implementation. void destroyClangImpl() { if (this->clangImplDeleter) this->clangImplDeleter(this->clangImpl); } /// Retrieve the dependencies map that corresponds to the given dependency /// kind. llvm::StringMap &getDependenciesMap( ModuleDependenciesKind kind); const llvm::StringMap &getDependenciesMap( ModuleDependenciesKind kind) const; public: ModuleDependenciesCache() { } ModuleDependenciesCache(const ModuleDependenciesCache &) = delete; ModuleDependenciesCache &operator=(const ModuleDependenciesCache &) = delete; ~ModuleDependenciesCache() { destroyClangImpl(); } /// Set the Clang-specific implementation data. void setClangImpl( ClangModuleDependenciesCacheImpl *clangImpl, void (*clangImplDeleter)(ClangModuleDependenciesCacheImpl *)) { destroyClangImpl(); this->clangImpl = clangImpl; this->clangImplDeleter = clangImplDeleter; } /// Retrieve the Clang-specific implementation data; ClangModuleDependenciesCacheImpl *getClangImpl() const { return clangImpl; } /// Whether we have cached dependency information for the given module. bool hasDependencies(StringRef moduleName, Optional kind) const; /// Look for module dependencies for a module with the given name. /// /// \returns the cached result, or \c None if there is no cached entry. Optional findDependencies( StringRef moduleName, Optional kind) const; /// Record dependencies for the given module. void recordDependencies(StringRef moduleName, ModuleDependencies dependencies); /// Update stored dependencies for the given module. void updateDependencies(ModuleDependencyID moduleID, ModuleDependencies dependencies); /// Reference the list of all module dependencies. const std::vector &getAllModules() const { return AllModules; } }; } #endif /* SWIFT_AST_MODULE_DEPENDENCIES_H */