Xcode 7 builds i386 instead of arm binary for Release-iphoneos - ios

I moved from XCode 6 to XCode 7 and without any changes to the source, or project, or anything my Archive builds started to fail.
After research on the error that lipo produced:
lipo:.../Release-iphoneos/libSDWebImage.a and .../Release-iphonesimulator/libSDWebImage.a have the same architectures (i386) and can't be in the same fat output file
I found that the following:
In XCode 6 the lipo -info returns Architectures in the fat file: .../Release-iphoneos/libSDWebImage.a are: armv7 arm64 and Architectures in the fat file: .../Release-iphonesimulator/libSDWebImage.a are: i386 x86_64 which is correct. I have arm for iphone device and i386 for iphone simulator.
In XCode 7 these two files are the same, and have the i386 architecture! So framework scripts that uses lipo to join these two .a files into one fails.
Why XCode 7 suddenly stopped building my SDWebImage framework for arm? The project settings are unchanged, the library is the same, the scheme has Archive set to Release. Please help.
iMac:~ lukasz$ lipo -info /Users/lukasz/Library/Developer/Xcode/DerivedData/…-etcsjmgakpylpmgchumhnsqpyrev/Build/Intermediates/ArchiveIntermediates/adhoc-stage/BuildProductsPath/Release-iphoneos/libSDWebImage.a
input file /Users/lukasz/Library/Developer/Xcode/DerivedData/…-etcsjmgakpylpmgchumhnsqpyrev/Build/Intermediates/ArchiveIntermediates/adhoc-stage/BuildProductsPath/Release-iphoneos/libSDWebImage.a is not a fat file
Non-fat file: /Users/lukasz/Library/Developer/Xcode/DerivedData/…-etcsjmgakpylpmgchumhnsqpyrev/Build/Intermediates/ArchiveIntermediates/adhoc-stage/BuildProductsPath/Release-iphoneos/libSDWebImage.a is architecture: i386
iMac:~ lukasz$ lipo -info /Users/lukasz/Library/Developer/Xcode/DerivedData/…-etcsjmgakpylpmgchumhnsqpyrev/Build/Intermediates/ArchiveIntermediates/adhoc-stage/BuildProductsPath/Release-iphonesimulator/libSDWebImage.a
input file /Users/lukasz/Library/Developer/Xcode/DerivedData/…-etcsjmgakpylpmgchumhnsqpyrev/Build/Intermediates/ArchiveIntermediates/adhoc-stage/BuildProductsPath/Release-iphonesimulator/libSDWebImage.a is not a fat file
Non-fat file: /Users/lukasz/Library/Developer/Xcode/DerivedData/…-etcsjmgakpylpmgchumhnsqpyrev/Build/Intermediates/ArchiveIntermediates/adhoc-stage/BuildProductsPath/Release-iphonesimulator/libSDWebImage.a is architecture: i386

I ran into the same problem trying to build a multi-architecture framework on Xcode 7. It seems like you are building a static library, which is different, but could be related. I'm assuming you are using xcodebuild command (in an Aggregate target run script?) to build your library for different SDKs and then doing lipo at the end to join all of them.
The problem for me was that the framework/library being built is located in the build/UninstalledProducts folder, and what lives in the BUILD_DIR are symlinks to that. So most likely the libraries in your Release-iphoneos and Release-iphonesimulator are aliases to the same one, hence you see that they have the same architecture (i386 in your case).
To avoid this, navigate to the 'Build Settings' of your static library target in Xcode and ensure the following under 'Deployment':
Deployment Location is NO for release
Deployment Postprocessing is NO for release
You should see that the build no longer outputs UninstalledProducts folder and that all libraries/frameworks built in the BUILD_DIR are unique files, which should now have the correct architectures. You can then do whatever you like with them using lipo. You might have to delete your DerivedData before attempting the above.

For me, the fix was to set the 'Skip install' from Yes no No (which is the default). So insure that in addition to other two options mentioned by Andrew Wei. +1 for great analysis dude.

