https://github.com/qiongsiwu updated https://github.com/llvm/llvm-project/pull/211966
>From 2b588fb940507652d0c5e2f74d88b998366d6df2 Mon Sep 17 00:00:00 2001 From: Qiongsi Wu <[email protected]> Date: Fri, 24 Jul 2026 16:13:14 -0700 Subject: [PATCH] Add a clang driver option to enable dependency scanning logging. --- clang/include/clang/Basic/AtomicLineLogger.h | 9 ++- .../DependencyScanningWorker.h | 2 + clang/include/clang/Options/Options.td | 7 ++ clang/lib/Basic/AtomicLineLogger.cpp | 76 ++++++++++++++----- clang/lib/Tooling/DependencyScanningTool.cpp | 3 + .../test/ClangScanDeps/logging-driver-flag.c | 26 +++++++ 6 files changed, 101 insertions(+), 22 deletions(-) create mode 100644 clang/test/ClangScanDeps/logging-driver-flag.c diff --git a/clang/include/clang/Basic/AtomicLineLogger.h b/clang/include/clang/Basic/AtomicLineLogger.h index 3d06ddfce0262..ddcd5993b060e 100644 --- a/clang/include/clang/Basic/AtomicLineLogger.h +++ b/clang/include/clang/Basic/AtomicLineLogger.h @@ -19,6 +19,7 @@ #include "llvm/ADT/SmallString.h" #include "llvm/Support/raw_ostream.h" #include <atomic> +#include <mutex> #include <optional> #include <string> @@ -60,9 +61,11 @@ class LogLine { }; class AtomicLineLogger { - int FD = -1; + std::atomic<int> FD{-1}; std::string LogPath; std::atomic<uint64_t> DroppedLines{0}; + std::mutex EnableMtx; + bool WarnedConflict = false; public: AtomicLineLogger() {} @@ -75,6 +78,10 @@ class AtomicLineLogger { ~AtomicLineLogger(); + // Enables the logger if it is not already enabled. Thread safe. + // If the logger is already enabled, call to enable is a no-op. + void enable(StringRef LogFilePath); + LogLine log(); }; diff --git a/clang/include/clang/DependencyScanning/DependencyScanningWorker.h b/clang/include/clang/DependencyScanning/DependencyScanningWorker.h index 04c0868fe3225..eeca027e91f22 100644 --- a/clang/include/clang/DependencyScanning/DependencyScanningWorker.h +++ b/clang/include/clang/DependencyScanning/DependencyScanningWorker.h @@ -79,6 +79,8 @@ class DependencyScanningWorker { return TracingFS.get(); } + DependencyScanningService &getService() const { return Service; } + private: /// The parent dependency scanning service. DependencyScanningService &Service; diff --git a/clang/include/clang/Options/Options.td b/clang/include/clang/Options/Options.td index 41848b18f2e1b..fcc058ac93e1e 100644 --- a/clang/include/clang/Options/Options.td +++ b/clang/include/clang/Options/Options.td @@ -3772,6 +3772,13 @@ def fno_modules_driver : Group<f_Group>, Visibility<[ClangOption]>, HelpText<"Disable support for driver managed module builds (experimental)">; +def fdepscan_log_path : Joined<["-"], "fdepscan-log-path=">, + Group<f_Group>, + Visibility<[ClangOption]>, + Flags<[NoArgumentUnused]>, + MetaVarName<"<file>">, + HelpText<"Log the timing of dependency scanning actions to <file>. Only " + "takes effect while running the dependency scanner.">; def fincremental_extensions : Flag<["-"], "fincremental-extensions">, diff --git a/clang/lib/Basic/AtomicLineLogger.cpp b/clang/lib/Basic/AtomicLineLogger.cpp index dc0f2bf5adc6c..4bf26f0cb756d 100644 --- a/clang/lib/Basic/AtomicLineLogger.cpp +++ b/clang/lib/Basic/AtomicLineLogger.cpp @@ -41,20 +41,43 @@ static uint64_t getTimestampMillis() { #endif } +#ifdef _WIN32 +// Write to files opened with OF_Append may not be guaranteed to be atomic +// on Windows. Both openLogFile and writeLineToFD are noops on Windows. +static int openLogFile(StringRef Path) { + (void)Path; + return -1; +} + +static bool writeLineToFD(int FD, const char *Data, size_t Size) { + (void)FD, (void)Data, (void)Size; + return false; +} + +#else + +static int openLogFile(StringRef Path) { + int FD = -1; + std::error_code EC = llvm::sys::fs::openFileForWrite( + Path, FD, llvm::sys::fs::CD_OpenAlways, llvm::sys::fs::OF_Append); + if (EC) { + llvm::errs() << "warning: unable to open log file '" << Path + << "': " << EC.message() << "\n"; + return -1; + } + return FD; +} + // Writes the whole line into an FD that is opened with OF_Append. // This function only does one write (up to retry due to interrupts), and the // single write is blocking and atomic on POSIX systems. static bool writeLineToFD(int FD, const char *Data, size_t Size) { -#ifndef _WIN32 ssize_t Written = llvm::sys::RetryAfterSignal(-1, write, FD, Data, Size); return Written >= 0 && (static_cast<size_t>(Written) == Size); -#else - (void)FD, (void)Data, (void)Size; - llvm_unreachable("Logging not supported on Windows!"); - return false; -#endif } +#endif + LogLine::LogLine(int FD, std::atomic<uint64_t> *DroppedLines) : FormattingOS(Buffer), FD(FD), DroppedLines(DroppedLines) { auto Millis = getTimestampMillis(); @@ -83,33 +106,44 @@ LogLine::~LogLine() { DroppedLines->fetch_add(1, std::memory_order_relaxed); } -AtomicLineLogger::AtomicLineLogger(StringRef LogFilePath) - : LogPath(LogFilePath.str()) { -#ifndef _WIN32 +AtomicLineLogger::AtomicLineLogger(StringRef LogFilePath) { if (LogFilePath.empty()) return; + LogPath = LogFilePath.str(); + FD.store(openLogFile(LogFilePath), std::memory_order_release); +} - std::error_code EC = llvm::sys::fs::openFileForWrite( - LogFilePath, FD, llvm::sys::fs::CD_OpenAlways, llvm::sys::fs::OF_Append); - if (EC) { - llvm::errs() << "warning: unable to open log file '" << LogFilePath - << "': " << EC.message() << "\n"; - FD = -1; +void AtomicLineLogger::enable(StringRef LogFilePath) { + if (LogFilePath.empty()) + return; + std::lock_guard<std::mutex> Lock(EnableMtx); + if (FD.load(std::memory_order_relaxed) != -1) { + if (LogFilePath != LogPath && !WarnedConflict) { + llvm::errs() << "warning: dependency scanning log path '" << LogFilePath + << "' ignored; already logging to '" << LogPath << "'\n"; + WarnedConflict = true; + } return; } -#endif - // Write to files opened with OF_Append may not be guaranteed to be atomic - // on Windows, so we do not enable logging on Windows. + + int NewFD = openLogFile(LogFilePath); + if (NewFD == -1) + return; + LogPath = LogFilePath.str(); + FD.store(NewFD, std::memory_order_relaxed); + return; } LogLine AtomicLineLogger::log() { - if (FD != -1) - return LogLine(FD, &DroppedLines); + int CurFD = FD.load(std::memory_order_relaxed); + if (CurFD != -1) + return LogLine(CurFD, &DroppedLines); return LogLine(); } AtomicLineLogger::~AtomicLineLogger() { - if (FD == -1) + int CurFD = FD.load(std::memory_order_relaxed); + if (CurFD == -1) return; if (uint64_t Dropped = DroppedLines.load(std::memory_order_relaxed)) llvm::errs() << "warning: log '" << LogPath diff --git a/clang/lib/Tooling/DependencyScanningTool.cpp b/clang/lib/Tooling/DependencyScanningTool.cpp index b435e42af28b4..e3ffcd6830ba6 100644 --- a/clang/lib/Tooling/DependencyScanningTool.cpp +++ b/clang/lib/Tooling/DependencyScanningTool.cpp @@ -16,6 +16,7 @@ #include "clang/Frontend/FrontendActions.h" #include "clang/Frontend/Utils.h" #include "clang/Lex/Preprocessor.h" +#include "clang/Options/Options.h" #include "llvm/ADT/ScopeExit.h" #include "llvm/ADT/SmallVectorExtras.h" #include "llvm/ADT/iterator.h" @@ -160,6 +161,8 @@ static bool computeDependenciesForDriverCommandLine( if (!Compilation) return false; + Worker.getService().getLogger().enable( + Compilation->getArgs().getLastArgValue(options::OPT_fdepscan_log_path)); SmallVector<SmallVector<std::string, 0>> FrontendCommandLines; for (const auto &Cmd : Compilation->getJobs()) FrontendCommandLines.push_back(buildCC1CommandLine(Cmd)); diff --git a/clang/test/ClangScanDeps/logging-driver-flag.c b/clang/test/ClangScanDeps/logging-driver-flag.c new file mode 100644 index 0000000000000..6578f04b1cd4e --- /dev/null +++ b/clang/test/ClangScanDeps/logging-driver-flag.c @@ -0,0 +1,26 @@ +// UNSUPPORTED: system-windows +// RUN: rm -rf %t +// RUN: split-file %s %t +// RUN: sed -e "s|DIR|%/t|g" %t/cdb.json.template > %t/cdb.json + +// RUN: clang-scan-deps -compilation-database %t/cdb.json \ +// RUN: -format experimental-full -j 1 -o %t/deps.json +// RUN: FileCheck %s --input-file %t/scan.log + +// CHECK: [{{[0-9]+\.[0-9]+}}] [[#PID:]] [[#TID:]]: starting scanning command:{{.*}}tu.c +// CHECK: [{{[0-9]+\.[0-9]+}}] {{.*}}: pcm_write: {{.*}}.pcm +// CHECK: [{{[0-9]+\.[0-9]+}}] {{.*}}: finished scanning command:{{.*}}tu.c +//--- cdb.json.template +[{ + "directory": "DIR", + "command": "clang -fsyntax-only DIR/tu.c -fmodules -fimplicit-module-maps -fmodules-cache-path=DIR/cache -fbuild-session-timestamp=1 -fmodules-validate-once-per-build-session -fdepscan-log-path=DIR/scan.log", + "file": "DIR/tu.c" +}] + +//--- module.modulemap +module A { header "A.h" } +//--- A.h +void A_func(void); +//--- tu.c +#include "A.h" +void foo(void) { A_func(); } _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
