cswiftswift-package-managerswiftpm

SwiftPM Framework not found for C library


I am working on creating a Swift wrapper for an existing C library, using Swift Package Manager. I think i have structured everything properly, but I am getting an error when create and build an Xcode project. I have tried everything I could find, with no luck. Officially leaving me stumped.

Here is a link to the project in its current state: https://github.com/JKcompute/Camiitool/tree/stackpost

Here is my Package.swift

// swift-tools-version:5.3
import PackageDescription

let package = Package(
    name: "CamiitoolPackage",
    products: [
        .library(name: "Camiitool", targets: ["Camiitool"]),
        .library(name: "amiitoolSwift", targets: ["amiitoolSwift"]),
    ],
    dependencies: [
    ],
    targets: [
        .target(
            name: "amiitoolSwift",
            dependencies: [ 
               "Camiitool"
            ],
            path: "./Sources/amiitoolSwift"
        ),

        .target(
            name: "Camiitool",
            dependencies: [ 
                "mbedtls"
            ],
            path: "./Sources/Camiitool",
            exclude: [
                "mbedtls",
                "LICENSE"
            ],
            resources: [
                .copy("."),
            ]
        ),
        .target(
            name: "mbedtls",
            dependencies: [],
            path: "./Sources/Camiitool/mbedtls",
            exclude: [
                "./mbedtls/yotta",
                "./mbedtls/visualc",
                "LICENSE"
            ],
            resources: [
                .copy("."),
            ]
        ),  

        .testTarget(
            name: "amiitoolSwiftTests",
            dependencies: ["amiitoolSwift"]
        )
    ]
)

So what I have here is Camiitool is the C library Amiitool. Amiitool depends on mbedtls. So i have a target for mbedtls, Camiitool, and then i also have one for amiitoolSwift, which i plan on having my swift API.

Here is my swift file from the amiitoolSwift target. Note: its very basic right now, just for testing.

import Foundation
import Camiitool

public class Amii {
    var someString = "test"

    public init() {
        someString = "initialized"
    }
    
    public func printTest() {
        print(someString)
    }

     public func methodJustForTesting() {
        print(someString)

        let cString: UnsafePointer<CChar> = Camiitool.nfc3d_version_fork()

       print(String(cString: cString))
     }
}

The issue is that when i build, i am getting a Framework Not Found Error for Camiitool.

> Ld /Users/ME/Library/Developer/Xcode/DerivedData/CamiitoolPackage-fjhqfruljmetilfuiykpzwhzobkc/Build/Products/Debug/amiitoolSwift.framework/Versions/A/amiitoolSwift normal (in target 'amiitoolSwift' from project 'CamiitoolPackage')
cd /Users/ME/GIT/PERSONAL/Amiibo/backup-wip/Camiitool
/Applications/Xcode_12.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/clang -target x86_64-apple-macos10.10 -dynamiclib -isysroot /Applications/Xcode_12.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.15.sdk -L/Users/ME/Library/Developer/Xcode/DerivedData/CamiitoolPackage-fjhqfruljmetilfuiykpzwhzobkc/Build/Products/Debug -F/Users/ME/Library/Developer/Xcode/DerivedData/CamiitoolPackage-fjhqfruljmetilfuiykpzwhzobkc/Build/Products/Debug -F/Applications/Xcode_12.app/Contents/Developer/Platforms/MacOSX.platform/Developer/Library/Frameworks -filelist /Users/ME/Library/Developer/Xcode/DerivedData/CamiitoolPackage-fjhqfruljmetilfuiykpzwhzobkc/Build/Intermediates.noindex/CamiitoolPackage.build/Debug/amiitoolSwift.build/Objects-normal/x86_64/amiitoolSwift.LinkFileList -install_name @rpath/amiitoolSwift.framework/Versions/A/amiitoolSwift -Xlinker -rpath -Xlinker /usr/lib/swift -Xlinker -rpath -Xlinker /Applications/Xcode_12.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/lib/swift/macosx -Xlinker -object_path_lto -Xlinker /Users/ME/Library/Developer/Xcode/DerivedData/CamiitoolPackage-fjhqfruljmetilfuiykpzwhzobkc/Build/Intermediates.noindex/CamiitoolPackage.build/Debug/amiitoolSwift.build/Objects-normal/x86_64/amiitoolSwift_lto.o -Xlinker -export_dynamic -Xlinker -no_deduplicate -fobjc-link-runtime -L/Applications/Xcode_12.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/lib/swift/macosx -L/usr/lib/swift -Xlinker -add_ast_path -Xlinker /Users/ME/Library/Developer/Xcode/DerivedData/CamiitoolPackage-fjhqfruljmetilfuiykpzwhzobkc/Build/Intermediates.noindex/CamiitoolPackage.build/Debug/amiitoolSwift.build/Objects-normal/x86_64/amiitoolSwift.swiftmodule -framework Camiitool -framework mbedtls -Xlinker -dependency_info -Xlinker /Users/ME/Library/Developer/Xcode/DerivedData/CamiitoolPackage-fjhqfruljmetilfuiykpzwhzobkc/Build/Intermediates.noindex/CamiitoolPackage.build/Debug/amiitoolSwift.build/Objects-normal/x86_64/amiitoolSwift_dependency_info.dat -o /Users/ME/Library/Developer/Xcode/DerivedData/CamiitoolPackage-fjhqfruljmetilfuiykpzwhzobkc/Build/Products/Debug/amiitoolSwift.framework/Versions/A/amiitoolSwift

