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
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"]),
]
)