[lld] [lld][ELF] Only convert dependency filename to native form on Windows (PR #160927)
Ruoyu Zhong via llvm-commits
llvm-commits at lists.llvm.org
Sun Oct 19 23:11:00 PDT 2025
https://github.com/ZhongRuoyu updated https://github.com/llvm/llvm-project/pull/160927
>From 46d6a53741fed96900f8011a12249ac8cfedca66 Mon Sep 17 00:00:00 2001
From: Ruoyu Zhong <zhongruoyu at outlook.com>
Date: Sat, 27 Sep 2025 00:52:40 +0800
Subject: [PATCH 1/2] [lld][ELF] Only convert dependency filename to native
form on Windows
Currently, llvm::sys::path::native is used unconditionally when
generating dependency filenames. This is correct on Windows, where
backslashes are valid path separators, but can be incorrect on
non-Windows platforms, because in that case backslashes in the
filenames are converted to forward slashes, while they should be treated
as ordinary characters.
This fixes the following inconsistency between ld.lld and ld.bfd:
$ cat test.s
.globl _start
_start:
$ cc -c test.s -o "back\\slash.o"
$ ld.lld -o test "back\\slash.o" --dependency-file=/dev/stdout
test: \
back/slash.o
back/slash.o:
$ ld.bfd -o test "back\\slash.o" --dependency-file=/dev/stdout
test: \
back\slash.o
back\slash.o:
In addition, while we're here, use 2-space indentation when printing out
dependency filenames (consistent with Clang and ld.bfd), and escape the
filename of the target (output file) too.
Signed-off-by: Ruoyu Zhong <zhongruoyu at outlook.com>
---
lld/ELF/Driver.cpp | 11 ++++++++---
.../ELF/dependency-file-backslash-as-normal-char.s | 13 +++++++++++++
.../dependency-file-backslash-as-path-separator.s | 13 +++++++++++++
3 files changed, 34 insertions(+), 3 deletions(-)
create mode 100644 lld/test/ELF/dependency-file-backslash-as-normal-char.s
create mode 100644 lld/test/ELF/dependency-file-backslash-as-path-separator.s
diff --git a/lld/ELF/Driver.cpp b/lld/ELF/Driver.cpp
index 62f7fffce7dbe..8750f324768ca 100644
--- a/lld/ELF/Driver.cpp
+++ b/lld/ELF/Driver.cpp
@@ -2483,10 +2483,14 @@ static void writeDependencyFile(Ctx &ctx) {
// We use the same escape rules as Clang/GCC which are accepted by Make/Ninja:
// * A space is escaped by a backslash which itself must be escaped.
// * A hash sign is escaped by a single backslash.
- // * $ is escapes as $$.
+ // * $ is escaped as $$.
auto printFilename = [](raw_fd_ostream &os, StringRef filename) {
llvm::SmallString<256> nativePath;
+#ifdef _WIN32
llvm::sys::path::native(filename.str(), nativePath);
+#else
+ nativePath = filename;
+#endif
llvm::sys::path::remove_dots(nativePath, /*remove_dot_dot=*/true);
for (unsigned i = 0, e = nativePath.size(); i != e; ++i) {
if (nativePath[i] == '#') {
@@ -2503,9 +2507,10 @@ static void writeDependencyFile(Ctx &ctx) {
}
};
- os << ctx.arg.outputFile << ":";
+ printFilename(os, ctx.arg.outputFile);
+ os << ":";
for (StringRef path : ctx.arg.dependencyFiles) {
- os << " \\\n ";
+ os << " \\\n ";
printFilename(os, path);
}
os << "\n";
diff --git a/lld/test/ELF/dependency-file-backslash-as-normal-char.s b/lld/test/ELF/dependency-file-backslash-as-normal-char.s
new file mode 100644
index 0000000000000..278e06d41d683
--- /dev/null
+++ b/lld/test/ELF/dependency-file-backslash-as-normal-char.s
@@ -0,0 +1,13 @@
+# REQUIRES: x86, !system-windows
+# RUN: mkdir -p %t
+# RUN: llvm-mc -filetype=obj -triple=x86_64 %s -o "%t/back\\slash.o"
+# RUN: ld.lld -o %t/foo.exe "%t/back\\slash.o" --dependency-file=%t/foo.d
+# RUN: FileCheck --match-full-lines -DFILE=%t %s < %t/foo.d
+
+# CHECK: [[FILE]]/foo.exe: \
+# CHECK-NEXT: [[FILE]]/back\slash.o
+# CHECK-EMPTY:
+# CHECK-NEXT: [[FILE]]/back\slash.o:
+
+.global _start
+_start:
diff --git a/lld/test/ELF/dependency-file-backslash-as-path-separator.s b/lld/test/ELF/dependency-file-backslash-as-path-separator.s
new file mode 100644
index 0000000000000..6e738626c4127
--- /dev/null
+++ b/lld/test/ELF/dependency-file-backslash-as-path-separator.s
@@ -0,0 +1,13 @@
+# REQUIRES: x86, system-windows
+# RUN: mkdir -p %t/back
+# RUN: llvm-mc -filetype=obj -triple=x86_64 %s -o "%t/back\\slash.o"
+# RUN: ld.lld -o %t/foo.exe "%t/back\\slash.o" --dependency-file=%t/foo.d
+# RUN: FileCheck --match-full-lines -DFILE=%t %s < %t/foo.d
+
+# CHECK: [[FILE]]\foo.exe: \
+# CHECK-NEXT: [[FILE]]\back\slash.o
+# CHECK-EMPTY:
+# CHECK-NEXT: [[FILE]]\back\slash.o:
+
+.global _start
+_start:
>From b59f1f8da99567ef21fc51777b2e7af1ecbbbd5c Mon Sep 17 00:00:00 2001
From: Ruoyu Zhong <zhongruoyu at outlook.com>
Date: Mon, 20 Oct 2025 14:02:25 +0800
Subject: [PATCH 2/2] [lld][ELF] Check indentation in dependency file tests
---
.../dependency-file-backslash-as-normal-char.s | 8 ++++----
...dependency-file-backslash-as-path-separator.s | 8 ++++----
lld/test/ELF/dependency-file.s | 16 ++++++++--------
3 files changed, 16 insertions(+), 16 deletions(-)
diff --git a/lld/test/ELF/dependency-file-backslash-as-normal-char.s b/lld/test/ELF/dependency-file-backslash-as-normal-char.s
index 278e06d41d683..3889cd8ef1d70 100644
--- a/lld/test/ELF/dependency-file-backslash-as-normal-char.s
+++ b/lld/test/ELF/dependency-file-backslash-as-normal-char.s
@@ -2,12 +2,12 @@
# RUN: mkdir -p %t
# RUN: llvm-mc -filetype=obj -triple=x86_64 %s -o "%t/back\\slash.o"
# RUN: ld.lld -o %t/foo.exe "%t/back\\slash.o" --dependency-file=%t/foo.d
-# RUN: FileCheck --match-full-lines -DFILE=%t %s < %t/foo.d
+# RUN: FileCheck --match-full-lines --strict-whitespace -DFILE=%t %s < %t/foo.d
-# CHECK: [[FILE]]/foo.exe: \
-# CHECK-NEXT: [[FILE]]/back\slash.o
+# CHECK:[[FILE]]/foo.exe: \
+# CHECK-NEXT: [[FILE]]/back\slash.o
# CHECK-EMPTY:
-# CHECK-NEXT: [[FILE]]/back\slash.o:
+# CHECK-NEXT:[[FILE]]/back\slash.o:
.global _start
_start:
diff --git a/lld/test/ELF/dependency-file-backslash-as-path-separator.s b/lld/test/ELF/dependency-file-backslash-as-path-separator.s
index 6e738626c4127..04d41bcb5d2b9 100644
--- a/lld/test/ELF/dependency-file-backslash-as-path-separator.s
+++ b/lld/test/ELF/dependency-file-backslash-as-path-separator.s
@@ -2,12 +2,12 @@
# RUN: mkdir -p %t/back
# RUN: llvm-mc -filetype=obj -triple=x86_64 %s -o "%t/back\\slash.o"
# RUN: ld.lld -o %t/foo.exe "%t/back\\slash.o" --dependency-file=%t/foo.d
-# RUN: FileCheck --match-full-lines -DFILE=%t %s < %t/foo.d
+# RUN: FileCheck --match-full-lines --strict-whitespace -DFILE=%t %s < %t/foo.d
-# CHECK: [[FILE]]\foo.exe: \
-# CHECK-NEXT: [[FILE]]\back\slash.o
+# CHECK:[[FILE]]\foo.exe: \
+# CHECK-NEXT: [[FILE]]\back\slash.o
# CHECK-EMPTY:
-# CHECK-NEXT: [[FILE]]\back\slash.o:
+# CHECK-NEXT:[[FILE]]\back\slash.o:
.global _start
_start:
diff --git a/lld/test/ELF/dependency-file.s b/lld/test/ELF/dependency-file.s
index e7dbf9c7695f7..e1271144a1553 100644
--- a/lld/test/ELF/dependency-file.s
+++ b/lld/test/ELF/dependency-file.s
@@ -4,18 +4,18 @@
# RUN: llvm-mc -filetype=obj -triple=x86_64 /dev/null -o "%t/bar baz.o"
# RUN: llvm-mc -filetype=obj -triple=x86_64 /dev/null -o "%t/#quux$.o"
# RUN: ld.lld -o %t/foo.exe %t/foo.o %t/"bar baz.o" "%t/#quux$.o" --dependency-file=%t/foo.d
-# RUN: FileCheck --match-full-lines -DFILE=%t %s < %t/foo.d
+# RUN: FileCheck --match-full-lines --strict-whitespace -DFILE=%t %s < %t/foo.d
-# CHECK: [[FILE]]{{/|(\\)+}}foo.exe: \
-# CHECK-NEXT: [[FILE]]{{/|(\\)+}}foo.o \
-# CHECK-NEXT: [[FILE]]{{/|(\\)+}}bar\ baz.o \
-# CHECK-NEXT: [[FILE]]{{/|(\\)+}}\#quux$$.o
+# CHECK:[[FILE]]{{/|(\\)+}}foo.exe: \
+# CHECK-NEXT: [[FILE]]{{/|(\\)+}}foo.o \
+# CHECK-NEXT: [[FILE]]{{/|(\\)+}}bar\ baz.o \
+# CHECK-NEXT: [[FILE]]{{/|(\\)+}}\#quux$$.o
# CHECK-EMPTY:
-# CHECK-NEXT: [[FILE]]{{/|(\\)+}}foo.o:
+# CHECK-NEXT:[[FILE]]{{/|(\\)+}}foo.o:
# CHECK-EMPTY:
-# CHECK-NEXT: [[FILE]]{{/|(\\)+}}bar\ baz.o:
+# CHECK-NEXT:[[FILE]]{{/|(\\)+}}bar\ baz.o:
# CHECK-EMPTY:
-# CHECK-NEXT: [[FILE]]{{/|(\\)+}}\#quux$$.o:
+# CHECK-NEXT:[[FILE]]{{/|(\\)+}}\#quux$$.o:
.global _start
_start:
More information about the llvm-commits
mailing list