[lld] 3254f46 - [lld/mac] For catalyst outputs, tolerate implicitly linking against mac-only tbd files

Nico Weber via llvm-commits llvm-commits at lists.llvm.org
Sat Apr 23 18:43:56 PDT 2022


Author: Nico Weber
Date: 2022-04-23T21:43:46-04:00
New Revision: 3254f46884d3ec2d6112ab49ba3c470906699cda

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

LOG: [lld/mac] For catalyst outputs, tolerate implicitly linking against mac-only tbd files

Before this,

  clang empty.cc -target x86_64-apple-ios13.1-macabi \
      -framework CoreServices -fuse-ld=lld

would error out with

    ld64.lld: error: path/to/MacOSX.sdk/System/Library/Frameworks/
         CoreServices.framework/Versions/A/Frameworks/CarbonCore.framework/
         Versions/A/CarbonCore.tbd(
             /System/Library/Frameworks/
             CoreServices.framework/Versions/A/Frameworks/CarbonCore.framework/
             Versions/A/CarbonCore) is incompatible with x86_64 (macCatalyst)

Now it works, like with ld64.

Differential Revision: https://reviews.llvm.org/D124336

Added: 
    lld/test/MachO/Inputs/MacOSX.sdk/System/Library/Frameworks/MacOnly-Indirect.framework/MacOnly-Indirect.tbd
    lld/test/MachO/Inputs/MacOSX.sdk/System/Library/Frameworks/MacOnly.framework/MacOnly.tbd

Modified: 
    lld/MachO/Driver.cpp
    lld/MachO/Driver.h
    lld/MachO/DriverUtils.cpp
    lld/MachO/InputFiles.cpp
    lld/MachO/InputFiles.h
    lld/test/MachO/zippered.yaml

Removed: 
    


################################################################################
diff  --git a/lld/MachO/Driver.cpp b/lld/MachO/Driver.cpp
index 23f9f1f1459d2..5b95278a991c3 100644
--- a/lld/MachO/Driver.cpp
+++ b/lld/MachO/Driver.cpp
@@ -327,11 +327,9 @@ static InputFile *addFile(StringRef path, ForceLoad forceLoadArchive,
   case file_magic::macho_dynamically_linked_shared_lib:
   case file_magic::macho_dynamically_linked_shared_lib_stub:
   case file_magic::tapi_file:
-    if (DylibFile *dylibFile = loadDylib(mbref)) {
-      if (isExplicit)
-        dylibFile->explicitlyLinked = true;
+    if (DylibFile *dylibFile =
+            loadDylib(mbref, nullptr, /*isBundleLoader=*/false, isExplicit))
       newFile = dylibFile;
-    }
     break;
   case file_magic::bitcode:
     newFile = make<BitcodeFile>(mbref, "", 0, isLazy);

diff  --git a/lld/MachO/Driver.h b/lld/MachO/Driver.h
index dbfc05a0497cf..355816272f87d 100644
--- a/lld/MachO/Driver.h
+++ b/lld/MachO/Driver.h
@@ -49,7 +49,8 @@ std::string createResponseFile(const llvm::opt::InputArgList &args);
 llvm::Optional<StringRef> resolveDylibPath(llvm::StringRef path);
 
 DylibFile *loadDylib(llvm::MemoryBufferRef mbref, DylibFile *umbrella = nullptr,
-                     bool isBundleLoader = false);
+                     bool isBundleLoader = false,
+                     bool explicitlyLinked = false);
 void resetLoadedDylibs();
 
 // Search for all possible combinations of `{root}/{name}.{extension}`.

