If you’re developing a QuickLook plugin using Swift,
make sure you flip on the
EMBEDDED_CONTENT_CONTAINS_SWIFT build setting for
the target, otherwise bundle loading will fail in a spectacularly unhelpful
Creating a Mixed-Language QuickLook Plugin
Recently I decided to add a QuickLook plugin to my ImageSlicer utility app.
The default QuickLook plugin template stamps out an entirely C plugin.
Changing the thumbnail/preview template files to have a
put us back in Obj-C land, but getting to Swift land takes a couple more steps.
Not to worry: Add a new Swift file to the target, and Xcode will offer to make bridging easy-peasy for you. Give it the go-ahead, and you should be good to go, right?
I add the main model and view classes from my app project to the QuickLook target, wire stuff up to load the document and render the view, and everything compiles and links all happy-like. Let’s test this thing!
I fire up qlmanage, point it at my generator and a
and I see That Error:
The bundle “QuickLookSlicedImage” couldn’t be loaded because it is damaged or missing necessary resources.
I’ve seen this error way too many times when I grab an older app bundle off the Internet. Every time before, “damaged or missing necessary resources” has been code for “no-one signed this app bundle”.
I’m asking the system to execute code, so, sure, that kind of makes sense?
I hare off looking at using
spctl to whitelist my bundle,
successfully whitelist it with
spctl --add --label JWSDev path/to/QuickLookSlicedImage.qlgenerator,
spctl --assess is OK with it.
Let’s try again.
I see the same error. Hrm. What if it really is missing something? Now I want to see the smoking gun.
After sufficient rooting around, I eventually work through to where it loads
the bundle, then the plugin, then finally to where the real business happens:
After the call to
CFBundle machinery checked for success with
dlerror, and that gave me an actually informative error message
(which I’ve abbreviated and hard-wrapped for readability):
(lldb) x/s $rax
0x100576819: "dlopen(LONG_PATH/QuickLookSlicedImage, 262):
Library not loaded: @rpath/libswiftAppKit.dylib\n
Referenced from: LONG_PATH/QuickLookSlicedImage\n
Reason: image not found"
Yup, missing Swift dylibs.
The fix is to tell Xcode to copy all the Swift dylibs the built product needs
into its bundle using the build setting
(The other fix is to ensure
qlmanage is actually running the generator
you’re building now, not the generator embedded in the copy of your app
you built an hour or two ago that still has the missing-dylib issue.
The take-away is this:
- When Xcode offers to add a Swift–Obj-C bridging header for you,
- Then that means the target was not previously configured for Swift,
- And you should probably ensure that
EMBEDDED_CONTENT_CONTAINS_SWIFT=YESgets set for the target.
The “probably” is there because, if you’re baking it into an app bundle that’s already embedding the Swift dylibs, you could probably mess with the rpath to get it to share those rather than having Yet Another Copy of the Swift support dylibs in your app bundle.
But that’ll be a pain, and disk space is cheap, so you’ll probably still want
to just flip on