[clang][deps] Split translation units into individual -cc1 or other commands

Instead of trying to "fix" the original driver invocation by appending
arguments to it, split it into multiple commands, and for each -cc1
command use a CompilerInvocation to give precise control over the
invocation.

This change should make it easier to (in the future) canonicalize the
command-line (e.g. to improve hits in something like ccache), apply
optimizations, or start supporting multi-arch builds, which would
require different modules for each arch.

In the long run it may make sense to treat the TU commands as a
dependency graph, each with their own dependencies on modules or earlier
TU commands, but for now they are simply a list that is executed in
order, and the dependencies are simply duplicated. Since we currently
only support single-arch builds, there is no parallelism available in
the execution.

Differential Revision: https://reviews.llvm.org/D132405
This commit is contained in:
Ben Langmuir 2022-08-25 09:22:31 -07:00
parent 260fb2bc3f
commit f80a0ea760
27 changed files with 650 additions and 207 deletions

View File

@ -49,8 +49,16 @@ struct FullDependencies {
/// determined that the differences are benign for this compilation.
std::vector<ModuleID> ClangModuleDeps;
/// The command line of the TU (excluding the compiler executable).
std::vector<std::string> CommandLine;
/// The sequence of commands required to build the translation unit. Commands
/// should be executed in order.
///
/// FIXME: If we add support for multi-arch builds in clang-scan-deps, we
/// should make the dependencies between commands explicit to enable parallel
/// builds of each architecture.
std::vector<Command> Commands;
/// Deprecated driver command-line. This will be removed in a future version.
std::vector<std::string> DriverCommandLine;
};
struct FullDependenciesResult {
@ -99,6 +107,12 @@ public:
LookupModuleOutputCallback LookupModuleOutput,
llvm::Optional<StringRef> ModuleName = None);
llvm::Expected<FullDependenciesResult> getFullDependenciesLegacyDriverCommand(
const std::vector<std::string> &CommandLine, StringRef CWD,
const llvm::StringSet<> &AlreadySeen,
LookupModuleOutputCallback LookupModuleOutput,
llvm::Optional<StringRef> ModuleName = None);
private:
DependencyScanningWorker Worker;
};
@ -111,6 +125,10 @@ public:
: AlreadySeen(AlreadySeen), LookupModuleOutput(LookupModuleOutput),
EagerLoadModules(EagerLoadModules) {}
void handleBuildCommand(Command Cmd) override {
Commands.push_back(std::move(Cmd));
}
void handleDependencyOutputOpts(const DependencyOutputOptions &) override {}
void handleFileDependency(StringRef File) override {
@ -134,14 +152,17 @@ public:
return LookupModuleOutput(ID, Kind);
}
FullDependenciesResult getFullDependencies(
FullDependenciesResult getFullDependenciesLegacyDriverCommand(
const std::vector<std::string> &OriginalCommandLine) const;
FullDependenciesResult takeFullDependencies();
private:
std::vector<std::string> Dependencies;
std::vector<PrebuiltModuleDep> PrebuiltModuleDeps;
llvm::MapVector<std::string, ModuleDeps, llvm::StringMap<unsigned>>
ClangModuleDeps;
std::vector<Command> Commands;
std::string ContextHash;
std::vector<std::string> OutputPaths;
const llvm::StringSet<> &AlreadySeen;

View File

@ -28,10 +28,20 @@ namespace dependencies {
class DependencyScanningWorkerFilesystem;
/// A command-line tool invocation that is part of building a TU.
///
/// \see FullDependencies::Commands.
struct Command {
std::string Executable;
std::vector<std::string> Arguments;
};
class DependencyConsumer {
public:
virtual ~DependencyConsumer() {}
virtual void handleBuildCommand(Command Cmd) = 0;
virtual void
handleDependencyOutputOpts(const DependencyOutputOptions &Opts) = 0;

View File

@ -181,12 +181,16 @@ class ModuleDepCollector final : public DependencyCollector {
public:
ModuleDepCollector(std::unique_ptr<DependencyOutputOptions> Opts,
CompilerInstance &ScanInstance, DependencyConsumer &C,
CompilerInvocation &&OriginalCI, bool OptimizeArgs,
CompilerInvocation OriginalCI, bool OptimizeArgs,
bool EagerLoadModules);
void attachToPreprocessor(Preprocessor &PP) override;
void attachToASTReader(ASTReader &R) override;
/// Apply any changes implied by the discovered dependencies to the given
/// invocation, (e.g. disable implicit modules, add explicit module paths).
void applyDiscoveredDependencies(CompilerInvocation &CI);
private:
friend ModuleDepCollectorPP;

View File

@ -45,6 +45,8 @@ llvm::Expected<std::string> DependencyScanningTool::getDependencyFile(
/// Prints out all of the gathered dependencies into a string.
class MakeDependencyPrinterConsumer : public DependencyConsumer {
public:
void handleBuildCommand(Command) override {}
void
handleDependencyOutputOpts(const DependencyOutputOptions &Opts) override {
this->Opts = std::make_unique<DependencyOutputOptions>(Opts);
@ -120,14 +122,53 @@ DependencyScanningTool::getFullDependencies(
Worker.computeDependencies(CWD, CommandLine, Consumer, ModuleName);
if (Result)
return std::move(Result);
return Consumer.getFullDependencies(CommandLine);
return Consumer.takeFullDependencies();
}
FullDependenciesResult FullDependencyConsumer::getFullDependencies(
llvm::Expected<FullDependenciesResult>
DependencyScanningTool::getFullDependenciesLegacyDriverCommand(
const std::vector<std::string> &CommandLine, StringRef CWD,
const llvm::StringSet<> &AlreadySeen,
LookupModuleOutputCallback LookupModuleOutput,
llvm::Optional<StringRef> ModuleName) {
FullDependencyConsumer Consumer(AlreadySeen, LookupModuleOutput,
Worker.shouldEagerLoadModules());
llvm::Error Result =
Worker.computeDependencies(CWD, CommandLine, Consumer, ModuleName);
if (Result)
return std::move(Result);
return Consumer.getFullDependenciesLegacyDriverCommand(CommandLine);
}
FullDependenciesResult FullDependencyConsumer::takeFullDependencies() {
FullDependenciesResult FDR;
FullDependencies &FD = FDR.FullDeps;
FD.ID.ContextHash = std::move(ContextHash);
FD.FileDeps = std::move(Dependencies);
FD.PrebuiltModuleDeps = std::move(PrebuiltModuleDeps);
FD.Commands = std::move(Commands);
for (auto &&M : ClangModuleDeps) {
auto &MD = M.second;
if (MD.ImportedByMainFile)
FD.ClangModuleDeps.push_back(MD.ID);
// TODO: Avoid handleModuleDependency even being called for modules
// we've already seen.
if (AlreadySeen.count(M.first))
continue;
FDR.DiscoveredModules.push_back(std::move(MD));
}
return FDR;
}
FullDependenciesResult
FullDependencyConsumer::getFullDependenciesLegacyDriverCommand(
const std::vector<std::string> &OriginalCommandLine) const {
FullDependencies FD;
FD.CommandLine = makeTUCommandLineWithoutPaths(
FD.DriverCommandLine = makeTUCommandLineWithoutPaths(
ArrayRef<std::string>(OriginalCommandLine).slice(1));
FD.ID.ContextHash = std::move(ContextHash);
@ -135,7 +176,7 @@ FullDependenciesResult FullDependencyConsumer::getFullDependencies(
FD.FileDeps.assign(Dependencies.begin(), Dependencies.end());
for (const PrebuiltModuleDep &PMD : PrebuiltModuleDeps)
FD.CommandLine.push_back("-fmodule-file=" + PMD.PCMFile);
FD.DriverCommandLine.push_back("-fmodule-file=" + PMD.PCMFile);
for (auto &&M : ClangModuleDeps) {
auto &MD = M.second;
@ -143,11 +184,12 @@ FullDependenciesResult FullDependencyConsumer::getFullDependencies(
FD.ClangModuleDeps.push_back(MD.ID);
auto PCMPath = LookupModuleOutput(MD.ID, ModuleOutputKind::ModuleFile);
if (EagerLoadModules) {
FD.CommandLine.push_back("-fmodule-file=" + PCMPath);
FD.DriverCommandLine.push_back("-fmodule-file=" + PCMPath);
} else {
FD.CommandLine.push_back("-fmodule-map-file=" + MD.ClangModuleMapFile);
FD.CommandLine.push_back("-fmodule-file=" + MD.ID.ModuleName + "=" +
PCMPath);
FD.DriverCommandLine.push_back("-fmodule-map-file=" +
MD.ClangModuleMapFile);
FD.DriverCommandLine.push_back("-fmodule-file=" + MD.ID.ModuleName +
"=" + PCMPath);
}
}
}

View File

@ -7,7 +7,12 @@
//===----------------------------------------------------------------------===//
#include "clang/Tooling/DependencyScanning/DependencyScanningWorker.h"
#include "clang/Basic/DiagnosticFrontend.h"
#include "clang/CodeGen/ObjectFilePCHContainerOperations.h"
#include "clang/Driver/Compilation.h"
#include "clang/Driver/Driver.h"
#include "clang/Driver/Job.h"
#include "clang/Driver/Tool.h"
#include "clang/Frontend/CompilerInstance.h"
#include "clang/Frontend/CompilerInvocation.h"
#include "clang/Frontend/FrontendActions.h"
@ -17,6 +22,7 @@
#include "clang/Tooling/DependencyScanning/DependencyScanningService.h"
#include "clang/Tooling/DependencyScanning/ModuleDepCollector.h"
#include "clang/Tooling/Tooling.h"
#include "llvm/Support/Host.h"
using namespace clang;
using namespace tooling;
@ -156,6 +162,17 @@ public:
// Restore the value of DisableFree, which may be modified by Tooling.
OriginalInvocation.getFrontendOpts().DisableFree = DisableFree;
if (Scanned) {
// Scanning runs once for the first -cc1 invocation in a chain of driver
// jobs. For any dependent jobs, reuse the scanning result and just
// update the LastCC1Arguments to correspond to the new invocation.
// FIXME: to support multi-arch builds, each arch requires a separate scan
setLastCC1Arguments(std::move(OriginalInvocation));
return true;
}
Scanned = true;
// Create a compiler instance to handle the actual work.
CompilerInstance ScanInstance(std::move(PCHContainerOps));
ScanInstance.setInvocation(std::move(Invocation));
@ -230,9 +247,10 @@ public:
std::move(Opts), WorkingDirectory, Consumer));
break;
case ScanningOutputFormat::Full:
ScanInstance.addDependencyCollector(std::make_shared<ModuleDepCollector>(
std::move(Opts), ScanInstance, Consumer,
std::move(OriginalInvocation), OptimizeArgs, EagerLoadModules));
MDC = std::make_shared<ModuleDepCollector>(
std::move(Opts), ScanInstance, Consumer, OriginalInvocation,
OptimizeArgs, EagerLoadModules);
ScanInstance.addDependencyCollector(MDC);
break;
}
@ -253,9 +271,31 @@ public:
const bool Result = ScanInstance.ExecuteAction(*Action);
if (!DepFS)
FileMgr->clearStatCache();
if (Result)
setLastCC1Arguments(std::move(OriginalInvocation));
return Result;
}
bool hasScanned() const { return Scanned; }
/// Take the cc1 arguments corresponding to the most recent invocation used
/// with this action. Any modifications implied by the discovered dependencies
/// will have already been applied.
std::vector<std::string> takeLastCC1Arguments() {
std::vector<std::string> Result;
std::swap(Result, LastCC1Arguments); // Reset LastCC1Arguments to empty.
return Result;
}
private:
void setLastCC1Arguments(CompilerInvocation &&CI) {
if (MDC)
MDC->applyDiscoveredDependencies(CI);
LastCC1Arguments = CI.getCC1CommandLine();
}
private:
StringRef WorkingDirectory;
DependencyConsumer &Consumer;
@ -265,6 +305,9 @@ private:
bool EagerLoadModules;
bool DisableFree;
llvm::Optional<StringRef> ModuleName;
std::shared_ptr<ModuleDepCollector> MDC;
std::vector<std::string> LastCC1Arguments;
bool Scanned = false;
};
} // end anonymous namespace
@ -313,6 +356,36 @@ runWithDiags(DiagnosticOptions *DiagOpts,
llvm::inconvertibleErrorCode());
}
static bool forEachDriverJob(
ArrayRef<std::string> Args, DiagnosticsEngine &Diags, FileManager &FM,
llvm::function_ref<bool(const driver::Command &Cmd)> Callback) {
std::unique_ptr<driver::Driver> Driver = std::make_unique<driver::Driver>(
Args[0], llvm::sys::getDefaultTargetTriple(), Diags,
"clang LLVM compiler", &FM.getVirtualFileSystem());
Driver->setTitle("clang_based_tool");
std::vector<const char *> Argv;
for (const std::string &Arg : Args)
Argv.push_back(Arg.c_str());
// The "input file not found" diagnostics from the driver are useful.
// The driver is only aware of the VFS working directory, but some clients
// change this at the FileManager level instead.
// In this case the checks have false positives, so skip them.
if (!FM.getFileSystemOpts().WorkingDir.empty())
Driver->setCheckInputsExist(false);
const std::unique_ptr<driver::Compilation> Compilation(
Driver->BuildCompilation(llvm::makeArrayRef(Argv)));
if (!Compilation)
return false;
for (const driver::Command &Job : Compilation->getJobs()) {
if (!Callback(Job))
return false;
}
return true;
}
llvm::Error DependencyScanningWorker::computeDependencies(
StringRef WorkingDirectory, const std::vector<std::string> &CommandLine,
DependencyConsumer &Consumer, llvm::Optional<StringRef> ModuleName) {
@ -338,25 +411,60 @@ llvm::Error DependencyScanningWorker::computeDependencies(
llvm::transform(CommandLine, FinalCCommandLine.begin(),
[](const std::string &Str) { return Str.c_str(); });
return runWithDiags(CreateAndPopulateDiagOpts(FinalCCommandLine).release(),
[&](DiagnosticConsumer &DC, DiagnosticOptions &DiagOpts) {
// DisableFree is modified by Tooling for running
// in-process; preserve the original value, which is
// always true for a driver invocation.
bool DisableFree = true;
DependencyScanningAction Action(
WorkingDirectory, Consumer, DepFS, Format,
OptimizeArgs, EagerLoadModules, DisableFree,
ModuleName);
// 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(FinalCommandLine, &Action,
CurrentFiles.get(),
PCHContainerOps);
Invocation.setDiagnosticConsumer(&DC);
Invocation.setDiagnosticOptions(&DiagOpts);
return Invocation.run();
});
return runWithDiags(
CreateAndPopulateDiagOpts(FinalCCommandLine).release(),
[&](DiagnosticConsumer &DC, DiagnosticOptions &DiagOpts) {
IntrusiveRefCntPtr<DiagnosticsEngine> Diags =
CompilerInstance::createDiagnostics(&DiagOpts, &DC, false);
// Although `Diagnostics` are used only for command-line parsing, the
// custom `DiagConsumer` might expect a `SourceManager` to be present.
SourceManager SrcMgr(*Diags, *CurrentFiles);
Diags->setSourceManager(&SrcMgr);
// DisableFree is modified by Tooling for running
// in-process; preserve the original value, which is
// always true for a driver invocation.
bool DisableFree = true;
DependencyScanningAction Action(WorkingDirectory, Consumer, DepFS,
Format, OptimizeArgs, EagerLoadModules,
DisableFree, ModuleName);
bool Success = forEachDriverJob(
FinalCommandLine, *Diags, *CurrentFiles,
[&](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,
&*CurrentFiles, 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;
});
if (Success && !Action.hasScanned()) {
Diags->Report(diag::err_fe_expected_compiler_job)
<< llvm::join(FinalCommandLine, " ");
}
return Success && Action.hasScanned();
});
}

View File

@ -174,6 +174,34 @@ void ModuleDepCollector::addModuleFiles(
}
}
static bool needsModules(FrontendInputFile FIF) {
switch (FIF.getKind().getLanguage()) {
case Language::Unknown:
case Language::Asm:
case Language::LLVM_IR:
return false;
default:
return true;
}
}
void ModuleDepCollector::applyDiscoveredDependencies(CompilerInvocation &CI) {
CI.clearImplicitModuleBuildOptions();
if (llvm::any_of(CI.getFrontendOpts().Inputs, needsModules)) {
SmallVector<ModuleID> DirectDeps;
for (const auto &KV : ModularDeps)
if (KV.second->ImportedByMainFile)
DirectDeps.push_back(KV.second->ID);
addModuleMapFiles(CI, DirectDeps);
addModuleFiles(CI, DirectDeps);
for (const auto &KV : DirectPrebuiltModularDeps)
CI.getFrontendOpts().ModuleFiles.push_back(KV.second.PCMFile);
}
}
static std::string getModuleContextHash(const ModuleDeps &MD,
const CompilerInvocation &CI,
bool EagerLoadModules) {
@ -508,7 +536,7 @@ void ModuleDepCollectorPP::addAffectingModule(
ModuleDepCollector::ModuleDepCollector(
std::unique_ptr<DependencyOutputOptions> Opts,
CompilerInstance &ScanInstance, DependencyConsumer &C,
CompilerInvocation &&OriginalCI, bool OptimizeArgs, bool EagerLoadModules)
CompilerInvocation OriginalCI, bool OptimizeArgs, bool EagerLoadModules)
: ScanInstance(ScanInstance), Consumer(C), Opts(std::move(Opts)),
OriginalInvocation(std::move(OriginalCI)), OptimizeArgs(OptimizeArgs),
EagerLoadModules(EagerLoadModules) {}

View File

@ -0,0 +1,38 @@
// Test the deprecated version of the API that returns a driver command instead
// of multiple -cc1 commands.
// RUN: rm -rf %t
// RUN: split-file %s %t
// RUN: sed -e "s|DIR|%/t|g" %t/cdb.json.in > %t/cdb.json
// RUN: clang-scan-deps -compilation-database=%t/cdb.json -format experimental-full \
// RUN: -deprecated-driver-command | sed 's:\\\\\?:/:g' | FileCheck %s
// CHECK: "command-line": [
// CHECK: "-c"
// CHECK: "{{.*}}tu.c"
// CHECK: "-save-temps"
// CHECK: "-fno-implicit-modules"
// CHECK: "-fno-implicit-module-maps"
// CHECK: ]
// CHECK: "file-deps": [
// CHECK: "{{.*}}tu.c",
// CHECK: "{{.*}}header.h"
// CHECK: ]
//--- cdb.json.in
[{
"directory": "DIR",
"command": "clang -c DIR/tu.c -save-temps",
"file": "DIR/tu.c"
}]
//--- header.h
void bar(void);
//--- tu.c
#include "header.h"
void foo(void) {
bar();
}

View File

@ -28,7 +28,7 @@
// CHECK-NEXT: ],
// CHECK-NEXT: "translation-units": [
// CHECK-NEXT: {
// CHECK-NEXT: "clang-context-hash": "[[HASH_TU:.*]],
// CHECK: "clang-context-hash": "[[HASH_TU:.*]],
// CHECK-NEXT: "clang-module-deps": [
// CHECK-NEXT: {
// CHECK-NEXT: "context-hash": "[[HASH_MOD]]",
@ -36,13 +36,11 @@
// CHECK-NEXT: }
// CHECK-NEXT: ],
// CHECK-NEXT: "command-line": [
// CHECK: "-fno-implicit-modules"
// CHECK: "-fno-implicit-module-maps"
// CHECK-NOT: "-fimplicit-modules"
// CHECK-NOT: "-fimplicit-module-maps"
// CHECK: ],
// CHECK-NEXT: "file-deps": [
// CHECK: "file-deps": [
// CHECK-NEXT: "[[PREFIX]]/tu.c"
// CHECK-NEXT: ],
// CHECK-NEXT: "input-file": "[[PREFIX]]/tu.c"
// CHECK-NEXT: }
// CHECK-NEXT: ]
// CHECK-NEXT: }

View File

@ -95,7 +95,7 @@ module X { header "X.h" }
// CHECK-NEXT: ],
// CHECK-NEXT: "translation-units": [
// CHECK-NEXT: {
// CHECK-NEXT: "clang-context-hash": "{{.*}}",
// CHECK: "clang-context-hash": "{{.*}}",
// CHECK-NEXT: "clang-module-deps": [
// CHECK-NEXT: {
// CHECK-NEXT: "context-hash": "[[HASH_X]]",
@ -104,14 +104,13 @@ module X { header "X.h" }
// CHECK-NEXT: ],
// CHECK-NEXT: "command-line": [
// CHECK: ],
// CHECK-NEXT: "file-deps": [
// CHECK: "file-deps": [
// CHECK-NEXT: "[[PREFIX]]/test.c"
// CHECK-NEXT: ],
// CHECK-NEXT: "input-file": "[[PREFIX]]/test.c"
// CHECK-NEXT: }
// CHECK-NEXT: ]
// CHECK-NEXT: }
// CHECK-NEXT: {
// CHECK: {
// CHECK-NEXT: "modules": [
// CHECK-NEXT: {
// CHECK-NEXT: "clang-module-deps": [
@ -149,7 +148,7 @@ module X { header "X.h" }
// CHECK-NEXT: ],
// CHECK-NEXT: "translation-units": [
// CHECK-NEXT: {
// CHECK-NEXT: "clang-context-hash": "{{.*}}",
// CHECK: "clang-context-hash": "{{.*}}",
// CHECK-NEXT: "clang-module-deps": [
// CHECK-NEXT: {
// CHECK-NEXT: "context-hash": "{{.*}}",
@ -158,10 +157,8 @@ module X { header "X.h" }
// CHECK-NEXT: ],
// CHECK-NEXT: "command-line": [
// CHECK: ],
// CHECK-NEXT: "file-deps": [
// CHECK: "file-deps": [
// CHECK-NEXT: "[[PREFIX]]/test.c"
// CHECK-NEXT: ],
// CHECK-NEXT: "input-file": "[[PREFIX]]/test.c"
// CHECK-NEXT: }
// CHECK-NEXT: ]
// CHECK-NEXT: }

View File

@ -38,10 +38,11 @@
// CHECK-NEXT: ]
// CHECK-NEXT: "command-line": [
// CHECK-NOT: "-DFOO"
// CHECK-NOT: "FOO"
// CHECK: ]
// CHECK: "input-file": "{{.*}}tu1.c"
// CHECK-NEXT: }
// CHECK-NEXT: {
// CHECK: {
// CHECK: "clang-module-deps": [
// CHECK-NEXT: {
// CHECK-NEXT: "context-hash": "[[HASH_FOO]]"
@ -49,11 +50,12 @@
// CHECK-NEXT: }
// CHECK-NEXT: ]
// CHECK-NEXT: "command-line": [
// CHECK: "-DFOO"
// CHECK: "-D"
// CHECK-NEXT: "FOO"
// CHECK: ]
// CHECK: "input-file": "{{.*}}tu2.c"
// CHECK-NEXT: }
// CHECK-NEXT: {
// CHECK: {
// CHECK: "clang-module-deps": [
// CHECK-NEXT: {
// CHECK-NEXT: "context-hash": "[[HASH_NO_FOO]]"
@ -61,8 +63,9 @@
// CHECK-NEXT: }
// CHECK-NEXT: ]
// CHECK-NEXT: "command-line": [
// CHECK: "-DFOO"
// CHECK: "-fmodules-ignore-macro=FOO"
// CHECK: "-D"
// CHECK-NEXT: "FOO"
// CHECK: ]
// CHECK: "input-file": "{{.*}}tu3.c"

View File

@ -35,11 +35,11 @@
// CHECK-NEXT: }
// CHECK-NEXT: ]
// CHECK-NEXT: "command-line": [
// CHECK: "-MF"
// CHECK: "-dependency-file"
// CHECK: ]
// CHECK: "input-file": "{{.*}}tu1.c"
// CHECK-NEXT: }
// CHECK-NEXT: {
// CHECK: {
// CHECK: "clang-module-deps": [
// CHECK-NEXT: {
// CHECK-NEXT: "context-hash": "[[HASH2]]"
@ -48,6 +48,7 @@
// CHECK-NEXT: ]
// CHECK-NEXT: "command-line": [
// CHECK-NOT: "-MF"
// CHECK-NOT: "-dependency-file"
// CHECK: ]
// CHECK: "input-file": "{{.*}}tu2.c"

View File

@ -39,7 +39,7 @@
// CHECK: ]
// CHECK: "input-file": "{{.*}}tu1.c"
// CHECK-NEXT: }
// CHECK-NEXT: {
// CHECK: {
// CHECK: "clang-module-deps": [
// CHECK-NEXT: {
// CHECK-NEXT: "context-hash": "[[HASH2]]"

View File

@ -40,7 +40,7 @@
// CHECK-NEXT: ],
// CHECK-NEXT: "translation-units": [
// CHECK-NEXT: {
// CHECK-NEXT: "clang-context-hash": "{{.*}}",
// CHECK: "clang-context-hash": "{{.*}}",
// CHECK-NEXT: "clang-module-deps": [
// CHECK-NEXT: {
// CHECK-NEXT: "context-hash": "[[HASH_MOD_A]]",
@ -49,15 +49,13 @@
// CHECK-NEXT: ],
// CHECK-NEXT: "command-line": [
// CHECK: ],
// CHECK-NEXT: "file-deps": [
// CHECK: "file-deps": [
// CHECK-NEXT: "[[PREFIX]]/tu.c"
// CHECK-NEXT: ],
// CHECK-NEXT: "input-file": "[[PREFIX]]/tu.c"
// CHECK-NEXT: }
// CHECK-NEXT: ]
// CHECK-NEXT: }
// CHECK-NEXT: {
// CHECK-NEXT: "modules": [
// CHECK: "modules": [
// CHECK-NEXT: {
// CHECK-NEXT: "clang-module-deps": [],
// CHECK-NEXT: "clang-modulemap-file": "[[PREFIX]]/module.modulemap",
@ -79,7 +77,7 @@
// CHECK-NEXT: ],
// CHECK-NEXT: "translation-units": [
// CHECK-NEXT: {
// CHECK-NEXT: "clang-context-hash": "{{.*}}",
// CHECK: "clang-context-hash": "{{.*}}",
// CHECK-NEXT: "clang-module-deps": [
// CHECK-NEXT: {
// CHECK-NOT: "context-hash": "[[HASH_MOD_A]]",
@ -88,10 +86,8 @@
// CHECK-NEXT: ],
// CHECK-NEXT: "command-line": [
// CHECK: ],
// CHECK-NEXT: "file-deps": [
// CHECK: "file-deps": [
// CHECK-NEXT: "[[PREFIX]]/tu.c"
// CHECK-NEXT: ],
// CHECK-NEXT: "input-file": "[[PREFIX]]/tu.c"
// CHECK-NEXT: }
// CHECK-NEXT: ]
// CHECK-NEXT: }

View File

@ -78,7 +78,7 @@ module Direct { header "direct.h" }
// CHECK-NEXT: ],
// CHECK-NEXT: "translation-units": [
// CHECK-NEXT: {
// CHECK-NEXT: "clang-context-hash": "{{.*}}",
// CHECK: "clang-context-hash": "{{.*}}",
// CHECK-NEXT: "clang-module-deps": [
// CHECK-NEXT: {
// CHECK-NEXT: "context-hash": "{{.*}}",
@ -93,10 +93,8 @@ module Direct { header "direct.h" }
// CHECK_EAGER-NOT: "-fmodule-map-file={{.*}}"
// CHECK_EAGER: "-fmodule-file=[[PREFIX]]/{{.*}}/Direct-{{.*}}.pcm"
// CHECK: ],
// CHECK-NEXT: "file-deps": [
// CHECK: "file-deps": [
// CHECK-NEXT: "[[PREFIX]]/tu.c"
// CHECK-NEXT: ],
// CHECK-NEXT: "input-file": "[[PREFIX]]/tu.c"
// CHECK-NEXT: }
// CHECK-NEXT: ]
// CHECK-NEXT: }

View File

@ -33,7 +33,7 @@
// CHECK-NEXT: ],
// CHECK-NEXT: "translation-units": [
// CHECK-NEXT: {
// CHECK-NEXT: "clang-context-hash": "[[HASH_TU:[A-Z0-9]+]]",
// CHECK: "clang-context-hash": "[[HASH_TU:[A-Z0-9]+]]",
// CHECK-NEXT: "clang-module-deps": [
// CHECK-NEXT: {
// CHECK-NEXT: "context-hash": "[[HASH_H2]]",
@ -42,12 +42,10 @@
// CHECK-NEXT: ],
// CHECK-NEXT: "command-line": [
// CHECK: ],
// CHECK-NEXT: "file-deps": [
// CHECK: "file-deps": [
// CHECK-NEXT: "[[PREFIX]]/modules-fmodule-name-no-module-built.m"
// CHECK-NEXT: "[[PREFIX]]/Inputs/header3.h"
// CHECK-NEXT: "[[PREFIX]]/Inputs/header.h"
// CHECK-NEXT: ],
// CHECK-NEXT: "input-file": "[[PREFIX]]/modules-fmodule-name-no-module-built.m"
// CHECK-NEXT: }
// CHECK-NEXT: ]
// CHECK-NEXT: }

View File

@ -82,76 +82,96 @@
// CHECK-NEXT: ],
// CHECK-NEXT: "translation-units": [
// CHECK-NEXT: {
// CHECK-NEXT: "clang-context-hash": "[[HASH_TU:[A-Z0-9]+]]",
// CHECK-NEXT: "clang-module-deps": [
// CHECK-NEXT: "commands": [
// CHECK-NEXT: {
// CHECK-NEXT: "context-hash": "[[HASH_H1]]",
// CHECK-NEXT: "module-name": "header1"
// CHECK-NEXT: "clang-context-hash": "[[HASH_TU:[A-Z0-9]+]]",
// CHECK-NEXT: "clang-module-deps": [
// CHECK-NEXT: {
// CHECK-NEXT: "context-hash": "[[HASH_H1]]",
// CHECK-NEXT: "module-name": "header1"
// CHECK-NEXT: }
// CHECK-NEXT: ],
// CHECK-NEXT: "command-line": [
// CHECK-NOT: "-fimplicit-modules"
// CHECK-NOT: "-fimplicit-module-maps"
// CHECK: "-fmodule-file={{.*}}[[PREFIX]]/module-cache{{(_clangcl)?}}/[[HASH_H1]]/header1-{{[A-Z0-9]+}}.pcm"
// CHECK: ],
// CHECK-NEXT: "executable": "{{.*}}clang{{.*}}"
// CHECK-NEXT: "file-deps": [
// CHECK-NEXT: "[[PREFIX]]/modules_cdb_input.cpp"
// CHECK-NEXT: ],
// CHECK-NEXT: "input-file": "[[PREFIX]]/modules_cdb_input.cpp"
// CHECK-NEXT: }
// CHECK-NEXT: ],
// CHECK-NEXT: "command-line": [
// CHECK: "-fno-implicit-modules"
// CHECK: "-fno-implicit-module-maps"
// CHECK: "-fmodule-file={{.*}}[[PREFIX]]/module-cache{{(_clangcl)?}}/[[HASH_H1]]/header1-{{[A-Z0-9]+}}.pcm"
// CHECK: ],
// CHECK-NEXT: "file-deps": [
// CHECK-NEXT: "[[PREFIX]]/modules_cdb_input.cpp"
// CHECK-NEXT: ],
// CHECK-NEXT: "input-file": "[[PREFIX]]/modules_cdb_input.cpp"
// CHECK-NEXT: ]
// CHECK-NEXT: },
// CHECK-NEXT: {
// CHECK-NEXT: "clang-context-hash": "[[HASH_TU:[A-Z0-9]+]]",
// CHECK-NEXT: "clang-module-deps": [
// CHECK-NEXT: "commands": [
// CHECK-NEXT: {
// CHECK-NEXT: "context-hash": "[[HASH_H1]]",
// CHECK-NEXT: "module-name": "header1"
// CHECK-NEXT: "clang-context-hash": "[[HASH_TU:[A-Z0-9]+]]",
// CHECK-NEXT: "clang-module-deps": [
// CHECK-NEXT: {
// CHECK-NEXT: "context-hash": "[[HASH_H1]]",
// CHECK-NEXT: "module-name": "header1"
// CHECK-NEXT: }
// CHECK-NEXT: ],
// CHECK-NEXT: "command-line": [
// CHECK-NOT: "-fimplicit-modules"
// CHECK-NOT: "-fimplicit-module-maps"
// CHECK: "-fmodule-file={{.*}}[[PREFIX]]/module-cache{{(_clangcl)?}}/[[HASH_H1]]/header1-{{[A-Z0-9]+}}.pcm"
// CHECK: ],
// CHECK-NEXT: "executable": "{{.*}}clang{{.*}}"
// CHECK-NEXT: "file-deps": [
// CHECK-NEXT: "[[PREFIX]]/modules_cdb_input.cpp"
// CHECK-NEXT: ],
// CHECK-NEXT: "input-file": "[[PREFIX]]/modules_cdb_input.cpp"
// CHECK-NEXT: }
// CHECK-NEXT: ],
// CHECK-NEXT: "command-line": [
// CHECK: "-fno-implicit-modules"
// CHECK: "-fno-implicit-module-maps"
// CHECK: "-fmodule-file={{.*}}[[PREFIX]]/module-cache{{(_clangcl)?}}/[[HASH_H1]]/header1-{{[A-Z0-9]+}}.pcm"
// CHECK: ],
// CHECK-NEXT: "file-deps": [
// CHECK-NEXT: "[[PREFIX]]/modules_cdb_input.cpp"
// CHECK-NEXT: ],
// CHECK-NEXT: "input-file": "[[PREFIX]]/modules_cdb_input.cpp"
// CHECK-NEXT: ]
// CHECK-NEXT: },
// CHECK-NEXT: {
// CHECK-NEXT: "clang-context-hash": "[[HASH_TU:[A-Z0-9]+]]",
// CHECK-NEXT: "clang-module-deps": [
// CHECK-NEXT: "commands": [
// CHECK-NEXT: {
// CHECK-NEXT: "context-hash": "[[HASH_H1]]",
// CHECK-NEXT: "module-name": "header1"
// CHECK-NEXT: "clang-context-hash": "[[HASH_TU:[A-Z0-9]+]]",
// CHECK-NEXT: "clang-module-deps": [
// CHECK-NEXT: {
// CHECK-NEXT: "context-hash": "[[HASH_H1]]",
// CHECK-NEXT: "module-name": "header1"
// CHECK-NEXT: }
// CHECK-NEXT: ],
// CHECK-NEXT: "command-line": [
// CHECK-NOT: "-fimplicit-modules"
// CHECK-NOT: "-fimplicit-module-maps"
// CHECK: "-fmodule-file={{.*}}[[PREFIX]]/module-cache{{(_clangcl)?}}/[[HASH_H1]]/header1-{{[A-Z0-9]+}}.pcm"
// CHECK: ],
// CHECK-NEXT: "executable": "{{.*}}clang{{.*}}"
// CHECK-NEXT: "file-deps": [
// CHECK-NEXT: "[[PREFIX]]/modules_cdb_input.cpp"
// CHECK-NEXT: ],
// CHECK-NEXT: "input-file": "[[PREFIX]]/modules_cdb_input.cpp"
// CHECK-NEXT: }
// CHECK-NEXT: ],
// CHECK-NEXT: "command-line": [
// CHECK: "-fno-implicit-modules"
// CHECK: "-fno-implicit-module-maps"
// CHECK: "-fmodule-file={{.*}}[[PREFIX]]/module-cache{{(_clangcl)?}}/[[HASH_H1]]/header1-{{[A-Z0-9]+}}.pcm"
// CHECK: ],
// CHECK-NEXT: "file-deps": [
// CHECK-NEXT: "[[PREFIX]]/modules_cdb_input.cpp"
// CHECK-NEXT: ],
// CHECK-NEXT: "input-file": "[[PREFIX]]/modules_cdb_input.cpp"
// CHECK-NEXT: ]
// CHECK-NEXT: },
// CHECK-NEXT: {
// CHECK-NEXT: "clang-context-hash": "[[HASH_TU_DINCLUDE:[A-Z0-9]+]]",
// CHECK-NEXT: "clang-module-deps": [
// CHECK-NEXT: "commands": [
// CHECK-NEXT: {
// CHECK-NEXT: "context-hash": "[[HASH_H1_DINCLUDE]]",
// CHECK-NEXT: "module-name": "header1"
// CHECK-NEXT: "clang-context-hash": "[[HASH_TU_DINCLUDE:[A-Z0-9]+]]",
// CHECK-NEXT: "clang-module-deps": [
// CHECK-NEXT: {
// CHECK-NEXT: "context-hash": "[[HASH_H1_DINCLUDE]]",
// CHECK-NEXT: "module-name": "header1"
// CHECK-NEXT: }
// CHECK-NEXT: ],
// CHECK-NEXT: "command-line": [
// CHECK-NOT: "-fimplicit-modules"
// CHECK-NOT: "-fimplicit-module-maps"
// CHECK: "-fmodule-file={{.*}}[[PREFIX]]/module-cache{{(_clangcl)?}}/[[HASH_H1_DINCLUDE]]/header1-{{[A-Z0-9]+}}.pcm"
// CHECK: ],
// CHECK-NEXT: "executable": "{{.*}}clang{{.*}}"
// CHECK-NEXT: "file-deps": [
// CHECK-NEXT: "[[PREFIX]]/modules_cdb_input2.cpp"
// CHECK-NEXT: ],
// CHECK-NEXT: "input-file": "[[PREFIX]]/modules_cdb_input2.cpp"
// CHECK-NEXT: }
// CHECK-NEXT: ],
// CHECK-NEXT: "command-line": [
// CHECK: "-fno-implicit-modules"
// CHECK: "-fno-implicit-module-maps"
// CHECK: "-fmodule-file={{.*}}[[PREFIX]]/module-cache{{(_clangcl)?}}/[[HASH_H1_DINCLUDE]]/header1-{{[A-Z0-9]+}}.pcm"
// CHECK: ],
// CHECK-NEXT: "file-deps": [
// CHECK-NEXT: "[[PREFIX]]/modules_cdb_input2.cpp"
// CHECK-NEXT: ],
// CHECK-NEXT: "input-file": "[[PREFIX]]/modules_cdb_input2.cpp"
// CHECK-NEXT: ]
// CHECK-NEXT: }
// CHECK-NEXT: ]
// CHECK-NEXT: }

View File

@ -26,35 +26,35 @@ framework module FW_Private { umbrella header "FW_Private.h" }
// CHECK: {
// CHECK-NEXT: "modules": [
// CHECK-NEXT: {
// CHECK-NEXT: "clang-module-deps": [],
// CHECK: "clang-module-deps": [],
// CHECK-NEXT: "clang-modulemap-file": "[[PREFIX]]/frameworks/FW.framework/Modules/module.modulemap",
// CHECK-NEXT: "command-line": [
// CHECK: ],
// CHECK-NEXT: "context-hash": "{{.*}}",
// CHECK-NEXT: "file-deps": [
// CHECK: "file-deps": [
// CHECK-NEXT: "[[PREFIX]]/frameworks/FW.framework/Headers/FW.h",
// CHECK-NEXT: "[[PREFIX]]/frameworks/FW.framework/Modules/module.modulemap",
// CHECK-NEXT: "[[PREFIX]]/frameworks/FW.framework/Modules/module.private.modulemap"
// CHECK-NEXT: ],
// CHECK-NEXT: "name": "FW"
// CHECK-NEXT: },
// CHECK-NEXT: {
// CHECK-NEXT: "clang-module-deps": [],
// CHECK: },
// CHECK: {
// CHECK: "clang-module-deps": [],
// CHECK-NEXT: "clang-modulemap-file": "[[PREFIX]]/frameworks/FW.framework/Modules/module.private.modulemap",
// CHECK-NEXT: "command-line": [
// CHECK: ],
// CHECK-NEXT: "context-hash": "{{.*}}",
// CHECK-NEXT: "file-deps": [
// CHECK: "file-deps": [
// CHECK-NEXT: "[[PREFIX]]/frameworks/FW.framework/Modules/module.modulemap",
// CHECK-NEXT: "[[PREFIX]]/frameworks/FW.framework/Modules/module.private.modulemap",
// CHECK-NEXT: "[[PREFIX]]/frameworks/FW.framework/PrivateHeaders/FW_Private.h"
// CHECK-NEXT: ],
// CHECK-NEXT: "name": "FW_Private"
// CHECK-NEXT: }
// CHECK-NEXT: ],
// CHECK: }
// CHECK: ],
// CHECK-NEXT: "translation-units": [
// CHECK-NEXT: {
// CHECK-NEXT: "clang-context-hash": "{{.*}}",
// CHECK: "clang-context-hash": "{{.*}}",
// CHECK-NEXT: "clang-module-deps": [
// CHECK-NEXT: {
// CHECK-NEXT: "context-hash": "{{.*}}",
@ -66,16 +66,14 @@ framework module FW_Private { umbrella header "FW_Private.h" }
// CHECK-NEXT: }
// CHECK-NEXT: ],
// CHECK-NEXT: "command-line": [
// CHECK: "-fmodule-file={{.*}}/FW_Private-{{.*}}.pcm"
// CHECK: "-fmodule-file={{.*}}/FW-{{.*}}.pcm"
// CHECK: "-fmodule-file={{.*}}/FW_Private-{{.*}}.pcm"
// CHECK: ],
// CHECK-NEXT: "file-deps": [
// CHECK: "file-deps": [
// CHECK-NEXT: "[[PREFIX]]/tu.m"
// CHECK-NEXT: ],
// CHECK-NEXT: "input-file": "[[PREFIX]]/tu.m"
// CHECK-NEXT: }
// CHECK-NEXT: ]
// CHECK-NEXT: }
// RUN: %deps-to-rsp %t/result.json --module-name=FW > %t/FW.cc1.rsp
// RUN: %deps-to-rsp %t/result.json --module-name=FW_Private > %t/FW_Private.cc1.rsp

View File

@ -67,7 +67,7 @@ framework module FW_Private {
// CHECK_TU-NEXT: ],
// CHECK_TU-NEXT: "translation-units": [
// CHECK_TU-NEXT: {
// CHECK_TU-NEXT: "clang-context-hash": "{{.*}}",
// CHECK_TU: "clang-context-hash": "{{.*}}",
// CHECK_TU-NEXT: "clang-module-deps": [
// CHECK_TU-NEXT: {
// CHECK_TU-NEXT: "context-hash": "{{.*}}",
@ -82,14 +82,12 @@ framework module FW_Private {
// CHECK_TU: "-fmodule-file={{.*}}/FW-{{.*}}.pcm"
// CHECK_TU: "-fmodule-file={{.*}}/FW_Private-{{.*}}.pcm"
// CHECK_TU: ],
// CHECK_TU-NEXT: "file-deps": [
// CHECK_TU: "file-deps": [
// CHECK_TU-NEXT: "[[PREFIX]]/from_tu.m",
// CHECK_TU-NEXT: "[[PREFIX]]/frameworks/FW.framework/PrivateHeaders/Two.h"
// CHECK_TU-NEXT: ],
// CHECK_TU-NEXT: "input-file": "[[PREFIX]]/from_tu.m"
// CHECK_TU-NEXT: }
// CHECK_TU-NEXT: ]
// CHECK_TU-NEXT: }
// RUN: %deps-to-rsp %t/from_tu_result.json --module-name=FW > %t/FW.cc1.rsp
// RUN: %deps-to-rsp %t/from_tu_result.json --module-name=FW_Private > %t/FW_Private.cc1.rsp
@ -175,7 +173,7 @@ module Mod { header "Mod.h" }
// CHECK_MODULE-NEXT: ],
// CHECK_MODULE-NEXT: "translation-units": [
// CHECK_MODULE-NEXT: {
// CHECK_MODULE-NEXT: "clang-context-hash": "{{.*}}",
// CHECK_MODULE: "clang-context-hash": "{{.*}}",
// CHECK_MODULE-NEXT: "clang-module-deps": [
// CHECK_MODULE-NEXT: {
// CHECK_MODULE-NEXT: "context-hash": "{{.*}}",
@ -184,13 +182,11 @@ module Mod { header "Mod.h" }
// CHECK_MODULE-NEXT: ],
// CHECK_MODULE-NEXT: "command-line": [
// CHECK_MODULE: ],
// CHECK_MODULE-NEXT: "file-deps": [
// CHECK_MODULE: "file-deps": [
// CHECK_MODULE-NEXT: "[[PREFIX]]/from_module.m"
// CHECK_MODULE-NEXT: ],
// CHECK_MODULE-NEXT: "input-file": "[[PREFIX]]/from_module.m"
// CHECK_MODULE-NEXT: }
// CHECK_MODULE-NEXT: ]
// CHECK_MODULE-NEXT: }
// RUN: %deps-to-rsp %t/from_module_result.json --module-name=FW > %t/FW.cc1.rsp
// RUN: %deps-to-rsp %t/from_module_result.json --module-name=FW_Private > %t/FW_Private.cc1.rsp

View File

@ -31,7 +31,7 @@ inferred a = 0;
// CHECK-NEXT: ],
// CHECK-NEXT: "translation-units": [
// CHECK-NEXT: {
// CHECK-NEXT: "clang-context-hash": "[[HASH_TU:[A-Z0-9]+]]",
// CHECK: "clang-context-hash": "[[HASH_TU:[A-Z0-9]+]]",
// CHECK-NEXT: "clang-module-deps": [
// CHECK-NEXT: {
// CHECK-NEXT: "context-hash": "[[HASH_INFERRED]]",
@ -40,10 +40,8 @@ inferred a = 0;
// CHECK-NEXT: ],
// CHECK-NEXT: "command-line": [
// CHECK: ],
// CHECK-NEXT: "file-deps": [
// CHECK: "file-deps": [
// CHECK-NEXT: "[[PREFIX]]/modules_cdb_input.cpp"
// CHECK-NEXT: ],
// CHECK-NEXT: "input-file": "[[PREFIX]]/modules_cdb_input.cpp"
// CHECK-NEXT: }
// CHECK-NEXT: ]
// CHECK-NEXT: }

View File

@ -52,7 +52,7 @@ module User [no_undeclared_includes] { header "user.h" }
// CHECK-NEXT: ],
// CHECK-NEXT: "translation-units": [
// CHECK-NEXT: {
// CHECK-NEXT: "clang-context-hash": "{{.*}}"
// CHECK: "clang-context-hash": "{{.*}}"
// CHECK-NEXT: "clang-module-deps": [
// CHECK-NEXT: {
// CHECK-NEXT: "context-hash": "{{.*}}"
@ -61,13 +61,11 @@ module User [no_undeclared_includes] { header "user.h" }
// CHECK-NEXT: ],
// CHECK-NEXT: "command-line": [
// CHECK: ],
// CHECK-NEXT: "file-deps": [
// CHECK: "file-deps": [
// CHECK-NEXT: "[[PREFIX]]/test.c"
// CHECK-NEXT: ],
// CHECK-NEXT: "input-file": "[[PREFIX]]/test.c"
// CHECK-NEXT: }
// CHECK: ]
// CHECK-NEXT: }
// RUN: %deps-to-rsp %t/result.json --module-name=User > %t/User.cc1.rsp
// RUN: %deps-to-rsp %t/result.json --tu-index=0 > %t/tu.rsp

View File

@ -36,7 +36,7 @@
// CHECK-PCH-NEXT: ],
// CHECK-PCH-NEXT: "translation-units": [
// CHECK-PCH-NEXT: {
// CHECK-PCH-NEXT: "clang-context-hash": "[[HASH_PCH:.*]]",
// CHECK-PCH: "clang-context-hash": "[[HASH_PCH:.*]]",
// CHECK-PCH-NEXT: "clang-module-deps": [
// CHECK-PCH-NEXT: {
// CHECK-PCH-NEXT: "context-hash": "[[HASH_MOD_COMMON]]",
@ -45,13 +45,11 @@
// CHECK-PCH-NEXT: ],
// CHECK-PCH-NEXT: "command-line": [
// CHECK-PCH: ],
// CHECK-PCH-NEXT: "file-deps": [
// CHECK-PCH: "file-deps": [
// CHECK-PCH-NEXT: "[[PREFIX]]/pch.h"
// CHECK-PCH-NEXT: ],
// CHECK-PCH-NEXT: "input-file": "[[PREFIX]]/pch.h"
// CHECK-PCH-NEXT: }
// CHECK-PCH-NEXT: ]
// CHECK-PCH-NEXT: }
// Explicitly build the PCH:
//
@ -85,7 +83,7 @@
// CHECK-TU-NEXT: ],
// CHECK-TU-NEXT: "translation-units": [
// CHECK-TU-NEXT: {
// CHECK-TU-NEXT: "clang-context-hash": "[[HASH_TU:.*]]",
// CHECK-TU: "clang-context-hash": "[[HASH_TU:.*]]",
// CHECK-TU-NEXT: "clang-module-deps": [
// CHECK-TU-NEXT: {
// CHECK-TU-NEXT: "context-hash": "[[HASH_MOD_TU]]"
@ -94,14 +92,12 @@
// CHECK-TU-NEXT: ],
// CHECK-TU-NEXT: "command-line": [
// CHECK-TU: ],
// CHECK-TU-NEXT: "file-deps": [
// CHECK-TU: "file-deps": [
// CHECK-TU-NEXT: "[[PREFIX]]/tu.c",
// CHECK-TU-NEXT: "[[PREFIX]]/pch.h.gch"
// CHECK-TU-NEXT: ],
// CHECK-TU-NEXT: "input-file": "[[PREFIX]]/tu.c"
// CHECK-TU-NEXT: }
// CHECK-TU-NEXT: ]
// CHECK-TU-NEXT: }
// Explicitly build the TU:
//

View File

@ -32,7 +32,7 @@
// CHECK-PCH-NEXT: ],
// CHECK-PCH-NEXT: "translation-units": [
// CHECK-PCH-NEXT: {
// CHECK-PCH-NEXT: "clang-context-hash": "[[HASH_PCH:.*]]",
// CHECK-PCH: "clang-context-hash": "[[HASH_PCH:.*]]",
// CHECK-PCH-NEXT: "clang-module-deps": [
// CHECK-PCH-NEXT: {
// CHECK-PCH-NEXT: "context-hash": "[[HASH_MOD_COMMON]]",
@ -41,13 +41,11 @@
// CHECK-PCH-NEXT: ],
// CHECK-PCH-NEXT: "command-line": [
// CHECK-PCH: ],
// CHECK-PCH-NEXT: "file-deps": [
// CHECK-PCH: "file-deps": [
// CHECK-PCH-NEXT: "[[PREFIX]]/pch.h"
// CHECK-PCH-NEXT: ],
// CHECK-PCH-NEXT: "input-file": "[[PREFIX]]/pch.h"
// CHECK-PCH-NEXT: }
// CHECK-PCH-NEXT: ]
// CHECK-PCH-NEXT: }
// Explicitly build the PCH:
//
@ -82,7 +80,7 @@
// CHECK-TU-NEXT: ],
// CHECK-TU-NEXT: "translation-units": [
// CHECK-TU-NEXT: {
// CHECK-TU-NEXT: "clang-context-hash": "[[HASH_TU:.*]]",
// CHECK-TU: "clang-context-hash": "[[HASH_TU:.*]]",
// CHECK-TU-NEXT: "clang-module-deps": [
// CHECK-TU-NEXT: {
// CHECK-TU-NEXT: "context-hash": "[[HASH_MOD_TU]]"
@ -91,14 +89,12 @@
// CHECK-TU-NEXT: ],
// CHECK-TU-NEXT: "command-line": [
// CHECK-TU: ],
// CHECK-TU-NEXT: "file-deps": [
// CHECK-TU: "file-deps": [
// CHECK-TU-NEXT: "[[PREFIX]]/tu.c",
// CHECK-TU-NEXT: "[[PREFIX]]/pch.h.gch"
// CHECK-TU-NEXT: ],
// CHECK-TU-NEXT: "input-file": "[[PREFIX]]/tu.c"
// CHECK-TU-NEXT: }
// CHECK-TU-NEXT: ]
// CHECK-TU-NEXT: }
// Explicitly build the TU:
//

View File

@ -61,7 +61,7 @@
// CHECK-PCH-NEXT: ],
// CHECK-PCH-NEXT: "translation-units": [
// CHECK-PCH-NEXT: {
// CHECK-PCH-NEXT: "clang-context-hash": "[[HASH_PCH:.*]]",
// CHECK-PCH: "clang-context-hash": "[[HASH_PCH:.*]]",
// CHECK-PCH-NEXT: "clang-module-deps": [
// CHECK-PCH-NEXT: {
// CHECK-PCH-NEXT: "context-hash": "[[HASH_MOD_COMMON_1]]",
@ -74,13 +74,11 @@
// CHECK-PCH-NEXT: ],
// CHECK-PCH-NEXT: "command-line": [
// CHECK-PCH: ],
// CHECK-PCH-NEXT: "file-deps": [
// CHECK-PCH: "file-deps": [
// CHECK-PCH-NEXT: "[[PREFIX]]/pch.h"
// CHECK-PCH-NEXT: ],
// CHECK-PCH-NEXT: "input-file": "[[PREFIX]]/pch.h"
// CHECK-PCH-NEXT: }
// CHECK-PCH-NEXT: ]
// CHECK-PCH-NEXT: }
// Explicitly build the PCH:
//
@ -118,7 +116,7 @@
// CHECK-TU-NEXT: ],
// CHECK-TU-NEXT: "translation-units": [
// CHECK-TU-NEXT: {
// CHECK-TU-NEXT: "clang-context-hash": "[[HASH_TU:.*]]",
// CHECK-TU: "clang-context-hash": "[[HASH_TU:.*]]",
// CHECK-TU-NEXT: "clang-module-deps": [
// CHECK-TU-NEXT: {
// CHECK-TU-NEXT: "context-hash": "[[HASH_MOD_TU]]",
@ -127,14 +125,12 @@
// CHECK-TU-NEXT: ],
// CHECK-TU-NEXT: "command-line": [
// CHECK-TU: ],
// CHECK-TU-NEXT: "file-deps": [
// CHECK-TU: "file-deps": [
// CHECK-TU-NEXT: "[[PREFIX]]/tu.c",
// CHECK-TU-NEXT: "[[PREFIX]]/pch.h.gch"
// CHECK-TU-NEXT: ],
// CHECK-TU-NEXT: "input-file": "[[PREFIX]]/tu.c"
// CHECK-TU-NEXT: }
// CHECK-TU-NEXT: ]
// CHECK-TU-NEXT: }
// Explicitly build the TU:
//
@ -168,7 +164,7 @@
// CHECK-TU-WITH-COMMON-NEXT: ],
// CHECK-TU-WITH-COMMON-NEXT: "translation-units": [
// CHECK-TU-WITH-COMMON-NEXT: {
// CHECK-TU-WITH-COMMON-NEXT: "clang-context-hash": "[[HASH_TU_WITH_COMMON:.*]]",
// CHECK-TU-WITH-COMMON: "clang-context-hash": "[[HASH_TU_WITH_COMMON:.*]]",
// CHECK-TU-WITH-COMMON-NEXT: "clang-module-deps": [
// CHECK-TU-WITH-COMMON-NEXT: {
// CHECK-TU-WITH-COMMON-NEXT: "context-hash": "[[HASH_MOD_TU_WITH_COMMON]]",
@ -178,14 +174,12 @@
// CHECK-TU-WITH-COMMON-NEXT: "command-line": [
// CHECK-TU-WITH-COMMON: "-fmodule-file=[[PREFIX]]/build/{{.*}}/ModCommon2-{{.*}}.pcm"
// CHECK-TU-WITH-COMMON: ],
// CHECK-TU-WITH-COMMON-NEXT: "file-deps": [
// CHECK-TU-WITH-COMMON: "file-deps": [
// CHECK-TU-WITH-COMMON-NEXT: "[[PREFIX]]/tu_with_common.c",
// CHECK-TU-WITH-COMMON-NEXT: "[[PREFIX]]/pch.h.gch"
// CHECK-TU-WITH-COMMON-NEXT: ],
// CHECK-TU-WITH-COMMON-NEXT: "input-file": "[[PREFIX]]/tu_with_common.c"
// CHECK-TU-WITH-COMMON-NEXT: }
// CHECK-TU-WITH-COMMON-NEXT: ]
// CHECK-TU-WITH-COMMON-NEXT: }
// Explicitly build the TU that has common modules with the PCH:
//

View File

@ -0,0 +1,169 @@
// Test scanning when the driver requires multiple jobs. E.g. with -save-temps
// there will be separate -E, -emit-llvm-bc, -S, and -cc1as jobs, which should
// each result in a "command" in the output.
// RUN: rm -rf %t
// RUN: split-file %s %t
// RUN: sed -e "s|DIR|%/t|g" %t/cdb.json.in > %t/cdb.json
// RUN: clang-scan-deps -compilation-database %t/cdb.json -module-files-dir %t/modules \
// RUN: -j 1 -format experimental-full -mode preprocess-dependency-directives \
// RUN: > %t/deps.json
// RUN: cat %t/deps.json | sed 's:\\\\\?:/:g' | FileCheck %s -DPREFIX=%/t
// Build the -save-temps + -fmodules case
// RUN: %deps-to-rsp %t/deps.json --module-name=Mod > %t/Mod.rsp
// RUN: %deps-to-rsp %t/deps.json --tu-index 1 --tu-cmd-index 0 > %t/tu-cpp.rsp
// RUN: %deps-to-rsp %t/deps.json --tu-index 1 --tu-cmd-index 1 > %t/tu-emit-ir.rsp
// RUN: %deps-to-rsp %t/deps.json --tu-index 1 --tu-cmd-index 2 > %t/tu-emit-asm.rsp
// RUN: %deps-to-rsp %t/deps.json --tu-index 1 --tu-cmd-index 3 > %t/tu-cc1as.rsp
// RUN: %clang @%t/Mod.rsp
// RUN: %clang @%t/tu-cpp.rsp
// RUN: ls %t/tu_save_temps_module.i
// RUN: %clang @%t/tu-emit-ir.rsp
// RUN: ls %t/tu_save_temps_module.bc
// RUN: %clang @%t/tu-emit-asm.rsp
// RUN: ls %t/tu_save_temps_module.s
// RUN: %clang @%t/tu-cc1as.rsp
// RUN: ls %t/tu_save_temps_module.o
// CHECK: "modules": [
// CHECK-NEXT: {
// CHECK: "clang-modulemap-file": "[[PREFIX]]{{.}}module.modulemap"
// CHECK: "name": "Mod"
// CHECK: }
// CHECK-NEXT: ]
// CHECK-NEXT: "translation-units": [
// CHECK-NEXT: {
// CHECK: "commands": [
// CHECK-NEXT: {
// CHECK-NEXT: "clang-context-hash":
// CHECK-NEXT: "clang-module-deps": []
// CHECK-NEXT: "command-line": [
// CHECK-NEXT: "-cc1"
// CHECK: "-o"
// CHECK-NEXT: "{{.*}}tu_no_integrated_cpp{{.*}}.i"
// CHECK: "-E"
// CHECK: ]
// CHECK-NEXT: "executable": "clang_tool"
// CHECK: "input-file": "[[PREFIX]]{{.}}tu_no_integrated_cpp.c"
// CHECK-NEXT: }
// CHECK-NEXT: {
// CHECK-NEXT: "clang-context-hash":
// CHECK-NEXT: "clang-module-deps": []
// CHECK-NEXT: "command-line": [
// CHECK-NEXT: "-cc1"
// CHECK: "-o"
// CHECK-NEXT: "{{.*}}tu_no_integrated_cpp.o"
// CHECK: "-emit-obj"
// CHECK: "{{.*}}tu_no_integrated_cpp{{.*}}.i"
// CHECK: ]
// CHECK-NEXT: "executable": "clang_tool"
// CHECK: "input-file": "[[PREFIX]]{{.}}tu_no_integrated_cpp.c"
// CHECK-NEXT: }
// CHECK-NEXT: ]
// CHECK-NEXT: }
// CHECK-NEXT: {
// CHECK-NEXT: "commands": [
// CHECK-NEXT: {
// CHECK: "clang-module-deps": [
// CHECK-NEXT: {
// CHECK: "module-name": "Mod"
// CHECK-NEXT: }
// CHECK-NEXT: ]
// CHECK-NEXT: "command-line": [
// CHECK-NEXT: "-cc1"
// CHECK: "-o"
// CHECK-NEXT: "{{.*}}tu_save_temps_module.i"
// CHECK: "-E"
// CHECK: "-fmodule-file={{.*}}[[PREFIX]]{{.}}modules{{.*}}Mod-{{.*}}.pcm"
// CHECK: "{{.*}}tu_save_temps_module.c"
// CHECK: ]
// CHECK-NEXT: "executable": "clang_tool"
// CHECK: "input-file": "[[PREFIX]]{{.}}tu_save_temps_module.c"
// CHECK-NEXT: }
// CHECK-NEXT: {
// CHECK: "clang-module-deps": [
// CHECK-NEXT: {
// CHECK: "module-name": "Mod"
// CHECK-NEXT: }
// CHECK-NEXT: ]
// CHECK-NEXT: "command-line": [
// CHECK-NEXT: "-cc1"
// CHECK: "-o"
// CHECK-NEXT: "{{.*}}tu_save_temps_module.bc"
// CHECK: "-emit-llvm-bc"
// CHECK: "{{.*}}tu_save_temps_module.i"
// CHECK: "-fmodule-file={{.*}}[[PREFIX]]{{.}}modules{{.*}}Mod-{{.*}}.pcm"
// CHECK: ]
// CHECK-NEXT: "executable": "clang_tool"
// CHECK: "input-file": "[[PREFIX]]{{.}}tu_save_temps_module.c"
// CHECK-NEXT: }
// CHECK-NEXT: {
// CHECK: "clang-module-deps": [
// CHECK-NEXT: {
// CHECK: "module-name": "Mod"
// CHECK-NEXT: }
// CHECK-NEXT: ]
// CHECK-NEXT: "command-line": [
// CHECK-NEXT: "-cc1"
// CHECK: "-o"
// CHECK-NEXT: "{{.*}}tu_save_temps_module.s"
// CHECK: "-S"
// CHECK: "{{.*}}tu_save_temps_module.bc"
// CHECK: ]
// CHECK-NEXT: "executable": "clang_tool"
// CHECK: "input-file": "[[PREFIX]]{{.}}tu_save_temps_module.c"
// CHECK-NEXT: }
// CHECK-NEXT: {
// CHECK: "clang-module-deps": [
// CHECK-NEXT: {
// CHECK: "module-name": "Mod"
// CHECK-NEXT: }
// CHECK-NEXT: ]
// CHECK-NEXT: "command-line": [
// CHECK-NEXT: "-cc1as"
// CHECK: "-o"
// CHECK-NEXT: "{{.*}}tu_save_temps_module.o"
// CHECK: "{{.*}}tu_save_temps_module.s"
// CHECK: ]
// CHECK-NEXT: "executable": "clang_tool"
// CHECK: "input-file": "[[PREFIX]]{{.}}tu_save_temps_module.c"
// CHECK-NEXT: }
// CHECK-NEXT: ]
// CHECK-NEXT: }
// CHECK-NEXT: ]
//--- cdb.json.in
[
{
"directory": "DIR"
"command": "clang_tool -c DIR/tu_no_integrated_cpp.c -no-integrated-cpp -o DIR/tu_no_integrated_cpp.o"
"file": "DIR/tu_no_integrated_cpp.c"
},
{
"directory": "DIR"
"command": "clang_tool -c DIR/tu_save_temps_module.c -save-temps=obj -o DIR/tu_save_temps_module.o -fmodules -fimplicit-modules -fimplicit-module-maps"
"file": "DIR/tu_save_temps_module.c"
}
]
//--- plain_header.h
void foo(void);
//--- module_header.h
void bar(void);
//--- module.modulemap
module Mod { header "module_header.h" }
//--- tu_no_integrated_cpp.c
#include "plain_header.h"
void tu_no_integrated_cpp(void) { foo(); }
//--- tu_save_temps_module.c
#include "module_header.h"
void tu_save_temps(void) { bar(); }

View File

@ -61,7 +61,7 @@
// CHECK-NEXT: ],
// CHECK-NEXT: "translation-units": [
// CHECK-NEXT: {
// CHECK-NEXT: "clang-context-hash": "[[HASH_TU:.*]]",
// CHECK: "clang-context-hash": "[[HASH_TU:.*]]",
// CHECK-NEXT: "clang-module-deps": [
// CHECK-NEXT: {
// CHECK-NEXT: "context-hash": "[[HASH_MOD_HEADER]]",
@ -73,13 +73,11 @@
// CHECK-NEXT: }
// CHECK-NEXT: ]
// CHECK-NEXT: "command-line": [
// CHECK-NEXT: "-fsyntax-only",
// CHECK-NEXT: "-cc1",
// CHECK-NOT: "-fmodules-cache-path=
// CHECK-NOT: "-fmodules-validate-once-per-build-session"
// CHECK-NOT: "-fbuild-session-timestamp=
// CHECK-NOT: "-fbuild-session-file=
// CHECK-NOT: "-fmodules-prune-interval=
// CHECK-NOT: "-fmodules-prune-after=
// CHECK: ],
// CHECK: }
// CHECK-NEXT: ]
// CHECK-NEXT: }

View File

@ -182,6 +182,11 @@ llvm::cl::list<std::string> ModuleDepTargets(
llvm::cl::desc("The names of dependency targets for the dependency file"),
llvm::cl::cat(DependencyScannerCategory));
llvm::cl::opt<bool> DeprecatedDriverCommand(
"deprecated-driver-command", llvm::cl::Optional,
llvm::cl::desc("use a single driver command to build the tu (deprecated)"),
llvm::cl::cat(DependencyScannerCategory));
enum ResourceDirRecipeKind {
RDRK_ModifyCompilerPath,
RDRK_InvokeCompiler,
@ -256,7 +261,7 @@ class FullDeps {
public:
void mergeDeps(StringRef Input, FullDependenciesResult FDR,
size_t InputIndex) {
const FullDependencies &FD = FDR.FullDeps;
FullDependencies &FD = FDR.FullDeps;
InputDeps ID;
ID.FileName = std::string(Input);
@ -274,7 +279,8 @@ public:
Modules.insert(I, {{MD.ID, InputIndex}, std::move(MD)});
}
ID.CommandLine = FD.CommandLine;
ID.DriverCommandLine = std::move(FD.DriverCommandLine);
ID.Commands = std::move(FD.Commands);
Inputs.push_back(std::move(ID));
}
@ -311,14 +317,33 @@ public:
Array TUs;
for (auto &&I : Inputs) {
Object O{
{"input-file", I.FileName},
{"clang-context-hash", I.ContextHash},
{"file-deps", I.FileDeps},
{"clang-module-deps", toJSONSorted(I.ModuleDeps)},
{"command-line", I.CommandLine},
};
TUs.push_back(std::move(O));
Array Commands;
if (I.DriverCommandLine.empty()) {
for (const auto &Cmd : I.Commands) {
Object O{
{"input-file", I.FileName},
{"clang-context-hash", I.ContextHash},
{"file-deps", I.FileDeps},
{"clang-module-deps", toJSONSorted(I.ModuleDeps)},
{"executable", Cmd.Executable},
{"command-line", Cmd.Arguments},
};
Commands.push_back(std::move(O));
}
} else {
Object O{
{"input-file", I.FileName},
{"clang-context-hash", I.ContextHash},
{"file-deps", I.FileDeps},
{"clang-module-deps", toJSONSorted(I.ModuleDeps)},
{"executable", "clang"},
{"command-line", I.DriverCommandLine},
};
Commands.push_back(std::move(O));
}
TUs.push_back(Object{
{"commands", std::move(Commands)},
});
}
Object Output{
@ -353,7 +378,8 @@ private:
std::string ContextHash;
std::vector<std::string> FileDeps;
std::vector<ModuleID> ModuleDeps;
std::vector<std::string> CommandLine;
std::vector<std::string> DriverCommandLine;
std::vector<Command> Commands;
};
std::mutex Lock;
@ -559,6 +585,14 @@ int main(int argc, const char **argv) {
if (handleMakeDependencyToolResult(Filename, MaybeFile, DependencyOS,
Errs))
HadErrors = true;
} else if (DeprecatedDriverCommand) {
auto MaybeFullDeps =
WorkerTools[I]->getFullDependenciesLegacyDriverCommand(
Input->CommandLine, CWD, AlreadySeenModules, LookupOutput,
MaybeModuleName);
if (handleFullDependencyToolResult(Filename, MaybeFullDeps, FD,
LocalIndex, DependencyOS, Errs))
HadErrors = true;
} else {
auto MaybeFullDeps = WorkerTools[I]->getFullDependencies(
Input->CommandLine, CWD, AlreadySeenModules, LookupOutput,

View File

@ -48,6 +48,9 @@ def main():
type=str)
action.add_argument("--tu-index", help="The index of the translation unit to get arguments for",
type=int)
parser.add_argument("--tu-cmd-index",
help="The index of the command within the translation unit (default=0)",
type=int, default=0)
args = parser.parse_args()
full_deps = parseFullDeps(json.load(open(args.full_deps_file, 'r')))
@ -58,7 +61,8 @@ def main():
if args.module_name:
cmd = findModule(args.module_name, full_deps)['command-line']
elif args.tu_index != None:
cmd = full_deps.translation_units[args.tu_index]['command-line']
tu = full_deps.translation_units[args.tu_index]
cmd = tu['commands'][args.tu_cmd_index]['command-line']
print(" ".join(map(quote, cmd)))
except: