Skip to content
Draft
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions clang/include/clang/Frontend/FrontendActions.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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(); }

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand All @@ -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; }

Expand All @@ -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
Expand Down
20 changes: 13 additions & 7 deletions clang/lib/Frontend/FrontendActions.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think the type here is just ModuleLoadResult. The general rule for auto in LLVM is "Use auto if and only if it makes the code more readable or easier to maintain."

PPCallbacks *CB = PP.getPPCallbacks();
CB->moduleImport(SourceLocation(), Path, ModResult);
// FIXME: how do you know that this offset is correct?
SLoc = SLoc.getLocWithOffset(1);
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am not quite sure setting an offset of 1 is correct. Will need to take a closer look.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I used it as an incrementer as we need to allocate one source location for each module to import.
IIRC I found this pattern used in different parts of the codebase.

assert(SLoc <= SM.getLocForEndOfFile(MainFileID) &&
"Import location extends past file");
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand Down
44 changes: 30 additions & 14 deletions clang/lib/Tooling/DependencyScanning/DependencyScanningWorker.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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>();

Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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;
Expand All @@ -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());
Expand Down Expand Up @@ -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);

Expand All @@ -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") {
Expand Down Expand Up @@ -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);

Expand All @@ -748,17 +751,30 @@ 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",
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What is the reason that we still need to create this file in memory? Should I create a "fake" file for each module in the list?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Someone should fact-check me, but I'm pretty sure compiler invocations always need a file to run an action over.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, you always need a main file id. I'm not actually sure why we need to create a unique path on disk though. I would think the in memory file is enough.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

IIUC this shouldn't actually be writing any file to disk, just a unique name to create the in memory file.

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<llvm::vfs::FileSystem> InMemoryOverlay = InMemoryFS;

OverlayFS->pushOverlay(InMemoryOverlay);
auto ModifiedCommandLine = CommandLine;
ModifiedCommandLine.emplace_back(FakeInputPath);

return scanDependencies(WorkingDirectory, ModifiedCommandLine, Consumer,
Controller, DC, OverlayFS, ModuleName);
Controller, DC, OverlayFS, ModuleNames);
}

DependencyActionController::~DependencyActionController() {}
2 changes: 1 addition & 1 deletion clang/test/ClangScanDeps/link-libraries.c
Original file line number Diff line number Diff line change
Expand Up @@ -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: {
Expand Down
2 changes: 1 addition & 1 deletion clang/test/ClangScanDeps/modules-full-by-mod-name.c
Original file line number Diff line number Diff line change
Expand Up @@ -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: {
Expand Down
16 changes: 11 additions & 5 deletions clang/tools/clang-scan-deps/ClangScanDeps.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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))
Expand Down Expand Up @@ -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(
*ModuleName, Input->CommandLine, CWD, AlreadySeenModules,
LookupOutput);
if (handleModuleResult(*ModuleName, MaybeModuleDepsGraph, *FD,
LocalIndex, DependencyOS, Errs))
NameList, Input->CommandLine, CWD,
AlreadySeenModules, LookupOutput);
// FIXME: Need to have better error handling logic for a list
// of modules. Probably through some call back.
Comment on lines +1034 to +1035
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think you need a callback. This should just drop the module name from the diag, as that should get printed by the normal Clang errors.

if (handleModuleResult(/* *ModuleName*/ NameList[0],
MaybeModuleDepsGraph, *FD, LocalIndex,
DependencyOS, Errs))
HadErrors = true;
} else {
std::unique_ptr<llvm::MemoryBuffer> TU;
Expand Down
2 changes: 1 addition & 1 deletion clang/tools/clang-scan-deps/Opts.td
Original file line number Diff line number Diff line change
Expand Up @@ -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">;
Expand Down
Loading