diff  --git a/lld/MachO/DriverUtils.cpp b/lld/MachO/DriverUtils.cpp
index 83940b54486ff..95a1183b71d94 100644
--- a/lld/MachO/DriverUtils.cpp
+++ b/lld/MachO/DriverUtils.cpp
@@ -204,11 +204,14 @@ Optional<StringRef> macho::resolveDylibPath(StringRef dylibPath) {
 static DenseMap<CachedHashStringRef, DylibFile *> loadedDylibs;
 
 DylibFile *macho::loadDylib(MemoryBufferRef mbref, DylibFile *umbrella,
-                            bool isBundleLoader) {
+                            bool isBundleLoader, bool explicitlyLinked) {
   CachedHashStringRef path(mbref.getBufferIdentifier());
   DylibFile *&file = loadedDylibs[path];
-  if (file)
+  if (file) {
+    if (explicitlyLinked)
+      file->explicitlyLinked = explicitlyLinked;
     return file;
+  }
 
   DylibFile *newFile;
   file_magic magic = identify_magic(mbref.getBuffer());
@@ -219,7 +222,8 @@ DylibFile *macho::loadDylib(MemoryBufferRef mbref, DylibFile *umbrella,
             ": " + toString(result.takeError()));
       return nullptr;
     }
-    file = make<DylibFile>(**result, umbrella, isBundleLoader);
+    file =
+        make<DylibFile>(**result, umbrella, isBundleLoader, explicitlyLinked);
 
     // parseReexports() can recursively call loadDylib(). That's fine since
     // we wrote the DylibFile we just loaded to the loadDylib cache via the
@@ -234,7 +238,7 @@ DylibFile *macho::loadDylib(MemoryBufferRef mbref, DylibFile *umbrella,
            magic == file_magic::macho_dynamically_linked_shared_lib_stub ||
            magic == file_magic::macho_executable ||
            magic == file_magic::macho_bundle);
-    file = make<DylibFile>(mbref, umbrella, isBundleLoader);
+    file = make<DylibFile>(mbref, umbrella, isBundleLoader, explicitlyLinked);
 
     // parseLoadCommands() can also recursively call loadDylib(). See comment
     // in previous block for why this means we must copy `file` here.

diff  --git a/lld/MachO/InputFiles.cpp b/lld/MachO/InputFiles.cpp
index c57ce60a7898f..0798abf28fe86 100644
--- a/lld/MachO/InputFiles.cpp
+++ b/lld/MachO/InputFiles.cpp
@@ -1134,7 +1134,8 @@ static DylibFile *findDylib(StringRef path, DylibFile *umbrella,
          make_pointee_range(currentTopLevelTapi->documents())) {
       assert(child.documents().empty());
       if (path == child.getInstallName()) {
-        auto file = make<DylibFile>(child, umbrella);
+        auto file = make<DylibFile>(child, umbrella, /*isBundleLoader=*/false,
+                                    /*explicitlyLinked=*/false);
         file->parseReexports(child);
         return file;
       }
@@ -1175,9 +1176,9 @@ static void loadReexport(StringRef path, DylibFile *umbrella,
 }
 
 DylibFile::DylibFile(MemoryBufferRef mb, DylibFile *umbrella,
-                     bool isBundleLoader)
+                     bool isBundleLoader, bool explicitlyLinked)
     : InputFile(DylibKind, mb), refState(RefState::Unreferenced),
-      isBundleLoader(isBundleLoader) {
+      explicitlyLinked(explicitlyLinked), isBundleLoader(isBundleLoader) {
   assert(!isBundleLoader || !umbrella);
   if (umbrella == nullptr)
     umbrella = this;
@@ -1286,7 +1287,7 @@ void DylibFile::parseLoadCommands(MemoryBufferRef mb) {
   }
 }
 
-// Some versions of XCode ship with .tbd files that don't have the right
+// Some versions of Xcode ship with .tbd files that don't have the right
 // platform settings.
 constexpr std::array<StringRef, 4> skipPlatformChecks{
     "/usr/lib/system/libsystem_kernel.dylib",
@@ -1294,10 +1295,19 @@ constexpr std::array<StringRef, 4> skipPlatformChecks{
     "/usr/lib/system/libsystem_pthread.dylib",
     "/usr/lib/system/libcompiler_rt.dylib"};
 
+static bool skipPlatformCheckForCatalyst(const InterfaceFile &interface,
+                                         bool explicitlyLinked) {
+  // Catalyst outputs can link against implicitly linked macOS-only libraries.
+  if (config->platform() != PLATFORM_MACCATALYST || explicitlyLinked)
+    return false;
+  return is_contained(interface.targets(),
+                      MachO::Target(config->arch(), PLATFORM_MACOS));
+}
+
 DylibFile::DylibFile(const InterfaceFile &interface, DylibFile *umbrella,
-                     bool isBundleLoader)
+                     bool isBundleLoader, bool explicitlyLinked)
     : InputFile(DylibKind, interface), refState(RefState::Unreferenced),
-      isBundleLoader(isBundleLoader) {
+      explicitlyLinked(explicitlyLinked), isBundleLoader(isBundleLoader) {
   // FIXME: Add test for the missing TBD code path.
 
   if (umbrella == nullptr)
@@ -1313,7 +1323,8 @@ DylibFile::DylibFile(const InterfaceFile &interface, DylibFile *umbrella,
   inputFiles.insert(this);
 
   if (!is_contained(skipPlatformChecks, installName) &&
-      !is_contained(interface.targets(), config->platformInfo.target)) {
+      !is_contained(interface.targets(), config->platformInfo.target) &&
+      !skipPlatformCheckForCatalyst(interface, explicitlyLinked)) {
     error(toString(this) + " is incompatible with " +
           std::string(config->platformInfo.target));
     return;

diff  --git a/lld/MachO/InputFiles.h b/lld/MachO/InputFiles.h
index 725f02af7b9a5..ca9943605a99b 100644
--- a/lld/MachO/InputFiles.h
+++ b/lld/MachO/InputFiles.h
@@ -184,10 +184,10 @@ class DylibFile final : public InputFile {
   // to the root. On the other hand, if a dylib is being directly loaded
   // (through an -lfoo flag), then `umbrella` should be a nullptr.
   explicit DylibFile(MemoryBufferRef mb, DylibFile *umbrella,
-                     bool isBundleLoader = false);
+                     bool isBundleLoader, bool explicitlyLinked);
   explicit DylibFile(const llvm::MachO::InterfaceFile &interface,
-                     DylibFile *umbrella = nullptr,
-                     bool isBundleLoader = false);
+                     DylibFile *umbrella, bool isBundleLoader,
+                     bool explicitlyLinked);
 
   void parseLoadCommands(MemoryBufferRef mb);
   void parseReexports(const llvm::MachO::InterfaceFile &interface);

diff  --git a/lld/test/MachO/Inputs/MacOSX.sdk/System/Library/Frameworks/MacOnly-Indirect.framework/MacOnly-Indirect.tbd b/lld/test/MachO/Inputs/MacOSX.sdk/System/Library/Frameworks/MacOnly-Indirect.framework/MacOnly-Indirect.tbd
new file mode 100644
index 0000000000000..a7f0322b0fd56
--- /dev/null
+++ b/lld/test/MachO/Inputs/MacOSX.sdk/System/Library/Frameworks/MacOnly-Indirect.framework/MacOnly-Indirect.tbd
@@ -0,0 +1,22 @@
+--- !tapi-tbd
+tbd-version:      4
+targets:          [ x86_64-macos, x86_64-maccatalyst ]
+uuids:
+  - target: x86_64-maccatalyst
+    value:  00000000-0000-0000-0000-000000000000
+  - target: x86_64-macos
+    value:  00000000-0000-0000-0000-000000000000
+install-name:     'MacOnly-Indirect.dylib'
+current-version:  0001.001.1
+reexported-libraries:
+  - targets:      [ x86_64-macos, x86_64-maccatalyst ]
+    libraries:    [ 'MacOnly-reexport.dylib' ]
+--- !tapi-tbd
+tbd-version:      4
+targets:          [ x86_64-macos ]
+uuids:
+  - target: x86_64-macos
+    value:  00000000-0000-0000-0000-000000000000
+install-name:     'MacOnly-reexport.dylib'
+current-version:  0001.001.1
+...

diff  --git a/lld/test/MachO/Inputs/MacOSX.sdk/System/Library/Frameworks/MacOnly.framework/MacOnly.tbd b/lld/test/MachO/Inputs/MacOSX.sdk/System/Library/Frameworks/MacOnly.framework/MacOnly.tbd
new file mode 100644
index 0000000000000..cd9c7da82b4f3
--- /dev/null
+++ b/lld/test/MachO/Inputs/MacOSX.sdk/System/Library/Frameworks/MacOnly.framework/MacOnly.tbd
@@ -0,0 +1,9 @@
+--- !tapi-tbd
+tbd-version:      4
+targets:          [ x86_64-macos ]
+uuids:
+  - target: x86_64-macos
+    value:  00000000-0000-0000-0000-000000000000
+install-name:     'MacOnly.dylib'
+current-version:  0001.001.1
+...

diff  --git a/lld/test/MachO/zippered.yaml b/lld/test/MachO/zippered.yaml
index bc289669e8d0b..1972be4454a47 100644
--- a/lld/test/MachO/zippered.yaml
+++ b/lld/test/MachO/zippered.yaml
@@ -8,6 +8,12 @@
 # RUN: %lld -lSystem -dylib %t/test.dylib %t/test_macos.o -o /dev/null
 # RUN: %no-arg-lld -syslibroot %S/Inputs/MacOSX.sdk -lSystem -dylib -arch x86_64 -platform_version mac-catalyst 13.15.0 14.0 %t/test.dylib %t/test_maccatalyst.o -o /dev/null
 
+
+# RUN: %no-arg-lld -syslibroot %S/Inputs/MacOSX.sdk -lSystem -dylib -arch x86_64 -platform_version mac-catalyst 13.15.0 14.0 %t/test_maccatalyst.o -o /dev/null -framework MacOnly-Indirect
+
+# RUN: not %no-arg-lld -syslibroot %S/Inputs/MacOSX.sdk -lSystem -dylib -arch x86_64 -platform_version mac-catalyst 13.15.0 14.0 %t/test_maccatalyst.o -o /dev/null -framework MacOnly 2>&1 | FileCheck --check-prefix=INCOMPATIBLE %s
+# INCOMPATIBLE: System/Library/Frameworks{{[\\/]}}MacOnly.framework{{[\\/]}}MacOnly.tbd(MacOnly.dylib) is incompatible with x86_64 (macCatalyst)
+
 # RUN: not %no-arg-lld -syslibroot %S/Inputs/MacOSX.sdk -lSystem -dylib -arch x86_64 -platform_version ios 13.15.0 14.0 %t/test.dylib %t/test_ios.o -o /dev/null 2>&1 | FileCheck %s
 # CHECK: test.dylib has platform macOS/macCatalyst, which is 
diff erent from target platform iOS
 


        


More information about the llvm-commits mailing list