Skip to content

Instantly share code, notes, and snippets.

@KaQuMiQ
Created January 19, 2021 12:02
Show Gist options
  • Save KaQuMiQ/5c02a27c736188e75d750c630cb9eb90 to your computer and use it in GitHub Desktop.
Save KaQuMiQ/5c02a27c736188e75d750c630cb9eb90 to your computer and use it in GitHub Desktop.
Convert fat binary framework into XCFramework
#! /bin/bash
mkdir ./arm64
mkdir ./x86_64
find "./" -name '*.framework' -type d | while read -r FRAMEWORK
do
echo "Preparing framework: $FRAMEWORK"
FRAMEWORK_EXECUTABLE_NAME=$(/usr/libexec/PlistBuddy -c "Print CFBundleExecutable" "$FRAMEWORK/Info.plist")
echo "Preparing arm64 framework"
cp -R "$FRAMEWORK" "./arm64/$FRAMEWORK_EXECUTABLE_NAME.framework"
rm "./arm64/$FRAMEWORK_EXECUTABLE_NAME.framework/$FRAMEWORK_EXECUTABLE_NAME"
$(/usr/libexec/PlistBuddy -c "Set CFBundleSupportedPlatforms iPhoneOS" "./arm64/$FRAMEWORK_EXECUTABLE_NAME.framework/Info.plist")
echo "Extracting arm64 from $FRAMEWORK_EXECUTABLE_NAME"
lipo -extract "arm64" "$FRAMEWORK/$FRAMEWORK_EXECUTABLE_NAME" -o "./arm64/$FRAMEWORK_EXECUTABLE_NAME.framework/$FRAMEWORK_EXECUTABLE_NAME"
echo "Preparing x86_64 framework"
cp -R "$FRAMEWORK" "./x86_64/$FRAMEWORK_EXECUTABLE_NAME.framework"
rm "./x86_64/$FRAMEWORK_EXECUTABLE_NAME.framework"
$(/usr/libexec/PlistBuddy -c "Set CFBundleSupportedPlatforms iPhoneSimulator" "./x86_64/$FRAMEWORK_EXECUTABLE_NAME.framework/Info.plist")
echo "Extracting x86_64 from $FRAMEWORK_EXECUTABLE_NAME"
lipo -extract "x86_64" "$FRAMEWORK/$FRAMEWORK_EXECUTABLE_NAME" -o "./x86_64/$FRAMEWORK_EXECUTABLE_NAME.framework/$FRAMEWORK_EXECUTABLE_NAME"
xcodebuild -create-xcframework -framework "./arm64/$FRAMEWORK_EXECUTABLE_NAME.framework" -framework "./x86_64/$FRAMEWORK_EXECUTABLE_NAME.framework" -output "$FRAMEWORK_EXECUTABLE_NAME.xcframework" || exit -1
done
rm -r ./arm64
rm -r ./x86_64
@KaQuMiQ
Copy link
Author

KaQuMiQ commented Jun 16, 2021

Good question @Blackjacx . I was using it only for pure binaries so haven't that case. You have to verify that, but it could work since there are two recursive copies of framework made and only binary and Info.plist becomes modified.

@jorgealegre
Copy link

Do you know what I can do if the framework doesn't have an Info.plist file?

@KaQuMiQ
Copy link
Author

KaQuMiQ commented Jan 10, 2022

I can't remember if I had such a case but I believe you should make one by hand inside (skip plist step and make it manually after merge). I am not sure if that also applies to static binaries, those could have no plist, so it should work without it.

@hassanvfx
Copy link

Hello there, so I recently had to convert openCV2 ncnn and openmp and I ended up creating a new working script, it looks like this:
image

#! /bin/bash


