[clang] [Dependency Scanning] Teach `DependencyScanningTool::getModuleDependencies` to Process a List of Module Names (PR #129915)
Qiongsi Wu via cfe-commits
cfe-commits at lists.llvm.org
Mon Mar 10 16:56:59 PDT 2025
https://github.com/qiongsiwu updated https://github.com/llvm/llvm-project/pull/129915
>From 7f29cb0c9e422f00ce5b6b26af8ebfb228b59830 Mon Sep 17 00:00:00 2001
From: Qiongsi Wu <qiongsi_wu at apple.com>
Date: Wed, 5 Mar 2025 11:16:38 -0800
Subject: [PATCH 1/2] Changing DependencyScanningTool::getModuleDependencies to
take a list of module names instead of one module name.
---
.../include/clang/Frontend/FrontendActions.h | 6 ++--
.../DependencyScanningTool.h | 14 ++++----
.../DependencyScanningWorker.h | 6 ++--
clang/lib/Frontend/FrontendActions.cpp | 20 +++++++----
.../DependencyScanningTool.cpp | 9 +++--
.../DependencyScanningWorker.cpp | 35 +++++++++++--------
clang/tools/clang-scan-deps/ClangScanDeps.cpp | 4 +--
7 files changed, 56 insertions(+), 38 deletions(-)
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<StringRef> ModuleNames;
void ExecuteAction() override;
public:
- GetDependenciesByModuleNameAction(StringRef ModuleName)
- : ModuleName(ModuleName) {}
+ GetDependenciesByModuleNameAction(ArrayRef<StringRef> 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..25473b5c2500f 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<llvm::MemoryBufferRef> 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<ModuleDepsGraph> getModuleDependencies(
- StringRef ModuleName, const std::vector<std::string> &CommandLine,
- StringRef CWD, const llvm::DenseSet<ModuleID> &AlreadySeen,
- LookupModuleOutputCallback LookupModuleOutput);
+ /// gather modular dependencies of modules specified by the the given list of
+ /// names, and return the information needed for explicit build.
+ llvm::Expected<ModuleDepsGraph>
+ getModuleDependencies(ArrayRef<StringRef> ModuleNames,
+ const std::vector<std::string> &CommandLine,
+ StringRef CWD,
+ const llvm::DenseSet<ModuleID> &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<StringRef> 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<std::string> &CommandLine,
DependencyConsumer &Consumer,
DependencyActionController &Controller,
- StringRef ModuleName);
+ ArrayRef<StringRef> ModuleNames);
llvm::vfs::FileSystem &getVFS() const { return *BaseFS; }
@@ -156,7 +156,7 @@ class DependencyScanningWorker {
DependencyActionController &Controller,
DiagnosticConsumer &DC,
llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> FS,
- std::optional<StringRef> ModuleName);
+ std::optional<ArrayRef<StringRef>> 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<std::pair<IdentifierInfo *, SourceLocation>, 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<std::pair<IdentifierInfo *, SourceLocation>, 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..e7b6f87e2db11 100644
--- a/clang/lib/Tooling/DependencyScanning/DependencyScanningTool.cpp
+++ b/clang/lib/Tooling/DependencyScanning/DependencyScanningTool.cpp
@@ -155,13 +155,16 @@ DependencyScanningTool::getTranslationUnitDependencies(
}
llvm::Expected<ModuleDepsGraph> DependencyScanningTool::getModuleDependencies(
- StringRef ModuleName, const std::vector<std::string> &CommandLine,
- StringRef CWD, const llvm::DenseSet<ModuleID> &AlreadySeen,
+ ArrayRef<StringRef> ModuleNames,
+ const std::vector<std::string> &CommandLine, StringRef CWD,
+ const llvm::DenseSet<ModuleID> &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);
+ Controller, ModuleNames);
if (Result)
return std::move(Result);
return Consumer.takeModuleGraphDeps();
diff --git a/clang/lib/Tooling/DependencyScanning/DependencyScanningWorker.cpp b/clang/lib/Tooling/DependencyScanning/DependencyScanningWorker.cpp
index 697f26ee5d12f..f2c5a0716126a 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<DependencyScanningWorkerFilesystem> DepFS,
- bool DisableFree, std::optional<StringRef> ModuleName = std::nullopt)
+ bool DisableFree,
+ std::optional<ArrayRef<StringRef>> 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<CompilerInvocation> Invocation,
FileManager *DriverFileMgr,
@@ -431,8 +432,9 @@ class DependencyScanningAction : public tooling::ToolAction {
if (Service.getFormat() == ScanningOutputFormat::P1689)
Action = std::make_unique<PreprocessOnlyAction>();
- else if (ModuleName)
- Action = std::make_unique<GetDependenciesByModuleNameAction>(*ModuleName);
+ else if (ModuleNames)
+ Action =
+ std::make_unique<GetDependenciesByModuleNameAction>(*ModuleNames);
else
Action = std::make_unique<ReadPCHAndPreprocessAction>();
@@ -478,7 +480,7 @@ class DependencyScanningAction : public tooling::ToolAction {
DependencyActionController &Controller;
llvm::IntrusiveRefCntPtr<DependencyScanningWorkerFilesystem> DepFS;
bool DisableFree;
- std::optional<StringRef> ModuleName;
+ std::optional<ArrayRef<StringRef>> ModuleNames;
std::optional<CompilerInstance> ScanInstanceStorage;
std::shared_ptr<ModuleDepCollector> MDC;
std::vector<std::string> LastCC1Arguments;
@@ -546,7 +548,7 @@ llvm::Error DependencyScanningWorker::computeDependencies(
llvm::Error DependencyScanningWorker::computeDependencies(
StringRef WorkingDirectory, const std::vector<std::string> &CommandLine,
DependencyConsumer &Consumer, DependencyActionController &Controller,
- StringRef ModuleName) {
+ ArrayRef<StringRef> ModuleNames) {
// Capture the emitted diagnostics and report them to the client
// in the case of a failure.
std::string DiagnosticOutput;
@@ -555,7 +557,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<llvm::StringError>(DiagnosticsOS.str(),
llvm::inconvertibleErrorCode());
@@ -625,7 +627,7 @@ bool DependencyScanningWorker::scanDependencies(
StringRef WorkingDirectory, const std::vector<std::string> &CommandLine,
DependencyConsumer &Consumer, DependencyActionController &Controller,
DiagnosticConsumer &DC, llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> FS,
- std::optional<StringRef> ModuleName) {
+ std::optional<ArrayRef<StringRef>> ModuleNames) {
auto FileMgr =
llvm::makeIntrusiveRefCnt<FileManager>(FileSystemOptions{}, FS);
@@ -648,7 +650,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 +731,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<std::string> &CommandLine,
DependencyConsumer &Consumer, DependencyActionController &Controller,
- DiagnosticConsumer &DC, StringRef ModuleName) {
+ DiagnosticConsumer &DC, ArrayRef<StringRef> ModuleNames) {
// Reset what might have been modified in the previous worker invocation.
BaseFS->setCurrentWorkingDirectory(WorkingDirectory);
@@ -748,9 +751,13 @@ 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: should we create files for multiple modules? I think so?
+ llvm::sys::fs::createUniquePath(ModuleNames[0] + "-%%%%%%%%.input",
+ FakeInputPath,
/*MakeAbsolute=*/false);
- InMemoryFS->addFile(FakeInputPath, 0, llvm::MemoryBuffer::getMemBuffer(""));
+ std::string FakeString(ModuleNames.size(), ' ');
+ InMemoryFS->addFile(FakeInputPath, 0,
+ llvm::MemoryBuffer::getMemBuffer(FakeString));
llvm::IntrusiveRefCntPtr<llvm::vfs::FileSystem> InMemoryOverlay = InMemoryFS;
OverlayFS->pushOverlay(InMemoryOverlay);
@@ -758,7 +765,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/tools/clang-scan-deps/ClangScanDeps.cpp b/clang/tools/clang-scan-deps/ClangScanDeps.cpp
index 3bdeb461e4bfa..8c857418b26ea 100644
--- a/clang/tools/clang-scan-deps/ClangScanDeps.cpp
+++ b/clang/tools/clang-scan-deps/ClangScanDeps.cpp
@@ -1025,8 +1025,8 @@ int clang_scan_deps_main(int argc, char **argv, const llvm::ToolContext &) {
}
} else if (ModuleName) {
auto MaybeModuleDepsGraph = WorkerTool.getModuleDependencies(
- *ModuleName, Input->CommandLine, CWD, AlreadySeenModules,
- LookupOutput);
+ ArrayRef<StringRef>({*ModuleName}), Input->CommandLine, CWD,
+ AlreadySeenModules, LookupOutput);
if (handleModuleResult(*ModuleName, MaybeModuleDepsGraph, *FD,
LocalIndex, DependencyOS, Errs))
HadErrors = true;
>From f816923106973a49d940217407c38812c205435c Mon Sep 17 00:00:00 2001
From: Qiongsi Wu <qiongsi_wu at apple.com>
Date: Mon, 10 Mar 2025 16:56:41 -0700
Subject: [PATCH 2/2] Renaming clang-scan-deps' module-name option to
module-names.
---
.../DependencyScanningWorker.cpp | 11 ++++++++++-
clang/test/ClangScanDeps/link-libraries.c | 2 +-
.../test/ClangScanDeps/modules-full-by-mod-name.c | 2 +-
clang/tools/clang-scan-deps/ClangScanDeps.cpp | 14 ++++++++++----
clang/tools/clang-scan-deps/Opts.td | 2 +-
5 files changed, 23 insertions(+), 8 deletions(-)
diff --git a/clang/lib/Tooling/DependencyScanning/DependencyScanningWorker.cpp b/clang/lib/Tooling/DependencyScanning/DependencyScanningWorker.cpp
index f2c5a0716126a..5e60b0d5ceac4 100644
--- a/clang/lib/Tooling/DependencyScanning/DependencyScanningWorker.cpp
+++ b/clang/lib/Tooling/DependencyScanning/DependencyScanningWorker.cpp
@@ -751,10 +751,19 @@ bool DependencyScanningWorker::computeDependencies(
InMemoryFS->setCurrentWorkingDirectory(WorkingDirectory);
SmallString<128> FakeInputPath;
// TODO: We should retry the creation if the path already exists.
- // FIXME: should we create files for multiple modules? I think so?
+ // 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);
+
+ // 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));
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 8c857418b26ea..e54ac9256ad5c 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))
@@ -1024,11 +1024,17 @@ int clang_scan_deps_main(int argc, char **argv, const llvm::ToolContext &) {
HadErrors = true;
}
} else if (ModuleName) {
+ StringRef NamesRef(*ModuleName);
+ SmallVector<StringRef, 16> NameList;
+ NamesRef.split(NameList, ",");
auto MaybeModuleDepsGraph = WorkerTool.getModuleDependencies(
- ArrayRef<StringRef>({*ModuleName}), Input->CommandLine, CWD,
+ NameList, Input->CommandLine, CWD,
AlreadySeenModules, LookupOutput);
- if (handleModuleResult(*ModuleName, MaybeModuleDepsGraph, *FD,
- LocalIndex, DependencyOS, Errs))
+ // FIXME: Need to have better error handling logic for a list
+ // of modules. Probably through some call back.
+ if (handleModuleResult(/* *ModuleName*/ NameList[0],
+ MaybeModuleDepsGraph, *FD, LocalIndex,
+ DependencyOS, Errs))
HadErrors = true;
} else {
std::unique_ptr<llvm::MemoryBuffer> 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">;
More information about the cfe-commits
mailing list