iOS 14, lipo error while creating library for both device and simulator
Asked Answered
W

4

19

We have been using lipo command to create a framework which works on both device and simulator when integrated in other project. following are the build commands used to generate device and simulator builds

xcodebuild -target SampleSDK ONLY_ACTIVE_ARCH=NO -configuration ${CONFIGURATION} -sdk iphonesimulator BUILD_DIR="${BUILD_DIR}" BUILD_ROOT="${BUILD_ROOT}" OBJROOT="${OBJROOT}/DependentBuilds"
xcodebuild -target SampleSDK ONLY_ACTIVE_ARCH=NO -configuration ${CONFIGURATION} -sdk iphoneos BUILD_DIR="${BUILD_DIR}" BUILD_ROOT="${BUILD_ROOT}" OBJROOT="${OBJROOT}/DependentBuilds"

after this we are copying swift modules from iphonesimulator(if it exists) to the copied framework dir

cp -R "$BUILD_DIR/${CONFIGURATION}-iphonesimulator/${PRODUCT_NAME}/Modules/SampleSDK.swiftmodule/" "${UNIVERSAL_OUTPUTFOLDER}/${PRODUCT_NAME}/Modules/${PROJECT_NAME}.swiftmodule/"

and then lipo command

lipo -create "$BUILD_DIR/${CONFIGURATION}-iphonesimulator/${PRODUCT_NAME}/${PROJECT_NAME}" "${BUILD_DIR}/${CONFIGURATION}-iphoneos/${PRODUCT_NAME}/${PROJECT_NAME}" -output "${UNIVERSAL_OUTPUTFOLDER}/${PRODUCT_NAME}/${PROJECT_NAME}"

the above command is failing with following error

fatal error: lipo: /path/to/Library/Developer/Xcode/DerivedData/Sample-bhfmlauxsdympmdjkjyvujaljevg/Build/Products/Debug-iphonesimulator/SampleSDK.framework/SampleSDK and /Users/rramshettysiddaraju/Library/Developer/Xcode/DerivedData/Sample-bhfmlauxsdympmdjkjyvujaljevg/Build/Products/Debug-iphoneos/SampleSDK.framework/SampleSDK have the same architectures (arm64) and can't be in the same fat output file

I tried one of the answers in stackoverflow, about adding user-defined setting VALID_ARCHS and then removing it. but that didnt work

Written answered 23/9, 2020 at 6:35 Comment(0)
C
40

The reason for the error is that Xcode 12 includes a slice for the "arm64" architecture when building for the simulator (in addition to the usual "i386" and "x86_64" architectures for Xcode <12). This is probably for supporting the simulator on (future) Macs using Apple Silicon processors. As your device build also includes the "arm64" architecture, lipo does not know which of the two "arm64" slices you want and refuses to create a combined fat binary framework.

As a workaround, you can either exclude the "arm64" architecture from the simulator build by appending the EXCLUDED_ARCHS build variable:

xcodebuild -target SampleSDK ONLY_ACTIVE_ARCH=NO -configuration ${CONFIGURATION} -sdk iphonesimulator BUILD_DIR="${BUILD_DIR}" BUILD_ROOT="${BUILD_ROOT}" OBJROOT="${OBJROOT}/DependentBuilds" EXCLUDED_ARCHS="arm64"

Alternatively, use lipo -remove to remove the "arm64" architecture from the simulator build before combining the simulator and device frameworks into one:

lipo -remove arm64 "$BUILD_DIR/${CONFIGURATION}-iphonesimulator/${PRODUCT_NAME}/${PROJECT_NAME}" -output "$BUILD_DIR/${CONFIGURATION}-iphonesimulator/${PRODUCT_NAME}/${PROJECT_NAME}"

In the long run, you might be better off building an XCFramework, which should support devices and simulators without the need for using lipo. But I haven’t tested this yet.

Catenary answered 23/9, 2020 at 10:37 Comment(3)
Thanks styv, this helped and will also look into XCFrameworkWritten
Thank god! Finally, I found this solution after 2 days for iOS 14.Calhoun
Also do remove the VALID_ARCHS build setting in your project first, if you have any.Stage
D
5

styv is right.

You can also set Excluded Architectures in the Xcode Build Settings

enter image description here

Delladelle answered 23/2, 2022 at 4:50 Comment(0)
F
1

@xtyv's suggestion is spot on: using an XCFramework is the way to go.

Here is a Makefile to generate an XCFramework (apply substitutions and add other architectures accordingly to your scenario):

ARCHS = aarch64-apple-ios aarch64-apple-ios-sim
LIB = lib<library_name>.a
XCFRAMEWORK = <framework_name>-iOS.xcframework

all: $(XCFRAMEWORK)

.PHONY: $(ARCHS)
$(ARCHS): %:
    cargo build --target $@
    
$(XCFRAMEWORK): $(ARCHS)
    xcodebuild -create-xcframework  $(addprefix -library , $(foreach arch, $(ARCHS),$(wildcard target/$(arch)/debug/$(LIB)))) -headers <header_file> -output $@
Florida answered 20/11, 2022 at 9:33 Comment(1)
Are you managing to build a rust framework that exposes / communicates with ObjC / Swift? I would love to be able to use UIKit from rust.Eventual
L
1

How to build this framework for devices

xcodebuild clean build \
  -project CodeToanBugUI.xcodeproj \
  -scheme CodeToanBugUI \
  -configuration Release \
  -sdk iphoneos \
  -derivedDataPath derived_data \
  BUILD_LIBRARY_FOR_DISTRIBUTION=YES

Copy to the build folder

mkdir build/devices
cp -r derived_data/Build/Products/Release-iphoneos/CodeToanBugUI.framework build/devices

Build the framework for simulators

xcodebuild clean build \
  -project CodeToanBugUI.xcodeproj \
  -scheme CodeToanBugUI \
  -configuration Release \
  -sdk iphonesimulator \
  -derivedDataPath derived_data \
  BUILD_LIBRARY_FOR_DISTRIBUTION=YES EXCLUDED_ARCHS=arm64

Copy to the build folder for simulators

mkdir build/simulator
cp -r derived_data/Build/Products/Release-iphonesimulator/ build/simulator/

Create the universal framework

mkdir build/universal
cp -r build/devices/CodeToanBugUI.framework build/universal/
lipo -create \
  build/simulator/CodeToanBugUI.framework/CodeToanBugUI \
  build/devices/CodeToanBugUI.framework/CodeToanBugUI \
  -output build/universal/CodeToanBugUI.framework/CodeToanBugUI

Copy the swiftmodule

cp -r build/simulator/CodeToanBugUI.framework/Modules/CodeToanBugUI.swiftmodule/* \
  build/universal/CodeToanBugUI.framework/Modules/CodeToanBugUI.swiftmodule/

Create the xcodebuild -create-xcframework command

xcodebuild -create-xcframework \
  -framework build/simulator/CodeToanBugUI.framework \
  -framework build/devices/CodeToanBugUI.framework \
  -output build/CodeToanBugUI.xcframework
Liegnitz answered 26/3, 2023 at 14:57 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.