find "." -name '*.framework' -type d | while read -r FRAMEWORK
do
    echo "-----------------------"
    FRAMEWORK_NAME=$(echo "$FRAMEWORK" | sed 's/\.\/\(.*\)\.framework/\1/')
    FRAMEWORK_BUNDLE_NAME=$(/usr/libexec/PlistBuddy -c "Print CFBundleName" "$FRAMEWORK/Resources/Info.plist") || exit
    XCFRAMEWORK_ROOT="./_$FRAMEWORK_NAME.xcframework"
    
    XCTEMP_IPHONE_ROOT="$XCFRAMEWORK_ROOT/iphoneos"
    XCTEMP_SIMULATOR_ROOT="$XCFRAMEWORK_ROOT/iphonesimulator"
    
    TEMP_IPHONE_ROOT="$XCFRAMEWORK_ROOT/iphoneos/$FRAMEWORK_NAME.framework"
    TEMP_SIMULATOR_ROOT="$XCFRAMEWORK_ROOT/iphonesimulator/$FRAMEWORK_NAME.framework"
    echo "Bundle Name: $FRAMEWORK_NAME"
    xcrun lipo -i "$FRAMEWORK/$FRAMEWORK_NAME"
    
    echo "Creating new $XCFRAMEWORK_ROOT"
    rm -rf "$XCFRAMEWORK_ROOT"
    mkdir "$XCFRAMEWORK_ROOT"
    
    echo "Creating new $XCTEMP_IPHONE_ROOT"
    echo "Creating new $XCTEMP_SIMULATOR_ROOT"
    mkdir -p "$XCTEMP_IPHONE_ROOT"
    mkdir -p "$XCTEMP_SIMULATOR_ROOT"
    
    echo "cp -r $FRAMEWORK $TEMP_IPHONE_ROOT"
    echo "cp -r $FRAMEWORK $TEMP_SIMULATOR_ROOT"
    cp -r "$FRAMEWORK" "$TEMP_IPHONE_ROOT"
    cp -r "$FRAMEWORK" "$TEMP_SIMULATOR_ROOT"
    
    declare -a ARCH_REMOVE_IPHONE=("i386" "x86_64")
    declare -a ARCH_REMOVE_SIM=("i386" "arm64" "arm64e" "armv7" "armv7s")
   
    echo "******************"
    for ARCH in "${ARCH_REMOVE_IPHONE[@]}"
    do
        echo "Remove $ARCH from device slice of the xcframework"
        xcrun lipo -remove "$ARCH" "$TEMP_IPHONE_ROOT/$FRAMEWORK_NAME" -o "$TEMP_IPHONE_ROOT/tmp" &&
        rm "$TEMP_IPHONE_ROOT/$FRAMEWORK_NAME" &&
        mv "$TEMP_IPHONE_ROOT/tmp" "$TEMP_IPHONE_ROOT/$FRAMEWORK_NAME"
    done
    echo "Confirm the DEVICE binary has the proper (arm64) slice"
    xcrun lipo -i "$TEMP_IPHONE_ROOT/$FRAMEWORK_NAME"
    
       
    echo "******************"
    for ARCH in "${ARCH_REMOVE_SIM[@]}"
    do
        echo "Remove $ARCH from sim slice of the xcframework"
        xcrun lipo -remove "$ARCH" "$TEMP_SIMULATOR_ROOT/$FRAMEWORK_NAME" -o "$TEMP_SIMULATOR_ROOT/tmp" &&
        rm "$TEMP_SIMULATOR_ROOT/$FRAMEWORK_NAME" &&
        mv "$TEMP_SIMULATOR_ROOT/tmp" "$TEMP_SIMULATOR_ROOT/$FRAMEWORK_NAME"
    done
    echo "Confirm the SIM binary has the proper (x86_64) slice."
    xcrun lipo -i "$TEMP_SIMULATOR_ROOT/$FRAMEWORK_NAME"

    echo "Create xcframework from the platform slices"
    echo "xcodebuild -create-xcframework -framework $TEMP_IPHONE_ROOT -framework $TEMP_SIMULATOR_ROOT -output ./$FRAMEWORK_NAME.xcframework"

    xcodebuild -create-xcframework -framework "$TEMP_IPHONE_ROOT" -framework "$TEMP_SIMULATOR_ROOT" -output "$FRAMEWORK_NAME.xcframework"
   
    rm -rf "$XCFRAMEWORK_ROOT"
    
    
done

Expected sample output:

 Frameworks ./convertFrameworks.sh
