From 20b4f4f76030f8712824c91b5f0b0a611476f747 Mon Sep 17 00:00:00 2001 From: Serge Pavlov Date: Fri, 24 Apr 2020 12:48:39 +0700 Subject: [PATCH] [Driver] Add callback to Command execution Summary: Object of type `Compilation` now can keep a callback that is called after each execution of `Command`. This must simplify adaptation of clang in custom distributions and allow facilities like collection of execution statistics. Reviewers: rsmith, rjmccall, Eugene.Zelenko Subscribers: cfe-commits Tags: #clang Differential Revision: https://reviews.llvm.org/D78899 --- clang/include/clang/Driver/Compilation.h | 13 +++++++++++++ clang/lib/Driver/Compilation.cpp | 2 ++ clang/unittests/Driver/ToolChainTest.cpp | 24 ++++++++++++++++++++++++ 3 files changed, 39 insertions(+) diff --git a/clang/include/clang/Driver/Compilation.h b/clang/include/clang/Driver/Compilation.h index 70b9014..89a43b5 100644 --- a/clang/include/clang/Driver/Compilation.h +++ b/clang/include/clang/Driver/Compilation.h @@ -115,6 +115,11 @@ class Compilation { /// Optional redirection for stdin, stdout, stderr. std::vector> Redirects; + /// Callback called after compilation job has been finished. + /// Arguments of the callback are the compilation job as an instance of + /// class Command and the exit status of the corresponding child process. + std::function PostCallback; + /// Whether we're compiling for diagnostic purposes. bool ForDiagnostics = false; @@ -212,6 +217,14 @@ public: return FailureResultFiles; } + /// Installs a handler that is executed when a compilation job is finished. + /// The arguments of the callback specify the compilation job as an instance + /// of class Command and the exit status of the child process executed that + /// job. + void setPostCallback(const std::function &CB) { + PostCallback = CB; + } + /// Returns the sysroot path. StringRef getSysRoot() const; diff --git a/clang/lib/Driver/Compilation.cpp b/clang/lib/Driver/Compilation.cpp index 05ee509..d330557 100644 --- a/clang/lib/Driver/Compilation.cpp +++ b/clang/lib/Driver/Compilation.cpp @@ -193,6 +193,8 @@ int Compilation::ExecuteCommand(const Command &C, std::string Error; bool ExecutionFailed; int Res = C.Execute(Redirects, &Error, &ExecutionFailed); + if (PostCallback) + PostCallback(C, Res); if (!Error.empty()) { assert(Res && "Error string set with 0 result code!"); getDriver().Diag(diag::err_drv_command_failure) << Error; diff --git a/clang/unittests/Driver/ToolChainTest.cpp b/clang/unittests/Driver/ToolChainTest.cpp index 227f7c7..3506056 100644 --- a/clang/unittests/Driver/ToolChainTest.cpp +++ b/clang/unittests/Driver/ToolChainTest.cpp @@ -289,4 +289,28 @@ TEST(ToolChainTest, CommandOutput) { EXPECT_EQ("a.out", ExeFile); } +TEST(ToolChainTest, PostCallback) { + IntrusiveRefCntPtr DiagOpts = new DiagnosticOptions(); + IntrusiveRefCntPtr DiagID(new DiagnosticIDs()); + struct TestDiagnosticConsumer : public DiagnosticConsumer {}; + DiagnosticsEngine Diags(DiagID, &*DiagOpts, new TestDiagnosticConsumer); + IntrusiveRefCntPtr InMemoryFileSystem( + new llvm::vfs::InMemoryFileSystem); + + // The executable path must not exist. + Driver CCDriver("/home/test/bin/clang", "arm-linux-gnueabi", Diags, + "clang LLVM compiler", InMemoryFileSystem); + CCDriver.setCheckInputsExist(false); + std::unique_ptr CC( + CCDriver.BuildCompilation({"/home/test/bin/clang", "foo.cpp"})); + bool CallbackHasCalled = false; + CC->setPostCallback( + [&](const Command &C, int Ret) { CallbackHasCalled = true; }); + const JobList &Jobs = CC->getJobs(); + auto &CmdCompile = Jobs.getJobs().front(); + const Command *FailingCmd = nullptr; + CC->ExecuteCommand(*CmdCompile, FailingCmd); + EXPECT_TRUE(CallbackHasCalled); +} + } // end anonymous namespace. -- 2.7.4