kastiglione created this revision.
kastiglione added reviewers: JDevlieghere, aprantl, mib.
Herald added a project: All.
kastiglione requested review of this revision.
Herald added a project: LLDB.
Herald added a subscriber: lldb-commits.

Update the Clang diagnostic consumer (in ClangModulesDeclVendor) to report
progress on Clang module builds, as both progress events and expression logs.

Module build remarks are enabled by with clang's `-Rmodule-build` flag.

With this change, command line users of lldb will see progress events showing
which modules are being built, and - by how long they stay on screen - how much
time it takes to build them. IDEs that show progress events can show these
updates if desired.

This does not show module-import remarks, although that may be added as a
future change.


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D140056

Files:
  lldb/source/Plugins/ExpressionParser/Clang/ClangModulesDeclVendor.cpp
  lldb/test/API/functionalities/progress_reporting/clang_modules/Makefile
  
lldb/test/API/functionalities/progress_reporting/clang_modules/TestClangModuleBuildProgress.py
  lldb/test/API/functionalities/progress_reporting/clang_modules/main.m

Index: lldb/test/API/functionalities/progress_reporting/clang_modules/main.m
===================================================================
--- /dev/null
+++ lldb/test/API/functionalities/progress_reporting/clang_modules/main.m
@@ -0,0 +1,3 @@
+@import Foundation;
+
+int main() {}
Index: lldb/test/API/functionalities/progress_reporting/clang_modules/TestClangModuleBuildProgress.py
===================================================================
--- /dev/null
+++ lldb/test/API/functionalities/progress_reporting/clang_modules/TestClangModuleBuildProgress.py
@@ -0,0 +1,41 @@
+"""
+Test clang module build progress events.
+"""
+import os
+import shutil
+
+import lldb
+import lldbsuite.test.lldbutil as lldbutil
+from lldbsuite.test.decorators import *
+from lldbsuite.test.lldbtest import *
+
+
+class TestCase(TestBase):
+    @skipUnlessDarwin
+    def test_clang_module_build_progress_report(self):
+        """Test receipt of progress events for clang module builds"""
+        self.build()
+
+        # Ensure an empty module cache.
+        mod_cache = os.path.join(self.getBuildDir(), "new-modules")
+        if os.path.isdir(mod_cache):
+            shutil.rmtree(mod_cache)
+        self.runCmd(f"settings set symbols.clang-modules-cache-path {mod_cache}")
+
+        lldbutil.run_to_name_breakpoint(self, "main")
+
+        # Just before triggering module builds, start listening for progress
+        # events. Listening any earlier would result in a queue filled with
+        # other unrelated progress events.
+        broadcaster = self.dbg.GetBroadcaster()
+        listener = lldbutil.start_listening_from(
+            broadcaster, lldb.SBDebugger.eBroadcastBitProgress
+        )
+
+        # Trigger module builds.
+        self.expect("p @2")
+
+        event = lldbutil.fetch_next_event(self, listener, broadcaster)
+        payload = lldb.SBDebugger.GetProgressFromEvent(event)
+        message = payload[0]
+        self.assertEqual(message, "Currently building module Foundation")
Index: lldb/test/API/functionalities/progress_reporting/clang_modules/Makefile
===================================================================
--- /dev/null
+++ lldb/test/API/functionalities/progress_reporting/clang_modules/Makefile
@@ -0,0 +1,5 @@
+OBJC_SOURCES := main.m
+CFLAGS_EXTRAS := -fmodules
+LD_EXTRAS := -framework Foundation
+
+include Makefile.rules
Index: lldb/source/Plugins/ExpressionParser/Clang/ClangModulesDeclVendor.cpp
===================================================================
--- lldb/source/Plugins/ExpressionParser/Clang/ClangModulesDeclVendor.cpp
+++ lldb/source/Plugins/ExpressionParser/Clang/ClangModulesDeclVendor.cpp
@@ -6,6 +6,9 @@
 //
 //===----------------------------------------------------------------------===//
 
+#include "clang/Basic/Diagnostic.h"
+#include "clang/Basic/DiagnosticFrontend.h"
+#include "clang/Basic/DiagnosticSerialization.h"
 #include "clang/Basic/TargetInfo.h"
 #include "clang/Frontend/CompilerInstance.h"
 #include "clang/Frontend/FrontendActions.h"
@@ -16,6 +19,7 @@
 #include "clang/Sema/Lookup.h"
 #include "clang/Serialization/ASTReader.h"
 #include "llvm/Support/FileSystem.h"
+#include "llvm/Support/FormatVariadic.h"
 #include "llvm/Support/Path.h"
 #include "llvm/Support/Threading.h"
 
@@ -25,6 +29,7 @@
 
 #include "Plugins/TypeSystem/Clang/TypeSystemClang.h"
 #include "lldb/Core/ModuleList.h"
