diff --git a/clang/include/clang/Tooling/DependencyScanning/DependencyScanningTool.h b/clang/include/clang/Tooling/DependencyScanning/DependencyScanningTool.h --- a/clang/include/clang/Tooling/DependencyScanning/DependencyScanningTool.h +++ b/clang/include/clang/Tooling/DependencyScanning/DependencyScanningTool.h @@ -49,8 +49,16 @@ /// determined that the differences are benign for this compilation. std::vector ClangModuleDeps; - /// The command line of the TU (excluding the compiler executable). - std::vector 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 Commands; + + /// Deprecated driver command-line. This will be removed in a future version. + std::vector DriverCommandLine; }; struct FullDependenciesResult { @@ -99,6 +107,12 @@ LookupModuleOutputCallback LookupModuleOutput, llvm::Optional ModuleName = None); + llvm::Expected getFullDependenciesLegacyDriverCommand( + const std::vector &CommandLine, StringRef CWD, + const llvm::StringSet<> &AlreadySeen, + LookupModuleOutputCallback LookupModuleOutput, + llvm::Optional ModuleName = None); + private: DependencyScanningWorker Worker; }; @@ -111,6 +125,10 @@ : 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 @@ return LookupModuleOutput(ID, Kind); } - FullDependenciesResult getFullDependencies( + FullDependenciesResult getFullDependenciesLegacyDriverCommand( const std::vector &OriginalCommandLine) const; + FullDependenciesResult takeFullDependencies(); + private: std::vector Dependencies; std::vector PrebuiltModuleDeps; llvm::MapVector> ClangModuleDeps; + std::vector Commands; std::string ContextHash; std::vector OutputPaths; const llvm::StringSet<> &AlreadySeen; diff --git a/clang/include/clang/Tooling/DependencyScanning/DependencyScanningWorker.h b/clang/include/clang/Tooling/DependencyScanning/DependencyScanningWorker.h --- a/clang/include/clang/Tooling/DependencyScanning/DependencyScanningWorker.h +++ b/clang/include/clang/Tooling/DependencyScanning/DependencyScanningWorker.h @@ -28,10 +28,20 @@ class DependencyScanningWorkerFilesystem; +/// A command-line tool invocation that is part of building a TU. +/// +/// \see FullDependencies::Commands. +struct Command { + std::string Executable; + std::vector Arguments; +}; + class DependencyConsumer { public: virtual ~DependencyConsumer() {} + virtual void handleBuildCommand(Command Cmd) = 0; + virtual void handleDependencyOutputOpts(const DependencyOutputOptions &Opts) = 0; diff --git a/clang/include/clang/Tooling/DependencyScanning/ModuleDepCollector.h b/clang/include/clang/Tooling/DependencyScanning/ModuleDepCollector.h --- a/clang/include/clang/Tooling/DependencyScanning/ModuleDepCollector.h +++ b/clang/include/clang/Tooling/DependencyScanning/ModuleDepCollector.h @@ -181,12 +181,16 @@ public: ModuleDepCollector(std::unique_ptr 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; diff --git a/clang/lib/Tooling/DependencyScanning/DependencyScanningTool.cpp b/clang/lib/Tooling/DependencyScanning/DependencyScanningTool.cpp --- a/clang/lib/Tooling/DependencyScanning/DependencyScanningTool.cpp +++ b/clang/lib/Tooling/DependencyScanning/DependencyScanningTool.cpp @@ -45,6 +45,8 @@ /// 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(Opts); @@ -120,14 +122,53 @@ Worker.computeDependencies(CWD, CommandLine, Consumer, ModuleName); if (Result) return std::move(Result); - return Consumer.getFullDependencies(CommandLine); + return Consumer.takeFullDependencies(); +} + +llvm::Expected +DependencyScanningTool::getFullDependenciesLegacyDriverCommand( + const std::vector &CommandLine, StringRef CWD, + const llvm::StringSet<> &AlreadySeen, + LookupModuleOutputCallback LookupModuleOutput, + llvm::Optional 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::getFullDependencies( +FullDependenciesResult +FullDependencyConsumer::getFullDependenciesLegacyDriverCommand( const std::vector &OriginalCommandLine) const { FullDependencies FD; - FD.CommandLine = makeTUCommandLineWithoutPaths( + FD.DriverCommandLine = makeTUCommandLineWithoutPaths( ArrayRef(OriginalCommandLine).slice(1)); FD.ID.ContextHash = std::move(ContextHash); @@ -135,7 +176,7 @@ 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 @@ 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); } } } diff --git a/clang/lib/Tooling/DependencyScanning/DependencyScanningWorker.cpp b/clang/lib/Tooling/DependencyScanning/DependencyScanningWorker.cpp --- a/clang/lib/Tooling/DependencyScanning/DependencyScanningWorker.cpp +++ b/clang/lib/Tooling/DependencyScanning/DependencyScanningWorker.cpp @@ -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 @@ // 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 @@ std::move(Opts), WorkingDirectory, Consumer)); break; case ScanningOutputFormat::Full: - ScanInstance.addDependencyCollector(std::make_shared( - std::move(Opts), ScanInstance, Consumer, - std::move(OriginalInvocation), OptimizeArgs, EagerLoadModules)); + MDC = std::make_shared( + std::move(Opts), ScanInstance, Consumer, OriginalInvocation, + OptimizeArgs, EagerLoadModules); + ScanInstance.addDependencyCollector(MDC); break; } @@ -253,9 +271,31 @@ 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 takeLastCC1Arguments() { + std::vector 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 @@ bool EagerLoadModules; bool DisableFree; llvm::Optional ModuleName; + std::shared_ptr MDC; + std::vector LastCC1Arguments; + bool Scanned = false; }; } // end anonymous namespace @@ -313,6 +356,36 @@ llvm::inconvertibleErrorCode()); } +static bool forEachDriverJob( + ArrayRef Args, DiagnosticsEngine &Diags, FileManager &FM, + llvm::function_ref Callback) { + std::unique_ptr Driver = std::make_unique( + Args[0], llvm::sys::getDefaultTargetTriple(), Diags, + "clang LLVM compiler", &FM.getVirtualFileSystem()); + Driver->setTitle("clang_based_tool"); + + std::vector 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 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 &CommandLine, DependencyConsumer &Consumer, llvm::Optional ModuleName) { @@ -338,25 +411,60 @@ 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 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 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 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(); + }); } diff --git a/clang/lib/Tooling/DependencyScanning/ModuleDepCollector.cpp b/clang/lib/Tooling/DependencyScanning/ModuleDepCollector.cpp --- a/clang/lib/Tooling/DependencyScanning/ModuleDepCollector.cpp +++ b/clang/lib/Tooling/DependencyScanning/ModuleDepCollector.cpp @@ -174,6 +174,34 @@ } } +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 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 @@ ModuleDepCollector::ModuleDepCollector( std::unique_ptr 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) {} diff --git a/clang/test/ClangScanDeps/deprecated-driver-api.c b/clang/test/ClangScanDeps/deprecated-driver-api.c new file mode 100644 --- /dev/null +++ b/clang/test/ClangScanDeps/deprecated-driver-api.c @@ -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(); +} diff --git a/clang/test/ClangScanDeps/diagnostics.c b/clang/test/ClangScanDeps/diagnostics.c --- a/clang/test/ClangScanDeps/diagnostics.c +++ b/clang/test/ClangScanDeps/diagnostics.c @@ -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: } diff --git a/clang/test/ClangScanDeps/header-search-pruning-transitive.c b/clang/test/ClangScanDeps/header-search-pruning-transitive.c --- a/clang/test/ClangScanDeps/header-search-pruning-transitive.c +++ b/clang/test/ClangScanDeps/header-search-pruning-transitive.c @@ -95,7 +95,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_X]]", @@ -104,14 +104,13 @@ // 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 @@ // 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 @@ // 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: } diff --git a/clang/test/ClangScanDeps/modules-context-hash-ignore-macros.c b/clang/test/ClangScanDeps/modules-context-hash-ignore-macros.c --- a/clang/test/ClangScanDeps/modules-context-hash-ignore-macros.c +++ b/clang/test/ClangScanDeps/modules-context-hash-ignore-macros.c @@ -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" diff --git a/clang/test/ClangScanDeps/modules-context-hash-outputs.c b/clang/test/ClangScanDeps/modules-context-hash-outputs.c --- a/clang/test/ClangScanDeps/modules-context-hash-outputs.c +++ b/clang/test/ClangScanDeps/modules-context-hash-outputs.c @@ -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" diff --git a/clang/test/ClangScanDeps/modules-context-hash-warnings.c b/clang/test/ClangScanDeps/modules-context-hash-warnings.c --- a/clang/test/ClangScanDeps/modules-context-hash-warnings.c +++ b/clang/test/ClangScanDeps/modules-context-hash-warnings.c @@ -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]]" diff --git a/clang/test/ClangScanDeps/modules-context-hash.c b/clang/test/ClangScanDeps/modules-context-hash.c --- a/clang/test/ClangScanDeps/modules-context-hash.c +++ b/clang/test/ClangScanDeps/modules-context-hash.c @@ -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: } diff --git a/clang/test/ClangScanDeps/modules-dep-args.c b/clang/test/ClangScanDeps/modules-dep-args.c --- a/clang/test/ClangScanDeps/modules-dep-args.c +++ b/clang/test/ClangScanDeps/modules-dep-args.c @@ -78,7 +78,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": "{{.*}}", @@ -93,10 +93,8 @@ // 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: } \ No newline at end of file diff --git a/clang/test/ClangScanDeps/modules-fmodule-name-no-module-built.m b/clang/test/ClangScanDeps/modules-fmodule-name-no-module-built.m --- a/clang/test/ClangScanDeps/modules-fmodule-name-no-module-built.m +++ b/clang/test/ClangScanDeps/modules-fmodule-name-no-module-built.m @@ -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: } diff --git a/clang/test/ClangScanDeps/modules-full.cpp b/clang/test/ClangScanDeps/modules-full.cpp --- a/clang/test/ClangScanDeps/modules-full.cpp +++ b/clang/test/ClangScanDeps/modules-full.cpp @@ -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: } diff --git a/clang/test/ClangScanDeps/modules-implicit-dot-private.m b/clang/test/ClangScanDeps/modules-implicit-dot-private.m --- a/clang/test/ClangScanDeps/modules-implicit-dot-private.m +++ b/clang/test/ClangScanDeps/modules-implicit-dot-private.m @@ -26,35 +26,35 @@ // 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 @@ // 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 diff --git a/clang/test/ClangScanDeps/modules-incomplete-umbrella.c b/clang/test/ClangScanDeps/modules-incomplete-umbrella.c --- a/clang/test/ClangScanDeps/modules-incomplete-umbrella.c +++ b/clang/test/ClangScanDeps/modules-incomplete-umbrella.c @@ -67,7 +67,7 @@ // 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 @@ // 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 @@ // 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 @@ // 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 diff --git a/clang/test/ClangScanDeps/modules-inferred.m b/clang/test/ClangScanDeps/modules-inferred.m --- a/clang/test/ClangScanDeps/modules-inferred.m +++ b/clang/test/ClangScanDeps/modules-inferred.m @@ -31,7 +31,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_INFERRED]]", @@ -40,10 +40,8 @@ // 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: } diff --git a/clang/test/ClangScanDeps/modules-no-undeclared-includes.c b/clang/test/ClangScanDeps/modules-no-undeclared-includes.c --- a/clang/test/ClangScanDeps/modules-no-undeclared-includes.c +++ b/clang/test/ClangScanDeps/modules-no-undeclared-includes.c @@ -52,7 +52,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": "{{.*}}" @@ -61,13 +61,11 @@ // 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 diff --git a/clang/test/ClangScanDeps/modules-pch-common-submodule.c b/clang/test/ClangScanDeps/modules-pch-common-submodule.c --- a/clang/test/ClangScanDeps/modules-pch-common-submodule.c +++ b/clang/test/ClangScanDeps/modules-pch-common-submodule.c @@ -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: // diff --git a/clang/test/ClangScanDeps/modules-pch-common-via-submodule.c b/clang/test/ClangScanDeps/modules-pch-common-via-submodule.c --- a/clang/test/ClangScanDeps/modules-pch-common-via-submodule.c +++ b/clang/test/ClangScanDeps/modules-pch-common-via-submodule.c @@ -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: // diff --git a/clang/test/ClangScanDeps/modules-pch.c b/clang/test/ClangScanDeps/modules-pch.c --- a/clang/test/ClangScanDeps/modules-pch.c +++ b/clang/test/ClangScanDeps/modules-pch.c @@ -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: // diff --git a/clang/test/ClangScanDeps/multiple-commands.c b/clang/test/ClangScanDeps/multiple-commands.c new file mode 100644 --- /dev/null +++ b/clang/test/ClangScanDeps/multiple-commands.c @@ -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(); } diff --git a/clang/test/ClangScanDeps/removed-args.c b/clang/test/ClangScanDeps/removed-args.c --- a/clang/test/ClangScanDeps/removed-args.c +++ b/clang/test/ClangScanDeps/removed-args.c @@ -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: } diff --git a/clang/tools/clang-scan-deps/ClangScanDeps.cpp b/clang/tools/clang-scan-deps/ClangScanDeps.cpp --- a/clang/tools/clang-scan-deps/ClangScanDeps.cpp +++ b/clang/tools/clang-scan-deps/ClangScanDeps.cpp @@ -182,6 +182,11 @@ llvm::cl::desc("The names of dependency targets for the dependency file"), llvm::cl::cat(DependencyScannerCategory)); +llvm::cl::opt 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 @@ 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 @@ 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 @@ 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 @@ std::string ContextHash; std::vector FileDeps; std::vector ModuleDeps; - std::vector CommandLine; + std::vector DriverCommandLine; + std::vector Commands; }; std::mutex Lock; @@ -559,6 +585,14 @@ 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, diff --git a/clang/utils/module-deps-to-rsp.py b/clang/utils/module-deps-to-rsp.py --- a/clang/utils/module-deps-to-rsp.py +++ b/clang/utils/module-deps-to-rsp.py @@ -48,6 +48,9 @@ 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 @@ 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: