Skip to content

Instantly share code, notes, and snippets.

@banjun
Last active October 30, 2023 07:28
Show Gist options
  • Save banjun/a8b46c26e7328137dc278ec045f0d1d5 to your computer and use it in GitHub Desktop.
Save banjun/a8b46c26e7328137dc278ec045f0d1d5 to your computer and use it in GitHub Desktop.
create an xcframework from a universal static lib .a or universal static .framework without rebuild
#!/bin/zsh
if [[ -z $BOGO_ARM64_TO_SIM ]]; then
echo "❌ requires BOGO_ARM64_TO_SIM: set an executable binary path built from https://github.com/bogo/arm64-to-sim"
exit 1;
fi
set -eu
# set -x # debug log
function lib_a_to_xcfw() {
TARGET_A="$(readlink -f "$1")" || {echo "⚠️ skip $1"; return 0}
TARGET_BASENAME="$(basename "$TARGET_A")"
TARGET_DIR="$(dirname "$TARGET_A")"
X86_64_A="$TARGET_A.x86_64.a"
ARM64_SIM_A="$TARGET_A.arm64-sim.a"
XCFW="$(dirname $TARGET_A)/${${TARGET_BASENAME//lib/}//.a/}.xcframework"
WORK_DIR="$(dirname $TARGET_A)/bogo-work"
ARM64_A="$WORK_DIR/device/$TARGET_BASENAME"
SIM_A="$WORK_DIR/sim/$TARGET_BASENAME"
echo "🦾 work on $TARGET_A"
mkdir -p "$WORK_DIR"
mkdir -p $(dirname "$ARM64_A")
mkdir -p $(dirname "$SIM_A")
lipo -thin x86_64 "$TARGET_A" -output "$X86_64_A"
lipo -thin arm64 "$TARGET_A" -output "$ARM64_A"
echo "🦾 device => sim"
cd "$WORK_DIR"
ar x "$ARM64_A"
for f in *.o; do "$BOGO_ARM64_TO_SIM" "$f"; done
ar crv "$ARM64_SIM_A" *.o > /dev/null
cd -
echo "🦾 sim (x86_64 + arm64) + device (arm64) => xcframework"
lipo -create "$X86_64_A" "$ARM64_SIM_A" -output "$SIM_A"
rm -rf "$XCFW"
xcodebuild -create-xcframework -library "$ARM64_A" -library "$SIM_A" -output "$XCFW"
rm "$TARGET_A" "$X86_64_A" "$ARM64_A" "$ARM64_SIM_A" "$SIM_A"
rm -rf "$WORK_DIR"
echo "✅ done"
}
function fw_to_xcfw() {
TARGET_FW="$(readlink -f "$1")" || {echo "⚠️ skip $1"; return 0}
FW_BASENAME="${$(basename "$TARGET_FW")//.framework/}"
FW_DIR="$(dirname "$TARGET_FW")"
TARGET_A=$(readlink -f "$TARGET_FW/Versions/A/$FW_BASENAME" || echo -n "$TARGET_FW/$FW_BASENAME")
TARGET_A_RELATIVE_TO_FW="${TARGET_A//"$TARGET_FW\/"/}"
X86_64_A="$TARGET_A.x86_64.a"
ARM64_A="$TARGET_A.arm64.a"
ARM64_SIM_A="$TARGET_A.arm64-sim.a"
WORK_DIR="$FW_DIR/bogo-work"
WORK_FW_SIM="$WORK_DIR/sim/$FW_BASENAME.framework"
WORK_FW_SIM_A="$WORK_FW_SIM/$TARGET_A_RELATIVE_TO_FW"
WORK_FW_DEVICE="$WORK_DIR/device/$FW_BASENAME.framework"
WORK_FW_DEVICE_A="$WORK_FW_DEVICE/$TARGET_A_RELATIVE_TO_FW"
XCFW="$FW_DIR/$FW_BASENAME.xcframework"
echo "🦾 copy to platform frameworks"
mkdir -p "$WORK_FW_SIM"
cp -a "$TARGET_FW/" "$WORK_FW_SIM"
rm "$WORK_FW_SIM_A"
mkdir -p "$WORK_FW_DEVICE"
cp -a "$TARGET_FW/" "$WORK_FW_DEVICE"
rm "$WORK_FW_DEVICE_A"
echo "🦾 work on $TARGET_A"
lipo -thin x86_64 "$TARGET_A" -output "$X86_64_A"
lipo -thin arm64 "$TARGET_A" -output "$ARM64_A"
if file "$TARGET_A" | grep -q 'Mach-O 64-bit object'; then
echo "🦾 (Mach-O object) device => sim"
cp "$ARM64_A" "$ARM64_SIM_A"
"$BOGO_ARM64_TO_SIM" "$ARM64_SIM_A"
elif file "$TARGET_A" | grep -q 'ar archive'; then
echo "🦾 (ar archive) device => sim"
mkdir -p $WORK_DIR
cd $WORK_DIR
ar x "$ARM64_A"
for f in *.o; do "$BOGO_ARM64_TO_SIM" "$f"; done
ar crv "$ARM64_SIM_A" *.o > /dev/null
cd -
else
echo "❌ unknown binary: $TARGET_A"
return 1
fi
echo "🦾 sim (x86_64 + arm64) framework"
lipo -create "$X86_64_A" "$ARM64_SIM_A" -output "$WORK_FW_SIM_A"
echo "🦾 device (arm64) framework"
cp -p "$ARM64_A" "$WORK_FW_DEVICE_A"
echo "🦾 sim (x86_64 + arm64) + device (arm64) => xcframework"
rm -rf "$XCFW"
xcodebuild -create-xcframework -framework "$WORK_FW_SIM" -framework "$WORK_FW_DEVICE" -output "$XCFW"
rm "$X86_64_A" "$ARM64_A" "$ARM64_SIM_A"
rm -rf "$WORK_DIR"
rm -rf "$TARGET_FW"
echo "✅ done"
}
# convert libs & frameworks to xcframeworks
#
# call one of the functions for each static libs/frameworks
# example:
lib_a_to_xcfw Pods/GoogleAnalytics/Libraries/libGoogleAnalytics.a
fw_to_xcfw Pods/OpenCV/opencv2.framework
@banjun
Copy link
Author

