From d8bab69ead22a10dc4cdb2e36f6ea6fdfe774e2e Mon Sep 17 00:00:00 2001 From: Jan Svoboda Date: Mon, 14 Jun 2021 12:06:08 +0200 Subject: [PATCH] [clang][deps] Move invocation adjustments from `clang-scan-deps` to `DependencyScanning` library The `clang-scan-deps` tool has some logic that parses and modifies the original Clang command-line. The goal is to setup `DependencyOutputOptions` by injecting `-M -MT ` and prevent the creation of output files. This patch moves the logic into the `DependencyScanning` library, and uses the parsed `CompilerInvocation` instead of the raw command-line. The code simpler and can be used from the C++ API as well. The `-o /dev/null` arguments are not necessary, since the `DependencyScanning` library only runs a preprocessing action, so there's no way it'll produce an actual object file. Related: The `-M` argument implies `-w`, which would appear on the command-line of modular dependencies even though it was not on the original TU command line (see D104036). Some related tests were updated. Reviewed By: arphaman Differential Revision: https://reviews.llvm.org/D104030 --- .../DependencyScanningWorker.cpp | 26 ++++++++- clang/test/ClangScanDeps/modules-pch.c | 3 + clang/test/ClangScanDeps/modules.cpp | 5 +- clang/test/ClangScanDeps/regular_cdb.cpp | 8 +-- clang/tools/clang-scan-deps/ClangScanDeps.cpp | 64 ++-------------------- 5 files changed, 39 insertions(+), 67 deletions(-) diff --git a/clang/lib/Tooling/DependencyScanning/DependencyScanningWorker.cpp b/clang/lib/Tooling/DependencyScanning/DependencyScanningWorker.cpp index 40466b0..e9392ee 100644 --- a/clang/lib/Tooling/DependencyScanning/DependencyScanningWorker.cpp +++ b/clang/lib/Tooling/DependencyScanning/DependencyScanningWorker.cpp @@ -62,6 +62,26 @@ private: std::map &PrebuiltModuleFiles; }; +/// Transform arbitrary file name into an object-like file name. +static std::string makeObjFileName(StringRef FileName) { + SmallString<128> ObjFileName(FileName); + llvm::sys::path::replace_extension(ObjFileName, "o"); + return std::string(ObjFileName.str()); +} + +/// Deduce the dependency target based on the output file and input files. +static std::string +deduceDepTarget(const std::string &OutputFile, + const SmallVectorImpl &InputFiles) { + if (OutputFile != "-") + return OutputFile; + + if (InputFiles.empty() || !InputFiles.front().isFile()) + return "clang-scan-deps\\ dependency"; + + return makeObjFileName(InputFiles.front().getFile()); +} + /// A clang tool that runs the preprocessor in a mode that's optimized for /// dependency scanning for the given compiler invocation. class DependencyScanningAction : public tooling::ToolAction { @@ -150,9 +170,11 @@ public: // 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. + // We need at least one -MT equivalent for the generator of make dependency + // files to work. if (Opts->Targets.empty()) - Opts->Targets = {"clang-scan-deps dependency"}; + Opts->Targets = {deduceDepTarget(Compiler.getFrontendOpts().OutputFile, + Compiler.getFrontendOpts().Inputs)}; switch (Format) { case ScanningOutputFormat::Make: diff --git a/clang/test/ClangScanDeps/modules-pch.c b/clang/test/ClangScanDeps/modules-pch.c index 34a0043..8b8b753 100644 --- a/clang/test/ClangScanDeps/modules-pch.c +++ b/clang/test/ClangScanDeps/modules-pch.c @@ -9,6 +9,9 @@ // RUN: -generate-modules-path-args -module-files-dir %t/build -mode preprocess >> %t/result_pch.json // RUN: cat %t/result_pch.json | sed 's:\\\\\?:/:g' | FileCheck %s -check-prefix=CHECK-PCH // +// Check we didn't build the PCH during dependency scanning. +// RUN: not cat %/t/pch.h.gch +// // CHECK-PCH: -[[PREFIX:.*]] // CHECK-PCH-NEXT: { // CHECK-PCH-NEXT: "modules": [ diff --git a/clang/test/ClangScanDeps/modules.cpp b/clang/test/ClangScanDeps/modules.cpp index f0d97dc0..b7daf51 100644 --- a/clang/test/ClangScanDeps/modules.cpp +++ b/clang/test/ClangScanDeps/modules.cpp @@ -42,13 +42,14 @@ #include "header.h" -// CHECK1: modules_cdb_input2.cpp +// CHECK1: modules_cdb_input2.o: // CHECK1-NEXT: modules_cdb_input2.cpp // CHECK1-NEXT: Inputs{{/|\\}}module.modulemap // CHECK1-NEXT: Inputs{{/|\\}}header2.h // CHECK1: Inputs{{/|\\}}header.h -// CHECK2: modules_cdb_input.cpp +// CHECK2: {{.*}}.o: +// CHECK2-NEXT: modules_cdb_input.cpp // CHECK2-NEXT: Inputs{{/|\\}}module.modulemap // CHECK2-NEXT: Inputs{{/|\\}}header.h // CHECK2NO-NOT: header2 diff --git a/clang/test/ClangScanDeps/regular_cdb.cpp b/clang/test/ClangScanDeps/regular_cdb.cpp index d7ba2519..ee98600 100644 --- a/clang/test/ClangScanDeps/regular_cdb.cpp +++ b/clang/test/ClangScanDeps/regular_cdb.cpp @@ -58,14 +58,14 @@ #include "header.h" -// CHECK1: regular_cdb_input2.cpp +// CHECK1: regular_cdb_input2.o: // CHECK1-NEXT: regular_cdb_input2.cpp // CHECK1-NEXT: Inputs{{/|\\}}header.h // CHECK1-NEXT: Inputs{{/|\\}}header2.h -// CHECK3: regular_cdb_input.o -// CHECK2: regular_cdb_input.cpp +// CHECK2: regular_cdb_input.o: +// CHECK2-NEXT: regular_cdb_input.cpp // CHECK2-NEXT: Inputs{{/|\\}}header.h // CHECK2NO-NOT: header2 -// CHECK3: adena.o +// CHECK3: adena.o: diff --git a/clang/tools/clang-scan-deps/ClangScanDeps.cpp b/clang/tools/clang-scan-deps/ClangScanDeps.cpp index 625a4c1..d9f1b58 100644 --- a/clang/tools/clang-scan-deps/ClangScanDeps.cpp +++ b/clang/tools/clang-scan-deps/ClangScanDeps.cpp @@ -201,13 +201,6 @@ llvm::cl::opt Verbose("v", llvm::cl::Optional, } // end anonymous namespace -/// \returns object-file path derived from source-file path. -static std::string getObjFilePath(StringRef SrcFile) { - SmallString<128> ObjFileName(SrcFile); - llvm::sys::path::replace_extension(ObjFileName, "o"); - return std::string(ObjFileName.str()); -} - class SingleCommandCompilationDatabase : public tooling::CompilationDatabase { public: SingleCommandCompilationDatabase(tooling::CompileCommand Cmd) @@ -463,16 +456,10 @@ int main(int argc, const char **argv) { std::move(Compilations)); ResourceDirectoryCache ResourceDirCache; - // FIXME: Adjust the resulting CompilerInvocation in DependencyScanningAction - // instead of parsing and adjusting the raw command-line. This will make it - // possible to remove some code specific to clang-cl and Windows. AdjustingCompilations->appendArgumentsAdjuster( [&ResourceDirCache](const tooling::CommandLineArguments &Args, StringRef FileName) { std::string LastO = ""; - bool HasMT = false; - bool HasMQ = false; - bool HasMD = false; bool HasResourceDir = false; bool ClangCLMode = false; auto FlagsEnd = llvm::find(Args, "--"); @@ -503,58 +490,17 @@ int main(int argc, const char **argv) { if (!LastO.empty() && !llvm::sys::path::has_extension(LastO)) LastO.append(".obj"); } - if (Arg == "/clang:-MT") - HasMT = true; - if (Arg == "/clang:-MQ") - HasMQ = true; - if (Arg == "/clang:-MD") - HasMD = true; - } else { - if (LastO.empty()) { - if (Arg == "-o" && I != R) - LastO = I[-1]; // Next argument (reverse iterator) - else if (Arg.startswith("-o")) - LastO = Arg.drop_front(2).str(); - } - if (Arg == "-MT") - HasMT = true; - if (Arg == "-MQ") - HasMQ = true; - if (Arg == "-MD") - HasMD = true; } if (Arg == "-resource-dir") HasResourceDir = true; } } - // If there's no -MT/-MQ Driver would add -MT with the value of the last - // -o option. tooling::CommandLineArguments AdjustedArgs(Args.begin(), FlagsEnd); - AdjustedArgs.push_back("-o"); -#ifdef _WIN32 - AdjustedArgs.push_back("nul"); -#else - AdjustedArgs.push_back("/dev/null"); -#endif - if (!HasMT && !HasMQ && Format == ScanningOutputFormat::Make) { - // We're interested in source dependencies of an object file. - std::string FileNameArg; - if (!HasMD) { - // FIXME: We are missing the directory unless the -o value is an - // absolute path. - FileNameArg = !LastO.empty() ? LastO : getObjFilePath(FileName); - } else { - FileNameArg = std::string(FileName); - } - if (ClangCLMode) { - AdjustedArgs.push_back("/clang:-M"); - AdjustedArgs.push_back("/clang:-MT"); - AdjustedArgs.push_back(Twine("/clang:", FileNameArg).str()); - } else { - AdjustedArgs.push_back("-M"); - AdjustedArgs.push_back("-MT"); - AdjustedArgs.push_back(std::move(FileNameArg)); - } + // The clang-cl driver passes "-o -" to the frontend. Inject the real + // file here to ensure "-MT" can be deduced if need be. + if (ClangCLMode && !LastO.empty()) { + AdjustedArgs.push_back("/clang:-o"); + AdjustedArgs.push_back("/clang:" + LastO); } AdjustedArgs.push_back("-Xclang"); AdjustedArgs.push_back("-sys-header-deps"); -- 2.7.4