+#include "lldb/Core/Progress.h"
 #include "lldb/Host/Host.h"
 #include "lldb/Host/HostInfo.h"
 #include "lldb/Symbol/CompileUnit.h"
@@ -61,6 +66,8 @@
   void EndSourceFile() override;
 
 private:
+  bool HandleModuleRemark(const clang::Diagnostic &info);
+
   typedef std::pair<clang::DiagnosticsEngine::Level, std::string>
       IDAndDiagnostic;
   std::vector<IDAndDiagnostic> m_diagnostics;
@@ -72,6 +79,8 @@
   /// Output string filled by m_os. Will be reused for different diagnostics.
   std::string m_output;
   Log *m_log;
+  std::unique_ptr<Progress> m_current_progress_up;
+  std::vector<std::string> m_module_build_stack;
 };
 
 /// The private implementation of our ClangModulesDeclVendor.  Contains all the
@@ -140,6 +149,9 @@
 
 void StoringDiagnosticConsumer::HandleDiagnostic(
     clang::DiagnosticsEngine::Level DiagLevel, const clang::Diagnostic &info) {
+  if (HandleModuleRemark(info))
+    return;
+
   // Print the diagnostic to m_output.
   m_output.clear();
   m_diag_printer->HandleDiagnostic(DiagLevel, info);
@@ -170,9 +182,42 @@
 }
 
 void StoringDiagnosticConsumer::EndSourceFile() {
+  m_current_progress_up.reset(nullptr);
   m_diag_printer->EndSourceFile();
 }
 
+bool StoringDiagnosticConsumer::HandleModuleRemark(
+    const clang::Diagnostic &info) {
+  Log *log = GetLog(LLDBLog::Expressions);
+  switch (info.getID()) {
+  case clang::diag::remark_module_build: {
+    const auto &module_name = info.getArgStdStr(0);
+    const auto &module_file_name = info.getArgStdStr(1);
+    m_module_build_stack.push_back(module_name);
+    // End the previous event before starting a new event.
+    m_current_progress_up.reset(nullptr);
+    m_current_progress_up.reset(new Progress(
+        llvm::formatv("Currently building module {0}", module_name)));
+    LLDB_LOG(log, "Building Clang module {0} as {1}", module_name,
+             module_file_name);
+    return true;
+  }
+  case clang::diag::remark_module_build_done: {
+    const auto &module_name = info.getArgStdStr(0);
+    const auto &parent_module_name = m_module_build_stack.back();
+    // End the previous event before starting a new event.
+    m_current_progress_up.reset(nullptr);
+    m_current_progress_up.reset(new Progress(
+        llvm::formatv("Currently building module {0}", parent_module_name)));
+    LLDB_LOG(log, "Finished building Clang module {0}", module_name);
+    m_module_build_stack.pop_back();
+    return true;
+  }
+  default:
+    return false;
+  }
+}
+
 ClangModulesDeclVendor::ClangModulesDeclVendor()
     : ClangDeclVendor(eClangModuleDeclVendor) {}
 
@@ -610,7 +655,8 @@
       arch.GetTriple().str(),
       "-fmodules-validate-system-headers",
       "-Werror=non-modular-include-in-framework-module",
-      "-Xclang=-fincremental-extensions"};
+      "-Xclang=-fincremental-extensions",
+      "-Rmodule-build"};
 
   target.GetPlatform()->AddClangModuleCompilationOptions(
       &target, compiler_invocation_arguments);
@@ -648,16 +694,18 @@
     }
   }
 
-  llvm::IntrusiveRefCntPtr<clang::DiagnosticsEngine> diagnostics_engine =
-      clang::CompilerInstance::createDiagnostics(new clang::DiagnosticOptions,
-                                                 new StoringDiagnosticConsumer);
-
   std::vector<const char *> compiler_invocation_argument_cstrs;
   compiler_invocation_argument_cstrs.reserve(
       compiler_invocation_arguments.size());
   for (const std::string &arg : compiler_invocation_arguments)
     compiler_invocation_argument_cstrs.push_back(arg.c_str());
 
+  auto diag_options_up =
+      clang::CreateAndPopulateDiagOpts(compiler_invocation_argument_cstrs);
+  llvm::IntrusiveRefCntPtr<clang::DiagnosticsEngine> diagnostics_engine =
+      clang::CompilerInstance::createDiagnostics(diag_options_up.release(),
+                                                 new StoringDiagnosticConsumer);
+
   Log *log = GetLog(LLDBLog::Expressions);
   LLDB_LOG(log, "ClangModulesDeclVendor's compiler flags {0:$[ ]}",
            llvm::make_range(compiler_invocation_arguments.begin(),
_______________________________________________
lldb-commits mailing list
lldb-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits

Reply via email to