Related

Lipo Error while creating Universal frameworks in xcode 12

I am facing problem while making universal frameworks in xcode 12. following is the command that i ran:-
lipo -create build/simulator/FrameworkName.framework/FrameworkName build/devices/FrameworkName.framework/FrameworkName -output build/universal/FrameworkName.framework/FrameworkName
And following is the error that i am facing:-
fatal error: /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/lipo: build/simulator/FrameworkName.framework/FrameworkName and build/devices/FrameworkName.framework/FrameworkName have the same architectures (arm64) and can't be in the same fat output file
when i googled this error i found solution to set my 'Architectures', in 'Build Settings', to Standard, however it was already set to standard find the screenshot attached
Note: I was following this tutorial:- https://medium.com/#anuragajwani/how-to-build-universal-ios-frameworks-74b6b07bf31d
The error tells you that both your frameworks in build/simulator and build/device folders have been built for the same architecture (arm64, which is a device architecture). You can verify this by yourself, by looking inside the .framework file: FrameworkName.framework/Modules/FrameworkName.swiftmodule.
It is possible, that one of the folders (or both) contain more than one architecture like this:
Personally, I like to build my 'fat' frameworks outside the Xcode.app folders (just to make sure I have complete control over what is where). First, run your framework for simulator (select any simulator as build target). After the process has completed, go to Products folder in Xcode Navigator, click Show in Finder on FrameworkName.framework file. Copy the shown .framework somewhere more convenient (e.g. Desktop/simulator folder)
Then, build the framework again, only this time for device (select Any iOS device as build target). Copy second .framework somewhere like Desktop/iphone folder.
Create empty Desktop/universal folder for output framework. Copy .framework file there from Desktop/iphone folder and remove Desktop/universal/FrameworkName.framework/Framework executable file. This file will later be replaced by lipo.
Next, do the lipo magic:
lipo -create ~/Desktop/iphone/FrameworkName.framework/FrameworkName ~/Desktop/simulator/FrameworkName.framework/FrameworkName -output ~/Desktop/universal/FrameworkName.framework/FrameworkName
Last step, go to Desktop/simulator/FrameworkName.framework/Modules/FrameworkName.swiftmodule copy all files that start with x86_64 prefix, and paste them to Desktop/universal/FrameworkName.framework/Modules/FrameworkName.swiftmodule. Now your Desktop/universal/FrameworkName.framework contains both device and simulator architectures. Congrats, you've got your 'fat' library!
Disclaimer: Yes, I realise there are easier ways to do this with various scripts and terminal commands, but all of them do pretty much the same thing. Once you try to do this manually step by step, it will help you understand what goes where, and what are architectures and how they can be combined.
Disclaimer 2: Starting from Xcode 12, Apple insists you build .xcframeworks instead of 'fat' libraries. See here

Will the compiler strip the unrelated arch symbols from dependent static library in product binary file?

I'm a new in framework development, here is my case. I build a private static library to provide it to the vendors to link it.
Currently, I build my library with arch armv7 and arm64 only, this should be work for vendors to debug it in iOS device and archive their apps, but not for debugging in iOS Simulator. The simulator needs the x86_64 ( and even i386 in iPhone 5 Simulator). It isn't friendly to disable the ability to debug it in a simulator. I'm considering to provide a fat architecture of static library for them.
Here is the action
lipo -create libSignatureLibary_armv6.a libSignatureLibary_armv7.a libSignatureLibary_i368.a -output libSignatureLibary.a
After the merge operation, the output library has a double size than the single one.
The question is, will the compiler/Xcode strip the i386 and x86_64 arch symbols from final app product binary? If not, the fat arch library will increase the product app's size directly, right? Should I build two versions of the library for vendors, one for debugging, another for archiving? What's the right solution for this case?
I don't know what keywords I should research, I didn't have an existing product app linking it to verify this, either. (Maybe I should build a new later.)
Don't worry, the linker only uses the .o (relocatable object file, it is the output file of assembler, when you build a static library, a .m file will be translated to a .o file. The static library is a collection of relocatable object files) files for target arch in the static library, so it will strip the x86_64 and i386 .o files when building product binary.
Also the linker won't link the .o file which is not referenced directly or indirectly by compiled files into executable file.

