Xcode 13 Breaks Linking to macOS Private Frameworks?

Since Apple withdrew the API for accessing Safari bookmarks ten years ago and is still working on a replacement API (FB5929825 and FB7772296), my macOS apps (Notarized Developer ID) have accessed Safari bookmarks via an XPC service which links to /System/Library/PrivateFrameworks/Safari.framework. Doing this requires that the XPC service' Build Settings have the following Other Linker Flags:

-weak_framework Safari
-Wl,-dyld_env -Wl,DYLD_VERSIONED_FRAMEWORK_PATH=/System/Library/StagedFrameworks/Safari

(The above is complicated by the fact that the target Safari framework can sometimes be in a staged framework depending on Apple's development cycle.)

Anyhow, upon trying to build with Xcode 13 for the first time this morning, I found that the Ld command fails when linking my XPC service, emitting this error:

Undefined symbols for architecture arm64:

  "_OBJC_CLASS_$_WebBookmarkList", referenced from:

      objc-class-ref in SheepSafariHelper.o

ld: symbol(s) not found for architecture arm64

The class WebBookmarkList is indeed defined in the Safari private framework and is apparently the first such class that it attempts to link to.

I know that Safari framework is still there, because my app still builds and links with no errors in Xcode 12.5, and runs OK in macOS 12. (I am running both Xcodes in macOS 12.)

Does anyone know what changed in Xcode 13, and is there a workaround?

  • I'm surprised no one else is mee-too-ing this. Just to confirm, I have tried it several more times since yesterday. Build in Xcode 12.5 – no problem. Quit Xcode 12.5, launch Xcode 13, same project, same target, same scheme, have not changed anything. Build – fails as described above.

Add a Comment

Accepted Reply

At the Silicon Valley, CA NSCoderNight meeting last night, Brian Webster of Fat Cat Software dug into Xcode and found the answer for me. Short version: In general, Xcode 13 can still link to Apple private frameworks. The issue is the SDK.

Brian compared the text-based dynamic library description file…

Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/System/Library/PrivateFrameworks/Safari.framework/Versions/A/Safari.tbd

between Xcode 12 and Xcode 13. In the section objc-classes, in the Xcode 12 SDK there is a class named WebBookmarkList as expected, but in the Xcode 13 SDK that has been replaced with SafariWebBookmarkList.

When today I changed the symbol name in my project to the new name, now it builds in Xcode 13.

But then, how can my code with the old class name still run in macOS 12? Apparently, for some reason, at least for now, macOS 12 is shipping with both the new and old Safari private frameworks.

So now, in the words of songwriters Joe Henry and Rhiannon Giddens,

I don't know where I'm going • But I'm on my way • Lord if you love me • Keep me I pray :))

Replies

At the Silicon Valley, CA NSCoderNight meeting last night, Brian Webster of Fat Cat Software dug into Xcode and found the answer for me. Short version: In general, Xcode 13 can still link to Apple private frameworks. The issue is the SDK.

Brian compared the text-based dynamic library description file…

Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/System/Library/PrivateFrameworks/Safari.framework/Versions/A/Safari.tbd

between Xcode 12 and Xcode 13. In the section objc-classes, in the Xcode 12 SDK there is a class named WebBookmarkList as expected, but in the Xcode 13 SDK that has been replaced with SafariWebBookmarkList.

When today I changed the symbol name in my project to the new name, now it builds in Xcode 13.

But then, how can my code with the old class name still run in macOS 12? Apparently, for some reason, at least for now, macOS 12 is shipping with both the new and old Safari private frameworks.

So now, in the words of songwriters Joe Henry and Rhiannon Giddens,

I don't know where I'm going • But I'm on my way • Lord if you love me • Keep me I pray :))