Index: clang/include/clang/Tooling/DependencyScanning/DependencyScanningTool.h =================================================================== --- clang/include/clang/Tooling/DependencyScanning/DependencyScanningTool.h +++ clang/include/clang/Tooling/DependencyScanning/DependencyScanningTool.h @@ -27,6 +27,14 @@ using LookupModuleOutputCallback = llvm::function_ref; +/// A command-line tool invocation that is part of building a TU. +/// +/// \see FullDependencies::Commands. +struct Command { + std::string Executable; + std::vector Arguments; +}; + /// The full dependencies and module graph for a specific input. struct FullDependencies { /// The identifier of the C++20 module this translation unit exports. @@ -49,8 +57,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 +115,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 +133,11 @@ : AlreadySeen(AlreadySeen), LookupModuleOutput(LookupModuleOutput), EagerLoadModules(EagerLoadModules) {} + void handleBuildCommand(std::string Executable, + std::vector Args) override { + Commands.push_back({std::move(Executable), std::move(Args)}); + } + void handleDependencyOutputOpts(const DependencyOutputOptions &) override {} void handleFileDependency(StringRef File) override { @@ -134,14 +161,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; Index: clang/include/clang/Tooling/DependencyScanning/DependencyScanningWorker.h =================================================================== --- clang/include/clang/Tooling/DependencyScanning/DependencyScanningWorker.h +++ clang/include/clang/Tooling/DependencyScanning/DependencyScanningWorker.h @@ -23,6 +23,10 @@ class DependencyOutputOptions; +namespace driver { +class Command; +} + namespace tooling { namespace dependencies { @@ -32,6 +36,9 @@ public: virtual ~DependencyConsumer() {} + virtual void handleBuildCommand(std::string Executable, + std::vector Args) = 0; + virtual void handleDependencyOutputOpts(const DependencyOutputOptions &Opts) = 0; @@ -72,6 +79,20 @@ bool shouldEagerLoadModules() const { return EagerLoadModules; } +private: + /// Helper for \c computeDependencies that handles computing dependencies for + /// a single driver command \p Cmd, or forwarding the invocation to + /// \p Consumer if it is downstream from a command that is already scaned. + /// + /// \returns true on success. + bool computeDependenciesForCommand(const driver::Command &Cmd, + StringRef WorkingDirectory, + llvm::Optional ModuleName, + DependencyConsumer &Consumer, + FileManager &FM, DiagnosticsEngine &Diags, + std::shared_ptr &MDC, + bool &Scanned); + private: std::shared_ptr PCHContainerOps; Index: clang/include/clang/Tooling/DependencyScanning/ModuleDepCollector.h =================================================================== --- clang/include/clang/Tooling/DependencyScanning/ModuleDepCollector.h +++ clang/include/clang/Tooling/DependencyScanning/ModuleDepCollector.h @@ -119,11 +119,9 @@ // the primary TU. bool ImportedByMainFile = false; - /// Compiler invocation that can be used to build this module (without paths). - CompilerInvocation BuildInvocation; - - /// Gets the canonical command line suitable for passing to clang. - std::vector getCanonicalCommandLine() const; + /// Compiler invocation that can be used to build this module. Does not + /// include argv[0]. + std::vector BuildArguments; }; class ModuleDepCollector; @@ -190,6 +188,14 @@ void attachToPreprocessor(Preprocessor &PP) override; void attachToASTReader(ASTReader &R) override; + /// Apply any modules-related changes to the given invocation and pass it to + /// the \c DependencyConsumer. + /// + /// This is called automatically for the original invocation, but it can also + /// be used by clients that wish to apply the same changes to another + /// invocation, for example when there are multiple chained invocations. + void handleInvocation(CompilerInvocation CI); + private: friend ModuleDepCollectorPP; @@ -206,6 +212,12 @@ std::vector FileDeps; /// Direct and transitive modular dependencies of the main source file. llvm::MapVector> ModularDeps; + /// Secondary mapping for \c ModularDeps allowing lookup by ModuleID without + /// a preprocessor. Storage owned by \c ModularDeps. + llvm::StringMap ModuleDepsByID; + /// Directly imported prebuilt deps. + std::vector DirectPrebuiltDeps; + /// Options that control the dependency output generation. std::unique_ptr Opts; /// The original Clang invocation passed to dependency scanner. @@ -223,6 +235,9 @@ /// Adds \p Path to \c MD.FileDeps, making it absolute if necessary. void addFileDep(ModuleDeps &MD, StringRef Path); + ModuleDeps *getModuleDepsForID(const ModuleID &ID) const; + void setModuleDepsForID(const ModuleID &ID, ModuleDeps *MD); + /// Constructs a CompilerInvocation that can be used to build the given /// module, excluding paths to discovered modular dependencies that are yet to /// be built. @@ -230,8 +245,15 @@ const ModuleDeps &Deps, llvm::function_ref Optimize) const; + /// Add module map files to the invocation, if needed. + void addModuleMapFiles(CompilerInvocation &CI, + ArrayRef ClangModuleDeps) const; + /// Add module files (pcm) to the invocation, if needed. + void addModuleFiles(CompilerInvocation &CI, + ArrayRef ClangModuleDeps) const; + /// Add paths that require looking up outputs to the given dependencies. - void addOutputPaths(ModuleDeps &Deps); + void addOutputPaths(CompilerInvocation &CI, const ModuleDeps &Deps); }; } // end namespace dependencies Index: clang/include/clang/Tooling/Tooling.h =================================================================== --- clang/include/clang/Tooling/Tooling.h +++ clang/include/clang/Tooling/Tooling.h @@ -508,7 +508,7 @@ /// Creates a \c CompilerInvocation. CompilerInvocation *newInvocation(DiagnosticsEngine *Diagnostics, - const llvm::opt::ArgStringList &CC1Args, + ArrayRef CC1Args, const char *const BinaryName); } // namespace tooling Index: clang/lib/Tooling/DependencyScanning/DependencyScanningTool.cpp =================================================================== --- clang/lib/Tooling/DependencyScanning/DependencyScanningTool.cpp +++ clang/lib/Tooling/DependencyScanning/DependencyScanningTool.cpp @@ -45,6 +45,9 @@ /// Prints out all of the gathered dependencies into a string. class MakeDependencyPrinterConsumer : public DependencyConsumer { public: + void handleBuildCommand(std::string Executable, + std::vector Args) override {} + void handleDependencyOutputOpts(const DependencyOutputOptions &Opts) override { this->Opts = std::make_unique(Opts); @@ -120,14 +123,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 +177,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 +185,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); } } } Index: clang/lib/Tooling/DependencyScanning/DependencyScanningWorker.cpp =================================================================== --- clang/lib/Tooling/DependencyScanning/DependencyScanningWorker.cpp +++ 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; @@ -230,9 +236,10 @@ std::move(Opts), WorkingDirectory, Consumer)); break; case ScanningOutputFormat::Full: - ScanInstance.addDependencyCollector(std::make_shared( + MDC = std::make_shared( std::move(Opts), ScanInstance, Consumer, - std::move(OriginalInvocation), OptimizeArgs, EagerLoadModules)); + std::move(OriginalInvocation), OptimizeArgs, EagerLoadModules); + ScanInstance.addDependencyCollector(MDC); break; } @@ -256,6 +263,10 @@ return Result; } + std::shared_ptr getModuleDepCollector() const { + return MDC; + } + private: StringRef WorkingDirectory; DependencyConsumer &Consumer; @@ -265,6 +276,7 @@ bool EagerLoadModules; bool DisableFree; llvm::Optional ModuleName; + std::shared_ptr MDC; }; } // end anonymous namespace @@ -313,6 +325,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 +380,86 @@ 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); + bool Scanned = false; + std::shared_ptr ScannerCollector; + bool Success = forEachDriverJob(FinalCommandLine, *Diags, *CurrentFiles, + [&](const driver::Command &Cmd) { + return computeDependenciesForCommand( + Cmd, WorkingDirectory, ModuleName, + Consumer, *CurrentFiles, *Diags, + ScannerCollector, Scanned); + }); + + if (Success && !Scanned) { + Diags->Report(diag::err_fe_expected_compiler_job) + << llvm::join(FinalCommandLine, " "); + } + return Success && Scanned; + }); +} + +bool DependencyScanningWorker::computeDependenciesForCommand( + const driver::Command &Cmd, StringRef WorkingDirectory, + llvm::Optional ModuleName, DependencyConsumer &Consumer, + FileManager &FM, DiagnosticsEngine &Diags, + std::shared_ptr &MDC, bool &Scanned) { + if (StringRef(Cmd.getCreator().getName()) != "clang") { + // Non-clang command. Just pass through to the consumer. + Consumer.handleBuildCommand( + Cmd.getExecutable(), + {Cmd.getArguments().begin(), Cmd.getArguments().end()}); + return true; + } + + if (Scanned) { + if (MDC) { + // Already scanned an upstream clang command. Apply the necessary changes + // to the compiler invocation using the original ModuleDepCollector. + CompilerInvocation CI; + if (!CompilerInvocation::CreateFromArgs(CI, Cmd.getArguments(), Diags, + Cmd.getExecutable())) + return false; + MDC->handleInvocation(std::move(CI)); + } else { + // Already scanned, but there are no changes to make. Just pass through to + // the consumer. + Consumer.handleBuildCommand( + Cmd.getExecutable(), + {Cmd.getArguments().begin(), Cmd.getArguments().end()}); + } + return true; + } + + Scanned = true; + // 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); + + 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, &FM, PCHContainerOps); + Invocation.setDiagnosticConsumer(Diags.getClient()); + Invocation.setDiagnosticOptions(&Diags.getDiagnosticOptions()); + bool Result = Invocation.run(); + MDC = Action.getModuleDepCollector(); + return Result; } Index: clang/lib/Tooling/DependencyScanning/ModuleDepCollector.cpp =================================================================== --- clang/lib/Tooling/DependencyScanning/ModuleDepCollector.cpp +++ clang/lib/Tooling/DependencyScanning/ModuleDepCollector.cpp @@ -52,21 +52,12 @@ return Result; } -void ModuleDepCollector::addOutputPaths(ModuleDeps &Deps) { - CompilerInvocation &CI = Deps.BuildInvocation; - +void ModuleDepCollector::addOutputPaths(CompilerInvocation &CI, + const ModuleDeps &Deps) { // These are technically *inputs* to the compilation, but we populate them // here in order to make \c getModuleContextHash() independent of // \c lookupModuleOutput(). - for (ModuleID MID : Deps.ClangModuleDeps) { - auto PCMPath = - Consumer.lookupModuleOutput(MID, ModuleOutputKind::ModuleFile); - if (EagerLoadModules) - CI.getFrontendOpts().ModuleFiles.push_back(PCMPath); - else - CI.getHeaderSearchOpts().PrebuiltModuleFiles.insert( - {MID.ModuleName, PCMPath}); - } + addModuleFiles(CI, Deps.ClangModuleDeps); CI.getFrontendOpts().OutputFile = Consumer.lookupModuleOutput(Deps.ID, ModuleOutputKind::ModuleFile); @@ -126,24 +117,12 @@ CI.getFrontendOpts().Inputs.emplace_back(Deps.ClangModuleMapFile, ModuleMapInputKind); CI.getFrontendOpts().ModuleMapFiles = Deps.ModuleMapFileDeps; + addModuleMapFiles(CI, Deps.ClangModuleDeps); // Report the prebuilt modules this module uses. for (const auto &PrebuiltModule : Deps.PrebuiltModuleDeps) CI.getFrontendOpts().ModuleFiles.push_back(PrebuiltModule.PCMFile); - if (!EagerLoadModules) { - ModuleMap &ModMap = - ScanInstance.getPreprocessor().getHeaderSearchInfo().getModuleMap(); - for (ModuleID MID : Deps.ClangModuleDeps) { - const Module *M = ModMap.findModule(MID.ModuleName); - assert(M && "Modular dependency not found"); - auto MDeps = ModularDeps.find(M); - assert(MDeps != ModularDeps.end() && "Inconsistent dependency info"); - CI.getFrontendOpts().ModuleMapFiles.push_back( - MDeps->second->ClangModuleMapFile); - } - } - // Remove any macro definitions that are explicitly ignored. if (!CI.getHeaderSearchOpts().ModulesIgnoreMacros.empty()) { llvm::erase_if( @@ -170,11 +149,85 @@ return CI; } -std::vector ModuleDeps::getCanonicalCommandLine() const { - return BuildInvocation.getCC1CommandLine(); +void ModuleDepCollector::addModuleMapFiles( + CompilerInvocation &CI, ArrayRef ClangModuleDeps) const { + if (EagerLoadModules) + return; // Only pcm is needed for eager load. + + for (const ModuleID &MID : ClangModuleDeps) { + ModuleDeps *MD = getModuleDepsForID(MID); + assert(MD && "Inconsistent dependency info"); + CI.getFrontendOpts().ModuleMapFiles.push_back(MD->ClangModuleMapFile); + } +} + +void ModuleDepCollector::addModuleFiles( + CompilerInvocation &CI, ArrayRef ClangModuleDeps) const { + for (const ModuleID &MID : ClangModuleDeps) { + std::string PCMPath = + Consumer.lookupModuleOutput(MID, ModuleOutputKind::ModuleFile); + if (EagerLoadModules) + CI.getFrontendOpts().ModuleFiles.push_back(std::move(PCMPath)); + else + CI.getHeaderSearchOpts().PrebuiltModuleFiles.insert( + {MID.ModuleName, std::move(PCMPath)}); + } +} + +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::handleInvocation(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 &PrebuiltModule : DirectPrebuiltDeps) + CI.getFrontendOpts().ModuleFiles.push_back(PrebuiltModule.PCMFile); + } + + std::string Executable = CI.getCodeGenOpts().Argv0; + Consumer.handleBuildCommand(std::move(Executable), CI.getCC1CommandLine()); +} + +static void getModuleIDKeyString(const ModuleID &ID, SmallVectorImpl &O) { + O.reserve(ID.ModuleName.size() + ID.ContextHash.size() + 1); + O.append(ID.ModuleName.begin(), ID.ModuleName.end()); + O.push_back(':'); + O.append(ID.ContextHash.begin(), ID.ContextHash.end()); +} + +ModuleDeps *ModuleDepCollector::getModuleDepsForID(const ModuleID &ID) const { + SmallString<64> Key; + getModuleIDKeyString(ID, Key); + return ModuleDepsByID.lookup(Key); +} + +void ModuleDepCollector::setModuleDepsForID(const ModuleID &ID, + ModuleDeps *MD) { + SmallString<64> Key; + getModuleIDKeyString(ID, Key); + assert(ModuleDepsByID.count(Key) == 0); + ModuleDepsByID[Key] = MD; } static std::string getModuleContextHash(const ModuleDeps &MD, + const CompilerInvocation &CI, bool EagerLoadModules) { llvm::HashBuilder, llvm::support::endianness::native> @@ -188,7 +241,7 @@ // Hash the BuildInvocation without any input files. SmallVector DummyArgs; - MD.BuildInvocation.generateCC1CommandLine(DummyArgs, [&](const Twine &Arg) { + CI.generateCC1CommandLine(DummyArgs, [&](const Twine &Arg) { Scratch.clear(); StringRef Str = Arg.toStringRef(Scratch); HashBuilder.add(Str); @@ -296,8 +349,12 @@ for (auto &&I : MDC.FileDeps) MDC.Consumer.handleFileDependency(I); - for (auto &&I : DirectPrebuiltModularDeps) - MDC.Consumer.handlePrebuiltModuleDependency(PrebuiltModuleDep{I}); + for (auto &&I : DirectPrebuiltModularDeps) { + MDC.DirectPrebuiltDeps.emplace_back(I); + MDC.Consumer.handlePrebuiltModuleDependency(MDC.DirectPrebuiltDeps.back()); + } + + MDC.handleInvocation(MDC.OriginalInvocation); } ModuleID ModuleDepCollectorPP::handleTopLevelModule(const Module *M) { @@ -390,7 +447,7 @@ llvm::DenseSet AddedModules; addAllSubmoduleDeps(M, MD, AddedModules); - MD.BuildInvocation = MDC.makeInvocationForModuleBuildWithoutOutputs( + auto CI = MDC.makeInvocationForModuleBuildWithoutOutputs( MD, [&](CompilerInvocation &BuildInvocation) { if (MDC.OptimizeArgs) optimizeHeaderSearchOpts(BuildInvocation.getHeaderSearchOpts(), @@ -398,9 +455,13 @@ }); // Compute the context hash from the inputs. Requires dependencies. - MD.ID.ContextHash = getModuleContextHash(MD, MDC.EagerLoadModules); + MD.ID.ContextHash = getModuleContextHash(MD, CI, MDC.EagerLoadModules); // Finish the compiler invocation. Requires dependencies and the context hash. - MDC.addOutputPaths(MD); + MDC.addOutputPaths(CI, MD); + + MD.BuildArguments = CI.getCC1CommandLine(); + + MDC.setModuleDepsForID(MD.ID, &MD); return MD.ID; } Index: clang/lib/Tooling/Tooling.cpp =================================================================== --- clang/lib/Tooling/Tooling.cpp +++ clang/lib/Tooling/Tooling.cpp @@ -161,7 +161,7 @@ /// Returns a clang build invocation initialized from the CC1 flags. CompilerInvocation *newInvocation(DiagnosticsEngine *Diagnostics, - const llvm::opt::ArgStringList &CC1Args, + ArrayRef CC1Args, const char *const BinaryName) { assert(!CC1Args.empty() && "Must at least contain the program name!"); CompilerInvocation *Invocation = new CompilerInvocation; @@ -339,7 +339,7 @@ } bool ToolInvocation::run() { - std::vector Argv; + llvm::opt::ArgStringList Argv; for (const std::string &Str : CommandLine) Argv.push_back(Str.c_str()); const char *const BinaryName = Argv[0]; @@ -362,6 +362,17 @@ SourceManager SrcMgr(*Diagnostics, *Files); Diagnostics->setSourceManager(&SrcMgr); + // We already have a cc1, just create an invocation. + if (CommandLine.size() >= 2 && CommandLine[1] == "-cc1") { + ArrayRef CC1Args = makeArrayRef(Argv).drop_front(); + std::unique_ptr Invocation( + newInvocation(&*Diagnostics, CC1Args, BinaryName)); + if (Diagnostics->hasErrorOccurred()) + return false; + return Action->runInvocation(std::move(Invocation), Files, + std::move(PCHContainerOps), DiagConsumer); + } + const std::unique_ptr Driver( newDriver(&*Diagnostics, BinaryName, &Files->getVirtualFileSystem())); // The "input file not found" diagnostics from the driver are useful. Index: clang/test/ClangScanDeps/deprecated-driver-api.c =================================================================== --- /dev/null +++ clang/test/ClangScanDeps/deprecated-driver-api.c @@ -0,0 +1,35 @@ +// 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(); +} Index: clang/test/ClangScanDeps/diagnostics.c =================================================================== --- clang/test/ClangScanDeps/diagnostics.c +++ 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: } Index: clang/test/ClangScanDeps/header-search-pruning-transitive.c =================================================================== --- clang/test/ClangScanDeps/header-search-pruning-transitive.c +++ 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: } Index: clang/test/ClangScanDeps/modules-context-hash-ignore-macros.c =================================================================== --- clang/test/ClangScanDeps/modules-context-hash-ignore-macros.c +++ 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" Index: clang/test/ClangScanDeps/modules-context-hash-outputs.c =================================================================== --- clang/test/ClangScanDeps/modules-context-hash-outputs.c +++ 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" Index: clang/test/ClangScanDeps/modules-context-hash-warnings.c =================================================================== --- clang/test/ClangScanDeps/modules-context-hash-warnings.c +++ 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]]" Index: clang/test/ClangScanDeps/modules-context-hash.c =================================================================== --- clang/test/ClangScanDeps/modules-context-hash.c +++ 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: } Index: clang/test/ClangScanDeps/modules-dep-args.c =================================================================== --- clang/test/ClangScanDeps/modules-dep-args.c +++ 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 Index: clang/test/ClangScanDeps/modules-fmodule-name-no-module-built.m =================================================================== --- clang/test/ClangScanDeps/modules-fmodule-name-no-module-built.m +++ 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: } Index: clang/test/ClangScanDeps/modules-full.cpp =================================================================== --- clang/test/ClangScanDeps/modules-full.cpp +++ 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: } Index: clang/test/ClangScanDeps/modules-inferred.m =================================================================== --- clang/test/ClangScanDeps/modules-inferred.m +++ 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: } Index: clang/test/ClangScanDeps/modules-no-undeclared-includes.c =================================================================== --- clang/test/ClangScanDeps/modules-no-undeclared-includes.c +++ 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 Index: clang/test/ClangScanDeps/modules-pch-common-submodule.c =================================================================== --- clang/test/ClangScanDeps/modules-pch-common-submodule.c +++ 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: // Index: clang/test/ClangScanDeps/modules-pch-common-via-submodule.c =================================================================== --- clang/test/ClangScanDeps/modules-pch-common-via-submodule.c +++ 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: // Index: clang/test/ClangScanDeps/modules-pch.c =================================================================== --- clang/test/ClangScanDeps/modules-pch.c +++ 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: // Index: clang/test/ClangScanDeps/multiple-commands.c =================================================================== --- /dev/null +++ clang/test/ClangScanDeps/multiple-commands.c @@ -0,0 +1,165 @@ +// 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(); } Index: clang/test/ClangScanDeps/removed-args.c =================================================================== --- clang/test/ClangScanDeps/removed-args.c +++ 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: } Index: clang/tools/clang-scan-deps/ClangScanDeps.cpp =================================================================== --- clang/tools/clang-scan-deps/ClangScanDeps.cpp +++ 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)); } @@ -304,21 +310,40 @@ {"file-deps", toJSONSorted(MD.FileDeps)}, {"clang-module-deps", toJSONSorted(MD.ClangModuleDeps)}, {"clang-modulemap-file", MD.ClangModuleMapFile}, - {"command-line", MD.getCanonicalCommandLine()}, + {"command-line", MD.BuildArguments}, }; OutModules.push_back(std::move(O)); } 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, Index: clang/unittests/Tooling/ToolingTest.cpp =================================================================== --- clang/unittests/Tooling/ToolingTest.cpp +++ clang/unittests/Tooling/ToolingTest.cpp @@ -326,6 +326,46 @@ EXPECT_TRUE(Consumer.SawSourceManager); } +TEST(ToolInvocation, CC1Args) { + llvm::IntrusiveRefCntPtr OverlayFileSystem( + new llvm::vfs::OverlayFileSystem(llvm::vfs::getRealFileSystem())); + llvm::IntrusiveRefCntPtr InMemoryFileSystem( + new llvm::vfs::InMemoryFileSystem); + OverlayFileSystem->pushOverlay(InMemoryFileSystem); + llvm::IntrusiveRefCntPtr Files( + new FileManager(FileSystemOptions(), OverlayFileSystem)); + std::vector Args; + Args.push_back("tool-executable"); + Args.push_back("-cc1"); + Args.push_back("-fsyntax-only"); + Args.push_back("test.cpp"); + clang::tooling::ToolInvocation Invocation( + Args, std::make_unique(), Files.get()); + InMemoryFileSystem->addFile( + "test.cpp", 0, llvm::MemoryBuffer::getMemBuffer("void foo(void);\n")); + EXPECT_TRUE(Invocation.run()); +} + +TEST(ToolInvocation, CC1ArgsInvalid) { + llvm::IntrusiveRefCntPtr OverlayFileSystem( + new llvm::vfs::OverlayFileSystem(llvm::vfs::getRealFileSystem())); + llvm::IntrusiveRefCntPtr InMemoryFileSystem( + new llvm::vfs::InMemoryFileSystem); + OverlayFileSystem->pushOverlay(InMemoryFileSystem); + llvm::IntrusiveRefCntPtr Files( + new FileManager(FileSystemOptions(), OverlayFileSystem)); + std::vector Args; + Args.push_back("tool-executable"); + Args.push_back("-cc1"); + Args.push_back("-invalid-arg"); + Args.push_back("test.cpp"); + clang::tooling::ToolInvocation Invocation( + Args, std::make_unique(), Files.get()); + InMemoryFileSystem->addFile( + "test.cpp", 0, llvm::MemoryBuffer::getMemBuffer("void foo(void);\n")); + EXPECT_FALSE(Invocation.run()); +} + namespace { /// Overlays the real filesystem with the given VFS and returns the result. llvm::IntrusiveRefCntPtr Index: clang/utils/module-deps-to-rsp.py =================================================================== --- clang/utils/module-deps-to-rsp.py +++ 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: