Swift standard libs missing in macOS app built in Xcode 11.2

Xcode 11.2 / Swift 5.1 appears to only bundle parts of the Standard Library in use by the app. I can compile the same project in Xcode 10.2 and 11.2, and the former contains more Swift libs. This is normally great stuff, but I need to bundle in Swift command line tools that rely on the shared Frameworks and Standard Library located within the .app bundle (I need to support macOS versions below 10.14).
Some of the command line tools will use parts of the standard library not used in the parent app. For example, one of my tools imports and uses os.log, and after compiling in Xcode 11.2, I get an error running the tool because libswiftos.dylib is missing.
I fiddled around with build settings, but could not find any way to force Xcode to include the complete Standard Library, or the parts needed by the tools. I know I can manually add them and link binaries, but that doesn't seem like the right way to do it. I suppose I could also add the .app bundle as a target for the code used in the tools, but that seems foolish as well. Am I missing something obvious?

You or anyone else using your app need to install this: https://support.apple.com/kb/DL1998?locale=en_GB when running on Mojave 10.14.3 or below.

Thanks, I know that's an option, but asking the user to install a separate package would be my last choice. There's no problem with linking the tools with the standard library located inside an app bundle. The issue is that starting in Xcode 11.2, the complete standard library isn't included in the bundle by default. No issue doing this with Swift 5 and Xcode 10.2.

If you turn off dead code stripping, does that change anything?

Dead Code Stripping is set to No.

I'm now using a script that checks each tool's @rpath for Swift dynamic libs, checks whether they're included in the bundle, then copies any that are missing from /usr/lib/swift at build time.

I don’t have time to do a full end-to-end test, but my limited testing suggests that you can get around this by adding the relevant Swift library to the Link Binary With Libraries build phase. For example, I created a test project that doesn’t use SpriteKit, added libswiftSpriteKit.tbd, and saw that the resulting app includes Contents/Frameworks/libswiftSpriteKit.dylib. If I remove the .tbd and rebuild the app, it goes away.

This isn’t a fully automatic solution, but it seems better than your current script. Perhaps you could tweak the script to check that the libraries are there, rather than try to fix it?

Share and Enjoy

Quinn “The Eskimo!” @ DTS @ Apple

1 Like

Thanks @eskimo. That definitely worked in my testing as well. I was just hoping for a more automated solution, and wondered what the "correct" way was. Yes, perhaps I should just let the script perform checks instead. It's not difficult to link a new library, and it's not something that needs to be done often.