SwiftPM: Distributing a library both as an XCFramework and built from source

Hi all,

I am building an SDK as a Swift Package, and I would like for it to be built from source, as well as being able to import it using a precompiled XCFramework coming from a url.

It contains 2 products: the SDK and a UI layer that depends on the SDK.

In my head, this would be the package definition for it, even thought this does not work:

let package = Package(
    name: "SDK",
    products: [
        // XCFrameworks
        .library(name: "SDK", targets: ["SDK"]),
        .library(name: "SDKUI", targets: ["SDKUI"]),

        // Built from source
        .library(name: "SDK-OSS", targets: ["SDK-OSS"]),
        .library(name: "SDKUI-OSS", targets: ["SDKUI-OSS"])
    ],
    targets: [
        .target(name: "SDK-OSS", path: "Sources/SDK"),
        .target(name: "SDKUI-OSS", dependencies: ["SDK-OSS"], path: "Sources/SDKUI"),
        .binaryTarget(name: "SDK", url: "https://github.com/[...]]/SDK.xcframework.zip", checksum: "..."),
        .binaryTarget(name: "SDKUI", url: "https://github.com/[...]]/SDKUI.xcframework.zip", checksum: "...")
    ]
)

It does not work because the product name expected by UI when importing SDK does not match

Keeping SDK-OSS as the target name for the SDK layer is not an option either given that the UI layer depends on SDK, and since its module name changes to SDK-OSS when building from source, all the places in the UI layer where I am importing the SDK break. And doing conditional imports everywhere seems like no-go.

#if canImport(SDK)
import SDK
#elseif canImport(SDK-OSS)
import SDK-OSS
#endif

And changing the XCFramework backed targets name to another one does not work either because .binaryTarget requires both the target name and the XCFramework file name to match

Whatever I try, I end up in multiple targets having the same name (similar to what's shared in Multiple Target Issue with SPM). I tried wrapping targets in other targets, as I thought that would solve the graph, but it didn't work either.

Is there any way to differentiate between Product Name and Target Name in a Package definition?

The only solution I have found so far is have 2 Packages definition, where the one pointing to OSS is hosted in the same repo as the source, and the one using XCFrameworks is hosted in another repo. But this is far from ideal.

Thank you in advance,
Pol

1 Like

A good mechanism to support both source and binary distributions would be a key enabler for what is, by far, Firebase's most requested Swift Package Manager related feature request - Support for Swift Package Manager binaryTarget by providing xcframework in a release · Issue #6564 · firebase/firebase-ios-sdk · GitHub

2 Likes