https://github.com/jhuber6 updated 
https://github.com/llvm/llvm-project/pull/216239

>From 3ce9b074ade94274d276481f5b5ceaf4eb99b63f Mon Sep 17 00:00:00 2001
From: Joseph Huber <[email protected]>
Date: Thu, 13 Aug 2026 22:46:41 -0500
Subject: [PATCH 1/2] [LinkerWrapper] Fix search paths for Windows link style
 invocations

Summary:
The windows link patterns were slightly wrong because `foo.lib` on the
command line as an input implies searching. We track this for the
`-libpath` argument and search them now as the linker would.
Additionally, fixes a problem with whole-archive not being handled
properly.
---
 .../clang-linker-wrapper/linker-wrapper.c     | 18 ++++++++++
 .../ClangLinkerWrapper.cpp                    | 33 ++++++++++++++++---
 .../clang-linker-wrapper/LinkerWrapperOpts.td |  7 ++--
 3 files changed, 51 insertions(+), 7 deletions(-)

diff --git a/clang/test/OffloadTools/clang-linker-wrapper/linker-wrapper.c 
b/clang/test/OffloadTools/clang-linker-wrapper/linker-wrapper.c
index eebae1a0cc153..e6026f79398c7 100644
--- a/clang/test/OffloadTools/clang-linker-wrapper/linker-wrapper.c
+++ b/clang/test/OffloadTools/clang-linker-wrapper/linker-wrapper.c
@@ -169,6 +169,24 @@ __attribute__((visibility("protected"), used)) int x;
 
 // COFF: "/usr/bin/lld-link" {{.*}}.o -libpath:./ -out:a.exe 
{{.*}}openmp.image.wrapper{{.*}}
 
+// RUN: rm -rf %t.dir && mkdir -p %t.dir
+// RUN: llvm-ar rcs %t.dir/foo.lib %t.o
+// RUN: llvm-ar rcs %t.dir/libbar.dll.a %t.o
+// RUN: clang-linker-wrapper --host-triple=x86_64-unknown-windows-msvc 
--dry-run \
+// RUN:   --linker-path=/usr/bin/lld-link %t.o -libpath:%t.dir foo.lib 
-out:a.exe 2>&1 \
+// RUN:   | FileCheck %s --check-prefix=COFF-LIBRARY
+// RUN: clang-linker-wrapper --host-triple=x86_64-w64-windows-gnu --dry-run \
+// RUN:   --linker-path=/usr/bin/ld.lld %t.o -L%t.dir -lbar -o a.exe 2>&1 \
+// RUN:   | FileCheck %s --check-prefix=COFF-LIBRARY
+
+// COFF-LIBRARY: clang{{.*}} --target=nvptx64-nvidia-cuda -march=sm_70 
{{.*}}.o {{.*}}.o
+
+// RUN: clang-linker-wrapper --host-triple=x86_64-unknown-windows-msvc 
--dry-run \
+// RUN:   --linker-path=/usr/bin/lld-link -wholearchive:%t.dir/foo.lib 
-out:a.exe 2>&1 \
+// RUN:   | FileCheck %s --check-prefix=COFF-WHOLE-ARCHIVE
+
+// COFF-WHOLE-ARCHIVE: clang{{.*}} --target=nvptx64-nvidia-cuda -march=sm_70 
{{[^ ]*}}.o{{$}}
+
 // RUN: llvm-offload-binary -o %t-lib.out \
 // RUN:   
--image=file=%t.elf.o,kind=openmp,triple=amdgpu9.0a-amd-amdhsa,arch=gfx90a
 // RUN: %clang -cc1 %s -triple x86_64-unknown-linux-gnu -emit-obj -o %t.o 
