Bug with .binaryTarget in Swift Packages with Xcode?

I'm building an App's test target with xcodebuild. The test target includes tests from a Swift Package, which has an XCFramework .binaryTarget—SwiftProtobuf.xcframework. We have used a symlink to link from a directory inside the Swift Package's directory, to the XCFramework, since you can't include a .binaryTarget from outside the Package's own directory structure (which isn't a bug, but nonetheless, is really dang annoying).

The build itself will encounter the error:

/REDACTED/TensorManifold/Sources/TensorManifold/base.pb.swift:13:8: 
error: no such module 'SwiftProtobuf'
import SwiftProtobuf

This error happens BEFORE we get to this build step:

ProcessXCFramework /REDACTED/TensorManifold/lib/SwiftProtobuf.xcframework 
(in target 'TensorManifold' from project 'TensorManifold')

The build command that was run:

set -o pipefail && env NSUnbufferedIO=YES xcodebuild \
 -workspace REDACTED.xcworkspace \
 -scheme AllUnitTests -configuration Debug_Testing \ 
 -derivedDataPath /private/tmp/build/REDACTED/ios/fastlane/output/derivedData \
 -destination 'platform=iOS Simulator,name=iPhone 7,OS=14.3' \
  clean build-for-testing

Here is what our Package.swift looks like:

import PackageDescription

let package = Package(
    name: "TensorManifold",
    platforms: [
        .iOS(.v13),
    ],
    products: [
        .library(
            name: "TensorManifold",
            targets: ["TensorManifold", "SwiftProtobuf"]
        ),
    ],
    dependencies: [
    ],
    targets: [
        .target(
            name: "TensorManifold",
            dependencies: ["SwiftProtobuf"]
        ),
        .binaryTarget(
            name: "SwiftProtobuf",
            path: "lib/SwiftProtobuf.xcframework" // this is a symlink
                                            // it builds just fine in Xcode
        ),
    ]
)
2 Likes

Another bizarre thing about this bug is that it seems to be quite intermittent. Our CI system has several fastlane "lanes" that each get built on a separate Mac. For reasons unknown, sometimes they will fail with the above-mentioned error, where SPM acts like like SwiftProtobuf doesn't exist:

/REDACTED/TensorManifold/Sources/TensorManifold/base.pb.swift:13:8: 
error: no such module 'SwiftProtobuf'
import SwiftProtobuf

I can assure you in all these cases, SwiftProtobuf.xcframework does in fact exist, and the path "lib/SwiftProtobuf.xcframework" is a valid path (it's a symlink to where the actual XCFramework is kept).

Can anyone think of a reason why this should fail intermittently like that?

Reading further, it seems there have been a lot of problems with using .binaryTarget in SPM, such as Xcode not signing them, or Xcode not copying them into the build folder before trying to compile the code in the module, etc.

It has started to occur to me—what we need is a way to list an XCFramework in the "dependencies" section of a Swift package. "Target" should only be used for when the binary is published as part of your package.

It seems .binaryTarget was created as a way to let someone wrap an XCFramework inside of a Swift Package so they can publish a closed-source package, like how Google now publishes Firebase.

But what we users need, is a way to link an XCFramework (that doesn't have a Swift package) into a locally-declared Swift package (that's not published anywhere and which we're basically just using as a way to avoid using .xcproj files to organize code in our app).

2 Likes
Terms of Service

Privacy Policy

Cookie Policy