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