https://github.com/pvelesko updated 
https://github.com/llvm/llvm-project/pull/216940

>From 26a899e7f57d89d3bfc537c013dda695ef56ae92 Mon Sep 17 00:00:00 2001
From: Paulius Velesko <[email protected]>
Date: Wed, 14 Oct 2026 05:36:29 +0300
Subject: [PATCH 1/3] [LinkerWrapper] Look for MachO library names when the
 host is Darwin

`-lfoo` was resolved by looking for `libfoo.so` and `libfoo.a` on every
host that is not Windows, so on a MachO host a library that exists only
as `libfoo.dylib` or as the text based stub `libfoo.tbd` was reported as
missing and the link failed with `unable to find library -lfoo`.

Look for the names ld64 looks for, in its order: `libfoo.tbd`,
`libfoo.dylib`, `libfoo.so`, then `libfoo.a` (the same list as
`findLibrary` in lld/MachO/Driver.cpp). Neither a stub nor a dylib holds
offloading code the wrapper can extract; finding them only keeps the
wrapper from rejecting a library the host linker will accept.
---
 .../clang-linker-wrapper/linker-wrapper.c         |  8 ++++++++
 .../clang-linker-wrapper/ClangLinkerWrapper.cpp   | 15 +++++++++------
 2 files changed, 17 insertions(+), 6 deletions(-)

diff --git a/clang/test/OffloadTools/clang-linker-wrapper/linker-wrapper.c 
b/clang/test/OffloadTools/clang-linker-wrapper/linker-wrapper.c
index 550cab4b0604de..42842835a97755 100644
--- a/clang/test/OffloadTools/clang-linker-wrapper/linker-wrapper.c
+++ b/clang/test/OffloadTools/clang-linker-wrapper/linker-wrapper.c
@@ -190,6 +190,14 @@ __attribute__((visibility("protected"), used)) int x;
 
 // COFF-WHOLE-ARCHIVE: clang{{.*}} --target=nvptx64-nvidia-cuda -march=sm_70 
{{[^ ]*}}.o{{$}}
 
+// RUN: rm -rf %t.dir && mkdir -p %t.dir
+// RUN: touch %t.dir/libfoo.dylib %t.dir/libbar.tbd
+// RUN: clang-linker-wrapper --dry-run --host-triple=x86_64-apple-macosx15.0.0 
\
+// RUN:   --linker-path=/usr/bin/ld -L%t.dir -lfoo -lbar %t.elf.o -o a.out 
2>&1 \
+// RUN:   | FileCheck %s --check-prefix=MACHO-LIBRARY
+
+// MACHO-LIBRARY: ld{{.*}} {{.*}}.o -o a.out
+
 // 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 069ac3d23c643f..53184dcc8a526f 100644
