[clang] [clang][DependencyScanning] Add a Clang Driver Option to Enable Dependency Scanning Logging (PR #211966)
Qiongsi Wu via cfe-commits
cfe-commits at lists.llvm.org
Wed Aug 5 09:00:49 PDT 2026
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 <qiongsi_wu at apple.com>
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(); }
More information about the cfe-commits
mailing list