//===- DependencyScanningTool.h - clang-scan-deps service -----------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// #ifndef LLVM_CLANG_TOOLING_DEPENDENCYSCANNING_DEPENDENCYSCANNINGTOOL_H #define LLVM_CLANG_TOOLING_DEPENDENCYSCANNING_DEPENDENCYSCANNINGTOOL_H #include "clang/Tooling/DependencyScanning/DependencyScanningService.h" #include "clang/Tooling/DependencyScanning/DependencyScanningWorker.h" #include "clang/Tooling/DependencyScanning/ModuleDepCollector.h" #include "clang/Tooling/JSONCompilationDatabase.h" #include "llvm/ADT/DenseSet.h" #include "llvm/ADT/MapVector.h" #include #include #include namespace clang { namespace tooling { namespace dependencies { /// A callback to lookup module outputs for "-fmodule-file=", "-o" etc. using LookupModuleOutputCallback = llvm::function_ref; /// Graph of modular dependencies. using ModuleDepsGraph = std::vector; /// The full dependencies and module graph for a specific input. struct TranslationUnitDeps { /// The graph of direct and transitive modular dependencies. ModuleDepsGraph ModuleGraph; /// The identifier of the C++20 module this translation unit exports. /// /// If the translation unit is not a module then \c ID.ModuleName is empty. ModuleID ID; /// A collection of absolute paths to files that this translation unit /// directly depends on, not including transitive dependencies. std::vector FileDeps; /// A collection of prebuilt modules this translation unit directly depends /// on, not including transitive dependencies. std::vector PrebuiltModuleDeps; /// A list of modules this translation unit directly depends on, not including /// transitive dependencies. /// /// This may include modules with a different context hash when it can be /// determined that the differences are benign for this compilation. std::vector ClangModuleDeps; /// The sequence of commands required to build the translation unit. Commands /// should be executed in order. /// /// FIXME: If we add support for multi-arch builds in clang-scan-deps, we /// should make the dependencies between commands explicit to enable parallel /// builds of each architecture. std::vector Commands; /// Deprecated driver command-line. This will be removed in a future version. std::vector DriverCommandLine; }; struct P1689Rule { std::string PrimaryOutput; std::optional Provides; std::vector Requires; }; /// The high-level implementation of the dependency discovery tool that runs on /// an individual worker thread. class DependencyScanningTool { public: /// Construct a dependency scanning tool. DependencyScanningTool(DependencyScanningService &Service, llvm::IntrusiveRefCntPtr FS = llvm::vfs::createPhysicalFileSystem()); /// Print out the dependency information into a string using the dependency /// file format that is specified in the options (-MD is the default) and /// return it. /// /// \returns A \c StringError with the diagnostic output if clang errors /// occurred, dependency file contents otherwise. llvm::Expected getDependencyFile(const std::vector &CommandLine, StringRef CWD); /// Collect the module dependency in P1689 format for C++20 named modules. /// /// \param MakeformatOutput The output parameter for dependency information /// in make format if the command line requires to generate make-format /// dependency information by `-MD -MF `. /// /// \param MakeformatOutputPath The output parameter for the path to /// \param MakeformatOutput. /// /// \returns A \c StringError with the diagnostic output if clang errors /// occurred, P1689 dependency format rules otherwise. llvm::Expected getP1689ModuleDependencyFile(const clang::tooling::CompileCommand &Command, StringRef CWD, std::string &MakeformatOutput, std::string &MakeformatOutputPath); llvm::Expected getP1689ModuleDependencyFile(const clang::tooling::CompileCommand &Command, StringRef CWD) { std::string MakeformatOutput; std::string MakeformatOutputPath; return getP1689ModuleDependencyFile(Command, CWD, MakeformatOutput, MakeformatOutputPath); } /// Given a Clang driver command-line for a translation unit, gather the /// modular dependencies and return the information needed for explicit build. /// /// \param AlreadySeen This stores modules which have previously been /// reported. Use the same instance for all calls to this /// function for a single \c DependencyScanningTool in a /// single build. Use a different one for different tools, /// and clear it between builds. /// \param LookupModuleOutput This function is called to fill in /// "-fmodule-file=", "-o" and other output /// arguments for dependencies. /// /// \returns a \c StringError with the diagnostic output if clang errors /// occurred, \c TranslationUnitDeps otherwise. llvm::Expected getTranslationUnitDependencies(const std::vector &CommandLine, StringRef CWD, const llvm::DenseSet &AlreadySeen, LookupModuleOutputCallback LookupModuleOutput); /// Given a compilation context specified via the Clang driver command-line, /// gather modular dependencies of module with the given name, and return the /// information needed for explicit build. llvm::Expected getModuleDependencies( StringRef ModuleName, const std::vector &CommandLine, StringRef CWD, const llvm::DenseSet &AlreadySeen, LookupModuleOutputCallback LookupModuleOutput); private: DependencyScanningWorker Worker; }; class FullDependencyConsumer : public DependencyConsumer { public: FullDependencyConsumer(const llvm::DenseSet &AlreadySeen) : AlreadySeen(AlreadySeen) {} void handleBuildCommand(Command Cmd) override { Commands.push_back(std::move(Cmd)); } void handleDependencyOutputOpts(const DependencyOutputOptions &) override {} void handleFileDependency(StringRef File) override { Dependencies.push_back(std::string(File)); } void handlePrebuiltModuleDependency(PrebuiltModuleDep PMD) override { PrebuiltModuleDeps.emplace_back(std::move(PMD)); } void handleModuleDependency(ModuleDeps MD) override { ClangModuleDeps[MD.ID] = std::move(MD); } void handleDirectModuleDependency(ModuleID ID) override { DirectModuleDeps.push_back(ID); } void handleContextHash(std::string Hash) override { ContextHash = std::move(Hash); } TranslationUnitDeps takeTranslationUnitDeps(); ModuleDepsGraph takeModuleGraphDeps(); private: std::vector Dependencies; std::vector PrebuiltModuleDeps; llvm::MapVector ClangModuleDeps; std::vector DirectModuleDeps; std::vector Commands; std::string ContextHash; std::vector OutputPaths; const llvm::DenseSet &AlreadySeen; }; /// A simple dependency action controller that uses a callback. If no callback /// is provided, it is assumed that looking up module outputs is unreachable. class CallbackActionController : public DependencyActionController { public: virtual ~CallbackActionController(); CallbackActionController(LookupModuleOutputCallback LMO) : LookupModuleOutput(std::move(LMO)) { if (!LookupModuleOutput) { LookupModuleOutput = [](const ModuleID &, ModuleOutputKind) -> std::string { llvm::report_fatal_error("unexpected call to lookupModuleOutput"); }; } } std::string lookupModuleOutput(const ModuleID &ID, ModuleOutputKind Kind) override { return LookupModuleOutput(ID, Kind); } private: LookupModuleOutputCallback LookupModuleOutput; }; } // end namespace dependencies } // end namespace tooling } // end namespace clang #endif // LLVM_CLANG_TOOLING_DEPENDENCYSCANNING_DEPENDENCYSCANNINGTOOL_H