Check supported architectures of framework in Objective-C - ios

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

Related

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.

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

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.

How do you build PoDoFo on iOS with Openssl support?

I have a project which uses PoDoFo for digitally signing PDF so I am trying to integrate CTOpenSSLWrapper into a single project which uses both PoDoFo and OpenSSL libraries. But when i try to build it, iam getting issues with linking:
The same error repeats with ld: symbol(s) not found for architecture armv7 if I try to run on device.
I have cross-checked every thing:
header search paths
library search paths
Buildphases->compile sources for any missing .m files
But i still have the same issue.
How can i resolve this?
I have cross-checked every thing:
1. header search paths
2. library search paths
3. Buildphases->compile sources for any missing .m files
It appears you are not including the library (only providing the library search path).
Here's what a typical library include looks like for me. Its for OpenSSL, but the same will apply to PoDoFo. In the example below, OpenSSL built for iOS is located in /usr/local/ssl/ios. Headers are located in is located in /usr/local/ssl/ios/include/openssl, and libraries are located in /usr/local/ssl/ios/lib.
Paths:
Library:
If you still have linker errors after adding the library, then perform the following to ensure you library has the architectures you need. I'm using OpenSSL as an example, you should use the PoDoFo library's name.
xcrun -sdk iphoneos lipo -info libcrypto.a
You should see something like:
Architectures in the fat file: libcrypto.a are: armv7 armv7s arm64 i386
If you need an OpenSSL built for iOS, then try this GitHub: noloader/openssl-1.0.1h-ios. Its a fat library, and has all the architectures you might need for iOS.

How to integrate MuPDF 1.3 in iOS Project

There is build-in PDF render engine for iOS, but it doesn't solve the "Transparency Flattening" issue. Hence I try to integrate MuPDF 1.3 into project.
I tried to use reference the MuPDF project, and it failed.
Then I build debug static libraries for each architecture, and use "Library Search Paths" and "Other Link Flags" to separate the linked library while building binary of different architecture, but XCode keeps showing "Undefined symbols for architecture armxxx".
Finally, I built the release version static library of MuPDF, which should compatible for all architecture, and XCode still keeps showing same thing as before.
Does there anyone integrate and compile MuPDF 1.3 successfully? Please give me some hint.
Thanks a lot.
Sorry for the late answer but it could help people a day or another.
As I had to integrate the MuPDF library into one of my (Swift) project, I generated
the static fat libraries and integrate them into Xcode.
Here you go with a step-by-step quick tutorial:
How to build the static fat library:
git clone --recursive git://git.ghostscript.com/mupdf.git
Go to mupdf/platform/ios
Open MuPDF.xcodeproj with Xcode.
Configure the scheme of the MuPDF target to Release.
Build and run the app on an iPhone simulator.
This will generate the library for platforms i386 and x86_64
Build and Run the app on a real iPhone device - use your own bundle id, certificate and provisioning profile.
This will generate the library for platforms armv7 and arm64
Go to mupdf/build/
You will find two folders that contains all built librairies: release-ios-i386-x86_64 and release-ios-armv7-arm64
Now you need to create fat libraries with all 4 architectures for the mupdf one and all its dependencies.
lipo -create ./*/libcurl.a -output 'libcurl.a' ; lipo -create ./*/libfreetype.a -output 'libfreetype.a' ; lipo -create ./*/libjbig2dec.a -output 'libjbig2dec.a' ; lipo -create ./*/libjpeg.a -output 'libjpeg.a' ; lipo -create ./*/libmujs.a -output 'libmujs.a' ; lipo -create ./*/libmupdf.a -output 'libmupdf.a' ; lipo -create ./*/libopenjpeg.a -output 'libopenjpeg.a' ; lipo -create ./*/libz.a -output 'libz.a'
How to integrate MuPDF into your project:
Add/import into your project:
All header files from mupdf/include/mupdf
All obj-c classes from mupdf/platform/ios/classes
The common.[h,m] files from mupdf/platform/ios
Add/import the previously generated fat libraries (8 files)
Configure the Library Search Path by adding the path to your library files.
For example $(inherited) $(PROJECT_DIR)/External/MuPDF/lib/
You should now be able to build and run your app with the library included.
Use the sample project to understand how the library works or any online tutorial.
Pro Tip:
The final fat libraries are pretty big all together (~ 46mb).
You could easily reduce the final size of your app by importing:
Under a release folder just the lib.a from mupdf/build/release-ios-armv7-arm64
Under a debug folder the big generated fat librairies from mupdf/build/
Set different Library Search Path for Debug and Release config.
Once done, you will be able to build and run on Debug on every simulator and devices. But only on devices for Release. Which in the end you need as your app, through, the AppStore
should only run on real devices. There is no need to include debug-simulator architecture static librairies.
Here is a screenshot of all imported files into my Xcode project:
The easiest way is probably to use the MuPDF CocoaPod, which I just created. There is an example application based on that pod.

Resources