-fembed-offload-object=%t-lib.out
diff --git a/clang/tools/clang-linker-wrapper/ClangLinkerWrapper.cpp 
b/clang/tools/clang-linker-wrapper/ClangLinkerWrapper.cpp
index f2a58774e99af..4a32962c0dabc 100644
--- a/clang/tools/clang-linker-wrapper/ClangLinkerWrapper.cpp
+++ b/clang/tools/clang-linker-wrapper/ClangLinkerWrapper.cpp
@@ -1261,6 +1261,12 @@ searchLibraryBaseName(StringRef Name, StringRef Root,
     if (std::optional<std::string> File =
             findFile(Dir, Root, "lib" + Name + ".a"))
       return File;
+    // Windows linkers also accept the MinGW and the MSVC spelling of a 
library.
+    if (std::optional<std::string> File =
+            findFile(Dir, Root, "lib" + Name + ".dll.a"))
+      return File;
+    if (std::optional<std::string> File = findFile(Dir, Root, Name + ".lib"))
+      return File;
   }
   return std::nullopt;
 }
@@ -1276,6 +1282,15 @@ std::optional<std::string> searchLibrary(StringRef 
Input, StringRef Root,
   return searchLibraryBaseName(Input, Root, SearchPaths);
 }
 
+/// Search for an input file given by name, e.g. `foo.lib`. COFF linkers use
+/// this in place of `-lfoo` and look it up in \p SearchPaths.
+std::optional<std::string> searchInput(StringRef Input, StringRef Root,
+                                       ArrayRef<StringRef> SearchPaths) {
+  if (sys::fs::exists(Input))
+    return std::string(Input);
+  return findFromSearchPaths(Input, Root, SearchPaths);
+}
+
 /// In verbose mode we need to replay the extracted files so the user can
 /// reproduce the generated. This only prints the steps that would result in 
the
 /// same output files given the input.