ld: framework not found Camiitool clang: error: linker command failed with exit code 1 (use -v to see invocation)

Anything i have tried to fix the issue just seems to create some different version of the same error. For example "Module not found Camiitool", or i have had Camiitool found, but then i get errors on the method call (nfc3d_version_fork), that the method does not exist.

One last note: the current state of my project is based on this example i found: https://github.com/RoaringBitmap/SwiftRoaring Which is basically the same thing i am doing, except without a submodule. I have pulled this project and i am able to build and run it just fine. I have compared all the settings between the projects and i can not notice any differences. Which lead me to finally post here.

Running MacOS 10.15.7, Xcode 12.0


Solution

  • So I figured this one out.

    First i noticed that even though the .framework file was being generated, it was mostly empty. This clearly did not seem right, so I started working on a separate project to make sure i was not missing any steps. I was able to get another project to work, so I went back to this one and made some changes.

    Looks like it was an issue with my setup for version 5.3. I went back to 5.1 and was getting errors for duplicate symbols. Once i cleared those out by excluding the c files that were not needed. I was able to get it to work on 5.1

    In order to go back to 5.1, I needed to remove resources.copy parameters I had in my original manifest. So when I went back to 5.3, I was getting a bunch of warnings about unhandled resources:

    warning: found 424 file(s) which are unhandled; explicitly declare them as resources or exclude from the target
    

    I received this warning before, and that was the reason i added the resource.copy(".") in the first place. I decided to take a different approach this time, and exclude everything that was not needed, and see if I needed to specifically include anything once i was done. Turns out I did not need to include any resources, and exclude solved all my errors and warnings.

    here is my manifest updated.

    // swift-tools-version:5.3
    // The swift-tools-version declares the minimum version of Swift required to build this package.
    
    import PackageDescription
    
    let package = Package(
        name: "CamiitoolPackage",
        products: [
            // Products define the executables and libraries a package produces, and make them visible to other packages.
            .library(name: "Camiitool", targets: ["Camiitool"]),
            .library(name: "amiitoolSwift", targets: ["amiitoolSwift"]),
            .library(name: "amiitoolSwiftDynamic", type: .dynamic,  targets: ["amiitoolSwift"]),
        ],
        dependencies: [
        ],
        targets: [
            .target(
                name: "amiitoolSwift",
                dependencies: [ 
                   "Camiitool"
                ],
                path: "./Sources/amiitoolSwift"
            ),
            .target(
                name: "Camiitool",
                dependencies: [ 
                    "mbedtls"
                ],
                path: "./Sources/Camiitool",
                exclude: [
                    "./mbedtls",
                    "./mbedtls/yotta",
                    "./mbedtls/visualc",
                    "./LICENSE",
                    "./amiitool.c",
                    "./README.md",
                    "./Makefile"
                ]
            ),
            .target(
                name: "mbedtls",
                dependencies: [],
                path: "./Sources/Camiitool/mbedtls",
                exclude: [
                    "./yotta",
                    "./visualc",
                    "./LICENSE",
                    "./programs",
                    "./tests",
                    "./scripts",
                    "./include/CMakeLists.txt",
                    "./DartConfiguration.tcl",
                    "./doxygen",
                    "./library/Makefile",
                    "./apache-2.0.txt",
                    "./Makefile",
                    "./README.md",
                    "./ChangeLog",
                    "./CMakeLists.txt",
                    "./circle.yml",
                    "./configs/README.txt",
                    "./library/CMakeLists.txt"
                ]
            ),  
            .testTarget(
                name: "amiitoolSwiftTests",
                dependencies: ["amiitoolSwift"]
            )
        ]
    )
    

    Now it builds, generates no warnings or errors, and my .framework files are complete, as expected. I think there might be a bug here that I was not getting a better error, since xcode would show my Camiitool.framework building as successful. Even though it was clearly not.

    I was able to then test my package with the following executable package setup, and this worked as well.

    // swift-tools-version:5.3
    // The swift-tools-version declares the minimum version of Swift required to build this package.
    
    import PackageDescription
    
    let package = Package(
        name: "packageTester",
    
        dependencies: [
            // Dependencies declare other packages that this package depends on.
            .package(name: "CamiitoolPackage", path: "../Camiitool"),
        ],
        targets: [
            .target(
                name: "packageTester",
                dependencies: [
                    .product(name: "amiitoolSwift", package: "CamiitoolPackage")
                ]
            ),
            .testTarget(
                name: "packageTesterTests",
                dependencies: ["packageTester"]),
        ]
    )