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