Creating iOS universal framework with Xcode 9 - ios

I am creating universal framework for iOS. I am trying to create one through lipo and it does create a universal one
I check the architecture with lipo after creation it returns me correct:
Architectures in the fat file: i386 x86_64 armv7 arm64
I run the application on phone and simulator that works fine as well.. But when I try to export the .ipa from xcarchive I get the following error:
Failed to verify bitcode in Myframework.framework/Myframework:\nerror: Platform iPhoneSimulator is not supported\n\n
Also I can the bitcode symbols in my universal framework running
otool -l /Path/To/Framework | grep __LLVM
segname __LLVM
segname __LLVM
If I choose only iphoneos framework that works fine

You need to strip i386 and x86_64 from the framework before exporting the archive.
e.g.
$ lipo -remove i386 ./path/to/binary_name -o ./path/to/binary_name
$ lipo -remove x86_64 ./path/to/binary_name -o ./path/to/binary_name
You need to do this, since i386 and x86_64 are not supported for export -- "Platform iPhoneSimulator is not supported"

Related

Cannot lipo arm64 .a files of iOS device with iOS simulator on Apple Silicon

Shell commands as below,
$ lipo -info libyuv-device.a
Architectures in the fat file: device/libyuv.a are: armv7 arm64
$ lipo -info libyuv-simulator.a
Architectures in the fat file: simulator/libyuv.a are: arm64 x86_64
$ lipo -create libyuv-device.a libyuv-simulator.a -output libyuv.a
fatal error: /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/lipo: libyuv-device.a and libyuv-simulator.a have the same architectures (arm64) and can't be in the same fat output file
How to lipo multiple arm64 .a files of iOS device and iOS simulator (on Apple Silicon, e.g. M1) into one single .a file?
I think you should output a XCFramework.
1 - Use lipo to combine architectures per platforms like you did.
2 - Then use xcodebuild -create-framework to combine the platforms.
xcodebuild -create-framework -library libyuv-device.a -library libyuv-simulator.a -output libyuv.xcframework

Build static lib for Apple Silicon mac simulator

My static lib is built with xcodebuild and then a fat lib is created from the simulator and device build result.
Here is my xcodebuild command:
xcodebuild OTHER_CFLAGS="-fembed-bitcode" -configuration "iphoneos" -target "${LIB_NAME}Common" -sdk iphoneos
xcodebuild OTHER_CFLAGS="-fembed-bitcode" -configuration "iphonesimulator" -target "${LIB_NAME}Common" -sdk iphonesimulator
lipo command:
lipo -create "${DEVICE_DIR}/lib${LIB_NAME}Common.a" "${SIMULATOR_DIR}/lib${LIB_NAME}Common.a" -output "${INSTALL_DIR}/include/${LIB_NAME}/lib${LIB_NAME}Common.a"
After checking the architectures in the fat lib, I got:
$ lipo -info MyLibCommon.a
Architectures in the fat file: MyLibCommon.a are: armv7 i386 x86_64 arm64
However, when I add the lib to a project via cocoapods and run the project on Apple's new Silicon (with arm64 chipset) on simulator, I got the following compile error:
building for iOS Simulator, but linking in object file built for iOS, file 'MyLibCommon.a' for architecture arm64
Excluding the arm64 architecture for Simulator is not an option because on Apple Silicon Mac has arm64 chipset.
Any idea how can I build a static library for Apple Silicon Simulator?
This is not possible.
In all likelihood, your simulator binaries are just i386 and x86_64. If you truly had arm64 iOS binaries and arm64 macOS binaries, lipo would error out on you:
fatal error: /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/lipo: test.a.ios and test.a.macos have the same architectures (arm64) and can't be in the same fat output file
This happens no matter whether you try it with full-fledged binaries, unlinked object files or static libraries. The reason is simply a shortcoming in the fat file format: you can only have one slice per architecture. You want both arm64 iOS and the Apple Silicon simulator, but that would be 2x arm64.
You might be tempted to try and build a single thin arm64 binary that works on both iOS and macOS, but that too is impossible. Binaries are platform-locked:
% otool -l test.o.ios | fgrep -B1 -A5 LC_BUILD_VERSION
Load command 1
cmd LC_BUILD_VERSION
cmdsize 24
platform 2
sdk 14.2
minos 14.2
ntools 0
% otool -l test.o.macos | fgrep -B1 -A5 LC_BUILD_VERSION
Load command 1
cmd LC_BUILD_VERSION
cmdsize 24
platform 1
sdk 11.0
minos 11.0
ntools 0
Notice the platform 2 vs platform 1. The kernel will actually ignore this load command, but dyld will not. And you can't have two such load commands in a single binary either, that's considered invalid as well.
You might also remember talk of a "Universal 2" file format from Apple's announcement or something citing that - but they lied. There is no "universal 2", it's exactly the same file format it was a decade ago. When they say "universal 2", all they mean is "adding an arm64 slice to your macOS binary".
The way I see it, you have three options:
You build separate libraries and keep the names separate.
You never build both architectures at the same time.
You build the simulator target for x86_64 and run it under Rosetta.
The latter two are both being suggested widely across the internet, with number 2 as "build only for active architecture" and number 3 being "exclude arm64". Given that Rosetta is expected to go away eventually, the third option seems not viable for the long term.

