Index: clang/include/clang/Frontend/DependencyOutputOptions.h =================================================================== --- clang/include/clang/Frontend/DependencyOutputOptions.h +++ clang/include/clang/Frontend/DependencyOutputOptions.h @@ -47,8 +47,7 @@ /// stderr. std::string HeaderIncludeOutputFile; - /// A list of names to use as the targets in the dependency file; this list - /// must contain at least one entry. + /// A list of names to use as the targets in the dependency file. std::vector Targets; /// A list of filenames to be used as extra dependencies for every target. Index: clang/lib/Tooling/DependencyScanning/DependencyScanningWorker.cpp =================================================================== --- clang/lib/Tooling/DependencyScanning/DependencyScanningWorker.cpp +++ clang/lib/Tooling/DependencyScanning/DependencyScanningWorker.cpp @@ -116,9 +116,6 @@ // and thus won't write out the extra '.d' files to disk. auto Opts = std::make_unique( std::move(Compiler.getInvocation().getDependencyOutputOpts())); - // We need at least one -MT equivalent for the generator to work. - if (Opts->Targets.empty()) - Opts->Targets = {"clang-scan-deps dependency"}; Compiler.addDependencyCollector( std::make_shared(std::move(Opts), Consumer)); Index: clang/test/ClangScanDeps/Inputs/subframework_header_dir_symlink_cdb.json =================================================================== --- clang/test/ClangScanDeps/Inputs/subframework_header_dir_symlink_cdb.json +++ clang/test/ClangScanDeps/Inputs/subframework_header_dir_symlink_cdb.json @@ -2,11 +2,11 @@ { "directory": "DIR", "command": "clang -E DIR/subframework_header_dir_symlink_input.m -D EMPTY -iframework Inputs/frameworks", - "file": "DIR/subframework_header_dir_symlink.m" + "file": "DIR/subframework_header_dir_symlink_input.m" }, { "directory": "DIR", "command": "clang -E DIR/subframework_header_dir_symlink_input2.m -FInputs/frameworks -iframework Inputs/frameworks_symlink", - "file": "DIR/subframework_header_dir_symlink2.m" + "file": "DIR/subframework_header_dir_symlink_input2.m" } ] Index: clang/test/ClangScanDeps/Inputs/symlink_cdb.json =================================================================== --- clang/test/ClangScanDeps/Inputs/symlink_cdb.json +++ clang/test/ClangScanDeps/Inputs/symlink_cdb.json @@ -2,11 +2,11 @@ { "directory": "DIR", "command": "clang -E DIR/symlink_input.cpp -IInputs", - "file": "DIR/symlink.cpp" + "file": "DIR/symlink_input.cpp" }, { "directory": "DIR", "command": "clang -E DIR/symlink_input2.cpp -IInputs", - "file": "DIR/symlink2.cpp" + "file": "DIR/symlink_input2.cpp" } ] Index: clang/test/ClangScanDeps/Inputs/vfsoverlay_cdb.json =================================================================== --- clang/test/ClangScanDeps/Inputs/vfsoverlay_cdb.json +++ clang/test/ClangScanDeps/Inputs/vfsoverlay_cdb.json @@ -2,6 +2,6 @@ { "directory": "DIR", "command": "clang -E DIR/vfsoverlay_input.cpp -IInputs -ivfsoverlay DIR/vfsoverlay.yaml", - "file": "DIR/vfsoverlay.cpp" + "file": "DIR/vfsoverlay_input.cpp" } ] Index: clang/test/ClangScanDeps/header_stat_before_open.m =================================================================== --- clang/test/ClangScanDeps/header_stat_before_open.m +++ clang/test/ClangScanDeps/header_stat_before_open.m @@ -12,7 +12,7 @@ #include "Framework/Framework.h" #include "Framework/PrivateHeader.h" -// CHECK: clang-scan-deps dependency +// CHECK: header_stat_before_open_input.o // CHECK-NEXT: header_stat_before_open_input.m // CHECK-NEXT: Inputs{{/|\\}}frameworks{{/|\\}}Framework.framework{{/|\\}}Headers{{/|\\}}Framework.h // CHECK-NEXT: Inputs{{/|\\}}frameworks{{/|\\}}Framework.framework{{/|\\}}PrivateHeaders{{/|\\}}PrivateHeader.h Index: clang/test/ClangScanDeps/subframework_header_dir_symlink.m =================================================================== --- clang/test/ClangScanDeps/subframework_header_dir_symlink.m +++ clang/test/ClangScanDeps/subframework_header_dir_symlink.m @@ -17,8 +17,8 @@ #include "Framework/Framework.h" #endif -// CHECK: clang-scan-deps dependency +// CHECK: subframework_header_dir_symlink_input.o // CHECK-NEXT: subframework_header_dir_symlink_input.m -// CHECK: clang-scan-deps dependency +// CHECK: subframework_header_dir_symlink_input2.o // CHECK-NEXT: subframework_header_dir_symlink_input2.m // CHECK-NEXT: Inputs{{/|\\}}frameworks_symlink{{/|\\}}Framework.framework{{/|\\}}Headers{{/|\\}}Framework.h Index: clang/test/ClangScanDeps/vfsoverlay.cpp =================================================================== --- clang/test/ClangScanDeps/vfsoverlay.cpp +++ clang/test/ClangScanDeps/vfsoverlay.cpp @@ -12,6 +12,6 @@ #include "not_real.h" -// CHECK: clang-scan-deps dependency +// CHECK: vfsoverlay_input.o // CHECK-NEXT: vfsoverlay_input.cpp // CHECK-NEXT: Inputs{{/|\\}}header.h Index: clang/tools/clang-scan-deps/ClangScanDeps.cpp =================================================================== --- clang/tools/clang-scan-deps/ClangScanDeps.cpp +++ clang/tools/clang-scan-deps/ClangScanDeps.cpp @@ -11,8 +11,10 @@ #include "clang/Tooling/DependencyScanning/DependencyScanningService.h" #include "clang/Tooling/DependencyScanning/DependencyScanningWorker.h" #include "clang/Tooling/JSONCompilationDatabase.h" +#include "llvm/ADT/StringRef.h" #include "llvm/Support/InitLLVM.h" #include "llvm/Support/Options.h" +#include "llvm/Support/Path.h" #include "llvm/Support/Program.h" #include "llvm/Support/Signals.h" #include "llvm/Support/Threading.h" @@ -57,8 +59,8 @@ /// /// \returns A \c StringError with the diagnostic output if clang errors /// occurred, dependency file contents otherwise. - llvm::Expected getDependencyFile(const std::string &Input, - StringRef CWD) { + llvm::Expected getDependencyFile(StringRef Input, StringRef CWD, + StringRef CompilationOutput) { /// Prints out all of the gathered dependencies into a string. class DependencyPrinterConsumer : public DependencyConsumer { public: @@ -69,10 +71,13 @@ Dependencies.push_back(File); } - void printDependencies(std::string &S) { + void printDependencies(StringRef CompilationOutput, std::string &S) { if (!Opts) return; + if (Opts->Targets.empty()) + Opts->Targets = {CompilationOutput}; + class DependencyPrinter : public DependencyFileGenerator { public: DependencyPrinter(DependencyOutputOptions &Opts, @@ -103,15 +108,17 @@ if (Result) return std::move(Result); std::string Output; - Consumer.printDependencies(Output); + + Consumer.printDependencies(CompilationOutput, Output); + return Output; } /// Computes the dependencies for the given file and prints them out. /// /// \returns True on error. - bool runOnFile(const std::string &Input, StringRef CWD) { - auto MaybeFile = getDependencyFile(Input, CWD); + bool runOnFile(StringRef Input, StringRef CWD, StringRef Output) { + auto MaybeFile = getDependencyFile(Input, CWD, Output); if (!MaybeFile) { llvm::handleAllErrors( MaybeFile.takeError(), [this, &Input](llvm::StringError &Err) { @@ -170,6 +177,13 @@ } // end anonymous namespace +/// \returns object-file name derived from source-file name. +static std::string getObjFileName(StringRef SrcFile) { + SmallString<128> ObjFileName(llvm::sys::path::filename(SrcFile)); + llvm::sys::path::replace_extension(ObjFileName, "o"); + return ObjFileName.str(); +} + int main(int argc, const char **argv) { llvm::InitLLVM X(argc, argv); llvm::cl::HideUnrelatedOptions(DependencyScannerCategory); @@ -188,10 +202,23 @@ llvm::cl::PrintOptionValues(); + struct DependencyScanInput { + std::string FileName; + std::string Directory; + std::string Output; + }; + // By default the tool runs on all inputs in the CDB. - std::vector> Inputs; - for (const auto &Command : Compilations->getAllCompileCommands()) - Inputs.emplace_back(Command.Filename, Command.Directory); + auto CompilationComands = Compilations->getAllCompileCommands(); + std::vector Inputs; + std::size_t CompilationComandIdx = 0; + for (const auto &Command : CompilationComands) { + Inputs.push_back( + {Command.Filename, Command.Directory, + std::to_string(CompilationComandIdx++) + "_" + + (Command.Output.empty() ? getObjFileName(Command.Filename) + : Command.Output)}); + } // The command options are rewritten to run Clang in preprocessor only mode. auto AdjustingCompilations = @@ -235,20 +262,21 @@ << " files using " << NumWorkers << " workers\n"; for (unsigned I = 0; I < NumWorkers; ++I) { auto Worker = [I, &Lock, &Index, &Inputs, &HadErrors, &WorkerTools]() { + size_t IndexToProcess; while (true) { - std::string Input; - StringRef CWD; // Take the next input. { std::unique_lock LockGuard(Lock); - if (Index >= Inputs.size()) - return; - const auto &Compilation = Inputs[Index++]; - Input = Compilation.first; - CWD = Compilation.second; + IndexToProcess = Index++; } + if (IndexToProcess >= Inputs.size()) + return; + + const auto &Compilation = Inputs[IndexToProcess]; // Run the tool on it. - if (WorkerTools[I]->runOnFile(Input, CWD)) + if (WorkerTools[I]->runOnFile(Compilation.FileName, + Compilation.Directory, + Compilation.Output)) HadErrors = true; } };