1 //===- DependencyScanningTool.h - clang-scan-deps service -----------------===// 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_DEPENDENCYSCANNINGTOOL_H 10 #define LLVM_CLANG_TOOLING_DEPENDENCYSCANNING_DEPENDENCYSCANNINGTOOL_H 11 12 #include "clang/Tooling/DependencyScanning/DependencyScanningService.h" 13 #include "clang/Tooling/DependencyScanning/DependencyScanningWorker.h" 14 #include "clang/Tooling/DependencyScanning/ModuleDepCollector.h" 15 #include "clang/Tooling/JSONCompilationDatabase.h" 16 #include "llvm/ADT/MapVector.h" 17 #include "llvm/ADT/StringSet.h" 18 #include "llvm/ADT/StringMap.h" 19 #include <optional> 20 #include <string> 21 #include <vector> 22 23 namespace clang { 24 namespace tooling { 25 namespace dependencies { 26 27 /// A callback to lookup module outputs for "-fmodule-file=", "-o" etc. 28 using LookupModuleOutputCallback = 29 llvm::function_ref<std::string(const ModuleID &, ModuleOutputKind)>; 30 31 /// The full dependencies and module graph for a specific input. 32 struct FullDependencies { 33 /// The identifier of the C++20 module this translation unit exports. 34 /// 35 /// If the translation unit is not a module then \c ID.ModuleName is empty. 36 ModuleID ID; 37 38 /// A collection of absolute paths to files that this translation unit 39 /// directly depends on, not including transitive dependencies. 40 std::vector<std::string> FileDeps; 41 42 /// A collection of prebuilt modules this translation unit directly depends 43 /// on, not including transitive dependencies. 44 std::vector<PrebuiltModuleDep> PrebuiltModuleDeps; 45 46 /// A list of modules this translation unit directly depends on, not including 47 /// transitive dependencies. 48 /// 49 /// This may include modules with a different context hash when it can be 50 /// determined that the differences are benign for this compilation. 51 std::vector<ModuleID> ClangModuleDeps; 52 53 /// The sequence of commands required to build the translation unit. Commands 54 /// should be executed in order. 55 /// 56 /// FIXME: If we add support for multi-arch builds in clang-scan-deps, we 57 /// should make the dependencies between commands explicit to enable parallel 58 /// builds of each architecture. 59 std::vector<Command> Commands; 60 61 /// Deprecated driver command-line. This will be removed in a future version. 62 std::vector<std::string> DriverCommandLine; 63 }; 64 65 struct FullDependenciesResult { 66 FullDependencies FullDeps; 67 std::vector<ModuleDeps> DiscoveredModules; 68 }; 69 70 struct P1689Rule { 71 std::string PrimaryOutput; 72 std::optional<P1689ModuleInfo> Provides; 73 std::vector<P1689ModuleInfo> Requires; 74 }; 75 76 /// The high-level implementation of the dependency discovery tool that runs on 77 /// an individual worker thread. 78 class DependencyScanningTool { 79 public: 80 /// Construct a dependency scanning tool. 81 DependencyScanningTool(DependencyScanningService &Service, 82 llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> FS = 83 llvm::vfs::createPhysicalFileSystem()); 84 85 /// Print out the dependency information into a string using the dependency 86 /// file format that is specified in the options (-MD is the default) and 87 /// return it. If \p ModuleName isn't empty, this function returns the 88 /// dependency information of module \p ModuleName. 89 /// 90 /// \returns A \c StringError with the diagnostic output if clang errors 91 /// occurred, dependency file contents otherwise. 92 llvm::Expected<std::string> 93 getDependencyFile(const std::vector<std::string> &CommandLine, StringRef CWD, 94 std::optional<StringRef> ModuleName = std::nullopt); 95 96 /// Collect the module dependency in P1689 format for C++20 named modules. 97 /// 98 /// \param MakeformatOutput The output parameter for dependency information 99 /// in make format if the command line requires to generate make-format 100 /// dependency information by `-MD -MF <dep_file>`. 101 /// 102 /// \param MakeformatOutputPath The output parameter for the path to 103 /// \param MakeformatOutput. 104 /// 105 /// \returns A \c StringError with the diagnostic output if clang errors 106 /// occurred, P1689 dependency format rules otherwise. 107 llvm::Expected<P1689Rule> 108 getP1689ModuleDependencyFile( 109 const clang::tooling::CompileCommand &Command, StringRef CWD, 110 std::string &MakeformatOutput, std::string &MakeformatOutputPath); 111 112 /// Given a Clang driver command-line for a translation unit, gather the 113 /// modular dependencies and return the information needed for explicit build. 114 /// 115 /// \param AlreadySeen This stores modules which have previously been 116 /// reported. Use the same instance for all calls to this 117 /// function for a single \c DependencyScanningTool in a 118 /// single build. Use a different one for different tools, 119 /// and clear it between builds. 120 /// \param LookupModuleOutput This function is called to fill in 121 /// "-fmodule-file=", "-o" and other output 122 /// arguments for dependencies. 123 /// 124 /// \returns a \c StringError with the diagnostic output if clang errors 125 /// occurred, \c FullDependencies otherwise. 126 llvm::Expected<FullDependenciesResult> 127 getFullDependencies(const std::vector<std::string> &CommandLine, 128 StringRef CWD, const llvm::StringSet<> &AlreadySeen, 129 LookupModuleOutputCallback LookupModuleOutput, 130 std::optional<StringRef> ModuleName = std::nullopt); 131 132 llvm::Expected<FullDependenciesResult> getFullDependenciesLegacyDriverCommand( 133 const std::vector<std::string> &CommandLine, StringRef CWD, 134 const llvm::StringSet<> &AlreadySeen, 135 LookupModuleOutputCallback LookupModuleOutput, 136 std::optional<StringRef> ModuleName = std::nullopt); 137 138 private: 139 DependencyScanningWorker Worker; 140 }; 141 142 class FullDependencyConsumer : public DependencyConsumer { 143 public: FullDependencyConsumer(const llvm::StringSet<> & AlreadySeen,LookupModuleOutputCallback LookupModuleOutput,bool EagerLoadModules)144 FullDependencyConsumer(const llvm::StringSet<> &AlreadySeen, 145 LookupModuleOutputCallback LookupModuleOutput, 146 bool EagerLoadModules) 147 : AlreadySeen(AlreadySeen), LookupModuleOutput(LookupModuleOutput), 148 EagerLoadModules(EagerLoadModules) {} 149 handleBuildCommand(Command Cmd)150 void handleBuildCommand(Command Cmd) override { 151 Commands.push_back(std::move(Cmd)); 152 } 153 handleDependencyOutputOpts(const DependencyOutputOptions &)154 void handleDependencyOutputOpts(const DependencyOutputOptions &) override {} 155 handleFileDependency(StringRef File)156 void handleFileDependency(StringRef File) override { 157 Dependencies.push_back(std::string(File)); 158 } 159 handlePrebuiltModuleDependency(PrebuiltModuleDep PMD)160 void handlePrebuiltModuleDependency(PrebuiltModuleDep PMD) override { 161 PrebuiltModuleDeps.emplace_back(std::move(PMD)); 162 } 163 handleModuleDependency(ModuleDeps MD)164 void handleModuleDependency(ModuleDeps MD) override { 165 ClangModuleDeps[MD.ID.ContextHash + MD.ID.ModuleName] = std::move(MD); 166 } 167 handleContextHash(std::string Hash)168 void handleContextHash(std::string Hash) override { 169 ContextHash = std::move(Hash); 170 } 171 lookupModuleOutput(const ModuleID & ID,ModuleOutputKind Kind)172 std::string lookupModuleOutput(const ModuleID &ID, 173 ModuleOutputKind Kind) override { 174 return LookupModuleOutput(ID, Kind); 175 } 176 177 FullDependenciesResult getFullDependenciesLegacyDriverCommand( 178 const std::vector<std::string> &OriginalCommandLine) const; 179 180 FullDependenciesResult takeFullDependencies(); 181 182 private: 183 std::vector<std::string> Dependencies; 184 std::vector<PrebuiltModuleDep> PrebuiltModuleDeps; 185 llvm::MapVector<std::string, ModuleDeps, llvm::StringMap<unsigned>> 186 ClangModuleDeps; 187 std::vector<Command> Commands; 188 std::string ContextHash; 189 std::vector<std::string> OutputPaths; 190 const llvm::StringSet<> &AlreadySeen; 191 LookupModuleOutputCallback LookupModuleOutput; 192 bool EagerLoadModules; 193 }; 194 195 } // end namespace dependencies 196 } // end namespace tooling 197 } // end namespace clang 198 199 #endif // LLVM_CLANG_TOOLING_DEPENDENCYSCANNING_DEPENDENCYSCANNINGTOOL_H 200