Make Swift package build using whole module optimization

I am converting an existing Xcode project (framework) into a Swift package. The project must be built using whole module optimization (WMO) otherwise it cannot build (specifically it must compile using whole module).

Steps so far in converting to use SPM: added Package.swift manifest to the root of the framework project, set target paths to custom sources folders, pushed the project to Github and to test this, added the Swift package as a dependency to a local app project. Problem: The package will not build when I build the app project. (The build error is the usual error I get when not using WMO.) This is true even if the containing app project is configured to use whole module compilation.

It seems adding swiftSettings:[.unsafeFlags(["-whole-module-optimization"])] to the manifest file would resolve this, but SPM appears to not allow this setting for published packages: "Error: The package product cannot be used as a dependency of this target because it uses unsafe build flags."

So my question is: How do I get a published Swift package to build using whole module compilation?

(Note: I believe Cocoapods supported this by adding the flag via pod_target_xcconfig setting in the podspec, but I don't see a way to do this with SPM.)

What are you doing that the project cannot compile unless WMO is enabled? I'm surprised you were able to find a way to write code that requires this functionality to be turned on.

SwiftPM always compiles with -whole-module-optimisation turned on when compiling in release mode. You can check the build logs to confirm this.

It's a legacy framework that uses some intricate generics/associated type relationships that won't build using incremental compilation (yields deserialization failures). I suspect it's a compiler bug, but the framework is closed source so can't be attached to a bug report, and therefore can't be reproduced.

I'm not seeing this. In order to get WMO I need to add swiftSettings:[.unsafeFlags(["-whole-module-optimization"])] to the manifest (locally). But this doesn't work for the remote version (as I mentioned).

How are you validating this?

Consider swift-argument-parser. I checked that out, jumped into its home directory, and typed swift build -v -c release. That repeatedly emits -whole-module-optimization into the command line. Similarly, adding a Swift Package dependency to an Xcode project and building in release mode also adds -whole-module-optimization to the command line for building that package: I can see it in the "compiling swift sources" line in the build log.

Additionally, this is a documented behaviour of Swift Package Manager.

1 Like

I see I was building the app project on Debug assuming the package would be Release regardless (took your "always compiles" the wrong way). As soon as I have a moment I will test this again on Release.

Thank you for your valuable feedback.

UPDATE: This problem has been resolved. It was a generics issue causing the compiler to crash (ironically with WMO – the default build mode per @lukasa). I wrongly assumed this to be another build problem I was having which prevented incremental builds (I have also resolved this!). Xcode 12-beta provided more debug info helping me to resolve the issue.