Index: clang/lib/Tooling/DependencyScanning/DependencyScanningWorker.cpp =================================================================== --- clang/lib/Tooling/DependencyScanning/DependencyScanningWorker.cpp +++ clang/lib/Tooling/DependencyScanning/DependencyScanningWorker.cpp @@ -385,6 +385,9 @@ if (!Compilation) return false; + if (Compilation->containsError()) + return false; + for (const driver::Command &Job : Compilation->getJobs()) { if (!Callback(Job)) return false; @@ -392,6 +395,26 @@ return true; } +static bool createAndRunToolInvocation( + std::vector CommandLine, DependencyScanningAction &Action, + FileManager &FM, + std::shared_ptr &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 Args = Action.takeLastCC1Arguments(); + Consumer.handleBuildCommand({std::move(Executable), std::move(Args)}); + return true; +} + bool DependencyScanningWorker::computeDependencies( StringRef WorkingDirectory, const std::vector &CommandLine, DependencyConsumer &Consumer, DependencyActionController &Controller, @@ -454,37 +477,37 @@ 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 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 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 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) Index: clang/test/ClangScanDeps/Inputs/modules_cc1_cdb.json =================================================================== --- /dev/null +++ clang/test/ClangScanDeps/Inputs/modules_cc1_cdb.json @@ -0,0 +1,22 @@ +[ +{ + "directory": "DIR", + "command": "clang -cc1 -E DIR/modules_cdb_input2.cpp -IInputs -D INCLUDE_HEADER2 -fmodules -MT modules_cdb_input2.o -dependency-file DIR/modules_cdb2.d -fmodules-cache-path=DIR/module-cache -fcoverage-compilation-dir=DIR -fimplicit-module-maps -fmodules-validate-system-headers", + "file": "DIR/modules_cdb_input2.cpp" +}, +{ + "directory": "DIR", + "command": "clang -cc1 -E DIR/modules_cdb_input.cpp -IInputs -fmodules -fmodules-cache-path=DIR/module-cache -fcoverage-compilation-dir=DIR -fdebug-compilation-dir=DIR -fimplicit-module-maps -fmodules-validate-system-headers", + "file": "DIR/modules_cdb_input.cpp" +}, +{ + "directory": "DIR", + "command": "clang -cc1 -E DIR/modules_cdb_input.cpp -IInputs -fmodules -fmodules-cache-path=DIR/module-cache -fcoverage-compilation-dir=DIR -fdebug-compilation-dir=DIR -fimplicit-module-maps -fmodules-validate-system-headers -o a.o", + "file": "DIR/modules_cdb_input.cpp" +}, +{ + "directory": "DIR", + "command": "clang -cc1 -E DIR/modules_cdb_input.cpp -IInputs -fmodules -fmodules-cache-path=DIR/module-cache -fcoverage-compilation-dir=DIR -fdebug-compilation-dir=DIR -fimplicit-module-maps -fmodules-validate-system-headers -o b.o", + "file": "DIR/modules_cdb_input.cpp" +} +] Index: clang/test/ClangScanDeps/modules-cc1.cpp =================================================================== --- /dev/null +++ clang/test/ClangScanDeps/modules-cc1.cpp @@ -0,0 +1,44 @@ +// RUN: rm -rf %t.dir +// RUN: rm -rf %t.cdb +// RUN: rm -rf %t_clangcl.cdb +// RUN: rm -rf %t.module-cache +// RUN: rm -rf %t.module-cache_clangcl +// 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_cc1_cdb.json > %t.cdb +// +// RUN: clang-scan-deps -compilation-database %t.cdb -j 1 -mode preprocess-dependency-directives | \ +// RUN: FileCheck --check-prefixes=CHECK1,CHECK2,CHECK2NO %s +// +// The output order is non-deterministic when using more than one thread, +// so check the output using two runs. Note that the 'NOT' check is not used +// as it might fail if the results for `modules_cdb_input.cpp` are reported before +// `modules_cdb_input2.cpp`. +// +// RUN: clang-scan-deps -compilation-database %t.cdb -j 2 -mode preprocess-dependency-directives | \ +// RUN: FileCheck --check-prefix=CHECK1 %s +// RUN: clang-scan-deps -compilation-database %t.cdb -j 2 -mode preprocess | \ +// RUN: FileCheck --check-prefix=CHECK1 %s +// RUN: clang-scan-deps -compilation-database %t.cdb -j 2 -mode preprocess-dependency-directives | \ +// RUN: FileCheck --check-prefix=CHECK2 %s +// RUN: clang-scan-deps -compilation-database %t.cdb -j 2 -mode preprocess | \ +// RUN: FileCheck --check-prefix=CHECK2 %s + +#include "header.h" + +// CHECK1: modules_cdb_input2.o: +// CHECK1-NEXT: modules_cdb_input2.cpp +// CHECK1-NEXT: Inputs{{/|\\}}module.modulemap +// CHECK1-NEXT: Inputs{{/|\\}}header2.h +// CHECK1: Inputs{{/|\\}}header.h + +// CHECK2: {{(modules_cdb_input)|(a)|(b)}}.o: +// CHECK2-NEXT: modules_cdb_input.cpp +// CHECK2-NEXT: Inputs{{/|\\}}module.modulemap +// CHECK2-NEXT: Inputs{{/|\\}}header.h +// CHECK2NO-NOT: header2 \ No newline at end of file