I XFAILED the test on Windows in 52194350cfe. The [/\\] regexes might need to match two slashes, and the PREFIX variable ends up having inconsistent slash direction.
On Wed, Oct 30, 2019 at 3:27 PM Michael Spencer via cfe-commits < cfe-commits@lists.llvm.org> wrote: > > Author: Michael Spencer > Date: 2019-10-30T15:27:27-07:00 > New Revision: 33a745e6fe7e81d3793f7831d2832aa0785ef327 > > URL: > https://github.com/llvm/llvm-project/commit/33a745e6fe7e81d3793f7831d2832aa0785ef327 > DIFF: > https://github.com/llvm/llvm-project/commit/33a745e6fe7e81d3793f7831d2832aa0785ef327.diff > > LOG: [clang][clang-scan-deps] Add support for extracting full module > dependencies. > > This is a recommit of d8a4ef0e685c with the nondeterminism fixed. > > This adds experimental support for extracting a Clang module dependency > graph > from a compilation database. The output format is experimental and will > change. > It is currently a concatenation of JSON outputs for each compilation. > Future > patches will change this to deduplicate modules between compilations. > > Differential Revision: https://reviews.llvm.org/D69420 > > Added: > clang/include/clang/Tooling/DependencyScanning/ModuleDepCollector.h > clang/lib/Tooling/DependencyScanning/ModuleDepCollector.cpp > clang/test/ClangScanDeps/modules-full.cpp > > Modified: > > clang/include/clang/Tooling/DependencyScanning/DependencyScanningService.h > clang/include/clang/Tooling/DependencyScanning/DependencyScanningTool.h > > clang/include/clang/Tooling/DependencyScanning/DependencyScanningWorker.h > clang/lib/Tooling/DependencyScanning/CMakeLists.txt > clang/lib/Tooling/DependencyScanning/DependencyScanningService.cpp > clang/lib/Tooling/DependencyScanning/DependencyScanningTool.cpp > clang/lib/Tooling/DependencyScanning/DependencyScanningWorker.cpp > clang/tools/clang-scan-deps/ClangScanDeps.cpp > > Removed: > > > > > ################################################################################ > diff --git > a/clang/include/clang/Tooling/DependencyScanning/DependencyScanningService.h > b/clang/include/clang/Tooling/DependencyScanning/DependencyScanningService.h > index fd8ed80b143c..76edf150dbee 100644 > --- > a/clang/include/clang/Tooling/DependencyScanning/DependencyScanningService.h > +++ > b/clang/include/clang/Tooling/DependencyScanning/DependencyScanningService.h > @@ -30,15 +30,30 @@ enum class ScanningMode { > MinimizedSourcePreprocessing > }; > > +/// The format that is output by the dependency scanner. > +enum class ScanningOutputFormat { > + /// This is the Makefile compatible dep format. This will include all > of the > + /// deps necessary for an implicit modules build, but won't include any > + /// intermodule dependency information. > + Make, > + > + /// This outputs the full module dependency graph suitable for use for > + /// explicitly building modules. > + Full, > +}; > + > /// The dependency scanning service contains the shared state that is > used by > /// the invidual dependency scanning workers. > class DependencyScanningService { > public: > - DependencyScanningService(ScanningMode Mode, bool ReuseFileManager = > true, > + DependencyScanningService(ScanningMode Mode, ScanningOutputFormat > Format, > + bool ReuseFileManager = true, > bool SkipExcludedPPRanges = true); > > ScanningMode getMode() const { return Mode; } > > + ScanningOutputFormat getFormat() const { return Format; } > + > bool canReuseFileManager() const { return ReuseFileManager; } > > bool canSkipExcludedPPRanges() const { return SkipExcludedPPRanges; } > @@ -49,6 +64,7 @@ class DependencyScanningService { > > private: > const ScanningMode Mode; > + const ScanningOutputFormat Format; > const bool ReuseFileManager; > /// Set to true to use the preprocessor optimization that skips > excluded PP > /// ranges by bumping the buffer pointer in the lexer instead of lexing > the > > diff --git > a/clang/include/clang/Tooling/DependencyScanning/DependencyScanningTool.h > b/clang/include/clang/Tooling/DependencyScanning/DependencyScanningTool.h > index c950cbe167cd..78b49e4fa0c5 100644 > --- > a/clang/include/clang/Tooling/DependencyScanning/DependencyScanningTool.h > +++ > b/clang/include/clang/Tooling/DependencyScanning/DependencyScanningTool.h > @@ -40,6 +40,7 @@ class DependencyScanningTool { > StringRef CWD); > > private: > + const ScanningOutputFormat Format; > DependencyScanningWorker Worker; > const tooling::CompilationDatabase &Compilations; > }; > > diff --git > a/clang/include/clang/Tooling/DependencyScanning/DependencyScanningWorker.h > b/clang/include/clang/Tooling/DependencyScanning/DependencyScanningWorker.h > index 45c9fb4f029d..689119330c41 100644 > --- > a/clang/include/clang/Tooling/DependencyScanning/DependencyScanningWorker.h > +++ > b/clang/include/clang/Tooling/DependencyScanning/DependencyScanningWorker.h > @@ -15,6 +15,8 @@ > #include "clang/Frontend/PCHContainerOperations.h" > #include "clang/Lex/PreprocessorExcludedConditionalDirectiveSkipMapping.h" > #include "clang/Tooling/CompilationDatabase.h" > +#include "clang/Tooling/DependencyScanning/DependencyScanningService.h" > +#include "clang/Tooling/DependencyScanning/ModuleDepCollector.h" > #include "llvm/Support/Error.h" > #include "llvm/Support/FileSystem.h" > #include <string> > @@ -26,7 +28,6 @@ class DependencyOutputOptions; > namespace tooling { > namespace dependencies { > > -class DependencyScanningService; > class DependencyScanningWorkerFilesystem; > > class DependencyConsumer { > @@ -36,7 +37,9 @@ class DependencyConsumer { > virtual void handleFileDependency(const DependencyOutputOptions &Opts, > StringRef Filename) = 0; > > - // FIXME: Add support for reporting modular dependencies. > + virtual void handleModuleDependency(ModuleDeps MD) = 0; > + > + virtual void handleContextHash(std::string Hash) = 0; > }; > > /// An individual dependency scanning worker that is able to run on its > own > @@ -73,6 +76,7 @@ class DependencyScanningWorker { > /// The file manager that is reused accross multiple invocations by this > /// worker. If null, the file manager will not be reused. > llvm::IntrusiveRefCntPtr<FileManager> Files; > + ScanningOutputFormat Format; > }; > > } // end namespace dependencies > > diff --git > a/clang/include/clang/Tooling/DependencyScanning/ModuleDepCollector.h > b/clang/include/clang/Tooling/DependencyScanning/ModuleDepCollector.h > new file mode 100644 > index 000000000000..7a9fc276fcaa > --- /dev/null > +++ b/clang/include/clang/Tooling/DependencyScanning/ModuleDepCollector.h > @@ -0,0 +1,94 @@ > +//===- ModuleDepCollector.h - Callbacks to collect deps ---------*- C++ > -*-===// > +// > +// The LLVM Compiler Infrastructure > +// > +// This file is distributed under the University of Illinois Open Source > +// License. See LICENSE.TXT for details. > +// > > +//===----------------------------------------------------------------------===// > + > +#ifndef LLVM_CLANG_TOOLING_DEPENDENCY_SCANNING_MODULE_DEP_COLLECTOR_H > +#define LLVM_CLANG_TOOLING_DEPENDENCY_SCANNING_MODULE_DEP_COLLECTOR_H > + > +#include "clang/Basic/LLVM.h" > +#include "clang/Basic/SourceManager.h" > +#include "clang/Frontend/Utils.h" > +#include "clang/Lex/HeaderSearch.h" > +#include "clang/Lex/PPCallbacks.h" > +#include "clang/Serialization/ASTReader.h" > +#include "llvm/ADT/DenseMap.h" > +#include "llvm/ADT/StringSet.h" > +#include "llvm/Support/raw_ostream.h" > + > +#include <string> > + > +namespace clang { > +namespace tooling { > +namespace dependencies { > + > +class DependencyConsumer; > + > +struct ModuleDeps { > + std::string ModuleName; > + std::string ClangModuleMapFile; > + std::string ModulePCMPath; > + std::string ContextHash; > + llvm::StringSet<> FileDeps; > + llvm::StringSet<> ClangModuleDeps; > + bool ImportedByMainFile = false; > +}; > + > +class ModuleDepCollector; > + > +class ModuleDepCollectorPP final : public PPCallbacks { > +public: > + ModuleDepCollectorPP(CompilerInstance &I, ModuleDepCollector &MDC) > + : Instance(I), MDC(MDC) {} > + > + void FileChanged(SourceLocation Loc, FileChangeReason Reason, > + SrcMgr::CharacteristicKind FileType, > + FileID PrevFID) override; > + void InclusionDirective(SourceLocation HashLoc, const Token &IncludeTok, > + StringRef FileName, bool IsAngled, > + CharSourceRange FilenameRange, const FileEntry > *File, > + StringRef SearchPath, StringRef RelativePath, > + const Module *Imported, > + SrcMgr::CharacteristicKind FileType) override; > + > + void EndOfMainFile() override; > + > +private: > + CompilerInstance &Instance; > + ModuleDepCollector &MDC; > + llvm::DenseSet<const Module *> DirectDeps; > + > + void handleTopLevelModule(const Module *M); > + void addAllSubmoduleDeps(const Module *M, ModuleDeps &MD); > + void addModuleDep(const Module *M, ModuleDeps &MD); > + > + void addDirectDependencies(const Module *Mod); > +}; > + > +class ModuleDepCollector final : public DependencyCollector { > +public: > + ModuleDepCollector(CompilerInstance &I, DependencyConsumer &C); > + > + void attachToPreprocessor(Preprocessor &PP) override; > + void attachToASTReader(ASTReader &R) override; > + > +private: > + friend ModuleDepCollectorPP; > + > + CompilerInstance &Instance; > + DependencyConsumer &Consumer; > + std::string MainFile; > + std::string ContextHash; > + std::vector<std::string> MainDeps; > + std::unordered_map<std::string, ModuleDeps> Deps; > +}; > + > +} // end namespace dependencies > +} // end namespace tooling > +} // end namespace clang > + > +#endif // LLVM_CLANG_TOOLING_DEPENDENCY_SCANNING_MODULE_DEP_COLLECTOR_H > > diff --git a/clang/lib/Tooling/DependencyScanning/CMakeLists.txt > b/clang/lib/Tooling/DependencyScanning/CMakeLists.txt > index 05e1aa54f8d4..c6fe207ab2f2 100644 > --- a/clang/lib/Tooling/DependencyScanning/CMakeLists.txt > +++ b/clang/lib/Tooling/DependencyScanning/CMakeLists.txt > @@ -8,6 +8,7 @@ add_clang_library(clangDependencyScanning > DependencyScanningService.cpp > DependencyScanningWorker.cpp > DependencyScanningTool.cpp > + ModuleDepCollector.cpp > > DEPENDS > ClangDriverOptions > > diff --git > a/clang/lib/Tooling/DependencyScanning/DependencyScanningService.cpp > b/clang/lib/Tooling/DependencyScanning/DependencyScanningService.cpp > index e5cebe381000..93bb0cde439d 100644 > --- a/clang/lib/Tooling/DependencyScanning/DependencyScanningService.cpp > +++ b/clang/lib/Tooling/DependencyScanning/DependencyScanningService.cpp > @@ -12,8 +12,8 @@ using namespace clang; > using namespace tooling; > using namespace dependencies; > > -DependencyScanningService::DependencyScanningService(ScanningMode Mode, > - bool > ReuseFileManager, > - bool > SkipExcludedPPRanges) > - : Mode(Mode), ReuseFileManager(ReuseFileManager), > +DependencyScanningService::DependencyScanningService( > + ScanningMode Mode, ScanningOutputFormat Format, bool ReuseFileManager, > + bool SkipExcludedPPRanges) > + : Mode(Mode), Format(Format), ReuseFileManager(ReuseFileManager), > SkipExcludedPPRanges(SkipExcludedPPRanges) {} > > diff --git > a/clang/lib/Tooling/DependencyScanning/DependencyScanningTool.cpp > b/clang/lib/Tooling/DependencyScanning/DependencyScanningTool.cpp > index d2af1a9d110c..bffd7c338124 100644 > --- a/clang/lib/Tooling/DependencyScanning/DependencyScanningTool.cpp > +++ b/clang/lib/Tooling/DependencyScanning/DependencyScanningTool.cpp > @@ -8,6 +8,15 @@ > > #include "clang/Tooling/DependencyScanning/DependencyScanningTool.h" > #include "clang/Frontend/Utils.h" > +#include "llvm/Support/JSON.h" > + > +static llvm::json::Array toJSONSorted(const llvm::StringSet<> &Set) { > + std::vector<llvm::StringRef> Strings; > + for (auto &&I : Set) > + Strings.push_back(I.getKey()); > + std::sort(Strings.begin(), Strings.end()); > + return llvm::json::Array(Strings); > +} > > namespace clang{ > namespace tooling{ > @@ -16,13 +25,14 @@ namespace dependencies{ > DependencyScanningTool::DependencyScanningTool( > DependencyScanningService &Service, > const tooling::CompilationDatabase &Compilations) > - : Worker(Service), Compilations(Compilations) {} > + : Format(Service.getFormat()), Worker(Service), > Compilations(Compilations) { > +} > > llvm::Expected<std::string> > DependencyScanningTool::getDependencyFile(const std::string &Input, > StringRef CWD) { > /// Prints out all of the gathered dependencies into a string. > - class DependencyPrinterConsumer : public DependencyConsumer { > + class MakeDependencyPrinterConsumer : public DependencyConsumer { > public: > void handleFileDependency(const DependencyOutputOptions &Opts, > StringRef File) override { > @@ -31,6 +41,14 @@ DependencyScanningTool::getDependencyFile(const > std::string &Input, > Dependencies.push_back(File); > } > > + void handleModuleDependency(ModuleDeps MD) override { > + // These are ignored for the make format as it can't support the > full > + // set of deps, and handleFileDependency handles enough for > implicitly > + // built modules to work. > + } > + > + void handleContextHash(std::string Hash) override {} > + > void printDependencies(std::string &S) { > if (!Opts) > return; > @@ -59,14 +77,88 @@ DependencyScanningTool::getDependencyFile(const > std::string &Input, > std::vector<std::string> Dependencies; > }; > > - DependencyPrinterConsumer Consumer; > - auto Result = > - Worker.computeDependencies(Input, CWD, Compilations, Consumer); > - if (Result) > - return std::move(Result); > - std::string Output; > - Consumer.printDependencies(Output); > - return Output; > + class FullDependencyPrinterConsumer : public DependencyConsumer { > + public: > + void handleFileDependency(const DependencyOutputOptions &Opts, > + StringRef File) override { > + Dependencies.push_back(File); > + } > + > + void handleModuleDependency(ModuleDeps MD) override { > + ModuleDeps[MD.ContextHash + MD.ModuleName] = std::move(MD); > + } > + > + void handleContextHash(std::string Hash) override { > + ContextHash = std::move(Hash); > + } > + > + void printDependencies(std::string &S, StringRef MainFile) { > + // Sort the modules by name to get a deterministic order. > + std::vector<StringRef> Modules; > + for (auto &&Dep : ModuleDeps) > + Modules.push_back(Dep.first); > + std::sort(Modules.begin(), Modules.end()); > + > + llvm::raw_string_ostream OS(S); > + > + using namespace llvm::json; > + > + Array Imports; > + for (auto &&ModName : Modules) { > + auto &MD = ModuleDeps[ModName]; > + if (MD.ImportedByMainFile) > + Imports.push_back(MD.ModuleName); > + } > + > + Array Mods; > + for (auto &&ModName : Modules) { > + auto &MD = ModuleDeps[ModName]; > + Object Mod{ > + {"name", MD.ModuleName}, > + {"file-deps", toJSONSorted(MD.FileDeps)}, > + {"clang-module-deps", toJSONSorted(MD.ClangModuleDeps)}, > + {"clang-modulemap-file", MD.ClangModuleMapFile}, > + }; > + Mods.push_back(std::move(Mod)); > + } > + > + Object O{ > + {"input-file", MainFile}, > + {"clang-context-hash", ContextHash}, > + {"file-deps", Dependencies}, > + {"clang-module-deps", std::move(Imports)}, > + {"clang-modules", std::move(Mods)}, > + }; > + > + S = llvm::formatv("{0:2},\n", Value(std::move(O))).str(); > + return; > + } > + > + private: > + std::vector<std::string> Dependencies; > + std::unordered_map<std::string, ModuleDeps> ModuleDeps; > + std::string ContextHash; > + }; > + > + if (Format == ScanningOutputFormat::Make) { > + MakeDependencyPrinterConsumer Consumer; > + auto Result = > + Worker.computeDependencies(Input, CWD, Compilations, Consumer); > + if (Result) > + return std::move(Result); > + std::string Output; > + Consumer.printDependencies(Output); > + return Output; > + } else { > + FullDependencyPrinterConsumer Consumer; > + auto Result = > + Worker.computeDependencies(Input, CWD, Compilations, Consumer); > + if (Result) > + return std::move(Result); > + std::string Output; > + Consumer.printDependencies(Output, Input); > + return Output; > + } > } > > } // end namespace dependencies > > diff --git > a/clang/lib/Tooling/DependencyScanning/DependencyScanningWorker.cpp > b/clang/lib/Tooling/DependencyScanning/DependencyScanningWorker.cpp > index f382c202f8c2..edf2cf8bd70f 100644 > --- a/clang/lib/Tooling/DependencyScanning/DependencyScanningWorker.cpp > +++ b/clang/lib/Tooling/DependencyScanning/DependencyScanningWorker.cpp > @@ -14,6 +14,7 @@ > #include "clang/Frontend/Utils.h" > #include "clang/Lex/PreprocessorOptions.h" > #include "clang/Tooling/DependencyScanning/DependencyScanningService.h" > +#include "clang/Tooling/DependencyScanning/ModuleDepCollector.h" > #include "clang/Tooling/Tooling.h" > > using namespace clang; > @@ -72,9 +73,11 @@ class DependencyScanningAction : public > tooling::ToolAction { > DependencyScanningAction( > StringRef WorkingDirectory, DependencyConsumer &Consumer, > llvm::IntrusiveRefCntPtr<DependencyScanningWorkerFilesystem> DepFS, > - ExcludedPreprocessorDirectiveSkipMapping *PPSkipMappings) > + ExcludedPreprocessorDirectiveSkipMapping *PPSkipMappings, > + ScanningOutputFormat Format) > : WorkingDirectory(WorkingDirectory), Consumer(Consumer), > - DepFS(std::move(DepFS)), PPSkipMappings(PPSkipMappings) {} > + DepFS(std::move(DepFS)), PPSkipMappings(PPSkipMappings), > + Format(Format) {} > > bool runInvocation(std::shared_ptr<CompilerInvocation> Invocation, > FileManager *FileMgr, > @@ -131,9 +134,20 @@ class DependencyScanningAction : public > tooling::ToolAction { > // We need at least one -MT equivalent for the generator to work. > if (Opts->Targets.empty()) > Opts->Targets = {"clang-scan-deps dependency"}; > - Compiler.addDependencyCollector( > - std::make_shared<DependencyConsumerForwarder>(std::move(Opts), > - Consumer)); > + > + switch (Format) { > + case ScanningOutputFormat::Make: > + Compiler.addDependencyCollector( > + std::make_shared<DependencyConsumerForwarder>(std::move(Opts), > + Consumer)); > + break; > + case ScanningOutputFormat::Full: > + Compiler.addDependencyCollector( > + std::make_shared<ModuleDepCollector>(Compiler, Consumer)); > + break; > + } > + > + Consumer.handleContextHash(Compiler.getInvocation().getModuleHash()); > > auto Action = std::make_unique<PreprocessOnlyAction>(); > const bool Result = Compiler.ExecuteAction(*Action); > @@ -147,12 +161,14 @@ class DependencyScanningAction : public > tooling::ToolAction { > DependencyConsumer &Consumer; > llvm::IntrusiveRefCntPtr<DependencyScanningWorkerFilesystem> DepFS; > ExcludedPreprocessorDirectiveSkipMapping *PPSkipMappings; > + ScanningOutputFormat Format; > }; > > } // end anonymous namespace > > DependencyScanningWorker::DependencyScanningWorker( > - DependencyScanningService &Service) { > + DependencyScanningService &Service) > + : Format(Service.getFormat()) { > DiagOpts = new DiagnosticOptions(); > PCHContainerOps = std::make_shared<PCHContainerOperations>(); > RealFS = new > ProxyFileSystemWithoutChdir(llvm::vfs::getRealFileSystem()); > @@ -195,7 +211,7 @@ llvm::Error > DependencyScanningWorker::computeDependencies( > Tool.setPrintErrorMessage(false); > Tool.setDiagnosticConsumer(&DC); > DependencyScanningAction Action(WorkingDirectory, Consumer, DepFS, > - PPSkipMappings.get()); > + PPSkipMappings.get(), Format); > return !Tool.run(&Action); > }); > } > > diff --git a/clang/lib/Tooling/DependencyScanning/ModuleDepCollector.cpp > b/clang/lib/Tooling/DependencyScanning/ModuleDepCollector.cpp > new file mode 100644 > index 000000000000..7f20ec7056c6 > --- /dev/null > +++ b/clang/lib/Tooling/DependencyScanning/ModuleDepCollector.cpp > @@ -0,0 +1,136 @@ > +//===- ModuleDepCollector.cpp - Callbacks to collect deps -------*- C++ > -*-===// > +// > +// The LLVM Compiler Infrastructure > +// > +// This file is distributed under the University of Illinois Open Source > +// License. See LICENSE.TXT for details. > +// > > +//===----------------------------------------------------------------------===// > + > +#include "clang/Tooling/DependencyScanning/ModuleDepCollector.h" > + > +#include "clang/Frontend/CompilerInstance.h" > +#include "clang/Lex/Preprocessor.h" > +#include "clang/Tooling/DependencyScanning/DependencyScanningWorker.h" > + > +using namespace clang; > +using namespace tooling; > +using namespace dependencies; > + > +void ModuleDepCollectorPP::FileChanged(SourceLocation Loc, > + FileChangeReason Reason, > + SrcMgr::CharacteristicKind > FileType, > + FileID PrevFID) { > + if (Reason != PPCallbacks::EnterFile) > + return; > + > + SourceManager &SM = Instance.getSourceManager(); > + > + // Dependency generation really does want to go all the way to the > + // file entry for a source location to find out what is depended on. > + // We do not want #line markers to affect dependency generation! > + Optional<FileEntryRef> File = > + SM.getFileEntryRefForID(SM.getFileID(SM.getExpansionLoc(Loc))); > + if (!File) > + return; > + > + StringRef FileName = > + llvm::sys::path::remove_leading_dotslash(File->getName()); > + > + MDC.MainDeps.push_back(FileName); > +} > + > +void ModuleDepCollectorPP::InclusionDirective( > + SourceLocation HashLoc, const Token &IncludeTok, StringRef FileName, > + bool IsAngled, CharSourceRange FilenameRange, const FileEntry *File, > + StringRef SearchPath, StringRef RelativePath, const Module *Imported, > + SrcMgr::CharacteristicKind FileType) { > + if (!File && !Imported) { > + // This is a non-modular include that HeaderSearch failed to find. > Add it > + // here as `FileChanged` will never see it. > + MDC.MainDeps.push_back(FileName); > + } > + > + if (!Imported) > + return; > + > + MDC.Deps[MDC.ContextHash + > Imported->getTopLevelModule()->getFullModuleName()] > + .ImportedByMainFile = true; > + DirectDeps.insert(Imported->getTopLevelModule()); > +} > + > +void ModuleDepCollectorPP::EndOfMainFile() { > + FileID MainFileID = Instance.getSourceManager().getMainFileID(); > + MDC.MainFile = > + > Instance.getSourceManager().getFileEntryForID(MainFileID)->getName(); > + > + for (const Module *M : DirectDeps) { > + handleTopLevelModule(M); > + } > + > + for (auto &&I : MDC.Deps) > + MDC.Consumer.handleModuleDependency(I.second); > + > + DependencyOutputOptions Opts; > + for (auto &&I : MDC.MainDeps) > + MDC.Consumer.handleFileDependency(Opts, I); > +} > + > +void ModuleDepCollectorPP::handleTopLevelModule(const Module *M) { > + assert(M == M->getTopLevelModule() && "Expected top level module!"); > + > + auto ModI = MDC.Deps.insert( > + std::make_pair(MDC.ContextHash + M->getFullModuleName(), > ModuleDeps{})); > + > + if (!ModI.first->second.ModuleName.empty()) > + return; > + > + ModuleDeps &MD = ModI.first->second; > + > + const FileEntry *ModuleMap = Instance.getPreprocessor() > + .getHeaderSearchInfo() > + .getModuleMap() > + .getContainingModuleMapFile(M); > + > + MD.ClangModuleMapFile = ModuleMap ? ModuleMap->getName() : ""; > + MD.ModuleName = M->getFullModuleName(); > + MD.ModulePCMPath = M->getASTFile()->getName(); > + MD.ContextHash = MDC.ContextHash; > + serialization::ModuleFile *MF = > + MDC.Instance.getModuleManager()->getModuleManager().lookup( > + M->getASTFile()); > + MDC.Instance.getModuleManager()->visitInputFiles( > + *MF, true, true, [&](const serialization::InputFile &IF, bool > isSystem) { > + MD.FileDeps.insert(IF.getFile()->getName()); > + }); > + > + addAllSubmoduleDeps(M, MD); > +} > + > +void ModuleDepCollectorPP::addAllSubmoduleDeps(const Module *M, > + ModuleDeps &MD) { > + addModuleDep(M, MD); > + > + for (const Module *SubM : M->submodules()) > + addAllSubmoduleDeps(SubM, MD); > +} > + > +void ModuleDepCollectorPP::addModuleDep(const Module *M, ModuleDeps &MD) { > + for (const Module *Import : M->Imports) { > + if (Import->getTopLevelModule() != M->getTopLevelModule()) { > + MD.ClangModuleDeps.insert(Import->getTopLevelModuleName()); > + handleTopLevelModule(Import->getTopLevelModule()); > + } > + } > +} > + > +ModuleDepCollector::ModuleDepCollector(CompilerInstance &I, > + DependencyConsumer &C) > + : Instance(I), Consumer(C), > ContextHash(I.getInvocation().getModuleHash()) { > +} > + > +void ModuleDepCollector::attachToPreprocessor(Preprocessor &PP) { > + PP.addPPCallbacks(std::make_unique<ModuleDepCollectorPP>(Instance, > *this)); > +} > + > +void ModuleDepCollector::attachToASTReader(ASTReader &R) {} > > diff --git a/clang/test/ClangScanDeps/modules-full.cpp > b/clang/test/ClangScanDeps/modules-full.cpp > new file mode 100644 > index 000000000000..f8bff06d8f74 > --- /dev/null > +++ b/clang/test/ClangScanDeps/modules-full.cpp > @@ -0,0 +1,74 @@ > +// RUN: rm -rf %t.dir > +// RUN: rm -rf %t.cdb > +// RUN: rm -rf %t.module-cache > +// RUN: mkdir -p %t.dir > +// RUN: cp %s %t.dir/modules_cdb_input.cpp > +// RUN: cp %s %t.dir/modules_cdb_input2.cpp > +// RUN: mkdir %t.dir/Inputs > +// RUN: cp %S/Inputs/header.h %t.dir/Inputs/header.h > +// RUN: cp %S/Inputs/header2.h %t.dir/Inputs/header2.h > +// RUN: cp %S/Inputs/module.modulemap %t.dir/Inputs/module.modulemap > +// RUN: sed -e "s|DIR|%/t.dir|g" %S/Inputs/modules_cdb.json > %t.cdb > +// > +// RUN: echo %t.dir > %t.result > +// RUN: clang-scan-deps -compilation-database %t.cdb -j 1 \ > +// RUN: -mode preprocess-minimized-sources -format experimental-full >> > %t.result > +// RUN: cat %t.result | FileCheck --check-prefixes=CHECK %s > + > +#include "header.h" > + > +// CHECK: [[PREFIX:(.*[/\\])+[a-zA-Z0-9.-]+]] > +// CHECK-NEXT: { > +// CHECK-NEXT: "clang-context-hash": "[[CONTEXT_HASH:[A-Z0-9]+]]", > +// CHECK-NEXT: "clang-module-deps": [ > +// CHECK-NEXT: "header1" > +// CHECK-NEXT: ], > +// CHECK-NEXT: "clang-modules": [ > +// CHECK-NEXT: { > +// CHECK-NEXT: "clang-module-deps": [ > +// CHECK-NEXT: "header2" > +// CHECK-NEXT: ], > +// CHECK-NEXT: "clang-modulemap-file": > "[[PREFIX]]{{[/\\]}}Inputs{{[/\\]}}module.modulemap", > +// CHECK-NEXT: "file-deps": [ > +// CHECK-NEXT: "[[PREFIX]]{{[/\\]}}Inputs{{[/\\]}}header.h", > +// CHECK-NEXT: "[[PREFIX]]{{[/\\]}}Inputs{{[/\\]}}module.modulemap" > +// CHECK-NEXT: ], > +// CHECK-NEXT: "name": "header1" > +// CHECK-NEXT: }, > +// CHECK-NEXT: { > +// CHECK-NEXT: "clang-module-deps": [], > +// CHECK-NEXT: "clang-modulemap-file": > "[[PREFIX]]{{[/\\]}}Inputs{{[/\\]}}module.modulemap", > +// CHECK-NEXT: "file-deps": [ > +// CHECK-NEXT: "[[PREFIX]]{{[/\\]}}Inputs{{[/\\]}}header2.h", > +// CHECK-NEXT: "[[PREFIX]]{{[/\\]}}Inputs{{[/\\]}}module.modulemap" > +// CHECK-NEXT: ], > +// CHECK-NEXT: "name": "header2" > +// CHECK-NEXT: } > +// CHECK-NEXT: ], > +// CHECK-NEXT: "file-deps": [ > +// CHECK-NEXT: "[[PREFIX]]{{[/\\]}}modules_cdb_input2.cpp" > +// CHECK-NEXT: ], > +// CHECK-NEXT: "input-file": "[[PREFIX]]{{[/\\]}}modules_cdb_input2.cpp" > +// CHECK-NEXT:}, > +// CHECK-NEXT:{ > +// CHECK-NOT: "clang-context-hash": "[[CONTEXT_HASH]]", > +// CHECK-NEXT: "clang-context-hash": "{{[A-Z0-9]+}}", > +// CHECK-NEXT: "clang-module-deps": [ > +// CHECK-NEXT: "header1" > +// CHECK-NEXT: ], > +// CHECK-NEXT: "clang-modules": [ > +// CHECK-NEXT: { > +// CHECK-NEXT: "clang-module-deps": [], > +// CHECK-NEXT: "clang-modulemap-file": > "[[PREFIX]]{{[/\\]}}Inputs{{[/\\]}}module.modulemap", > +// CHECK-NEXT: "file-deps": [ > +// CHECK-NEXT: "[[PREFIX]]{{[/\\]}}Inputs{{[/\\]}}header.h", > +// CHECK-NEXT: "[[PREFIX]]{{[/\\]}}Inputs{{[/\\]}}module.modulemap" > +// CHECK-NEXT: ], > +// CHECK-NEXT: "name": "header1" > +// CHECK-NEXT: } > +// CHECK-NEXT: ], > +// CHECK-NEXT: "file-deps": [ > +// CHECK-NEXT: "[[PREFIX]]{{[/\\]}}modules_cdb_input.cpp" > +// CHECK-NEXT: ], > +// CHECK-NEXT: "input-file": "[[PREFIX]]{{[/\\]}}modules_cdb_input.cpp" > +// CHECK-NEXT:}, > > diff --git a/clang/tools/clang-scan-deps/ClangScanDeps.cpp > b/clang/tools/clang-scan-deps/ClangScanDeps.cpp > index d57983ed1664..a6abb4a9600b 100644 > --- a/clang/tools/clang-scan-deps/ClangScanDeps.cpp > +++ b/clang/tools/clang-scan-deps/ClangScanDeps.cpp > @@ -59,6 +59,17 @@ static llvm::cl::opt<ScanningMode> ScanMode( > llvm::cl::init(ScanningMode::MinimizedSourcePreprocessing), > llvm::cl::cat(DependencyScannerCategory)); > > +static llvm::cl::opt<ScanningOutputFormat> Format( > + "format", llvm::cl::desc("The output format for the dependencies"), > + llvm::cl::values(clEnumValN(ScanningOutputFormat::Make, "make", > + "Makefile compatible dep file"), > + clEnumValN(ScanningOutputFormat::Full, > "experimental-full", > + "Full dependency graph suitable" > + " for explicitly building modules. This > format " > + "is experimental and will change.")), > + llvm::cl::init(ScanningOutputFormat::Make), > + llvm::cl::cat(DependencyScannerCategory)); > + > llvm::cl::opt<unsigned> > NumThreads("j", llvm::cl::Optional, > llvm::cl::desc("Number of worker threads to use (default: > use " > @@ -200,7 +211,7 @@ int main(int argc, const char **argv) { > // Print out the dependency results to STDOUT by default. > SharedStream DependencyOS(llvm::outs()); > > - DependencyScanningService Service(ScanMode, ReuseFileManager, > + DependencyScanningService Service(ScanMode, Format, ReuseFileManager, > SkipExcludedPPRanges); > #if LLVM_ENABLE_THREADS > unsigned NumWorkers = > > > > _______________________________________________ > cfe-commits mailing list > cfe-commits@lists.llvm.org > https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits >
_______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits