iosswiftmacosswift-package-managerxcframework

Build project with binary framework using swift CLI


I am building a swift package and it depends on a xcframework binary. I want to build this swift package using only the CLI, not Xcode, so I can do swift build and swift test to see if things works locally and in the CI.

The package works as expected with the binary when using it in Xcode (for both build & test); I also achieved to run swift build successfully, but when it comes to test, it fails with the error:

Undefined symbols for architecture x86_64:
ld: symbol(s) not found for architecture x86_64
[0/1] Linking PolywrapClientPackageTests
error: fatalError

After a lot of research, the reason of this error is because it is not able to find the implementation of the binary (it is saying "I have this header with this methods (as interface) but I don't know where the implementation of this is"). I've seen that I would need to modify the linkerSettings in my Package.swift in order to link it, but I haven't been able to... I have tried to add the -F argument and pass the path of the Frameworks folder but it doesn't work .

Its worth mentioning that when trying to import my swift package in another swift package, it throws the same error previously shown; which makes me think that I am missing the same step in both (the test target and in this other project that is importing my swift package).

This is my Package.swift:

// swift-tools-version: 5.7
// The swift-tools-version declares the minimum version of Swift required to build this package.

import PackageDescription

let package = Package(
    name: "PolywrapClient",
    platforms: [.iOS(.v13), .macOS(.v10_15)],
    products: [
        // Products define the executables and libraries a package produces, and make them visible to other packages.
        .library(
            name: "PolywrapClient",
            targets: ["PolywrapClient", "PolywrapClientNative"]),
    ],
    dependencies: [
        // Dependencies declare other packages that this package depends on.
        .package(url: "https://github.com/hirotakan/MessagePacker.git", from: "0.4.7"),
        .package(url: "https://github.com/SwiftyLab/AsyncObjects.git", from: "2.1.0")
    ],
    targets: [
        // Targets are the basic building blocks of a package. A target can define a module or a test suite.
        // Targets can depend on other targets in this package, and on products in packages this package depends on.
        .target(
            name: "PolywrapClient",
            dependencies: ["MessagePacker", "PolywrapClientNative", "AsyncObjects"],
            publicHeadersPath: "include",
            cSettings: [ .headerSearchPath("include") ]
        ),
        .binaryTarget(
            name: "PolywrapClientNative",
            path: "Frameworks/PolywrapClientNative.xcframework"
            // url: "https://github.com/polywrap/swift-client/releases/download/v0.0.1/PolywrapClientNative.xcframework.zip",
            // checksum: "da1b45242f3a9194e23b4f2a595ea8d5b3d9cc912a201066c8b56deedd52d34a"
        ),
        .testTarget(
            name: "PolywrapClientTests",
            dependencies: [
                "PolywrapClient",
            ],
            resources: [ .copy("Cases") ],
            cSettings: [ .headerSearchPath("../../Sources/PolywrapClient/include")]
        )
    ]
)

And this is the link of the project, if someone would like to see it: https://github.com/polywrap/swift-client


Solution

  • At the end, I was able to find the solution. It seems that swift compiler expectes binaries to have lib prefix. So for example, in my xcframework, I had the binaries like PolywrapClientNative.a, just by converting the name to libPolywrapClientNative.a it worked as expected when running swift build and swift test