Details | Last modification | View Log | RSS feed
| Rev | Author | Line No. | Line |
|---|---|---|---|
| 14 | pmbaty | 1 | //===- ModuleDepCollector.h - Callbacks to collect deps ---------*- 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 | #ifndef LLVM_CLANG_TOOLING_DEPENDENCYSCANNING_MODULEDEPCOLLECTOR_H |
||
| 10 | #define LLVM_CLANG_TOOLING_DEPENDENCYSCANNING_MODULEDEPCOLLECTOR_H |
||
| 11 | |||
| 12 | #include "clang/Basic/LLVM.h" |
||
| 13 | #include "clang/Basic/SourceManager.h" |
||
| 14 | #include "clang/Frontend/CompilerInvocation.h" |
||
| 15 | #include "clang/Frontend/Utils.h" |
||
| 16 | #include "clang/Lex/HeaderSearch.h" |
||
| 17 | #include "clang/Lex/PPCallbacks.h" |
||
| 18 | #include "clang/Serialization/ASTReader.h" |
||
| 19 | #include "llvm/ADT/DenseMap.h" |
||
| 20 | #include "llvm/ADT/StringSet.h" |
||
| 21 | #include "llvm/Support/raw_ostream.h" |
||
| 22 | #include <optional> |
||
| 23 | #include <string> |
||
| 24 | #include <unordered_map> |
||
| 25 | |||
| 26 | namespace clang { |
||
| 27 | namespace tooling { |
||
| 28 | namespace dependencies { |
||
| 29 | |||
| 30 | class DependencyConsumer; |
||
| 31 | |||
| 32 | /// Modular dependency that has already been built prior to the dependency scan. |
||
| 33 | struct PrebuiltModuleDep { |
||
| 34 | std::string ModuleName; |
||
| 35 | std::string PCMFile; |
||
| 36 | std::string ModuleMapFile; |
||
| 37 | |||
| 38 | explicit PrebuiltModuleDep(const Module *M) |
||
| 39 | : ModuleName(M->getTopLevelModuleName()), |
||
| 40 | PCMFile(M->getASTFile()->getName()), |
||
| 41 | ModuleMapFile(M->PresumedModuleMapFile) {} |
||
| 42 | }; |
||
| 43 | |||
| 44 | /// This is used to identify a specific module. |
||
| 45 | struct ModuleID { |
||
| 46 | /// The name of the module. This may include `:` for C++20 module partitions, |
||
| 47 | /// or a header-name for C++20 header units. |
||
| 48 | std::string ModuleName; |
||
| 49 | |||
| 50 | /// The context hash of a module represents the compiler options that affect |
||
| 51 | /// the resulting command-line invocation. |
||
| 52 | /// |
||
| 53 | /// Modules with the same name and ContextHash but different invocations could |
||
| 54 | /// cause non-deterministic build results. |
||
| 55 | /// |
||
| 56 | /// Modules with the same name but a different \c ContextHash should be |
||
| 57 | /// treated as separate modules for the purpose of a build. |
||
| 58 | std::string ContextHash; |
||
| 59 | |||
| 60 | bool operator==(const ModuleID &Other) const { |
||
| 61 | return ModuleName == Other.ModuleName && ContextHash == Other.ContextHash; |
||
| 62 | } |
||
| 63 | }; |
||
| 64 | |||
| 65 | /// P1689ModuleInfo - Represents the needed information of standard C++20 |
||
| 66 | /// modules for P1689 format. |
||
| 67 | struct P1689ModuleInfo { |
||
| 68 | /// The name of the module. This may include `:` for partitions. |
||
| 69 | std::string ModuleName; |
||
| 70 | |||
| 71 | /// Optional. The source path to the module. |
||
| 72 | std::string SourcePath; |
||
| 73 | |||
| 74 | /// If this module is a standard c++ interface unit. |
||
| 75 | bool IsStdCXXModuleInterface = true; |
||
| 76 | |||
| 77 | enum class ModuleType { |
||
| 78 | NamedCXXModule |
||
| 79 | // To be supported |
||
| 80 | // AngleHeaderUnit, |
||
| 81 | // QuoteHeaderUnit |
||
| 82 | }; |
||
| 83 | ModuleType Type = ModuleType::NamedCXXModule; |
||
| 84 | }; |
||
| 85 | |||
| 86 | /// An output from a module compilation, such as the path of the module file. |
||
| 87 | enum class ModuleOutputKind { |
||
| 88 | /// The module file (.pcm). Required. |
||
| 89 | ModuleFile, |
||
| 90 | /// The path of the dependency file (.d), if any. |
||
| 91 | DependencyFile, |
||
| 92 | /// The null-separated list of names to use as the targets in the dependency |
||
| 93 | /// file, if any. Defaults to the value of \c ModuleFile, as in the driver. |
||
| 94 | DependencyTargets, |
||
| 95 | /// The path of the serialized diagnostic file (.dia), if any. |
||
| 96 | DiagnosticSerializationFile, |
||
| 97 | }; |
||
| 98 | |||
| 99 | struct ModuleDeps { |
||
| 100 | /// The identifier of the module. |
||
| 101 | ModuleID ID; |
||
| 102 | |||
| 103 | /// Whether this is a "system" module. |
||
| 104 | bool IsSystem; |
||
| 105 | |||
| 106 | /// The path to the modulemap file which defines this module. |
||
| 107 | /// |
||
| 108 | /// This can be used to explicitly build this module. This file will |
||
| 109 | /// additionally appear in \c FileDeps as a dependency. |
||
| 110 | std::string ClangModuleMapFile; |
||
| 111 | |||
| 112 | /// A collection of absolute paths to files that this module directly depends |
||
| 113 | /// on, not including transitive dependencies. |
||
| 114 | llvm::StringSet<> FileDeps; |
||
| 115 | |||
| 116 | /// A collection of absolute paths to module map files that this module needs |
||
| 117 | /// to know about. The ordering is significant. |
||
| 118 | std::vector<std::string> ModuleMapFileDeps; |
||
| 119 | |||
| 120 | /// A collection of prebuilt modular dependencies this module directly depends |
||
| 121 | /// on, not including transitive dependencies. |
||
| 122 | std::vector<PrebuiltModuleDep> PrebuiltModuleDeps; |
||
| 123 | |||
| 124 | /// A list of module identifiers this module directly depends on, not |
||
| 125 | /// including transitive dependencies. |
||
| 126 | /// |
||
| 127 | /// This may include modules with a different context hash when it can be |
||
| 128 | /// determined that the differences are benign for this compilation. |
||
| 129 | std::vector<ModuleID> ClangModuleDeps; |
||
| 130 | |||
| 131 | // Used to track which modules that were discovered were directly imported by |
||
| 132 | // the primary TU. |
||
| 133 | bool ImportedByMainFile = false; |
||
| 134 | |||
| 135 | /// Compiler invocation that can be used to build this module. Does not |
||
| 136 | /// include argv[0]. |
||
| 137 | std::vector<std::string> BuildArguments; |
||
| 138 | }; |
||
| 139 | |||
| 140 | class ModuleDepCollector; |
||
| 141 | |||
| 142 | /// Callback that records textual includes and direct modular includes/imports |
||
| 143 | /// during preprocessing. At the end of the main file, it also collects |
||
| 144 | /// transitive modular dependencies and passes everything to the |
||
| 145 | /// \c DependencyConsumer of the parent \c ModuleDepCollector. |
||
| 146 | class ModuleDepCollectorPP final : public PPCallbacks { |
||
| 147 | public: |
||
| 148 | ModuleDepCollectorPP(ModuleDepCollector &MDC) : MDC(MDC) {} |
||
| 149 | |||
| 150 | void FileChanged(SourceLocation Loc, FileChangeReason Reason, |
||
| 151 | SrcMgr::CharacteristicKind FileType, |
||
| 152 | FileID PrevFID) override; |
||
| 153 | void InclusionDirective(SourceLocation HashLoc, const Token &IncludeTok, |
||
| 154 | StringRef FileName, bool IsAngled, |
||
| 155 | CharSourceRange FilenameRange, |
||
| 156 | OptionalFileEntryRef File, StringRef SearchPath, |
||
| 157 | StringRef RelativePath, const Module *Imported, |
||
| 158 | SrcMgr::CharacteristicKind FileType) override; |
||
| 159 | void moduleImport(SourceLocation ImportLoc, ModuleIdPath Path, |
||
| 160 | const Module *Imported) override; |
||
| 161 | |||
| 162 | void EndOfMainFile() override; |
||
| 163 | |||
| 164 | private: |
||
| 165 | /// The parent dependency collector. |
||
| 166 | ModuleDepCollector &MDC; |
||
| 167 | /// Working set of direct modular dependencies. |
||
| 168 | llvm::SetVector<const Module *> DirectModularDeps; |
||
| 169 | |||
| 170 | void handleImport(const Module *Imported); |
||
| 171 | |||
| 172 | /// Adds direct modular dependencies that have already been built to the |
||
| 173 | /// ModuleDeps instance. |
||
| 174 | void |
||
| 175 | addAllSubmodulePrebuiltDeps(const Module *M, ModuleDeps &MD, |
||
| 176 | llvm::DenseSet<const Module *> &SeenSubmodules); |
||
| 177 | void addModulePrebuiltDeps(const Module *M, ModuleDeps &MD, |
||
| 178 | llvm::DenseSet<const Module *> &SeenSubmodules); |
||
| 179 | |||
| 180 | /// Traverses the previously collected direct modular dependencies to discover |
||
| 181 | /// transitive modular dependencies and fills the parent \c ModuleDepCollector |
||
| 182 | /// with both. |
||
| 183 | /// Returns the ID or nothing if the dependency is spurious and is ignored. |
||
| 184 | std::optional<ModuleID> handleTopLevelModule(const Module *M); |
||
| 185 | void addAllSubmoduleDeps(const Module *M, ModuleDeps &MD, |
||
| 186 | llvm::DenseSet<const Module *> &AddedModules); |
||
| 187 | void addModuleDep(const Module *M, ModuleDeps &MD, |
||
| 188 | llvm::DenseSet<const Module *> &AddedModules); |
||
| 189 | |||
| 190 | /// Traverses the affecting modules and updates \c MD with references to the |
||
| 191 | /// parent \c ModuleDepCollector info. |
||
| 192 | void addAllAffectingClangModules(const Module *M, ModuleDeps &MD, |
||
| 193 | llvm::DenseSet<const Module *> &AddedModules); |
||
| 194 | void addAffectingClangModule(const Module *M, ModuleDeps &MD, |
||
| 195 | llvm::DenseSet<const Module *> &AddedModules); |
||
| 196 | }; |
||
| 197 | |||
| 198 | /// Collects modular and non-modular dependencies of the main file by attaching |
||
| 199 | /// \c ModuleDepCollectorPP to the preprocessor. |
||
| 200 | class ModuleDepCollector final : public DependencyCollector { |
||
| 201 | public: |
||
| 202 | ModuleDepCollector(std::unique_ptr<DependencyOutputOptions> Opts, |
||
| 203 | CompilerInstance &ScanInstance, DependencyConsumer &C, |
||
| 204 | CompilerInvocation OriginalCI, bool OptimizeArgs, |
||
| 205 | bool EagerLoadModules, bool IsStdModuleP1689Format); |
||
| 206 | |||
| 207 | void attachToPreprocessor(Preprocessor &PP) override; |
||
| 208 | void attachToASTReader(ASTReader &R) override; |
||
| 209 | |||
| 210 | /// Apply any changes implied by the discovered dependencies to the given |
||
| 211 | /// invocation, (e.g. disable implicit modules, add explicit module paths). |
||
| 212 | void applyDiscoveredDependencies(CompilerInvocation &CI); |
||
| 213 | |||
| 214 | private: |
||
| 215 | friend ModuleDepCollectorPP; |
||
| 216 | |||
| 217 | /// The compiler instance for scanning the current translation unit. |
||
| 218 | CompilerInstance &ScanInstance; |
||
| 219 | /// The consumer of collected dependency information. |
||
| 220 | DependencyConsumer &Consumer; |
||
| 221 | /// Path to the main source file. |
||
| 222 | std::string MainFile; |
||
| 223 | /// Hash identifying the compilation conditions of the current TU. |
||
| 224 | std::string ContextHash; |
||
| 225 | /// Non-modular file dependencies. This includes the main source file and |
||
| 226 | /// textually included header files. |
||
| 227 | std::vector<std::string> FileDeps; |
||
| 228 | /// Direct and transitive modular dependencies of the main source file. |
||
| 229 | llvm::MapVector<const Module *, std::unique_ptr<ModuleDeps>> ModularDeps; |
||
| 230 | /// Secondary mapping for \c ModularDeps allowing lookup by ModuleID without |
||
| 231 | /// a preprocessor. Storage owned by \c ModularDeps. |
||
| 232 | llvm::DenseMap<ModuleID, ModuleDeps *> ModuleDepsByID; |
||
| 233 | /// Direct modular dependencies that have already been built. |
||
| 234 | llvm::MapVector<const Module *, PrebuiltModuleDep> DirectPrebuiltModularDeps; |
||
| 235 | /// Options that control the dependency output generation. |
||
| 236 | std::unique_ptr<DependencyOutputOptions> Opts; |
||
| 237 | /// The original Clang invocation passed to dependency scanner. |
||
| 238 | CompilerInvocation OriginalInvocation; |
||
| 239 | /// Whether to optimize the modules' command-line arguments. |
||
| 240 | bool OptimizeArgs; |
||
| 241 | /// Whether to set up command-lines to load PCM files eagerly. |
||
| 242 | bool EagerLoadModules; |
||
| 243 | /// If we're generating dependency output in P1689 format |
||
| 244 | /// for standard C++ modules. |
||
| 245 | bool IsStdModuleP1689Format; |
||
| 246 | |||
| 247 | std::optional<P1689ModuleInfo> ProvidedStdCXXModule; |
||
| 248 | std::vector<P1689ModuleInfo> RequiredStdCXXModules; |
||
| 249 | |||
| 250 | /// Checks whether the module is known as being prebuilt. |
||
| 251 | bool isPrebuiltModule(const Module *M); |
||
| 252 | |||
| 253 | /// Adds \p Path to \c FileDeps, making it absolute if necessary. |
||
| 254 | void addFileDep(StringRef Path); |
||
| 255 | /// Adds \p Path to \c MD.FileDeps, making it absolute if necessary. |
||
| 256 | void addFileDep(ModuleDeps &MD, StringRef Path); |
||
| 257 | |||
| 258 | /// Constructs a CompilerInvocation that can be used to build the given |
||
| 259 | /// module, excluding paths to discovered modular dependencies that are yet to |
||
| 260 | /// be built. |
||
| 261 | CompilerInvocation makeInvocationForModuleBuildWithoutOutputs( |
||
| 262 | const ModuleDeps &Deps, |
||
| 263 | llvm::function_ref<void(CompilerInvocation &)> Optimize) const; |
||
| 264 | |||
| 265 | /// Collect module map files for given modules. |
||
| 266 | llvm::DenseSet<const FileEntry *> |
||
| 267 | collectModuleMapFiles(ArrayRef<ModuleID> ClangModuleDeps) const; |
||
| 268 | |||
| 269 | /// Add module map files to the invocation, if needed. |
||
| 270 | void addModuleMapFiles(CompilerInvocation &CI, |
||
| 271 | ArrayRef<ModuleID> ClangModuleDeps) const; |
||
| 272 | /// Add module files (pcm) to the invocation, if needed. |
||
| 273 | void addModuleFiles(CompilerInvocation &CI, |
||
| 274 | ArrayRef<ModuleID> ClangModuleDeps) const; |
||
| 275 | |||
| 276 | /// Add paths that require looking up outputs to the given dependencies. |
||
| 277 | void addOutputPaths(CompilerInvocation &CI, ModuleDeps &Deps); |
||
| 278 | |||
| 279 | /// Compute the context hash for \p Deps, and create the mapping |
||
| 280 | /// \c ModuleDepsByID[Deps.ID] = &Deps. |
||
| 281 | void associateWithContextHash(const CompilerInvocation &CI, ModuleDeps &Deps); |
||
| 282 | }; |
||
| 283 | |||
| 284 | } // end namespace dependencies |
||
| 285 | } // end namespace tooling |
||
| 286 | } // end namespace clang |
||
| 287 | |||
| 288 | namespace llvm { |
||
| 289 | template <> struct DenseMapInfo<clang::tooling::dependencies::ModuleID> { |
||
| 290 | using ModuleID = clang::tooling::dependencies::ModuleID; |
||
| 291 | static inline ModuleID getEmptyKey() { return ModuleID{"", ""}; } |
||
| 292 | static inline ModuleID getTombstoneKey() { |
||
| 293 | return ModuleID{"~", "~"}; // ~ is not a valid module name or context hash |
||
| 294 | } |
||
| 295 | static unsigned getHashValue(const ModuleID &ID) { |
||
| 296 | return hash_combine(ID.ModuleName, ID.ContextHash); |
||
| 297 | } |
||
| 298 | static bool isEqual(const ModuleID &LHS, const ModuleID &RHS) { |
||
| 299 | return LHS == RHS; |
||
| 300 | } |
||
| 301 | }; |
||
| 302 | } // namespace llvm |
||
| 303 | |||
| 304 | #endif // LLVM_CLANG_TOOLING_DEPENDENCYSCANNING_MODULEDEPCOLLECTOR_H |