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
