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 @@ public: 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 @@ public: 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 @@ -26,7 +28,6 @@ class DependencyOutputOptions; namespace tooling { namespace dependencies { -class DependencyScanningService; class DependencyScanningWorkerFilesystem; class DependencyConsumer { @@ -36,7 +37,9 @@ public: 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 @@ private: /// The file manager that is reused accross multiple invocations by this /// worker. If null, the file manager will not be reused. llvm::IntrusiveRefCntPtr 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 + +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 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 MainDeps; + std::unordered_map 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 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 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 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 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 Dependencies; + std::unordered_map 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 @@ public: DependencyScanningAction( StringRef WorkingDirectory, DependencyConsumer &Consumer, llvm::IntrusiveRefCntPtr 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 Invocation, FileManager *FileMgr, @@ -131,9 +134,20 @@ public: // 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(std::move(Opts), - Consumer)); + + switch (Format) { + case ScanningOutputFormat::Make: + Compiler.addDependencyCollector( + std::make_shared(std::move(Opts), + Consumer)); + break; + case ScanningOutputFormat::Full: + Compiler.addDependencyCollector( + std::make_shared(Compiler, Consumer)); + break; + } + + Consumer.handleContextHash(Compiler.getInvocation().getModuleHash()); auto Action = std::make_unique(); const bool Result = Compiler.ExecuteAction(*Action); @@ -147,12 +161,14 @@ private: DependencyConsumer &Consumer; llvm::IntrusiveRefCntPtr DepFS; ExcludedPreprocessorDirectiveSkipMapping *PPSkipMappings; + ScanningOutputFormat Format; }; } // end anonymous namespace DependencyScanningWorker::DependencyScanningWorker( - DependencyScanningService &Service) { + DependencyScanningService &Service) + : Format(Service.getFormat()) { DiagOpts = new DiagnosticOptions(); PCHContainerOps = std::make_shared(); 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 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(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 ScanMode( llvm::cl::init(ScanningMode::MinimizedSourcePreprocessing), llvm::cl::cat(DependencyScannerCategory)); +static llvm::cl::opt 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 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 =