[lld] e98ab4a - [lld][MachO] Fix --reproduce paths for non-global symbol lists and SDK libraries/frameworks (#223687)

via llvm-commits llvm-commits at lists.llvm.org
Thu Sep 17 06:54:15 PDT 2026


Author: Xiaoyang Gong
Date: 2026-09-17T09:54:09-04:00
New Revision: e98ab4afe7dfb83d66ddc80a3c81e471f240cc99

URL: https://github.com/llvm/llvm-project/commit/e98ab4afe7dfb83d66ddc80a3c81e471f240cc99
DIFF: https://github.com/llvm/llvm-project/commit/e98ab4afe7dfb83d66ddc80a3c81e471f240cc99.diff

LOG: [lld][MachO] Fix --reproduce paths for non-global symbol lists and SDK libraries/frameworks (#223687)

`--reproduce` currently has two path-rewriting problems:
1. Non-global symbol lists are included in the archive, but their paths
in the response file are not
     relativized.
2. SDK roots and library/framework search paths are relativized
independently. Since the driver does not
reroot relative search paths, replay can fail to find libraries or
frameworks inside the SDK.
  
This patch fixes both by relativizing non-global symbol-list paths and
resolving SDK prefixes before
  relativizing library/framework search paths.

---------

Co-authored-by: Vy Nguyen <1762963+oontvoo at users.noreply.github.com>

Added: 
    lld/test/MachO/reproduce-search-paths.s

Modified: 
    lld/MachO/Driver.cpp
    lld/MachO/Driver.h
    lld/MachO/DriverUtils.cpp
    lld/test/MachO/reproduce.s

Removed: 
    


################################################################################
diff  --git a/lld/MachO/Driver.cpp b/lld/MachO/Driver.cpp
index 8edaff6e38657..5603dcba5a38a 100644
--- a/lld/MachO/Driver.cpp
+++ b/lld/MachO/Driver.cpp
@@ -170,23 +170,10 @@ getSearchPaths(unsigned optionCode, InputArgList &args,
                const SmallVector<StringRef, 2> &systemPaths) {
   std::vector<StringRef> paths;
   StringRef optionLetter{optionCode == OPT_F ? "F" : "L"};
-  for (StringRef path : args::getStrings(args, optionCode)) {
-    // NOTE: only absolute paths are re-rooted to syslibroot(s)
-    bool found = false;
-    if (path::is_absolute(path, path::Style::posix)) {
-      for (StringRef root : roots) {
-        SmallString<261> buffer(root);
-        path::append(buffer, path);
-        // Do not warn about paths that are computed via the syslib roots
-        if (fs::is_directory(buffer)) {
-          paths.push_back(saver().save(buffer.str()));
-          found = true;
-        }
-      }
-    }
-    if (!found && warnIfNotDirectory(optionLetter, path))
-      paths.push_back(path);
-  }
+  for (StringRef path : args::getStrings(args, optionCode))
+    for (StringRef searchPath : getRerootedSearchPaths(path, roots))
+      if (searchPath != path || warnIfNotDirectory(optionLetter, searchPath))
+        paths.push_back(searchPath);
 
   // `-Z` suppresses the standard "system" search paths.
   if (args.hasArg(OPT_Z))

diff  --git a/lld/MachO/Driver.h b/lld/MachO/Driver.h
index bd1cd960768bf..9374dffffd8bd 100644
--- a/lld/MachO/Driver.h
+++ b/lld/MachO/Driver.h
@@ -11,6 +11,7 @@
 
 #include "lld/Common/LLVM.h"
 #include "llvm/ADT/SetVector.h"
+#include "llvm/ADT/SmallVector.h"
 #include "llvm/ADT/StringRef.h"
 #include "llvm/BinaryFormat/MachO.h"
 #include "llvm/Option/OptTable.h"
@@ -49,6 +50,9 @@ void parseLCLinkerOption(llvm::SmallVectorImpl<StringRef> &LCLinkerOptions,
                          InputFile *f, unsigned argc, StringRef data);
 void resolveLCLinkerOptions();
 
+SmallVector<StringRef> getRerootedSearchPaths(StringRef path,
+                                              ArrayRef<StringRef> roots);
+
 std::string createResponseFile(const llvm::opt::InputArgList &args);
 
 // Check for both libfoo.dylib and libfoo.tbd (in that order).

diff  --git a/lld/MachO/DriverUtils.cpp b/lld/MachO/DriverUtils.cpp
index 3ff9d96ed53ce..bbfc4477bb978 100644
--- a/lld/MachO/DriverUtils.cpp
+++ b/lld/MachO/DriverUtils.cpp
@@ -134,6 +134,26 @@ void MachOOptTable::printHelp(CommonLinkerContext &ctx, const char *argv0,
   outs << '\n';
 }
 
+// If any SDK contains the directory, use those directories in SDK order
+// instead of falling back to the host.
+SmallVector<StringRef>
+macho::getRerootedSearchPaths(StringRef searchPath, ArrayRef<StringRef> roots) {
+  SmallVector<StringRef> paths;
+  // NOTE: only absolute paths are re-rooted to syslibroot(s)
+  if (path::is_absolute(searchPath, path::Style::posix)) {
+    for (StringRef root : roots) {
+      SmallString<261> buffer(root);
+      path::append(buffer, searchPath);
+      // Do not warn about paths that are computed via the syslib roots
+      if (fs::is_directory(buffer))
+        paths.push_back(saver().save(buffer.str()));
+    }
+  }
+  if (paths.empty())
+    paths.push_back(searchPath);
+  return paths;
+}
+
 static std::string rewritePath(StringRef s) {
   if (fs::exists(s))
     return relativeToRoot(s);
@@ -178,6 +198,14 @@ std::string macho::createResponseFile(const InputArgList &args) {
       break;
     case OPT_F:
     case OPT_L:
+      // Resolve SDK prefixes before making search paths relative: relative
+      // search paths are not rerooted when the reproducer is replayed.
+      for (StringRef path :
+           getRerootedSearchPaths(arg->getValue(), config->systemLibraryRoots))
+        os << arg->getSpelling() << " " << quote(rewritePath(path)) << "\n";
+      break;
+    case OPT_non_global_symbols_strip_list:
+    case OPT_non_global_symbols_no_strip_list:
     case OPT_bundle_loader:
     case OPT_exported_symbols_list:
     case OPT_order_file:

diff  --git a/lld/test/MachO/reproduce-search-paths.s b/lld/test/MachO/reproduce-search-paths.s
new file mode 100644
index 0000000000000..51e6e0c91f847
--- /dev/null
+++ b/lld/test/MachO/reproduce-search-paths.s
@@ -0,0 +1,48 @@
+# REQUIRES: x86
+# UNSUPPORTED: system-windows
+
+# RUN: rm -rf %t; mkdir -p %t/host %t/sdk1/%:t/host/Foo.framework %t/sdk2/%:t/host/Bar.framework
+# RUN: llvm-mc -filetype=obj -triple=x86_64-apple-macos %s -o %t/foo.o
+# RUN: %no-arg-lld -arch x86_64 -platform_version macos 11.0 11.0 -dylib -Z \
+# RUN:     %t/foo.o -o %t/sdk1/%:t/host/libfoo.dylib
+# RUN: cp %t/sdk1/%:t/host/libfoo.dylib %t/sdk1/%:t/host/Foo.framework/Foo
+# RUN: cp %t/sdk1/%:t/host/libfoo.dylib %t/sdk2/%:t/host/libbar.dylib
+# RUN: cp %t/sdk1/%:t/host/libfoo.dylib %t/sdk2/%:t/host/Bar.framework/Bar
+
+## Libraries and frameworks exist in SDKs only.
+# RUN: %no-arg-lld -arch x86_64 -platform_version macos 11.0 11.0 -dylib -Z \
+# RUN:     -syslibroot %t/sdk1 -syslibroot %t/sdk2 -L %t/host -F %t/host \
+# RUN:     -lfoo -lbar -framework Foo -framework Bar -o %t/out --reproduce %t/repro.tar
+# RUN: cd %t; tar xf repro.tar
+# RUN: FileCheck %s --check-prefix=SDK -DPATH=%:t < repro/response.txt
+# SDK:      -L [[PATH]]/sdk1/[[PATH]]/host
+# SDK-NEXT: -L [[PATH]]/sdk2/[[PATH]]/host
+# SDK-NEXT: -F [[PATH]]/sdk1/[[PATH]]/host
+# SDK-NEXT: -F [[PATH]]/sdk2/[[PATH]]/host
+# RUN: rm -rf sdk1 sdk2
+# RUN: cd repro; %no-arg-lld @response.txt
+
+## Libraries and frameworks exist outside the SDK only.
+## Absolute paths fall back to host directories; relative paths ignore SDK roots.
+# RUN: mkdir -p %t/sdk/relative %t/fallback/Foo.framework %t/relative/Bar.framework
+# RUN: %no-arg-lld -arch x86_64 -platform_version macos 11.0 11.0 -dylib -Z \
+# RUN:     %t/foo.o -o %t/fallback/libfoo.dylib
+# RUN: cp %t/fallback/libfoo.dylib %t/fallback/Foo.framework/Foo
+# RUN: cp %t/fallback/libfoo.dylib %t/relative/libbar.dylib
+# RUN: cp %t/fallback/libfoo.dylib %t/relative/Bar.framework/Bar
+# RUN: cd %t
+# RUN: %no-arg-lld -arch x86_64 -platform_version macos 11.0 11.0 -dylib -Z \
+# RUN:     -syslibroot %t/sdk -L %t/fallback -F %t/fallback -L relative -F relative \
+# RUN:     -lfoo -lbar -framework Foo -framework Bar -o out --reproduce fallback.tar
+# RUN: tar xf fallback.tar
+# RUN: FileCheck %s --check-prefix=FALLBACK -DPATH=%:t < fallback/response.txt
+# FALLBACK:      -L [[PATH]]/fallback
+# FALLBACK-NEXT: -F [[PATH]]/fallback
+# FALLBACK-NEXT: -L [[PATH]]/relative
+# FALLBACK-NEXT: -F [[PATH]]/relative
+# RUN: rm -rf sdk relative fallback/libfoo.dylib fallback/Foo.framework
+# RUN: cd fallback; %no-arg-lld @response.txt
+
+.globl _foo
+_foo:
+  ret

diff  --git a/lld/test/MachO/reproduce.s b/lld/test/MachO/reproduce.s
index 68d94cab2c7ee..f6949fbab068b 100644
--- a/lld/test/MachO/reproduce.s
+++ b/lld/test/MachO/reproduce.s
@@ -7,6 +7,7 @@
 # RUN: llvm-mc -filetype=obj -triple=x86_64-apple-macos %s -o %t.dir/build1/foo.o
 # RUN: echo '_main' > %t.dir/main.exports
 # RUN: echo '_main' > %t.dir/main.order
+# RUN: echo '_local' > %t.dir/main.locals
 # RUN: echo 'not a virus' > %t.dir/sectdata.txt
 # RUN: cd %t.dir
 # RUN: %lld -platform_version macos 10.10.0 11.0 \
@@ -14,6 +15,7 @@
 # RUN:     -order_file main.order \
 # RUN:     -sectcreate __COMPLETELY __legit sectdata.txt \
 # RUN:     -rpath /usr/lib/swift \
+# RUN:     -non_global_symbols_strip_list main.locals \
 # RUN:     build1/foo.o -o bar --reproduce repro1.tar
 
 # RUN: tar tf repro1.tar | FileCheck -DPATH='%:t.dir' --check-prefix=LIST %s
@@ -34,6 +36,7 @@
 # RSP1-NEXT: -order_file [[BASEDIR]]/main.order
 # RSP1-NEXT: -sectcreate __COMPLETELY __legit [[BASEDIR]]/sectdata.txt
 # RSP1-NEXT: -rpath /usr/lib/swift
+# RSP1-NEXT: -non_global_symbols_strip_list [[BASEDIR]]/main.locals
 # RSP1-NOT:  {{^}}repro1{{[/\\]}}
 # RSP1-NEXT: [[BASEDIR]]/build1/foo.o
 # RSP1-NEXT: -o bar
@@ -48,11 +51,14 @@
 # RUN: llvm-mc -filetype=obj -triple=x86_64-apple-macos %s -o %t.dir/build2/foo.o
 # RUN: cd %t.dir/build2/a/b/c
 # RUN: echo ./../../../foo.o > %t.dir/build2/filelist
-# RUN: env LLD_REPRODUCE=repro2.tar %lld -filelist %t.dir/build2/filelist -o /dev/null
+# RUN: env LLD_REPRODUCE=repro2.tar %lld \
+# RUN:     -non_global_symbols_no_strip_list %t.dir/main.locals \
+# RUN:     -filelist %t.dir/build2/filelist -o /dev/null
 # RUN: tar xf repro2.tar
 # RUN: cmp %t.dir/build2/foo.o repro2/%:t.dir/build2/foo.o
-# RUN: FileCheck %s --check-prefix=RSP2 < repro2/response.txt
+# RUN: FileCheck %s --check-prefix=RSP2 -DPATH=%:t.dir < repro2/response.txt
 # RSP2-NOT:  {{^}}repro2{{[/\\]}}
+# RSP2:      -non_global_symbols_no_strip_list [[PATH]]/main.locals
 # RSP2:      {{[/\\]}}foo.o
 
 # RUN: cd repro2; %no-arg-lld @response.txt


        


More information about the llvm-commits mailing list