-----------------------
Bundle Name: openmp
Architectures in the fat file: ./openmp.framework/openmp are: armv7 i386 x86_64 arm64 arm64e
Creating new ./_openmp.xcframework
Creating new ./_openmp.xcframework/iphoneos
Creating new ./_openmp.xcframework/iphonesimulator
cp -r ./openmp.framework ./_openmp.xcframework/iphoneos/openmp.framework
cp -r ./openmp.framework ./_openmp.xcframework/iphonesimulator/openmp.framework
******************
Remove i386 from device slice of the xcframework
Remove x86_64 from device slice of the xcframework
Confirm the DEVICE binary has the proper (arm64) slice
Architectures in the fat file: ./_openmp.xcframework/iphoneos/openmp.framework/openmp are: armv7 arm64 arm64e
******************
Remove i386 from sim slice of the xcframework
Remove arm64 from sim slice of the xcframework
Remove arm64e from sim slice of the xcframework
Remove armv7 from sim slice of the xcframework
Remove armv7s from sim slice of the xcframework
fatal error: /Applications/Xcode14.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/lipo: -remove armv7s specified but fat file: ./_openmp.xcframework/iphonesimulator/openmp.framework/openmp does not contain that architecture
Confirm the SIM binary has the proper (x86_64) slice.
Architectures in the fat file: ./_openmp.xcframework/iphonesimulator/openmp.framework/openmp are: x86_64
Create xcframework from the platform slices
xcodebuild -create-xcframework -framework ./_openmp.xcframework/iphoneos/openmp.framework -framework ./_openmp.xcframework/iphonesimulator/openmp.framework -output ./openmp.xcframework
xcframework successfully written out to: /Users/hassan/projects/FaceKit/Sources/FaceKit/Frameworks/openmp.xcframework
-----------------------
Bundle Name: opencv2
Architectures in the fat file: ./opencv2.framework/opencv2 are: armv7 armv7s i386 x86_64 arm64
Creating new ./_opencv2.xcframework
Creating new ./_opencv2.xcframework/iphoneos
Creating new ./_opencv2.xcframework/iphonesimulator
cp -r ./opencv2.framework ./_opencv2.xcframework/iphoneos/opencv2.framework
cp -r ./opencv2.framework ./_opencv2.xcframework/iphonesimulator/opencv2.framework
******************
Remove i386 from device slice of the xcframework
Remove x86_64 from device slice of the xcframework
Confirm the DEVICE binary has the proper (arm64) slice
Architectures in the fat file: ./_opencv2.xcframework/iphoneos/opencv2.framework/opencv2 are: armv7 armv7s arm64
******************
Remove i386 from sim slice of the xcframework
Remove arm64 from sim slice of the xcframework
Remove arm64e from sim slice of the xcframework
fatal error: /Applications/Xcode14.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/lipo: -remove arm64e specified but fat file: ./_opencv2.xcframework/iphonesimulator/opencv2.framework/opencv2 does not contain that architecture
Remove armv7 from sim slice of the xcframework
Remove armv7s from sim slice of the xcframework
Confirm the SIM binary has the proper (x86_64) slice.
Architectures in the fat file: ./_opencv2.xcframework/iphonesimulator/opencv2.framework/opencv2 are: x86_64
Create xcframework from the platform slices
xcodebuild -create-xcframework -framework ./_opencv2.xcframework/iphoneos/opencv2.framework -framework ./_opencv2.xcframework/iphonesimulator/opencv2.framework -output ./opencv2.xcframework
xcframework successfully written out to: /Users/hassan/projects/FaceKit/Sources/FaceKit/Frameworks/opencv2.xcframework
-----------------------
Bundle Name: ncnn
Architectures in the fat file: ./ncnn.framework/ncnn are: armv7 i386 x86_64 arm64 arm64e
Creating new ./_ncnn.xcframework
Creating new ./_ncnn.xcframework/iphoneos
Creating new ./_ncnn.xcframework/iphonesimulator
cp -r ./ncnn.framework ./_ncnn.xcframework/iphoneos/ncnn.framework
cp -r ./ncnn.framework ./_ncnn.xcframework/iphonesimulator/ncnn.framework
******************
Remove i386 from device slice of the xcframework
Remove x86_64 from device slice of the xcframework
Confirm the DEVICE binary has the proper (arm64) slice
Architectures in the fat file: ./_ncnn.xcframework/iphoneos/ncnn.framework/ncnn are: armv7 arm64 arm64e
******************
Remove i386 from sim slice of the xcframework
Remove arm64 from sim slice of the xcframework
Remove arm64e from sim slice of the xcframework
Remove armv7 from sim slice of the xcframework
Remove armv7s from sim slice of the xcframework
fatal error: /Applications/Xcode14.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/lipo: -remove armv7s specified but fat file: ./_ncnn.xcframework/iphonesimulator/ncnn.framework/ncnn does not contain that architecture
Confirm the SIM binary has the proper (x86_64) slice.
Architectures in the fat file: ./_ncnn.xcframework/iphonesimulator/ncnn.framework/ncnn are: x86_64
Create xcframework from the platform slices
xcodebuild -create-xcframework -framework ./_ncnn.xcframework/iphoneos/ncnn.framework -framework ./_ncnn.xcframework/iphonesimulator/ncnn.framework -output ./ncnn.xcframework
xcframework successfully written out to: /Users/hassan/projects/FaceKit/Sources/FaceKit/Frameworks/ncnn.xcframework

@dancarvajc
Copy link

dancarvajc commented Oct 2, 2024

What when the framework contains resources? Are they also transferred to the XCFramework? Cannot see any references.

@Blackjacx I have the same question, is there any way to convert the fat binary with resources to XCFramework including arm64-simulator slice?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment