diff --git a/clang/include/clang/Driver/Compilation.h b/clang/include/clang/Driver/Compilation.h --- a/clang/include/clang/Driver/Compilation.h +++ b/clang/include/clang/Driver/Compilation.h @@ -115,6 +115,9 @@ /// Optional redirection for stdin, stdout, stderr. std::vector> Redirects; + /// Callback called after the command has been executed. + std::function PostCallback; + /// Whether we're compiling for diagnostic purposes. bool ForDiagnostics = false; @@ -212,6 +215,10 @@ return FailureResultFiles; } + 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 --- a/clang/lib/Driver/Compilation.cpp +++ b/clang/lib/Driver/Compilation.cpp @@ -193,6 +193,8 @@ 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 --- a/clang/unittests/Driver/ToolChainTest.cpp +++ b/clang/unittests/Driver/ToolChainTest.cpp @@ -259,4 +259,29 @@ EXPECT_STREQ(Res.DriverMode, "--driver-mode=cl"); EXPECT_FALSE(Res.TargetIsValid); } + +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, + 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.