How to remove unwanted architecture x86_64 from Xcode build?

I am trying to recompile someone else's code. The code includes a reference to a third party library myLib.a, which has two slices:
Architectures in the fat file: myLib.a are: armv7 arm64
I get this warning, following by a bunch of link errors:
ld: warning: ignoring file myLib.a, missing required architecture x86_64 in file myLib.a (2 slices)
Now, I know this library is not intended to work in a simulator. So I want to throw the simulator away from build. I don't really understand build targets, so I did this:
Still, same error. What am I doing wrong?
Xcode 7.3
I answered this question here: https://stackoverflow.com/a/65307436/5303139
Same anwser
For an iOS project, you have the following architectures: arm64 armv7 armv7s i386 x86_64
x86_64, i386 are used for the simulator.
What could be your problem is the framework you are using was build for iOS and not a simulator.
To fix this issue you can bypass the build framework and use lipo command lines.
First: lipo -info [The library.framework location]
Example Usage : lipo -info /Users/.../library.framework/LibrarySDK
Example output :
Architectures in the fat file: /Users/.../library.framework/LibrarySDK are: i386 x86_64 armv7 arm64
You will get the list of architecture used for that framework.
Second: we need to strip the framework from the simulator architecture and make 2 versions of that framework (1 is used for iOS Device and 1 for the simulator)
using: lipo -remove [architecture] [location] -o [output_location]
Example: lipo -remove i386 /Users/.../SDK -o /Users/.../SDK_Output_Directory
Go to your chosen output directory to get the new generated SDK without the removed architecture to verify you can use the lipo -info command same as above
You can use the same lipo remove command on the newly created SDK but with another architecture
lipo -remove x86_64 ... and you will get an SDK only for iOS devices
Third: Take that final SDK and rename it "SDK_Name_IOS" and use it.
Happy coding!!
You did set architect to armv7, arm64 so just change Build Active Architecture Only to YES in debug mode:
debug mode: YES
release mode: NO (default value)
So when debug you will build only for current device

Error: ld: warning: ignoring file libfile01.a, file was built for archive which is not the architecture being linked (armv7): libfile01.a

