[clang] [llvm] [clang-cl] Omit command line and workdir in CIFF CV debug info for reproducible builds. (PR #205736)
Vladimir Vereschaka via cfe-commits
cfe-commits at lists.llvm.org
Tue Jul 7 18:59:30 PDT 2026
https://github.com/vvereschaka updated https://github.com/llvm/llvm-project/pull/205736
>From 1eb2d285bc306fdff23f01e90c23d31849c34d06 Mon Sep 17 00:00:00 2001
From: Vladimir Vereschaka <vvereschaka at accesssoftek.com>
Date: Tue, 30 Jun 2026 19:48:51 -0700
Subject: [PATCH 1/7] [clang-cl] Omit command line and workdir in CIFF CV debug
info for reproducible builds.
The command line can contain the arguments, such as the pathes or /pathmap options,
which could break a reproducible output for the object files. In addition to
`-gcodeview-commandline` option that drops the command line from the build info,
this patch adds a new `-gcodeview-cwd` option to exclude the current working
directory from the build info of the CodeView debug info sections.
Also it links `-gno-codeview-cwd` and `-gno-codeview-commandline` options with
CL's `/Brepro` option to match (partly) compiler behaviour with MSVC.
---
clang/include/clang/Basic/DebugOptions.def | 3 +++
clang/include/clang/Options/Options.td | 6 ++++++
clang/lib/CodeGen/BackendUtil.cpp | 1 +
clang/lib/Driver/ToolChains/Clang.cpp | 3 +++
clang/test/DebugInfo/Generic/codeview-buildinfo.c | 10 ++++++++++
clang/test/Driver/cl-options.c | 2 ++
llvm/include/llvm/MC/MCTargetOptions.h | 1 +
llvm/lib/CodeGen/AsmPrinter/CodeViewDebug.cpp | 4 +++-
8 files changed, 29 insertions(+), 1 deletion(-)
diff --git a/clang/include/clang/Basic/DebugOptions.def b/clang/include/clang/Basic/DebugOptions.def
index c9dd3f726e799..6cba505901146 100644
--- a/clang/include/clang/Basic/DebugOptions.def
+++ b/clang/include/clang/Basic/DebugOptions.def
@@ -122,6 +122,9 @@ DEBUGOPT(CodeViewGHash, 1, 0, Compatible)
/// Whether to emit the compiler path and command line into the CodeView debug information.
DEBUGOPT(CodeViewCommandLine, 1, 0, Compatible)
+/// Whether to emit the current working directory into the CodeView debug information.
+DEBUGOPT(CodeViewEmitCurrentWorkdir, 1, 0, Compatible)
+
/// Whether emit extra debug info for sample pgo profile collection.
DEBUGOPT(DebugInfoForProfiling, 1, 0, Compatible)
diff --git a/clang/include/clang/Options/Options.td b/clang/include/clang/Options/Options.td
index 59bfd621a5994..5fb96a94cd5ae 100644
--- a/clang/include/clang/Options/Options.td
+++ b/clang/include/clang/Options/Options.td
@@ -5154,6 +5154,12 @@ defm codeview_command_line : BoolOption<"g", "codeview-command-line",
NegFlag<SetFalse, [], [ClangOption], "Don't emit compiler path and command line into CodeView debug information">,
BothFlags<[], [ClangOption, CLOption, DXCOption, CC1Option]>>,
Group<g_flags_Group>;
+defm codeview_cwd : BoolOption<"g", "codeview-cwd",
+ CodeGenOpts<"CodeViewEmitCurrentWorkdir">, DefaultTrue,
+ PosFlag<SetTrue, [], [ClangOption], "Emit current working directory into CodeView debug information">,
+ NegFlag<SetFalse, [], [ClangOption], "Don't emit current working directory into CodeView debug information">,
+ BothFlags<[], [ClangOption, CLOption, DXCOption, CC1Option]>>,
+ Group<g_flags_Group>;
defm inline_line_tables : BoolGOption<"inline-line-tables",
CodeGenOpts<"NoInlineLineTables">, DefaultFalse,
NegFlag<SetTrue, [], [ClangOption, CC1Option],
diff --git a/clang/lib/CodeGen/BackendUtil.cpp b/clang/lib/CodeGen/BackendUtil.cpp
index 971cb409de3ca..f0dd70dc0ca99 100644
--- a/clang/lib/CodeGen/BackendUtil.cpp
+++ b/clang/lib/CodeGen/BackendUtil.cpp
@@ -548,6 +548,7 @@ static bool initTargetOptions(const CompilerInstance &CI,
InputFiles.push_back(Input.getFile());
Options.MCOptions.CommandlineArgs = flattenClangCommandLine(
CodeGenOpts.CommandLineArgs, CodeGenOpts.MainFileName, InputFiles);
+ Options.MCOptions.EmitCurrentWorkdir = CodeGenOpts.CodeViewEmitCurrentWorkdir;
Options.MCOptions.AsSecureLogFile = CodeGenOpts.AsSecureLogFile;
Options.MCOptions.PPCUseFullRegisterNames =
CodeGenOpts.PPCUseFullRegisterNames;
diff --git a/clang/lib/Driver/ToolChains/Clang.cpp b/clang/lib/Driver/ToolChains/Clang.cpp
index a30b01a675b99..eb6fd53791f12 100644
--- a/clang/lib/Driver/ToolChains/Clang.cpp
+++ b/clang/lib/Driver/ToolChains/Clang.cpp
@@ -9095,6 +9095,9 @@ void Clang::AddClangCLArgs(const ArgList &Args, types::ID InputType,
// This option does not allow the user redefinitions for these macros.
if (!HasNoDateTime)
CmdArgs.push_back("-init-datetime-macros=literalone");
+ // Omit tool, current workdir and command line in COFF CV debug section.
+ CmdArgs.push_back("-gno-codeview-command-line");
+ CmdArgs.push_back("-gno-codeview-cwd");
}
}
diff --git a/clang/test/DebugInfo/Generic/codeview-buildinfo.c b/clang/test/DebugInfo/Generic/codeview-buildinfo.c
index b930e3cc642c4..853ffde86b7a4 100644
--- a/clang/test/DebugInfo/Generic/codeview-buildinfo.c
+++ b/clang/test/DebugInfo/Generic/codeview-buildinfo.c
@@ -24,6 +24,9 @@
// RUN: cd %t.relpath && %clang_cl --target=i686-windows-msvc /c /Z7 /Fo:hello.obj -- hello.cpp
// RUN: llvm-pdbutil dump --types %t.relpath/hello.obj | FileCheck %s --check-prefix RELPATH
+// RUN: %clang_cl --target=i686-windows-msvc /Brepro /c /Z7 /Fo%t.obj -- %s
+// RUN: llvm-pdbutil dump --types %t.obj | FileCheck %s --check-prefix BREPRO
+
int main(void) { return 42; }
// CHECK: Types (.debug$T)
@@ -78,3 +81,10 @@ int main(void) { return 42; }
// RELPATH-NEXT: 0x{{.*}}: `
// RELPATH-NOT: {{hello\.cpp}}
// RELPATH-SAME: `
+
+// BREPRO: 0x{{.+}} | LF_BUILDINFO [size = {{.+}}]
+// BREPRO-NEXT: 0x{{.*}}: ``
+// BREPRO-NEXT: 0x{{.*}}: ``
+// BREPRO-NEXT: 0x{{.*}}: `{{.+[\\/]codeview-buildinfo\.c}}`
+// BREPRO-NEXT: 0x{{.*}}: ``
+// BREPRO-NEXT: 0x{{.*}}: ``
diff --git a/clang/test/Driver/cl-options.c b/clang/test/Driver/cl-options.c
index 57d82622ef4de..27f4f7476c9f0 100644
--- a/clang/test/Driver/cl-options.c
+++ b/clang/test/Driver/cl-options.c
@@ -584,6 +584,8 @@
// RUN: %clang_cl /Brepro- /Brepro /c '-###' -- %s 2>&1 | FileCheck -check-prefix=Brepro %s
// Brepro: "-mno-incremental-linker-compatible"
+// Brepro: "-gno-codeview-command-line"
+// Brepro: "-gno-codeview-cwd"
// RUN: %clang_cl /Brepro /Brepro- /c '-###' -- %s 2>&1 | FileCheck -check-prefix=Brepro_ %s
// Brepro_: "-mincremental-linker-compatible"
diff --git a/llvm/include/llvm/MC/MCTargetOptions.h b/llvm/include/llvm/MC/MCTargetOptions.h
index e3d1a8cc763b7..5451086b15833 100644
--- a/llvm/include/llvm/MC/MCTargetOptions.h
+++ b/llvm/include/llvm/MC/MCTargetOptions.h
@@ -102,6 +102,7 @@ class MCTargetOptions {
// Used for codeview debug info. These will be set as compiler path and commandline arguments in LF_BUILDINFO
std::string Argv0;
std::string CommandlineArgs;
+ bool EmitCurrentWorkdir : 1;
/// Additional paths to search for `.include` directives when using the
/// integrated assembler.
diff --git a/llvm/lib/CodeGen/AsmPrinter/CodeViewDebug.cpp b/llvm/lib/CodeGen/AsmPrinter/CodeViewDebug.cpp
index 06353a0e039db..a63e40127f9fa 100644
--- a/llvm/lib/CodeGen/AsmPrinter/CodeViewDebug.cpp
+++ b/llvm/lib/CodeGen/AsmPrinter/CodeViewDebug.cpp
@@ -956,8 +956,10 @@ void CodeViewDebug::emitBuildInfo() {
const MDNode *Node = *CUs->operands().begin(); // FIXME: Multiple CUs.
const auto *CU = cast<DICompileUnit>(Node);
const DIFile *MainSourceFile = CU->getFile();
+ const llvm::StringRef cwd = Asm->TM.Options.MCOptions.EmitCurrentWorkdir ?
+ MainSourceFile->getDirectory() : llvm::StringRef("");
BuildInfoArgs[BuildInfoRecord::CurrentDirectory] =
- getStringIdTypeIdx(TypeTable, MainSourceFile->getDirectory());
+ getStringIdTypeIdx(TypeTable, cwd);
BuildInfoArgs[BuildInfoRecord::SourceFile] =
getStringIdTypeIdx(TypeTable, MainSourceFile->getFilename());
// FIXME: PDB is intentionally blank unless we implement /Zi type servers.
>From 99b890b9512734e344a68cd83af6b9e26ee92dac Mon Sep 17 00:00:00 2001
From: Vladimir Vereschaka <vvereschaka at accesssoftek.com>
Date: Tue, 30 Jun 2026 20:05:41 -0700
Subject: [PATCH 2/7] Fix code formatting
---
llvm/lib/CodeGen/AsmPrinter/CodeViewDebug.cpp | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)
diff --git a/llvm/lib/CodeGen/AsmPrinter/CodeViewDebug.cpp b/llvm/lib/CodeGen/AsmPrinter/CodeViewDebug.cpp
index a63e40127f9fa..8664eefc1b235 100644
--- a/llvm/lib/CodeGen/AsmPrinter/CodeViewDebug.cpp
+++ b/llvm/lib/CodeGen/AsmPrinter/CodeViewDebug.cpp
@@ -956,8 +956,9 @@ void CodeViewDebug::emitBuildInfo() {
const MDNode *Node = *CUs->operands().begin(); // FIXME: Multiple CUs.
const auto *CU = cast<DICompileUnit>(Node);
const DIFile *MainSourceFile = CU->getFile();
- const llvm::StringRef cwd = Asm->TM.Options.MCOptions.EmitCurrentWorkdir ?
- MainSourceFile->getDirectory() : llvm::StringRef("");
+ const llvm::StringRef cwd = Asm->TM.Options.MCOptions.EmitCurrentWorkdir
+ ? MainSourceFile->getDirectory()
+ : llvm::StringRef("");
BuildInfoArgs[BuildInfoRecord::CurrentDirectory] =
getStringIdTypeIdx(TypeTable, cwd);
BuildInfoArgs[BuildInfoRecord::SourceFile] =
>From c7545e342bfaa5f84d6fa3dc49fb9a4a93f9cbd6 Mon Sep 17 00:00:00 2001
From: Vladimir Vereschaka <vvereschaka at accesssoftek.com>
Date: Tue, 30 Jun 2026 21:42:20 -0700
Subject: [PATCH 3/7] Default True for MCTargetOptions::EmitCurrentWorkdir.
---
llvm/include/llvm/MC/MCTargetOptions.h | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/llvm/include/llvm/MC/MCTargetOptions.h b/llvm/include/llvm/MC/MCTargetOptions.h
index 5451086b15833..b08fcd0b62904 100644
--- a/llvm/include/llvm/MC/MCTargetOptions.h
+++ b/llvm/include/llvm/MC/MCTargetOptions.h
@@ -102,7 +102,7 @@ class MCTargetOptions {
// Used for codeview debug info. These will be set as compiler path and commandline arguments in LF_BUILDINFO
std::string Argv0;
std::string CommandlineArgs;
- bool EmitCurrentWorkdir : 1;
+ bool EmitCurrentWorkdir = true;
/// Additional paths to search for `.include` directives when using the
/// integrated assembler.
>From b48d52c3a1dd488b0f018d4e0d391f53522ddf19 Mon Sep 17 00:00:00 2001
From: Vladimir Vereschaka <vvereschaka at accesssoftek.com>
Date: Mon, 6 Jul 2026 22:45:32 -0700
Subject: [PATCH 4/7] Revert "Default True for
MCTargetOptions::EmitCurrentWorkdir."
This reverts commit d5204a73ef52c613735a9747c28da23f3e4d7cef.
---
llvm/include/llvm/MC/MCTargetOptions.h | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/llvm/include/llvm/MC/MCTargetOptions.h b/llvm/include/llvm/MC/MCTargetOptions.h
index b08fcd0b62904..5451086b15833 100644
--- a/llvm/include/llvm/MC/MCTargetOptions.h
+++ b/llvm/include/llvm/MC/MCTargetOptions.h
@@ -102,7 +102,7 @@ class MCTargetOptions {
// Used for codeview debug info. These will be set as compiler path and commandline arguments in LF_BUILDINFO
std::string Argv0;
std::string CommandlineArgs;
- bool EmitCurrentWorkdir = true;
+ bool EmitCurrentWorkdir : 1;
/// Additional paths to search for `.include` directives when using the
/// integrated assembler.
>From c3c01a11423783abee5bd48af52bde370037f21d Mon Sep 17 00:00:00 2001
From: Vladimir Vereschaka <vvereschaka at accesssoftek.com>
Date: Mon, 6 Jul 2026 22:45:49 -0700
Subject: [PATCH 5/7] Revert "Fix code formatting"
This reverts commit 4cb6e336e52ea3c3f1463b0b3e4beaa904026c8d.
---
llvm/lib/CodeGen/AsmPrinter/CodeViewDebug.cpp | 5 ++---
1 file changed, 2 insertions(+), 3 deletions(-)
diff --git a/llvm/lib/CodeGen/AsmPrinter/CodeViewDebug.cpp b/llvm/lib/CodeGen/AsmPrinter/CodeViewDebug.cpp
index 8664eefc1b235..a63e40127f9fa 100644
--- a/llvm/lib/CodeGen/AsmPrinter/CodeViewDebug.cpp
+++ b/llvm/lib/CodeGen/AsmPrinter/CodeViewDebug.cpp
@@ -956,9 +956,8 @@ void CodeViewDebug::emitBuildInfo() {
const MDNode *Node = *CUs->operands().begin(); // FIXME: Multiple CUs.
const auto *CU = cast<DICompileUnit>(Node);
const DIFile *MainSourceFile = CU->getFile();
- const llvm::StringRef cwd = Asm->TM.Options.MCOptions.EmitCurrentWorkdir
- ? MainSourceFile->getDirectory()
- : llvm::StringRef("");
+ const llvm::StringRef cwd = Asm->TM.Options.MCOptions.EmitCurrentWorkdir ?
+ MainSourceFile->getDirectory() : llvm::StringRef("");
BuildInfoArgs[BuildInfoRecord::CurrentDirectory] =
getStringIdTypeIdx(TypeTable, cwd);
BuildInfoArgs[BuildInfoRecord::SourceFile] =
>From feded3b247a4023b9add4dcc0b337f711463b004 Mon Sep 17 00:00:00 2001
From: Vladimir Vereschaka <vvereschaka at accesssoftek.com>
Date: Tue, 7 Jul 2026 18:47:41 -0700
Subject: [PATCH 6/7] Revert MCOptions.EmitCurrentWorkdir flag
---
clang/lib/CodeGen/BackendUtil.cpp | 1 -
llvm/include/llvm/MC/MCTargetOptions.h | 1 -
llvm/lib/CodeGen/AsmPrinter/CodeViewDebug.cpp | 4 +---
3 files changed, 1 insertion(+), 5 deletions(-)
diff --git a/clang/lib/CodeGen/BackendUtil.cpp b/clang/lib/CodeGen/BackendUtil.cpp
index f0dd70dc0ca99..971cb409de3ca 100644
--- a/clang/lib/CodeGen/BackendUtil.cpp
+++ b/clang/lib/CodeGen/BackendUtil.cpp
@@ -548,7 +548,6 @@ static bool initTargetOptions(const CompilerInstance &CI,
InputFiles.push_back(Input.getFile());
Options.MCOptions.CommandlineArgs = flattenClangCommandLine(
CodeGenOpts.CommandLineArgs, CodeGenOpts.MainFileName, InputFiles);
- Options.MCOptions.EmitCurrentWorkdir = CodeGenOpts.CodeViewEmitCurrentWorkdir;
Options.MCOptions.AsSecureLogFile = CodeGenOpts.AsSecureLogFile;
Options.MCOptions.PPCUseFullRegisterNames =
CodeGenOpts.PPCUseFullRegisterNames;
diff --git a/llvm/include/llvm/MC/MCTargetOptions.h b/llvm/include/llvm/MC/MCTargetOptions.h
index 5451086b15833..e3d1a8cc763b7 100644
--- a/llvm/include/llvm/MC/MCTargetOptions.h
+++ b/llvm/include/llvm/MC/MCTargetOptions.h
@@ -102,7 +102,6 @@ class MCTargetOptions {
// Used for codeview debug info. These will be set as compiler path and commandline arguments in LF_BUILDINFO
std::string Argv0;
std::string CommandlineArgs;
- bool EmitCurrentWorkdir : 1;
/// Additional paths to search for `.include` directives when using the
/// integrated assembler.
diff --git a/llvm/lib/CodeGen/AsmPrinter/CodeViewDebug.cpp b/llvm/lib/CodeGen/AsmPrinter/CodeViewDebug.cpp
index a63e40127f9fa..06353a0e039db 100644
--- a/llvm/lib/CodeGen/AsmPrinter/CodeViewDebug.cpp
+++ b/llvm/lib/CodeGen/AsmPrinter/CodeViewDebug.cpp
@@ -956,10 +956,8 @@ void CodeViewDebug::emitBuildInfo() {
const MDNode *Node = *CUs->operands().begin(); // FIXME: Multiple CUs.
const auto *CU = cast<DICompileUnit>(Node);
const DIFile *MainSourceFile = CU->getFile();
- const llvm::StringRef cwd = Asm->TM.Options.MCOptions.EmitCurrentWorkdir ?
- MainSourceFile->getDirectory() : llvm::StringRef("");
BuildInfoArgs[BuildInfoRecord::CurrentDirectory] =
- getStringIdTypeIdx(TypeTable, cwd);
+ getStringIdTypeIdx(TypeTable, MainSourceFile->getDirectory());
BuildInfoArgs[BuildInfoRecord::SourceFile] =
getStringIdTypeIdx(TypeTable, MainSourceFile->getFilename());
// FIXME: PDB is intentionally blank unless we implement /Zi type servers.
>From f5f6e57c1710e5e093e0f70e755d47faefc655c3 Mon Sep 17 00:00:00 2001
From: Vladimir Vereschaka <vvereschaka at accesssoftek.com>
Date: Tue, 7 Jul 2026 18:48:41 -0700
Subject: [PATCH 7/7] Handle CGOpts.CodeViewEmitCurrentWorkdir flag on CU
creation.
---
clang/lib/CodeGen/CGDebugInfo.cpp | 11 ++++++++---
1 file changed, 8 insertions(+), 3 deletions(-)
diff --git a/clang/lib/CodeGen/CGDebugInfo.cpp b/clang/lib/CodeGen/CGDebugInfo.cpp
index 7421733efcc24..5206154cce2bb 100644
--- a/clang/lib/CodeGen/CGDebugInfo.cpp
+++ b/clang/lib/CodeGen/CGDebugInfo.cpp
@@ -868,9 +868,14 @@ void CGDebugInfo::CreateCompileUnit() {
// file was specified with an absolute path.
if (CSKind)
CSInfo.emplace(*CSKind, Checksum);
- llvm::DIFile *CUFile = DBuilder.createFile(
- remapDIPath(MainFileName), remapDIPath(getCurrentDirname()), CSInfo,
- getSource(SM, SM.getMainFileID()));
+ const llvm::StringRef cwd =
+ !CGOpts.EmitCodeView ||
+ (CGOpts.EmitCodeView && CGOpts.CodeViewEmitCurrentWorkdir)
+ ? getCurrentDirname()
+ : llvm::StringRef("");
+ llvm::DIFile *CUFile =
+ DBuilder.createFile(remapDIPath(MainFileName), remapDIPath(cwd), CSInfo,
+ getSource(SM, SM.getMainFileID()));
StringRef Sysroot, SDK;
if (CGM.getCodeGenOpts().getDebuggerTuning() == llvm::DebuggerKind::LLDB) {
More information about the cfe-commits
mailing list