banjun commented Feb 22, 2023

for example, use this:

  pod "GoogleAnalytics", "3.17.0"
  pod "OpenCV", "3.4.6"

and convert them to xcframeworks

BOGO_ARM64_TO_SIM=~/projects/github/arm64-to-sim/.build/release/arm64-to-sim zsh /Users/jun.ban/Downloads/convert-lib-fw-to-sim-device-universal-xcfw.sh

output:

🦾 work on /Users/jun.ban/projects/inbox/xcfwtest/Pods/GoogleAnalytics/Libraries/libGoogleAnalytics.a
🦾 device => sim
🦾 sim (x86_64 + arm64) + device (arm64) => xcframework
xcframework successfully written out to: /Users/jun.ban/projects/inbox/xcfwtest/Pods/GoogleAnalytics/Libraries/GoogleAnalytics.xcframework
override r-xr-xr-x jun.ban/staff for /Users/jun.ban/projects/inbox/xcfwtest/Pods/GoogleAnalytics/Libraries/libGoogleAnalytics.a? y
override r-xr-xr-x jun.ban/staff for /Users/jun.ban/projects/inbox/xcfwtest/Pods/GoogleAnalytics/Libraries/libGoogleAnalytics.a.x86_64.a? y
override r-xr-xr-x jun.ban/staff for /Users/jun.ban/projects/inbox/xcfwtest/Pods/GoogleAnalytics/Libraries/bogo-work/device/libGoogleAnalytics.a? y
✅ done
🦾 copy to platform frameworks
🦾 work on /Users/jun.ban/projects/inbox/xcfwtest/Pods/OpenCV/opencv2.framework/Versions/A/opencv2
🦾 (ar archive) device => sim
🦾 sim (x86_64 + arm64) framework
🦾 device (arm64) framework
🦾 sim (x86_64 + arm64) + device (arm64) => xcframework
xcframework successfully written out to: /Users/jun.ban/projects/inbox/xcfwtest/Pods/OpenCV/opencv2.xcframework
✅ done

image

your todo after them

  • link generated xcframeworks by making changes to build settings manually or programatically (such as removing link settings to the original ones, and adding link settings to the generated frameworks. see also the install_xcframework build phase of CocoaPods for a good reference)

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