--- a/clang/tools/clang-linker-wrapper/ClangLinkerWrapper.cpp
+++ b/clang/tools/clang-linker-wrapper/ClangLinkerWrapper.cpp
@@ -1233,11 +1233,15 @@ findFromSearchPaths(StringRef Name, StringRef Root,
 
 std::optional<std::string>
 searchLibraryBaseName(StringRef Name, StringRef Root,
-                      ArrayRef<StringRef> SearchPaths, bool IsWindows) {
+                      ArrayRef<StringRef> SearchPaths,
+                      const llvm::Triple &HostTriple) {
   SmallVector<std::string> Candidates;
-  if (IsWindows)
+  if (HostTriple.isOSWindows())
     Candidates = {"lib" + Name.str() + ".dll.a", Name.str() + ".dll.a",
                   "lib" + Name.str() + ".a", Name.str() + ".lib"};
+  else if (HostTriple.isOSBinFormatMachO())
+    Candidates = {"lib" + Name.str() + ".tbd", "lib" + Name.str() + ".dylib",
+                  "lib" + Name.str() + ".so", "lib" + Name.str() + ".a"};
   else
     Candidates = {"lib" + Name.str() + ".so", "lib" + Name.str() + ".a"};
 
@@ -1252,12 +1256,12 @@ searchLibraryBaseName(StringRef Name, StringRef Root,
 /// `-lfoo` or `-l:libfoo.a`.
 std::optional<std::string> searchLibrary(StringRef Input, StringRef Root,
                                          ArrayRef<StringRef> SearchPaths,
-                                         bool IsWindows) {
+                                         const llvm::Triple &HostTriple) {
   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, IsWindows);
+  return searchLibraryBaseName(Input, Root, SearchPaths, HostTriple);
 }
 
 /// Search for an input file given by name, e.g. `foo.lib`. COFF linkers use
@@ -1370,8 +1374,7 @@ getDeviceInput(const ArgList &Args) {
 
     std::optional<std::string> Filename =
         Arg->getOption().matches(OPT_library)
-            ? searchLibrary(Arg->getValue(), Root, LibraryPaths,
-                            HostTriple.isOSWindows())
+            ? searchLibrary(Arg->getValue(), Root, LibraryPaths, HostTriple)
             : searchInput(Arg->getValue(), Root, InputPaths);
 
     if (!Filename && Arg->getOption().matches(OPT_library))

>From 5a586a040def084aa2fea2578b6b48175035d055 Mon Sep 17 00:00:00 2001
From: Paulius Velesko <[email protected]>
Date: Wed, 14 Oct 2026 05:36:58 +0300
Subject: [PATCH 2/3] [LinkerWrapper] Search ld64's default library paths under
 -syslibroot

Clang hands ld64 the SDK with `-syslibroot`, and ld64 looks for `-l`
libraries in `/usr/lib` and `/usr/local/lib` underneath it. The linker
wrapper only searched the paths given with `-L`, so `-lSystem` and every
other library that lives in the SDK was reported as missing and the link
failed before the host linker ran.

Parse `-syslibroot` and search ld64's default paths under each of them
after the `-L` paths, as lld's MachO port does. The option is still
forwarded to the host linker unchanged.

ld64 also applies `-syslibroot` to the `-L` paths, ignores earlier roots
when the last one is `/`, and skips its default paths under `-Z`; none
of that is modelled here.
---
 .../OffloadTools/clang-linker-wrapper/linker-wrapper.c     | 7 +++++++
 clang/tools/clang-linker-wrapper/ClangLinkerWrapper.cpp    | 5 +++++
 clang/tools/clang-linker-wrapper/LinkerWrapperOpts.td      | 3 +++
 3 files changed, 15 insertions(+)

diff --git a/clang/test/OffloadTools/clang-linker-wrapper/linker-wrapper.c 
b/clang/test/OffloadTools/clang-linker-wrapper/linker-wrapper.c
index 42842835a97755..0f10c58f5c7d8a 100644
--- a/clang/test/OffloadTools/clang-linker-wrapper/linker-wrapper.c
+++ b/clang/test/OffloadTools/clang-linker-wrapper/linker-wrapper.c
@@ -198,6 +198,13 @@ __attribute__((visibility("protected"), used)) int x;
 
 // MACHO-LIBRARY: ld{{.*}} {{.*}}.o -o a.out
 
+// RUN: mkdir -p %t.dir/sdk/usr/lib && touch %t.dir/sdk/usr/lib/libbaz.tbd
+// RUN: clang-linker-wrapper --dry-run --host-triple=x86_64-apple-macosx15.0.0 
\
+// RUN:   --linker-path=/usr/bin/ld -syslibroot %t.dir/sdk -lbaz %t.elf.o -o 
a.out 2>&1 \
+// RUN:   | FileCheck %s --check-prefix=MACHO-SYSLIBROOT
+
+// MACHO-SYSLIBROOT: ld{{.*}} -syslibroot {{.*}}sdk {{.*}}.o -o a.out
+
 // 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 53184dcc8a526f..c22c0a3e30917a 100644
--- a/clang/tools/clang-linker-wrapper/ClangLinkerWrapper.cpp
+++ b/clang/tools/clang-linker-wrapper/ClangLinkerWrapper.cpp
@@ -1358,6 +1358,11 @@ getDeviceInput(const ArgList &Args) {
   BumpPtrAllocator Alloc;
   StringSaver Saver(Alloc);
 
+  // ld64 also searches its default library paths under each -syslibroot.
+  for (StringRef Dir : {"/usr/lib", "/usr/local/lib"})
+    for (const opt::Arg *Arg : Args.filtered(OPT_syslibroot))
+      LibraryPaths.push_back(Saver.save(Twine(Arg->getValue()) + Dir));
+
   // Try to extract device code from the linker input files.
   bool WholeArchive = Args.hasArg(OPT_wholearchive_flag);
   SmallVector<OffloadFile> ObjectFilesToExtract;
diff --git a/clang/tools/clang-linker-wrapper/LinkerWrapperOpts.td 
b/clang/tools/clang-linker-wrapper/LinkerWrapperOpts.td
index fc48eac2637eeb..fa2ee096e9a5a7 100644
--- a/clang/tools/clang-linker-wrapper/LinkerWrapperOpts.td
+++ b/clang/tools/clang-linker-wrapper/LinkerWrapperOpts.td
@@ -136,6 +136,9 @@ def relocatable : Flag<["--", "-"], "relocatable">,
     HelpText<"Link device code to create a relocatable offloading 
application">;
 def r : Flag<["-"], "r">, Alias<relocatable>;
 
+// ld64-style linker options.
+def syslibroot : Separate<["-"], "syslibroot">, Flags<[HelpHidden]>;
+
 // link.exe-style linker options.
 def out : Joined<["/", "-", "/?", "-?"], "out:">, Flags<[HelpHidden]>;
 def libpath : Joined<["/", "-", "/?", "-?"], "libpath:">, Flags<[HelpHidden]>;

>From 3d015ce146ab0c14b9c244a9a01682e697ca2da1 Mon Sep 17 00:00:00 2001
From: Paulius Velesko <[email protected]>
Date: Sat, 17 Oct 2026 21:16:25 +0300
Subject: [PATCH 3/3] [LinkerWrapper] Move the MachO library lookup tests to an
 ungated test

The lookup needs no registered target and runs on any host, so it should not 
inherit linker-wrapper.c's target and Windows gating.
---
 .../linker-wrapper-macho-library.c               | 16 ++++++++++++++++
 .../clang-linker-wrapper/linker-wrapper.c        | 15 ---------------
 2 files changed, 16 insertions(+), 15 deletions(-)
 create mode 100644 
clang/test/OffloadTools/clang-linker-wrapper/linker-wrapper-macho-library.c

diff --git 
a/clang/test/OffloadTools/clang-linker-wrapper/linker-wrapper-macho-library.c 
b/clang/test/OffloadTools/clang-linker-wrapper/linker-wrapper-macho-library.c
new file mode 100644
index 00000000000000..7b24c00a5da042
--- /dev/null
+++ 
b/clang/test/OffloadTools/clang-linker-wrapper/linker-wrapper-macho-library.c
@@ -0,0 +1,16 @@
+// Check that -l and -syslibroot are resolved the way ld64 does for a MachO 
host.
+
+// RUN: rm -rf %t.dir && mkdir -p %t.dir
+// RUN: touch %t.dir/in.o %t.dir/libfoo.dylib %t.dir/libbar.tbd
+// RUN: clang-linker-wrapper --dry-run --host-triple=x86_64-apple-macosx15.0.0 
\
+// RUN:   --linker-path=/usr/bin/ld -L%t.dir -lfoo -lbar %t.dir/in.o -o a.out 
2>&1 \
+// RUN:   | FileCheck %s --check-prefix=MACHO-LIBRARY
+
+// MACHO-LIBRARY: ld{{.*}} {{.*}}.o -o a.out
+
+// RUN: mkdir -p %t.dir/sdk/usr/lib && touch %t.dir/sdk/usr/lib/libbaz.tbd
+// RUN: clang-linker-wrapper --dry-run --host-triple=x86_64-apple-macosx15.0.0 
\
+// RUN:   --linker-path=/usr/bin/ld -syslibroot %t.dir/sdk -lbaz %t.dir/in.o 
-o a.out 2>&1 \
+// RUN:   | FileCheck %s --check-prefix=MACHO-SYSLIBROOT
+
+// MACHO-SYSLIBROOT: ld{{.*}} -syslibroot {{.*}}sdk {{.*}}.o -o a.out
diff --git a/clang/test/OffloadTools/clang-linker-wrapper/linker-wrapper.c 
b/clang/test/OffloadTools/clang-linker-wrapper/linker-wrapper.c
index 0f10c58f5c7d8a..550cab4b0604de 100644
--- a/clang/test/OffloadTools/clang-linker-wrapper/linker-wrapper.c
+++ b/clang/test/OffloadTools/clang-linker-wrapper/linker-wrapper.c
@@ -190,21 +190,6 @@ __attribute__((visibility("protected"), used)) int x;
 
 // COFF-WHOLE-ARCHIVE: clang{{.*}} --target=nvptx64-nvidia-cuda -march=sm_70 
{{[^ ]*}}.o{{$}}
 
-// RUN: rm -rf %t.dir && mkdir -p %t.dir
-// RUN: touch %t.dir/libfoo.dylib %t.dir/libbar.tbd
-// RUN: clang-linker-wrapper --dry-run --host-triple=x86_64-apple-macosx15.0.0 
\
-// RUN:   --linker-path=/usr/bin/ld -L%t.dir -lfoo -lbar %t.elf.o -o a.out 
2>&1 \
-// RUN:   | FileCheck %s --check-prefix=MACHO-LIBRARY
-
-// MACHO-LIBRARY: ld{{.*}} {{.*}}.o -o a.out
-
-// RUN: mkdir -p %t.dir/sdk/usr/lib && touch %t.dir/sdk/usr/lib/libbaz.tbd
-// RUN: clang-linker-wrapper --dry-run --host-triple=x86_64-apple-macosx15.0.0 
\
-// RUN:   --linker-path=/usr/bin/ld -syslibroot %t.dir/sdk -lbaz %t.elf.o -o 
a.out 2>&1 \
-// RUN:   | FileCheck %s --check-prefix=MACHO-SYSLIBROOT
-
-// MACHO-SYSLIBROOT: ld{{.*}} -syslibroot {{.*}}sdk {{.*}}.o -o a.out
-
 // 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

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

Reply via email to