@@ -1350,6 +1365,11 @@ getDeviceInput(const ArgList &Args) {
   for (const opt::Arg *Arg : Args.filtered(OPT_library_path, OPT_libpath))
     LibraryPaths.push_back(Arg->getValue());
 
+  // Only `link.exe` style linkers search for their input files.
+  SmallVector<StringRef> InputPaths;
+  for (const opt::Arg *Arg : Args.filtered(OPT_libpath))
+    InputPaths.push_back(Arg->getValue());
+
   BumpPtrAllocator Alloc;
   StringSaver Saver(Alloc);
 
@@ -1358,8 +1378,9 @@ getDeviceInput(const ArgList &Args) {
   SmallVector<OffloadFile> ObjectFilesToExtract;
   SmallVector<OffloadFile> ArchiveFilesToExtract;
   DenseMap<StringRef, StringRef> SourceForImage;
-  for (const opt::Arg *Arg : Args.filtered(
-           OPT_INPUT, OPT_library, OPT_whole_archive, OPT_no_whole_archive)) {
+  for (const opt::Arg *Arg :
+       Args.filtered(OPT_INPUT, OPT_library, OPT_wholearchive_file,
+                     OPT_whole_archive, OPT_no_whole_archive)) {
     if (Arg->getOption().matches(OPT_whole_archive) ||
         Arg->getOption().matches(OPT_no_whole_archive)) {
       WholeArchive = Arg->getOption().matches(OPT_whole_archive);
@@ -1369,7 +1390,7 @@ getDeviceInput(const ArgList &Args) {
     std::optional<std::string> Filename =
         Arg->getOption().matches(OPT_library)
             ? searchLibrary(Arg->getValue(), Root, LibraryPaths)
-            : std::string(Arg->getValue());
+            : searchInput(Arg->getValue(), Root, InputPaths);
 
     if (!Filename && Arg->getOption().matches(OPT_library))
       return createStringError("unable to find library -l%s", Arg->getValue());
@@ -1378,6 +1399,10 @@ getDeviceInput(const ArgList &Args) {
         sys::fs::is_directory(*Filename))
       continue;
 
+    // Unlike `--whole-archive`, `/wholearchive:` applies to a single library.
+    bool ExtractWholeArchive =
+        WholeArchive || Arg->getOption().matches(OPT_wholearchive_file);
+
     ErrorOr<std::unique_ptr<MemoryBuffer>> BufferOrErr =
         MemoryBuffer::getFileOrSTDIN(*Filename);
     if (std::error_code EC = BufferOrErr.getError())
@@ -1397,7 +1422,7 @@ getDeviceInput(const ArgList &Args) {
             Binary.getBinary()->getMemoryBufferRef().getBufferIdentifier(),
             Saver.save(StringRef(*Filename)));
       if (identify_magic(Buffer.getBuffer()) == file_magic::archive &&
-          !WholeArchive)
+          !ExtractWholeArchive)
         ArchiveFilesToExtract.emplace_back(std::move(Binary));
       else
         ObjectFilesToExtract.emplace_back(std::move(Binary));
diff --git a/clang/tools/clang-linker-wrapper/LinkerWrapperOpts.td 
b/clang/tools/clang-linker-wrapper/LinkerWrapperOpts.td
index 53b6c596de291..fc48eac2637ee 100644
--- a/clang/tools/clang-linker-wrapper/LinkerWrapperOpts.td
+++ b/clang/tools/clang-linker-wrapper/LinkerWrapperOpts.td
@@ -120,9 +120,9 @@ def library_path_EQ : Joined<["--", "-"], "library-path=">, 
Flags<[HelpHidden]>,
 def library : JoinedOrSeparate<["-"], "l">, MetaVarName<"<libname>">,
   HelpText<"Search for library <libname>">;
 def library_S : Separate<["--", "-"], "library">, Flags<[HelpHidden]>,
-  Alias<library_path>;
+  Alias<library>;
 def library_EQ : Joined<["--", "-"], "library=">, Flags<[HelpHidden]>,
-  Alias<library_path>;
+  Alias<library>;
 
 def rpath : Separate<["--", "-"], "rpath">;
 def rpath_EQ : Joined<["--", "-"], "rpath=">, Flags<[HelpHidden]>, 
Alias<rpath>;
@@ -139,4 +139,5 @@ def r : Flag<["-"], "r">, Alias<relocatable>;
 // link.exe-style linker options.
 def out : Joined<["/", "-", "/?", "-?"], "out:">, Flags<[HelpHidden]>;
 def libpath : Joined<["/", "-", "/?", "-?"], "libpath:">, Flags<[HelpHidden]>;
-def wholearchive_flag : Joined<["/", "-", "/?", "-?"], "wholearchive">, 
Flags<[HelpHidden]>;
+def wholearchive_file : Joined<["/", "-", "/?", "-?"], "wholearchive:">, 
Flags<[HelpHidden]>;
+def wholearchive_flag : Flag<["/", "-", "/?", "-?"], "wholearchive">, 
Flags<[HelpHidden]>;

>From 2dcba64177df5c91a2a9c1d361534a61d5830c57 Mon Sep 17 00:00:00 2001
From: Joseph Huber <[email protected]>
Date: Fri, 14 Aug 2026 10:55:23 -0500
Subject: [PATCH 2/2] comments

---
 .../clang-linker-wrapper/linker-wrapper.c     |  3 ++
 .../ClangLinkerWrapper.cpp                    | 38 ++++++++++---------
 2 files changed, 23 insertions(+), 18 deletions(-)

diff --git a/clang/test/OffloadTools/clang-linker-wrapper/linker-wrapper.c 
b/clang/test/OffloadTools/clang-linker-wrapper/linker-wrapper.c
index e6026f79398c7..ca2743114cd7b 100644
--- a/clang/test/OffloadTools/clang-linker-wrapper/linker-wrapper.c
+++ b/clang/test/OffloadTools/clang-linker-wrapper/linker-wrapper.c
@@ -184,6 +184,9 @@ __attribute__((visibility("protected"), used)) int x;
 // RUN: clang-linker-wrapper --host-triple=x86_64-unknown-windows-msvc 
--dry-run \
 // RUN:   --linker-path=/usr/bin/lld-link -wholearchive:%t.dir/foo.lib 
-out:a.exe 2>&1 \
 // RUN:   | FileCheck %s --check-prefix=COFF-WHOLE-ARCHIVE
+// RUN: clang-linker-wrapper --host-triple=x86_64-unknown-windows-msvc 
--dry-run \
+// RUN:   --linker-path=/usr/bin/lld-link -libpath:%t.dir 
-wholearchive:foo.lib -out:a.exe 2>&1 \
+// RUN:   | FileCheck %s --check-prefix=COFF-WHOLE-ARCHIVE
 
 // COFF-WHOLE-ARCHIVE: clang{{.*}} --target=nvptx64-nvidia-cuda -march=sm_70 
{{[^ ]*}}.o{{$}}
 
diff --git a/clang/tools/clang-linker-wrapper/ClangLinkerWrapper.cpp 
b/clang/tools/clang-linker-wrapper/ClangLinkerWrapper.cpp
index 4a32962c0dabc..4babfae82805b 100644
--- a/clang/tools/clang-linker-wrapper/ClangLinkerWrapper.cpp
+++ b/clang/tools/clang-linker-wrapper/ClangLinkerWrapper.cpp
@@ -1253,33 +1253,31 @@ findFromSearchPaths(StringRef Name, StringRef Root,
 
 std::optional<std::string>
 searchLibraryBaseName(StringRef Name, StringRef Root,
-                      ArrayRef<StringRef> SearchPaths) {
-  for (StringRef Dir : SearchPaths) {
-    if (std::optional<std::string> File =
-            findFile(Dir, Root, "lib" + Name + ".so"))
-      return File;
-    if (std::optional<std::string> File =
-            findFile(Dir, Root, "lib" + Name + ".a"))
-      return File;
-    // Windows linkers also accept the MinGW and the MSVC spelling of a 
library.
-    if (std::optional<std::string> File =
-            findFile(Dir, Root, "lib" + Name + ".dll.a"))
-      return File;
-    if (std::optional<std::string> File = findFile(Dir, Root, Name + ".lib"))
-      return File;
-  }
+                      ArrayRef<StringRef> SearchPaths, bool IsWindows) {
+  SmallVector<std::string> Candidates;
+  if (IsWindows)
+    Candidates = {"lib" + Name.str() + ".dll.a", Name.str() + ".dll.a",
+                  "lib" + Name.str() + ".a", Name.str() + ".lib"};
+  else
+    Candidates = {"lib" + Name.str() + ".so", "lib" + Name.str() + ".a"};
+
+  for (StringRef Dir : SearchPaths)
+    for (StringRef Candidate : Candidates)
+      if (std::optional<std::string> File = findFile(Dir, Root, Candidate))
+        return File;
   return std::nullopt;
 }
 
 /// Search for static libraries in the linker's library path given input like
 /// `-lfoo` or `-l:libfoo.a`.
 std::optional<std::string> searchLibrary(StringRef Input, StringRef Root,
-                                         ArrayRef<StringRef> SearchPaths) {
+                                         ArrayRef<StringRef> SearchPaths,
+                                         bool IsWindows) {
   if (Input.starts_with(":"))
     return findFromSearchPaths(Input.drop_front(), Root, SearchPaths);
   if (Input.ends_with(".lib"))
     return findFromSearchPaths(Input, Root, SearchPaths);
-  return searchLibraryBaseName(Input, Root, SearchPaths);
+  return searchLibraryBaseName(Input, Root, SearchPaths, IsWindows);
 }
 
 /// Search for an input file given by name, e.g. `foo.lib`. COFF linkers use
@@ -1360,6 +1358,9 @@ getDeviceInput(const ArgList &Args) {
   if (Args.hasArg(OPT_override_image))
     return SmallVector<SmallVector<OffloadFile>>();
 
+  const llvm::Triple HostTriple(
+      Args.getLastArgValue(OPT_host_triple_EQ, sys::getDefaultTargetTriple()));
+
   StringRef Root = Args.getLastArgValue(OPT_sysroot_EQ);
   SmallVector<StringRef> LibraryPaths;
   for (const opt::Arg *Arg : Args.filtered(OPT_library_path, OPT_libpath))
@@ -1389,7 +1390,8 @@ getDeviceInput(const ArgList &Args) {
 
     std::optional<std::string> Filename =
         Arg->getOption().matches(OPT_library)
-            ? searchLibrary(Arg->getValue(), Root, LibraryPaths)
+            ? searchLibrary(Arg->getValue(), Root, LibraryPaths,
+                            HostTriple.isOSWindows())
             : searchInput(Arg->getValue(), Root, InputPaths);
 
     if (!Filename && Arg->getOption().matches(OPT_library))

_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to