I'm trying to compile a project developed in C language for iOS devices. It uses custom library file, libcurl, libcrypto, libssl and libpthread. I have successfully compiled it for Mac OS X, but having issues compiling it for iOS. Also, any help I try to find online is more of Xcode GUI help, and I need command line help for it. Need to compile it through commands instead of Xcode GUI.
First it needs to compile couple of C files, then make a static library file out of these compiled files, which further used when compiling a native binary.
This is how I generated iOS arm ouptut files from c files inside file01:
Store the iphoneos sdk path in environemnt variable:
CC="$(xcrun --sdk iphoneos9.2 --find clang) -isysroot $(xcrun --sdk iphoneos9.2 --show-sdk-path) -arch armv7 -arch armv7s -arch arm64 -arch armv6 -arch arm64"
Compile the c files in file01 with command:
$CC -c -O2 *.c
To check which architect these files are compiled for can be checked with this lipo command. Example:
$ lipo -info example_file01.o
Architectures in the fat file: example_file01.o are: armv7 armv7s armv6 arm64
To make a static library file I can get iOS ar file path using command:
$ xcrun --sdk iphoneos9.2 --find ar /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/ar
I could store the path in an environment variable, but it was not working throwing error not recognising ar command arguments rcu. So, used the ar path instead to create the library file with this command:
/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/ar rcu ../output/libfile01.a *.o
If checking which architectures this lib file supports it gives this output:
$ lipo -info ../output/libfile01.a
fatal error: /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/lipo: archive with no architecture specification: ../output/libfile01.a (can't determine architecture for it)
But, it should have given output similar to this one:
$ lipo -info ../ios/lib/libcurl.a
Architectures in the fat file: ../ios/lib/libcurl.a are: i386 armv7 armv7s x86_64 arm64
This is causing error when trying compiling files in using the generated static lib file with command:
$CC -o ../output/FinalProjectFile -O2 *.c ../output/libfile01.a ../ios/lib/libcurl.a ../ios/lib/libssl.a ../ios/lib/libcrypto.a -lpthread -lm
Error: ​ld: warning: ignoring file ../output/libfile01.a, file was built for archive which is not the architecture being linked (armv7): ../output/libfile01.a​
Thanks for help
I finally solved the issue by using different argument for ar.
Instead of using
$ /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/ar rcu ../output/libfile01.a *.o
used
$ /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/ar -rcs ../output/libfile01.a *.o
The only difference was it's -rcs instead of rcu.
When checking the info of this libfile it shows the output like this:
$ lipo -info ../output/libfile01.a
Architectures in the fat file: ../output/libfile01.a are: armv7 armv7s armv6 arm64

How to build Cocoa Touch Framework for i386 and x86_64 architecture?

After building a Cocoa Touch framework (Swift or Object-C) and adding it to another project as "Embedded Binaries" I get the following error message when I try to build
missing required architecture i386
...
ld: symbol(s) not found for architecture i386
clang: error: linker command failed with exit code 1 (use -v to see invocation)
Following various existing answers and extended research I already added i386 to the Architectures build settings …
However this doesn't seem to have an effect. When I check using
lipo -info TesterFrameworkObjC
I only get
Architectures in the fat file: TesterFrameworkObjC are: armv7 arm64
… shouldn't i386 (and x86_64) appear here as well? What am I missing?
(I am using Xcode 6.2 + building for iOS 8.2)
Some new insights
Using a version of this build script I am able to build the missing architectures for the Swift version of the framework.
However when I add this framework to my app and build I still get errors
Undefined symbols for architecture x86_64:
"_OBJC_CLASS_$__TtC20TesterFrameworkSwift18TestFrameworkSwift", referenced from:
objc-class-ref in ViewController.o
ld: symbol(s) not found for architecture x86_64
Looking at the final build folder building for the simulator
Build/Products/Debug-iphoneos/TesterFrameworkSwift.framework/
I can see that the architectures are still missing although they were part of the framework (as shown). How can I ensure all the right architecture builds of my framework are included when building the app?
Update
Looking at all the error messages to me it looks like the issue isn't actually to have the wrong products/archictures being built but one step later there the Linker isn't using the correct paths to them. Not sure how correct this.
This is the same problem that I had.
Seems this is a Xcode bug, I workaround it by adding a build script.
It will just compile your library with all architectures, and lipo it to fat binary image.
Also note
Looking at the final build folder building for the simulator
Build/Products/Debug-iphoneos/TesterFrameworkSwift.framework/
you are looking x86_64 and i386 images in iphone build folder, they should be in Debug-iphonesimulator/TesterFrameworkSwift.framework/
Also there is a recursion issue in your script, I've corrected it.
UNIVERSAL_OUTPUTFOLDER=${BUILD_DIR}/${CONFIGURATION}-universal
if [ "true" == ${ALREADYINVOKED:-false} ]
then
echo "RECURSION: Detected, stopping"
else
export ALREADYINVOKED="true"
# Step 1. Build Device and Simulator versions
xcodebuild -target "${PROJECT_NAME}" ONLY_ACTIVE_ARCH=NO -configuration ${CONFIGURATION} -sdk iphoneos BUILD_DIR="${BUILD_DIR}" BUILD_ROOT="${BUILD_ROOT}" clean build
xcodebuild -target "${PROJECT_NAME}" -configuration ${CONFIGURATION} -sdk iphonesimulator ONLY_ACTIVE_ARCH=NO BUILD_DIR="${BUILD_DIR}" BUILD_ROOT="${BUILD_ROOT}" clean build
# Step 2. Copy the framework structure (from iphoneos build) to the universal folder
cp -R "${BUILD_DIR}/${CONFIGURATION}-iphoneos/${PROJECT_NAME}.framework" "${UNIVERSAL_OUTPUTFOLDER}/"
# Step 3. Copy Swift modules (from iphonesimulator build) to the copied framework directory
cp -R "${BUILD_DIR}/${CONFIGURATION}-iphonesimulator/${PROJECT_NAME}.framework/Modules/${PROJECT_NAME}.swiftmodule/." "${UNIVERSAL_OUTPUTFOLDER}/${PROJECT_NAME}.framework/Modules/${PROJECT_NAME}.swiftmodule"
# Step 4. Create universal binary file using lipo and place the combined executable in the copied framework directory
lipo -create -output "${UNIVERSAL_OUTPUTFOLDER}/${PROJECT_NAME}.framework/${PROJECT_NAME}" "${BUILD_DIR}/${CONFIGURATION}-iphonesimulator/${PROJECT_NAME}.framework/${PROJECT_NAME}" "${BUILD_DIR}/${CONFIGURATION}-iphoneos/${PROJECT_NAME}.framework/${PROJECT_NAME}"
# Step 5. Convenience step to copy the framework to the project's directory
cp -R "${UNIVERSAL_OUTPUTFOLDER}/${PROJECT_NAME}.framework" "${PROJECT_DIR}"
# Step 6. Convenience step to open the project's directory in Finder
open "${PROJECT_DIR}"
fi
6) Hit "cmd + B" (Build Project)
7) Open Product in Finder
8) Navigate 1 directory up ("cmd + ↑"), and you will see "Release-universal" directory.
There will be your "fat/universal" library, You are ready to go!
You can check it via
file test.dylib
test.dylib: Mach-O universal binary with 4 architectures
test.dylib (for architecture i386): Mach-O dynamically linked shared library i386
test.dylib (for architecture x86_64): Mach-O 64-bit dynamically linked shared library x86_64
test.dylib (for architecture armv7): Mach-O dynamically linked shared library arm
test.dylib (for architecture arm64): Mach-O 64-bit dynamically linked shared library
I encounter the same problem and fortunately I solved it.
When you create a framework with Xcode and build it with the iPhone 5 simulator or the simulator before iPhone 5(such as iPhone 4s or iPhone 4),you will get a framework with i386 architecture.And if you build it with iPhone 5s simulator or the simulatro after iPhone 5s,you will get a framework with x86_64 architecture.
But if you use the framework in your project and you want to run the app on a simulator,the framework must contain both i386 and x86_64 architecture,otherwise you will get a linker error.
So you need to use lipo -create command to merge two framework,at this point your framework is ready for use.
Go to Build Settings -> Set Build Active Architecture Only to NO
Build your Framework in iPhone 5 and iPhone 6 or above Simulators.
Add the run script in post actions to generate the universal framework.
Go to terminal and type cd (path of your framework, or drag and drop your framework) which will take you to the frameworks directory
type file YOUR_FRAMEWORK_NAME which lists all the architectures your framework is supporting
you can see that your framework supports all four architectures i386, x86_64, armv7 arm64.
Active Architecture => NO
Valid Architecture => "armv7 armv7s arm64 i386 x86_64"
Use Above Build Setting when in are aggregating !!!
I worked for me for all Architecture Framework creation

Resources