Hey @quentinfasquel !
I think I finally solved it!
There were a couple of issues in my path, first and foremost, xcframeworks are a mess and the xcodebuild create-xcframework option is definitely not prime time ready.
My observations so fare with that option are:
- If you create the xcframework initially with one architecture and then trying to add a second to the same xcframework, will result in the framework being added to the filesystem but not the Info.plist of the xcframework ...
- If you added the static library for arm64, you'll get a message that armv7 and armv7s aren't needed when you try to specify those too ... I couldn't find much information why, other than some github issue where people were guessing that those 32bit libraries are simply not supported anyway. Would love if someone could clarify this...
- The very same applies to i386 and x86_64
- Each of the static libs have to be for a single architecture. I don't know how true this really is, since I've seen an example where armv7, armv7s and arm64 are actually bundled into one file. If someone could clarify that too, that'd be superb!
- I've initially specified the full path to my headers file e.g. libA/libA.h which ended up cloning the headerfile as HEADERS (no file extension) into the .xcframework folder which in turn made Xcode error (No header issue). I don't think you're supposed to specify the full path for the headerfile, but rather a directory. I later changed that and was more successful.
What helped me a lot was this post on the Apple Forums that I found after initially running into my issue.
Luckily (for once) I decided to go the painful route of writing a script right at the beginning that'll do the work for me, I would have gone crazy otherwise.
Here's my script, module.modulemap and my Package.swift in case that might help you. Other than that, I didn't add each of the headers to the user header path as described in the Apple dev forums link, but I think that wasn't necessary due to my modulemap.
// swift-tools-version:5.3
import PackageDescription
let package = Package(
name: "Wrapper Project",
platforms: [
.iOS(.v12),
],
products: [
.library(name: "WrapperProject", targets: ["WrapperProject"]),
],
dependencies: [],
targets: [
.binaryTarget(name: "DependencyA", path: "DJMetrics/Frameworks/DependencyA.xcframework"),
.binaryTarget(name: "DependencyB", path: "DJMetrics/Frameworks/DependencyB.xcframework"),
.binaryTarget(name: "DependencyC", path: "DJMetrics/Frameworks/DependencyC.xcframework"),
.binaryTarget(name: "DependencyD", path: "DJMetrics/Frameworks/DependencyD.xcframework"),
.binaryTarget(name: "DependencyE", path: "DJMetrics/Frameworks/DependencyE.xcframework"),
.binaryTarget(name: "DependencyF", path: "DJMetrics/Frameworks/DependencyF.xcframework"),
.target(
name: "WrapperProject",
dependencies: [
"DependencyA",
"DependencyB",
"DependencyC",
"DependencyD",
"DependencyE",
"DependencyF",
],
path: "Sources",
exclude: [
"Frameworks",
"Supporting Files/Info.plist",
],
cSettings: [
.headerSearchPath("Frameworks/**"),
]
),
]
)
module DependencyA {
header "DependencyA.xcframework/ios-arm64/Headers/DepA.h" #Same header file for every Arch, hence this works for me (or so I hope)
export *
}
And here's my script:
#!/bin/bash
set -x
rm -rf *.xcframework
rm -rf ./*-Thin
find . -name '*.a' | while read -r FRAMEWORK
do
FRAMEWORK_NAME="${FRAMEWORK%.*}"
FRAMEWORK_NAME="$(basename -- "$FRAMEWORK_NAME")"
echo "Framework is $FRAMEWORK_NAME"
FRAMEWORK_THIN_FOLDER="${FRAMEWORK_NAME}-Thin"
mkdir ${FRAMEWORK_THIN_FOLDER}
ARCHS="x86_64 arm64" #Only extracting these two architectures, since xcframework won't take more anyways
for ARCH in $ARCHS
do
echo "Extracting $ARCH from $FRAMEWORK"
lipo -extract "$ARCH" "$FRAMEWORK" -o "${FRAMEWORK_THIN_FOLDER}/$FRAMEWORK_NAME-$ARCH.a"
done
echo "Creating XCFramework for $FRAMEWORK_NAME:"
# Matching the Headerfiles
case $FRAMEWORK_NAME in
lib1)
HEADERFILES=("./header.h")
;;
lib2)
HEADERFILES=("./header.h")
;;
lib3)
HEADERFILES=("./header.h" "./header.h")
;;
lib4)
HEADERFILES=("./header.h")
;;
lib5)
HEADERFILES=("./header.h")
;;
lib6)
HEADERFILES=("./Header1.h" "./Header2.h")
;;
*)
exit 1
;;
esac
# Put Headers into place
mkdir "${FRAMEWORK}"-Headers
cp ${HEADERFILES[@]} "${FRAMEWORK}"-Headers/
# Matching the -library and -headers parameters
THINFRAMEWORKSFILES="$(find ${FRAMEWORK_THIN_FOLDER} -name "*.a")"
THINFRAMEWORKSARRAY=($THINFRAMEWORKSFILES)
echo "Building XCFramework for $THINFRAMEWORKSARRAY with ${HEADERFILES[@]/#/-headers }"
xcodebuild -create-xcframework -library ${THINFRAMEWORKSARRAY[0]} -headers "${FRAMEWORK}"-Headers/ -library ${THINFRAMEWORKSARRAY[1]} -headers "${FRAMEWORK}"-Headers/ -output ${HEADERFILES[0]%.*}.xcframework
# Remove Temp Headers
rm -rf "${FRAMEWORK}"-Headers/
done
# Cleaning Thin Folders
rm -rf ./*-Thin
I hope this helps (and someone can still verify the remaining of my assumptions)