Merging iOS .dylib into framework with lipo breaks bitcode recompilation

I'm trying to build a dynamic iOS framework manually from .dylib files. Binaries are created with cmake and xcodebuild and produce two .dylib files, one containing armv7, armv7s and arm64 and the other x86_64 and i386 architectures. Libraries are compiled with -fembed-bitcode parameter and everything succeeds.
.dylib files are then merged with next command:
lipo -create lib_arm.dylib lib_i386.dylib -output MyFramework
Framework is then created by copying the output from lipo command to:
MyFramework.framework/MyFramework
Headers and Info.plist are manually generated and added to the framework.
This framework is then installed via CocoaPods into the application as a vendored_framework. It is known that CocoaPods will strip the i386/x86_64 libraries from any fat binaries, for App Store distribution.
Application builds, runs, archives and uploads successfully to App Store.
However, since Bitcode is enabled, App Store will process the .ipa, and recompile with bitcode, this is where it fails and I receive an email from App Store, that it failed processing. Following instructions, I can reproduce the error locally with Exporting for Ad-Hoc Distribution and recompiling for bitcode. The error I receive is this:
ipatool failed with an exception: #<Errno::ENOENT: No such file or directory - /lib_arm.dylib>\n
So apparently during the recompilation, there is still a reference or somewhere to lib_arm.dylib, even though it was merged into a fat dylib Mach-O universal binary (file output of the merged dylib binary below):
>> file MyFramework
MyFramework: Mach-O universal binary with 5 architectures: [x86_64: Mach-O 64-bit dynamically linked shared library x86_64] [i386] [arm_v7] [arm_v7s] [arm64]
MyFramework (for architecture x86_64): Mach-O 64-bit dynamically linked shared library x86_64
MyFramework (for architecture i386): Mach-O dynamically linked shared library i386
MyFramework (for architecture armv7): Mach-O dynamically linked shared library arm_v7
MyFramework (for architecture armv7s): Mach-O dynamically linked shared library arm_v7s
MyFramework (for architecture arm64): Mach-O 64-bit dynamically linked shared library arm64
This is pretty much where my compiler/linker knowledge gets out of scope.
So my question is:
Where am I going wrong with this? Maybe bitcode should be compiled differently? Or maybe I am using lipo in wrong way?
Thank you!
After inspecting load commands of the created fat binary with otool -l command, I realized that using lipo itself does not change the LC_ID_DYLIB in the binary and it will reuse one from the first provided library. Using install_name_tool to change the id to correct one of the framework (including #rpath for iOS dynamic frameworks) fixes the error.
install_name_tool -id #rpath/MyFramework.framework/MyFramework MyFramework
Make sure the entire path to binary is included, together with .framework directory.

ERROR ITMS-90085: “No architectures in the binary. Lipo failed to detect any architectures in the bundle executable.”

We have built a Xamarin app (iOS, Android) with several native bindings. The app runs fine on device and simulator and we are able to build an archive without any issues (apparently).
The issue is when we want to upload the build to the app store (using the app loader or xcode 7.3.1), we get the following error:
ERROR ITMS-90085: “No architectures in the binary. Lipo failed to detect any architectures in the bundle executable.”
Running lipo -info on the app yields the following response :
Architectures in the fat file: NameOfMyApp.iOS.app/NameOfMyApp.iOS are: armv7 arm64
We have searched for an answer thoroughly before posting this question and have made sure of the following:
The product name is correct
Xcode is installed
Application loader is the latest version
Bundle Id is correct
If anyone has an idea the help would be greatly appreciated!
Thanks,
A.
I recently ran into this error for a totally different reason. We were using this really popular script to remove unused architectures from our app before app store submission.
The problem is that this script does the totally wrong thing if you include a watch app and are building with Xcode 10! It looks for all architectures in the ARCHS variable and removes all other architectures from fat binaries, the problem is
ARCHS doesn't include watch architectures, and
starting in Xcode 10, watch binaries are fat (due to the new watch)
In XCode 9 the script would skip over watch stuff, but now it wrongly strips them.
I fixed the error by changing the script to instead only remove simulator architectures.
EXTRACTED_ARCHS=()
GOOD_ARCHS=()
PRESENT_ARCHS=($(lipo -archs "$FRAMEWORK_EXECUTABLE_PATH"))
if [[ "${#PRESENT_ARCHS[#]}" -lt 2 ]]
then
echo "Framework is not a Fat binary, skipping..."
continue
fi
for ARCH in "${PRESENT_ARCHS[#]}"
do
if [[ "$ARCH" != x86_64 && "$ARCH" != i386 ]]
then
echo "Extracting $ARCH from $FRAMEWORK_EXECUTABLE_NAME"
lipo -extract "$ARCH" "$FRAMEWORK_EXECUTABLE_PATH" -o "$FRAMEWORK_EXECUTABLE_PATH-$ARCH"
GOOD_ARCHS+=("$ARCH")
EXTRACTED_ARCHS+=("$FRAMEWORK_EXECUTABLE_PATH-$ARCH")
fi
done
So it turns out that we were doing some native bindings in our project.
In one of these bindings we included a framework at the root of the project, the framework being a folder that includes sub-folders that contain the lib.a.
It turns out that at compilation time the whole framework folder structure was being copied into the resulting IPA and this was causing the issue.
The solution was to simply extract the lib.a and move it to the root of the project and delete the framework folder.
The resulting IPA no longer had the framework folder and the submission went through without a glitch.
May sometimes this error occurs when you in hurry and forgot to change Build Environment to Generic iOS Device for Archiving !
Find image here!
In my case the error was a bit misleading. It had nothing to do with architectures, it just wasn't finding the binary itself.
I'm generating an app extension through CMake, using add_library. CMake renames the extension's executable from MyExtension to libMyExtension.so.
Since "CFBundleExecutable must match the name of the bundle directory minus its extension.", I had to tweak my CMakeLists.txt file to prevent that the extension's executable is renamed:
set_target_properties(${APPEX_NAME} PROPERTIES
XCODE_ATTRIBUTE_EXECUTABLE_SUFFIX ""
XCODE_ATTRIBUTE_EXECUTABLE_PREFIX ""
)
In my case,
turn "Embed & Sign" to "Do not embedded" of each framework.
Then restart Xcode. No need to use pod update or pod disintegrate.

Check supported architectures of framework in Objective-C

As requested by Apple in the next February (February 2014), every app submitted to AppStore needs to support Arm64 architecture. In my project, I used many static libraries (*.a) and I can check if these libs support arm64 arch. However, I don't know if some frameworks such as Facebook.framework supports this new arch. How can I check it?
Each framework is really just a directory - not even like a package directory, but a plain directory you can browse directly into with Finder. Go into the .framework folder, at the top level you'll find a file with the same name as the framework (for older frameworks that file may be located under a folder called Versions/A within the .framework folder).
That file is really a static library (.a) file, just without the extension. Check it as you would any static library (using file or lipo -info) and you'll see what binaries the file contains.
You'll also know through XCode though. If you switch your project to support arm64 and the libraries you are linking to do not have arm64 support, XCode will not finish linking when compiling for a device.
Check below command in Terminal
lipo -info yourlib.a
Output like :
Architectures in the fat file: yourlib.a are: i386 x86_64 armv7 arm64
In case Framework.framework
Go to inside framework like below
cd /Your_Path_/CocoaLumberjack.framework
then run command
lipo -info CocoaLumberjack

Resources