diff --git a/clang/include/clang/Frontend/FrontendActions.h b/clang/include/clang/Frontend/FrontendActions.h index a620ddfc40447..c80422e97462d 100644 --- a/clang/include/clang/Frontend/FrontendActions.h +++ b/clang/include/clang/Frontend/FrontendActions.h @@ -320,12 +320,12 @@ class PrintPreprocessedAction : public PreprocessorFrontendAction { }; class GetDependenciesByModuleNameAction : public PreprocessOnlyAction { - StringRef ModuleName; + ArrayRef ModuleNames; void ExecuteAction() override; public: - GetDependenciesByModuleNameAction(StringRef ModuleName) - : ModuleName(ModuleName) {} + GetDependenciesByModuleNameAction(ArrayRef ModuleNames) + : ModuleNames(ModuleNames) {} }; } // end namespace clang diff --git a/clang/include/clang/Tooling/DependencyScanning/DependencyScanningTool.h b/clang/include/clang/Tooling/DependencyScanning/DependencyScanningTool.h index d13c3ee76d74f..48f17bfbd3dbb 100644 --- a/clang/include/clang/Tooling/DependencyScanning/DependencyScanningTool.h +++ b/clang/include/clang/Tooling/DependencyScanning/DependencyScanningTool.h @@ -144,12 +144,14 @@ class DependencyScanningTool { std::optional TUBuffer = std::nullopt); /// 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); + /// gather modular dependencies of modules specified by the the given list of + /// names, and return the information needed for explicit build. + std::pair + getModuleDependencies(ArrayRef ModuleNames, + const std::vector &CommandLine, + StringRef CWD, + const llvm::DenseSet &AlreadySeen, + LookupModuleOutputCallback LookupModuleOutput); llvm::vfs::FileSystem &getWorkerVFS() const { return Worker.getVFS(); } diff --git a/clang/include/clang/Tooling/DependencyScanning/DependencyScanningWorker.h b/clang/include/clang/Tooling/DependencyScanning/DependencyScanningWorker.h index 5f0b983ebb58f..901f42715e6e6 100644 --- a/clang/include/clang/Tooling/DependencyScanning/DependencyScanningWorker.h +++ b/clang/include/clang/Tooling/DependencyScanning/DependencyScanningWorker.h @@ -111,7 +111,7 @@ class DependencyScanningWorker { DependencyConsumer &DepConsumer, DependencyActionController &Controller, DiagnosticConsumer &DiagConsumer, - StringRef ModuleName); + ArrayRef ModuleNames); /// Run the dependency scanning tool for a given clang driver command-line /// for a specific translation unit via file system or memory buffer. @@ -132,7 +132,7 @@ class DependencyScanningWorker { const std::vector &CommandLine, DependencyConsumer &Consumer, DependencyActionController &Controller, - StringRef ModuleName); + ArrayRef ModuleNames); llvm::vfs::FileSystem &getVFS() const { return *BaseFS; } @@ -156,7 +156,7 @@ class DependencyScanningWorker { DependencyActionController &Controller, DiagnosticConsumer &DC, llvm::IntrusiveRefCntPtr FS, - std::optional ModuleName); + std::optional> ModuleNames); }; } // end namespace dependencies diff --git a/clang/lib/Frontend/FrontendActions.cpp b/clang/lib/Frontend/FrontendActions.cpp index 1ea4a2e9e88cf..5c6419bd4e677 100644 --- a/clang/lib/Frontend/FrontendActions.cpp +++ b/clang/lib/Frontend/FrontendActions.cpp @@ -1213,11 +1213,17 @@ void GetDependenciesByModuleNameAction::ExecuteAction() { Preprocessor &PP = CI.getPreprocessor(); SourceManager &SM = PP.getSourceManager(); FileID MainFileID = SM.getMainFileID(); - SourceLocation FileStart = SM.getLocForStartOfFile(MainFileID); - SmallVector, 2> Path; - IdentifierInfo *ModuleID = PP.getIdentifierInfo(ModuleName); - Path.push_back(std::make_pair(ModuleID, FileStart)); - auto ModResult = CI.loadModule(FileStart, Path, Module::Hidden, false); - PPCallbacks *CB = PP.getPPCallbacks(); - CB->moduleImport(SourceLocation(), Path, ModResult); + SourceLocation SLoc = SM.getLocForStartOfFile(MainFileID); + for (auto ModuleName : ModuleNames) { + SmallVector, 2> Path; + IdentifierInfo *ModuleID = PP.getIdentifierInfo(ModuleName); + Path.push_back(std::make_pair(ModuleID, SLoc)); + auto ModResult = CI.loadModule(SLoc, Path, Module::Hidden, false); + PPCallbacks *CB = PP.getPPCallbacks(); + CB->moduleImport(SourceLocation(), Path, ModResult); + // FIXME: how do you know that this offset is correct? + SLoc = SLoc.getLocWithOffset(1); + assert(SLoc <= SM.getLocForEndOfFile(MainFileID) && + "Import location extends past file"); + } } diff --git a/clang/lib/Tooling/DependencyScanning/DependencyScanningTool.cpp b/clang/lib/Tooling/DependencyScanning/DependencyScanningTool.cpp index 2b4c2bb76434a..2ac67a6759a28 100644 --- a/clang/lib/Tooling/DependencyScanning/DependencyScanningTool.cpp +++ b/clang/lib/Tooling/DependencyScanning/DependencyScanningTool.cpp @@ -154,17 +154,20 @@ DependencyScanningTool::getTranslationUnitDependencies( return Consumer.takeTranslationUnitDeps(); } -llvm::Expected DependencyScanningTool::getModuleDependencies( - StringRef ModuleName, const std::vector &CommandLine, - StringRef CWD, const llvm::DenseSet &AlreadySeen, +std::pair +DependencyScanningTool::getModuleDependencies( + ArrayRef ModuleNames, + const std::vector &CommandLine, StringRef CWD, + const llvm::DenseSet &AlreadySeen, LookupModuleOutputCallback LookupModuleOutput) { FullDependencyConsumer Consumer(AlreadySeen); CallbackActionController Controller(LookupModuleOutput); + + assert(ModuleNames.size() && "GettingModuleDependencies for an empty list!"); llvm::Error Result = Worker.computeDependencies(CWD, CommandLine, Consumer, - Controller, ModuleName); - if (Result) - return std::move(Result); - return Consumer.takeModuleGraphDeps(); + Controller, ModuleNames); + + return std::make_pair(std::move(Result), Consumer.takeModuleGraphDeps()); } TranslationUnitDeps FullDependencyConsumer::takeTranslationUnitDeps() { diff --git a/clang/lib/Tooling/DependencyScanning/DependencyScanningWorker.cpp b/clang/lib/Tooling/DependencyScanning/DependencyScanningWorker.cpp index 697f26ee5d12f..f9b6e7189e531 100644 --- a/clang/lib/Tooling/DependencyScanning/DependencyScanningWorker.cpp +++ b/clang/lib/Tooling/DependencyScanning/DependencyScanningWorker.cpp @@ -287,10 +287,11 @@ class DependencyScanningAction : public tooling::ToolAction { DependencyScanningService &Service, StringRef WorkingDirectory, DependencyConsumer &Consumer, DependencyActionController &Controller, llvm::IntrusiveRefCntPtr DepFS, - bool DisableFree, std::optional ModuleName = std::nullopt) + bool DisableFree, + std::optional> ModuleNames = std::nullopt) : Service(Service), WorkingDirectory(WorkingDirectory), Consumer(Consumer), Controller(Controller), DepFS(std::move(DepFS)), - DisableFree(DisableFree), ModuleName(ModuleName) {} + DisableFree(DisableFree), ModuleNames(ModuleNames) {} bool runInvocation(std::shared_ptr Invocation, FileManager *DriverFileMgr, @@ -431,9 +432,11 @@ class DependencyScanningAction : public tooling::ToolAction { if (Service.getFormat() == ScanningOutputFormat::P1689) Action = std::make_unique(); - else if (ModuleName) - Action = std::make_unique(*ModuleName); - else + else if (ModuleNames) { + ScanInstance.getDiagnostics().setFatalsAsError(true); + Action = + std::make_unique(*ModuleNames); + } else Action = std::make_unique(); if (ScanInstance.getDiagnostics().hasErrorOccurred()) @@ -478,7 +481,7 @@ class DependencyScanningAction : public tooling::ToolAction { DependencyActionController &Controller; llvm::IntrusiveRefCntPtr DepFS; bool DisableFree; - std::optional ModuleName; + std::optional> ModuleNames; std::optional ScanInstanceStorage; std::shared_ptr MDC; std::vector LastCC1Arguments; @@ -546,7 +549,7 @@ llvm::Error DependencyScanningWorker::computeDependencies( llvm::Error DependencyScanningWorker::computeDependencies( StringRef WorkingDirectory, const std::vector &CommandLine, DependencyConsumer &Consumer, DependencyActionController &Controller, - StringRef ModuleName) { + ArrayRef ModuleNames) { // Capture the emitted diagnostics and report them to the client // in the case of a failure. std::string DiagnosticOutput; @@ -555,7 +558,7 @@ llvm::Error DependencyScanningWorker::computeDependencies( TextDiagnosticPrinter DiagPrinter(DiagnosticsOS, DiagOpts.release()); if (computeDependencies(WorkingDirectory, CommandLine, Consumer, Controller, - DiagPrinter, ModuleName)) + DiagPrinter, ModuleNames)) return llvm::Error::success(); return llvm::make_error(DiagnosticsOS.str(), llvm::inconvertibleErrorCode()); @@ -625,7 +628,7 @@ bool DependencyScanningWorker::scanDependencies( StringRef WorkingDirectory, const std::vector &CommandLine, DependencyConsumer &Consumer, DependencyActionController &Controller, DiagnosticConsumer &DC, llvm::IntrusiveRefCntPtr FS, - std::optional ModuleName) { + std::optional> ModuleNames) { auto FileMgr = llvm::makeIntrusiveRefCnt(FileSystemOptions{}, FS); @@ -648,7 +651,7 @@ bool DependencyScanningWorker::scanDependencies( // always true for a driver invocation. bool DisableFree = true; DependencyScanningAction Action(Service, WorkingDirectory, Consumer, - Controller, DepFS, DisableFree, ModuleName); + Controller, DepFS, DisableFree, ModuleNames); bool Success = false; if (CommandLine[1] == "-cc1") { @@ -729,13 +732,14 @@ bool DependencyScanningWorker::computeDependencies( auto &FinalFS = ModifiedFS ? ModifiedFS : BaseFS; return scanDependencies(WorkingDirectory, FinalCommandLine, Consumer, - Controller, DC, FinalFS, /*ModuleName=*/std::nullopt); + Controller, DC, FinalFS, + /*ModuleNames=*/std::nullopt); } bool DependencyScanningWorker::computeDependencies( StringRef WorkingDirectory, const std::vector &CommandLine, DependencyConsumer &Consumer, DependencyActionController &Controller, - DiagnosticConsumer &DC, StringRef ModuleName) { + DiagnosticConsumer &DC, ArrayRef ModuleNames) { // Reset what might have been modified in the previous worker invocation. BaseFS->setCurrentWorkingDirectory(WorkingDirectory); @@ -748,9 +752,22 @@ bool DependencyScanningWorker::computeDependencies( InMemoryFS->setCurrentWorkingDirectory(WorkingDirectory); SmallString<128> FakeInputPath; // TODO: We should retry the creation if the path already exists. - llvm::sys::fs::createUniquePath(ModuleName + "-%%%%%%%%.input", FakeInputPath, + // FIXME: Using ModuleNames[0] should be sufficient to create a unique + // input file name. The diagnostic information is specifc enough about + // in which exact module an error occurs. That said any error reporting + // that relies on the path below could be confusing.We may want to + // find better ways (e.g. by concatenating the module names) to make + // the temporary file name more precise. + llvm::sys::fs::createUniquePath(ModuleNames[0] + "-%%%%%%%%.input", + FakeInputPath, /*MakeAbsolute=*/false); - InMemoryFS->addFile(FakeInputPath, 0, llvm::MemoryBuffer::getMemBuffer("")); + + // The fake file must contain at least ModuleNames.size() characters, + // since we are simulating lexing it, and we are assuming each module name + // takes the space of one character. + std::string FakeString(ModuleNames.size(), ' '); + InMemoryFS->addFile(FakeInputPath, 0, + llvm::MemoryBuffer::getMemBuffer(FakeString)); llvm::IntrusiveRefCntPtr InMemoryOverlay = InMemoryFS; OverlayFS->pushOverlay(InMemoryOverlay); @@ -758,7 +775,7 @@ bool DependencyScanningWorker::computeDependencies( ModifiedCommandLine.emplace_back(FakeInputPath); return scanDependencies(WorkingDirectory, ModifiedCommandLine, Consumer, - Controller, DC, OverlayFS, ModuleName); + Controller, DC, OverlayFS, ModuleNames); } DependencyActionController::~DependencyActionController() {} diff --git a/clang/test/ClangScanDeps/link-libraries.c b/clang/test/ClangScanDeps/link-libraries.c index cc2e223102024..3719d713e775c 100644 --- a/clang/test/ClangScanDeps/link-libraries.c +++ b/clang/test/ClangScanDeps/link-libraries.c @@ -32,7 +32,7 @@ module transitive { }] // RUN: sed "s|DIR|%/t|g" %t/cdb.json.template > %t/cdb.json -// RUN: clang-scan-deps -compilation-database %t/cdb.json -format experimental-full -module-name=root > %t/result.json +// RUN: clang-scan-deps -compilation-database %t/cdb.json -format experimental-full -module-names=root > %t/result.json // RUN: cat %t/result.json | sed 's:\\\\\?:/:g' | FileCheck -DPREFIX=%/t %s // CHECK: { diff --git a/clang/test/ClangScanDeps/modules-full-by-mod-name.c b/clang/test/ClangScanDeps/modules-full-by-mod-name.c index c838614d0bfde..edb99636aaf25 100644 --- a/clang/test/ClangScanDeps/modules-full-by-mod-name.c +++ b/clang/test/ClangScanDeps/modules-full-by-mod-name.c @@ -25,7 +25,7 @@ module transitive { header "transitive.h" } }] // RUN: sed "s|DIR|%/t|g" %t/cdb.json.template > %t/cdb.json -// RUN: clang-scan-deps -compilation-database %t/cdb.json -format experimental-full -module-name=root > %t/result.json +// RUN: clang-scan-deps -compilation-database %t/cdb.json -format experimental-full -module-names=root > %t/result.json // RUN: cat %t/result.json | sed 's:\\\\\?:/:g' | FileCheck -DPREFIX=%/t %s // CHECK: { diff --git a/clang/tools/clang-scan-deps/ClangScanDeps.cpp b/clang/tools/clang-scan-deps/ClangScanDeps.cpp index 3bdeb461e4bfa..aed9f150a4e28 100644 --- a/clang/tools/clang-scan-deps/ClangScanDeps.cpp +++ b/clang/tools/clang-scan-deps/ClangScanDeps.cpp @@ -203,7 +203,7 @@ static void ParseArgs(int argc, char **argv) { if (const llvm::opt::Arg *A = Args.getLastArg(OPT_compilation_database_EQ)) CompilationDB = A->getValue(); - if (const llvm::opt::Arg *A = Args.getLastArg(OPT_module_name_EQ)) + if (const llvm::opt::Arg *A = Args.getLastArg(OPT_module_names_EQ)) ModuleName = A->getValue(); for (const llvm::opt::Arg *A : Args.filtered(OPT_dependency_target_EQ)) @@ -594,11 +594,12 @@ static bool handleTranslationUnitResult( return false; } -static bool handleModuleResult( - StringRef ModuleName, llvm::Expected &MaybeModuleGraph, - FullDeps &FD, size_t InputIndex, SharedStream &OS, SharedStream &Errs) { - if (!MaybeModuleGraph) { - llvm::handleAllErrors(MaybeModuleGraph.takeError(), +static bool handleModuleResult(StringRef ModuleName, llvm::Error &&Error, + ModuleDepsGraph &DepsGraph, FullDeps &FD, + size_t InputIndex, SharedStream &OS, + SharedStream &Errs) { + if (Error) { + llvm::handleAllErrors(std::move(Error), [&ModuleName, &Errs](llvm::StringError &Err) { Errs.applyLocked([&](raw_ostream &OS) { OS << "Error while scanning dependencies for " @@ -608,7 +609,7 @@ static bool handleModuleResult( }); return true; } - FD.mergeDeps(std::move(*MaybeModuleGraph), InputIndex); + FD.mergeDeps(std::move(DepsGraph), InputIndex); return false; } @@ -1024,11 +1025,17 @@ int clang_scan_deps_main(int argc, char **argv, const llvm::ToolContext &) { HadErrors = true; } } else if (ModuleName) { - auto MaybeModuleDepsGraph = WorkerTool.getModuleDependencies( - *ModuleName, Input->CommandLine, CWD, AlreadySeenModules, - LookupOutput); - if (handleModuleResult(*ModuleName, MaybeModuleDepsGraph, *FD, - LocalIndex, DependencyOS, Errs)) + StringRef NamesRef(*ModuleName); + SmallVector NameList; + NamesRef.split(NameList, ","); + auto [Error, ModuleDepsGraph] = + WorkerTool.getModuleDependencies(NameList, Input->CommandLine, CWD, + AlreadySeenModules, LookupOutput); + // FIXME: Need to have better error handling logic for a list + // of modules. Probably through some call back. + if (handleModuleResult(/* *ModuleName*/ NameList[0], std::move(Error), + ModuleDepsGraph, *FD, LocalIndex, DependencyOS, + Errs)) HadErrors = true; } else { std::unique_ptr TU; diff --git a/clang/tools/clang-scan-deps/Opts.td b/clang/tools/clang-scan-deps/Opts.td index 9cccbb3aaf0c8..2c34a78c6af75 100644 --- a/clang/tools/clang-scan-deps/Opts.td +++ b/clang/tools/clang-scan-deps/Opts.td @@ -26,7 +26,7 @@ def eager_load_pcm : F<"eager-load-pcm", "Load PCM files eagerly (instead of laz def j : Arg<"j", "Number of worker threads to use (default: use all concurrent threads)">; defm compilation_database : Eq<"compilation-database", "Compilation database">; -defm module_name : Eq<"module-name", "the module of which the dependencies are to be computed">; +defm module_names : Eq<"module-names", "the module of which the dependencies are to be computed">; defm dependency_target : Eq<"dependency-target", "The names of dependency targets for the dependency file">; defm tu_buffer_path: Eq<"tu-buffer-path", "The path to the translation unit for depscan. Not compatible with -module-name">;