Skip to content

Commit

Permalink
[clang][deps] add support for dependency scanning with cc1 command line
Browse files Browse the repository at this point in the history
Allow users to run a dependency scan with a cc1 command line in addition to a driver command line. DependencyScanningAction was already being run with a cc1 command line, but DependencyScanningWorker::computeDependencies assumed that it was always provided a driver command line. Now DependencyScanningWorker::computeDependencies can handle cc1 command lines too.

Reviewed By: jansvoboda11

Differential Revision: https://reviews.llvm.org/D156234
  • Loading branch information
cpsughrue authored and jansvoboda11 committed Aug 4, 2023
1 parent 00769d6 commit 6b4de7b
Show file tree
Hide file tree
Showing 2 changed files with 83 additions and 31 deletions.
85 changes: 54 additions & 31 deletions clang/lib/Tooling/DependencyScanning/DependencyScanningWorker.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -385,13 +385,36 @@ static bool forEachDriverJob(
if (!Compilation)
return false;

if (Compilation->containsError())
return false;

for (const driver::Command &Job : Compilation->getJobs()) {
if (!Callback(Job))
return false;
}
return true;
}

static bool createAndRunToolInvocation(
std::vector<std::string> CommandLine, DependencyScanningAction &Action,
FileManager &FM,
std::shared_ptr<clang::PCHContainerOperations> &PCHContainerOps,
DiagnosticsEngine &Diags, DependencyConsumer &Consumer) {

// Save executable path before providing CommandLine to ToolInvocation
std::string Executable = CommandLine[0];
ToolInvocation Invocation(std::move(CommandLine), &Action, &FM,
PCHContainerOps);
Invocation.setDiagnosticConsumer(Diags.getClient());
Invocation.setDiagnosticOptions(&Diags.getDiagnosticOptions());
if (!Invocation.run())
return false;

std::vector<std::string> Args = Action.takeLastCC1Arguments();
Consumer.handleBuildCommand({std::move(Executable), std::move(Args)});
return true;
}

bool DependencyScanningWorker::computeDependencies(
StringRef WorkingDirectory, const std::vector<std::string> &CommandLine,
DependencyConsumer &Consumer, DependencyActionController &Controller,
Expand Down Expand Up @@ -454,37 +477,37 @@ bool DependencyScanningWorker::computeDependencies(
DependencyScanningAction Action(WorkingDirectory, Consumer, Controller, DepFS,
Format, OptimizeArgs, EagerLoadModules,
DisableFree, ModuleName);
bool Success = forEachDriverJob(
FinalCommandLine, *Diags, *FileMgr, [&](const driver::Command &Cmd) {
if (StringRef(Cmd.getCreator().getName()) != "clang") {
// Non-clang command. Just pass through to the dependency
// consumer.
Consumer.handleBuildCommand(
{Cmd.getExecutable(),
{Cmd.getArguments().begin(), Cmd.getArguments().end()}});
return true;
}

std::vector<std::string> Argv;
Argv.push_back(Cmd.getExecutable());
Argv.insert(Argv.end(), Cmd.getArguments().begin(),
Cmd.getArguments().end());

// Create an invocation that uses the underlying file
// system to ensure that any file system requests that
// are made by the driver do not go through the
// dependency scanning filesystem.
ToolInvocation Invocation(std::move(Argv), &Action, &*FileMgr,
PCHContainerOps);
Invocation.setDiagnosticConsumer(Diags->getClient());
Invocation.setDiagnosticOptions(&Diags->getDiagnosticOptions());
if (!Invocation.run())
return false;

std::vector<std::string> Args = Action.takeLastCC1Arguments();
Consumer.handleBuildCommand({Cmd.getExecutable(), std::move(Args)});
return true;
});

bool Success = false;
if (FinalCommandLine[1] == "-cc1") {
Success = createAndRunToolInvocation(FinalCommandLine, Action, *FileMgr,
PCHContainerOps, *Diags, Consumer);
} else {
Success = forEachDriverJob(
FinalCommandLine, *Diags, *FileMgr, [&](const driver::Command &Cmd) {
if (StringRef(Cmd.getCreator().getName()) != "clang") {
// Non-clang command. Just pass through to the dependency
// consumer.
Consumer.handleBuildCommand(
{Cmd.getExecutable(),
{Cmd.getArguments().begin(), Cmd.getArguments().end()}});
return true;
}

// Insert -cc1 comand line options into Argv
std::vector<std::string> Argv;
Argv.push_back(Cmd.getExecutable());
Argv.insert(Argv.end(), Cmd.getArguments().begin(),
Cmd.getArguments().end());

// Create an invocation that uses the underlying file
// system to ensure that any file system requests that
// are made by the driver do not go through the
// dependency scanning filesystem.
return createAndRunToolInvocation(std::move(Argv), Action, *FileMgr,
PCHContainerOps, *Diags, Consumer);
});
}

if (Success && !Action.hasScanned())
Diags->Report(diag::err_fe_expected_compiler_job)
Expand Down
29 changes: 29 additions & 0 deletions clang/test/ClangScanDeps/modules-cc1.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
// Check that clang-scan-deps works with cc1 command lines

// RUN: rm -rf %t
// RUN: split-file %s %t


//--- modules_cc1.cpp
#include "header.h"

//--- header.h

//--- module.modulemap
module header1 { header "header.h" }

//--- cdb.json.template
[{
"file": "DIR/modules_cc1.cpp",
"directory": "DIR",
"command": "clang -cc1 DIR/modules_cc1.cpp -fimplicit-module-maps -o modules_cc1.o"
}]

// RUN: sed "s|DIR|%/t|g" %t/cdb.json.template > %t/cdb.json
// RUN: clang-scan-deps -compilation-database %t/cdb.json -j 1 -mode preprocess-dependency-directives > %t/result
// RUN: cat %t/result | sed 's:\\\\\?:/:g' | FileCheck %s -DPREFIX=%/t

// CHECK: modules_cc1.o:
// CHECK-NEXT: [[PREFIX]]/modules_cc1.cpp
// CHECK-NEXT: [[PREFIX]]/module.modulemap
// CHECK-NEXT: [[PREFIX]]/header.h

0 comments on commit 6b4de7b

Please sign in to comment.