From c12577c61dbf37b1b6ae25ed422a900ac71f18fe Mon Sep 17 00:00:00 2001 From: Jan Svoboda Date: Thu, 9 Jun 2022 16:58:09 +0200 Subject: [PATCH] [clang][driver] Introduce new -fdriver-only flag This patch introduces the new -fdriver-only flag which instructs Clang to only execute the driver logic without running individual jobs. In a way, this is very similar to -###, with the following differences: * it doesn't automatically print all jobs, * it doesn't avoid side effects (e.g. it will generate compilation database when -MJ is specified). This flag will be useful in testing D121997. Reviewed By: dexonsmith, egorzhdan Differential Revision: https://reviews.llvm.org/D127408 --- clang/include/clang/Driver/Compilation.h | 14 ++++++++++---- clang/include/clang/Driver/Options.td | 2 ++ clang/lib/Driver/Compilation.cpp | 11 ++++++++--- clang/lib/Driver/Driver.cpp | 15 +++++++++++++++ .../lib/Frontend/CreateInvocationFromCommandLine.cpp | 3 +++ clang/test/Driver/cc-print-options.c | 10 ++++++++-- clang/test/Driver/driver-only.c | 19 +++++++++++++++++++ 7 files changed, 65 insertions(+), 9 deletions(-) create mode 100644 clang/test/Driver/driver-only.c diff --git a/clang/include/clang/Driver/Compilation.h b/clang/include/clang/Driver/Compilation.h index 260e2a3..c5714d3 100644 --- a/clang/include/clang/Driver/Compilation.h +++ b/clang/include/clang/Driver/Compilation.h @@ -295,16 +295,22 @@ public: /// /// \param FailingCommand - For non-zero results, this will be set to the /// Command which failed, if any. + /// \param LogOnly - When true, only tries to log the command, not actually + /// execute it. /// \return The result code of the subprocess. - int ExecuteCommand(const Command &C, const Command *&FailingCommand) const; + int ExecuteCommand(const Command &C, const Command *&FailingCommand, + bool LogOnly = false) const; /// ExecuteJob - Execute a single job. /// /// \param FailingCommands - For non-zero results, this will be a vector of /// failing commands and their associated result code. - void ExecuteJobs( - const JobList &Jobs, - SmallVectorImpl> &FailingCommands) const; + /// \param LogOnly - When true, only tries to log the command, not actually + /// execute it. + void + ExecuteJobs(const JobList &Jobs, + SmallVectorImpl> &FailingCommands, + bool LogOnly = false) const; /// initCompilationForDiagnostics - Remove stale state and suppress output /// so compilation can be reexecuted to generate additional diagnostic diff --git a/clang/include/clang/Driver/Options.td b/clang/include/clang/Driver/Options.td index 002cd6c..5d65053 100644 --- a/clang/include/clang/Driver/Options.td +++ b/clang/include/clang/Driver/Options.td @@ -2751,6 +2751,8 @@ defm strict_vtable_pointers : BoolFOption<"strict-vtable-pointers", " overwriting polymorphic C++ objects">, NegFlag>; def fstrict_overflow : Flag<["-"], "fstrict-overflow">, Group; +def fdriver_only : Flag<["-"], "fdriver-only">, Flags<[NoXarchOption, CoreOption]>, + Group, HelpText<"Only run the driver.">; def fsyntax_only : Flag<["-"], "fsyntax-only">, Flags<[NoXarchOption,CoreOption,CC1Option,FC1Option]>, Group; def ftabstop_EQ : Joined<["-"], "ftabstop=">, Group; diff --git a/clang/lib/Driver/Compilation.cpp b/clang/lib/Driver/Compilation.cpp index 67d941c..b4367a0 100644 --- a/clang/lib/Driver/Compilation.cpp +++ b/clang/lib/Driver/Compilation.cpp @@ -162,7 +162,8 @@ bool Compilation::CleanupFileMap(const ArgStringMap &Files, } int Compilation::ExecuteCommand(const Command &C, - const Command *&FailingCommand) const { + const Command *&FailingCommand, + bool LogOnly) const { if ((getDriver().CCPrintOptions || getArgs().hasArg(options::OPT_v)) && !getDriver().CCGenDiagnostics) { raw_ostream *OS = &llvm::errs(); @@ -191,6 +192,9 @@ int Compilation::ExecuteCommand(const Command &C, C.Print(*OS, "\n", /*Quote=*/getDriver().CCPrintOptions); } + if (LogOnly) + return 0; + std::string Error; bool ExecutionFailed; int Res = C.Execute(Redirects, &Error, &ExecutionFailed); @@ -237,7 +241,8 @@ static bool InputsOk(const Command &C, } void Compilation::ExecuteJobs(const JobList &Jobs, - FailingCommandList &FailingCommands) const { + FailingCommandList &FailingCommands, + bool LogOnly) const { // According to UNIX standard, driver need to continue compiling all the // inputs on the command line even one of them failed. // In all but CLMode, execute all the jobs unless the necessary inputs for the @@ -246,7 +251,7 @@ void Compilation::ExecuteJobs(const JobList &Jobs, if (!InputsOk(Job, FailingCommands)) continue; const Command *FailingCommand = nullptr; - if (int Res = ExecuteCommand(Job, FailingCommand)) { + if (int Res = ExecuteCommand(Job, FailingCommand, LogOnly)) { FailingCommands.push_back(std::make_pair(Res, FailingCommand)); // Bail as soon as one command fails in cl driver mode. if (TheDriver.IsCLMode()) diff --git a/clang/lib/Driver/Driver.cpp b/clang/lib/Driver/Driver.cpp index 8f7e411..bb87980 100644 --- a/clang/lib/Driver/Driver.cpp +++ b/clang/lib/Driver/Driver.cpp @@ -1689,6 +1689,19 @@ void Driver::setUpResponseFiles(Compilation &C, Command &Cmd) { int Driver::ExecuteCompilation( Compilation &C, SmallVectorImpl> &FailingCommands) { + if (C.getArgs().hasArg(options::OPT_fdriver_only)) { + if (C.getArgs().hasArg(options::OPT_v)) + C.getJobs().Print(llvm::errs(), "\n", true); + + C.ExecuteJobs(C.getJobs(), FailingCommands, /*LogOnly=*/true); + + // If there were errors building the compilation, quit now. + if (!FailingCommands.empty() || Diags.hasErrorOccurred()) + return 1; + + return 0; + } + // Just print if -### was present. if (C.getArgs().hasArg(options::OPT__HASH_HASH_HASH)) { C.getJobs().Print(llvm::errs(), "\n", true); @@ -4761,6 +4774,8 @@ void Driver::BuildJobs(Compilation &C) const { C.getArgs().hasArg(options::OPT_Qunused_arguments)) return; + // Claim -fdriver-only here. + (void)C.getArgs().hasArg(options::OPT_fdriver_only); // Claim -### here. (void)C.getArgs().hasArg(options::OPT__HASH_HASH_HASH); diff --git a/clang/lib/Frontend/CreateInvocationFromCommandLine.cpp b/clang/lib/Frontend/CreateInvocationFromCommandLine.cpp index 49e814b..35b5e21 100644 --- a/clang/lib/Frontend/CreateInvocationFromCommandLine.cpp +++ b/clang/lib/Frontend/CreateInvocationFromCommandLine.cpp @@ -54,6 +54,9 @@ clang::createInvocation(ArrayRef ArgList, if (!C) return nullptr; + if (C->getArgs().hasArg(driver::options::OPT_fdriver_only)) + return nullptr; + // Just print the cc1 options if -### was present. if (C->getArgs().hasArg(driver::options::OPT__HASH_HASH_HASH)) { C->getJobs().Print(llvm::errs(), "\n", true); diff --git a/clang/test/Driver/cc-print-options.c b/clang/test/Driver/cc-print-options.c index 5a17810..58375fa 100644 --- a/clang/test/Driver/cc-print-options.c +++ b/clang/test/Driver/cc-print-options.c @@ -1,8 +1,14 @@ +// RUN: rm -f %t.log // RUN: env CC_PRINT_OPTIONS=1 \ // RUN: CC_PRINT_OPTIONS_FILE=%t.log \ // RUN: %clang -S -o %t.s %s // RUN: FileCheck %s < %t.log -// CHECK: [Logging clang options] -// CHECK: {{.*}} "-S" +// RUN: rm -f %t.log +// RUN: env CC_PRINT_OPTIONS=1 \ +// RUN: CC_PRINT_OPTIONS_FILE=%t.log \ +// RUN: %clang -fdriver-only -o %t.s %s +// RUN: FileCheck %s < %t.log +// CHECK: [Logging clang options] +// CHECK: {{.*}} "-cc1" diff --git a/clang/test/Driver/driver-only.c b/clang/test/Driver/driver-only.c new file mode 100644 index 0000000..067f174 --- /dev/null +++ b/clang/test/Driver/driver-only.c @@ -0,0 +1,19 @@ +// RUN: rm -rf %t +// RUN: mkdir %t + +// Check that -fdriver-only doesn't actually run the generated -cc1 job. +// +// RUN: %clang -c %s -o %t/a.o -fdriver-only +// RUN: not cat %t/a.o + +// Check that -fdriver-only respects errors. +// +// RUN: not %clang -c %s -fdriver-only -target i386-apple-darwin9 -m32 -Xarch_i386 -o + +// Check that -fdriver-only respects -v. +// +// RUN: %clang -c %s -fdriver-only -v 2>&1 | FileCheck %s --check-prefix=CHECK-V +// CHECK-V: {{.*}} "-cc1" +// +// RUN: %clang -c %s -fdriver-only 2>&1 | FileCheck %s --check-prefix=CHECK-NO-V --allow-empty +// CHECK-NO-V-NOT: {{.*}} "-cc1" -- 2.7.4