how to build ios framework to support i386 and armv7 - ios

I need to build dynamic library as framework. I have building settings as follows:
ARCHS: armv7 armv7s arm64 i386 x86_64
ONLY_ACTIVE_ARCH: NO
VALID_ARCHS: arm64 armv7 armv7s x86_64 i386
I built target for ios device, and used lipo -info to check the architectures, the result is :
Architectures in the fat file: dyl are: armv7s armv7 arm64
So, does xcode can not build for both i386 and arm?

You need to select iOS simulator and build a framework for i386 arch. Then you can use lipo -create command to merge the two framework into one.

There is a way of doing it without exiting the Xcode. First you need to identify the latest iOS versions (64 bits) do not support i386 architecture. So if you still need i386 compatible framework, you have to build your project by selecting an old iOS version. I tried with iOS 10.
Next thing that you have to do is, add all the architectures that you need under Valid Architectures filed in the Build Settings.
Then, add a Run Script with your lipo commands to create the FAT file. (Following script I've taken from the Internet sometime back & credit goes to those who wrote that)
#!/bin/sh
UNIVERSAL_OUTPUTFOLDER=${BUILD_DIR}/${CONFIGURATION}-universal
# make sure the output directory exists
mkdir -p "${UNIVERSAL_OUTPUTFOLDER}"
# 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 (if it exists) to the copied framework directory
SIMULATOR_SWIFT_MODULES_DIR="${BUILD_DIR}/${CONFIGURATION}-iphonesimulator/${PROJECT_NAME}.framework/Modules/${PROJECT_NAME}.swiftmodule/."
if [ -d "${SIMULATOR_SWIFT_MODULES_DIR}" ]; then
cp -R "${SIMULATOR_SWIFT_MODULES_DIR}" "${UNIVERSAL_OUTPUTFOLDER}/${PROJECT_NAME}.framework/Modules/${PROJECT_NAME}.swiftmodule"
fi
# 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}"
Finally what you have to do is, build the framework by selecting Generic iOS Device option.
Then to verify, run the lipo -info command

Related

Could not find module 'MyCustomFramework' for target 'x86_64-apple-ios-simulator'; found: arm64, armv7-apple-ios, arm64-apple-ios, arm, armv7

I have a custom framework that I am archiving for use in another project. After updating to Xcode11 I get the following error in my project utilizing the framework.
Could not find module 'MyCustomFramework' for target 'x86_64-apple-ios-simulator'; found: arm64, armv7-apple-ios, arm64-apple-ios, arm, armv7
My framework works fine on Xcode10 but does not on 11. My target is set to NO for build active architectures only. I have the following for Valid Architectures; arm64e, armv7s, armv7, arm64.
My build script
exec > ${PROJECT_DIR}/${PROJECT_NAME}_archive.log 2>&1
UNIVERSAL_OUTPUTFOLDER=${BUILD_DIR}/${CONFIGURATION}-universal
if [ "true" == ${ALREADYINVOKED:-false} ]
then
echo "RECURSION: Detected, stopping"
else
export ALREADYINVOKED="true"
# make sure the output directory exists
mkdir -p "${UNIVERSAL_OUTPUTFOLDER}"
echo "Building for iPhoneSimulator"
xcodebuild -workspace "${WORKSPACE_PATH}" -scheme "${TARGET_NAME}" -configuration ${CONFIGURATION} -sdk iphonesimulator -destination 'platform=iOS Simulator,name=iPhone 11 Pro Max' ONLY_ACTIVE_ARCH=NO ARCHS='i386 x86_64' BUILD_DIR="${BUILD_DIR}" BUILD_ROOT="${BUILD_ROOT}" ENABLE_BITCODE=YES OTHER_CFLAGS="-fembed-bitcode" BITCODE_GENERATION_MODE=bitcode clean build
# Step 1. Copy the framework structure (from iphoneos build) to the universal folder
echo "Copying to output folder"
cp -R "${ARCHIVE_PRODUCTS_PATH}${INSTALL_PATH}" "${UNIVERSAL_OUTPUTFOLDER}/"
# Step 2. Copy Swift modules from iphonesimulator build (if it exists) to the copied framework directory
SIMULATOR_SWIFT_MODULES_DIR="${BUILD_DIR}/${CONFIGURATION}-iphonesimulator/${TARGET_NAME}.framework/Modules/${TARGET_NAME}.swiftmodule/."
if [ -d "${SIMULATOR_SWIFT_MODULES_DIR}" ]; then
cp -R "${SIMULATOR_SWIFT_MODULES_DIR}" "${UNIVERSAL_OUTPUTFOLDER}/${TARGET_NAME}.framework/Modules/${TARGET_NAME}.swiftmodule"
fi
# Step 3. Create universal binary file using lipo and place the combined executable in the copied framework directory
echo "Combining executables"
lipo -create -output "${UNIVERSAL_OUTPUTFOLDER}/${EXECUTABLE_PATH}" "${BUILD_DIR}/${CONFIGURATION}-iphonesimulator/${EXECUTABLE_PATH}" "${ARCHIVE_PRODUCTS_PATH}${INSTALL_PATH}/${EXECUTABLE_PATH}"
# Step 4. Create universal binaries for embedded frameworks
#for SUB_FRAMEWORK in $( ls "${UNIVERSAL_OUTPUTFOLDER}/${TARGET_NAME}.framework/Frameworks" ); do
#BINARY_NAME="${SUB_FRAMEWORK%.*}"
#lipo -create -output "${UNIVERSAL_OUTPUTFOLDER}/${TARGET_NAME}.framework/Frameworks/${SUB_FRAMEWORK}/${BINARY_NAME}" "${BUILD_DIR}/${CONFIGURATION}-iphonesimulator/${SUB_FRAMEWORK}/${BINARY_NAME}" "${ARCHIVE_PRODUCTS_PATH}${INSTALL_PATH}/${TARGET_NAME}.framework/Frameworks/${SUB_FRAMEWORK}/${BINARY_NAME}"
#done
# Step 5. Convenience step to copy the framework to the project's directory
ARCHIVE_PATH="${PROJECT_DIR}/Products"
rm -rf "${ARCHIVE_PATH}"
mkdir "${ARCHIVE_PATH}"
echo "Copying to project dir"
yes | cp -Rf "${UNIVERSAL_OUTPUTFOLDER}/${FULL_PRODUCT_NAME}" "${ARCHIVE_PATH}"
open "${ARCHIVE_PATH}"
fi
This line is incorrect
cp -R "${SIMULATOR_SWIFT_MODULES_DIR}" "${UNIVERSAL_OUTPUTFOLDER}/${TARGET_NAME}.framework/Modules/${TARGET_NAME}.swiftmodule"
Should be
cp -R "${SIMULATOR_SWIFT_MODULES_DIR}" "${UNIVERSAL_OUTPUTFOLDER}/${TARGET_NAME}.framework/Modules/"
You'll need to check in the target folder
"${UNIVERSAL_OUTPUTFOLDER}/${TARGET_NAME}.framework/Modules/"
If there are files like
x86_64-apple-ios-simulator.swiftdoc
x86_64-apple-ios-simulator.swiftmodule
x86_64.swiftdoc
x86_64.swiftmodule
Before Xcode 11, Apple seems neglect those files so your script works well.
From Xcode 11 those files are seem to be checked rigorously.
Swift 5.0-5.1, Xcode 11 Open Xcode, <your project>, Build Settings, Build Active Architecture Only and change to <NO> for Debug and Release. Architectures set/leave in Standard Architecture -$(ARCHS_STANDART), important is next step:Valid Architecture: armv7, armv7s, amr64, amr64e, ADD here x86_64 and if you need add i386 for Debug and Release. (String: armv7, armv7s, amr64, amr64e, x86_64)
Choose any simulator in your simulator list and BUILT IT. DONE.
I hope it is works for you.
Description of Architecture:
armv64: iPhoneX, iPhone 5s-8, iPad Air — iPad Pro
armv7 : iPhone3Gs-5c, iPad WIFI(4th gen)
armv6 : iPhone — iPhone3G
-the above if for real devices
i386 : 32-bit simulator
x86_64 : 64-bit simulator

Build framework for multiple architectures (arm64, armv7, armv7s)

I'm trying to upload to TestFlight a project build for arm64, armv7, and armv7s. It is using a framework from another project. But the frameowork appears to be built only for arm64 and not arm64 (file was built for arm64 which is not the architecture being linked (armv7)).
The question is how do I make the framework containing all architectures? I want to keep the projects separated. And I don't care for simulators. I want to make sure it is built for release.
This is the framework target:
EDIT: My project is Cordova based. So it is using a plugin which utilize a pre-built framework. There are instructions out there for building a fat framework, containing simulators and device, then concatenating it with lipo. What I need is the architecture from the device I don't have as well. Does that actually mean I need three devices from arm64, armv7, and armv7s to be able to concatenating them altogether?
Apple has discontinued support for 32-bit in iOS 11. You can neither run 32 bit apps on iOS 11 nor run iOS 11 on 32 bit processors. Thus, you have to set your Deployment Target to an iOS version earlier than iOS 11 for your framework.
You can try to create an aggregate target and write an script which will support all the platform. This is sample script from one of my project.
unset TOOLCHAINS #Xcode 7.3 BUG FIX http://stackoverflow.com/questions/36184930/xcodebuild-7-3-cant-enable-bitcode
# define output folder environment variable
C_PROJECT_NAME="<<YOUR_FRAMEWORK_NAME>>"
UNIVERSAL_OUTPUTFOLDER=${BUILD_DIR}/${CONFIGURATION}-universal
# Step 1. Build Device and Simulator versions
xcodebuild -target <<YOUR_FRAMEWORK_NAME>> ONLY_ACTIVE_ARCH=NO -configuration ${CONFIGURATION} -sdk iphoneos BUILD_DIR="${BUILD_DIR}" BUILD_ROOT="${BUILD_ROOT}"
xcodebuild -target <<YOUR_FRAMEWORK_NAME>> ONLY_ACTIVE_ARCH=NO -configuration ${CONFIGURATION} -sdk iphonesimulator -arch i386 -arch x86_64 BUILD_DIR="${BUILD_DIR}" BUILD_ROOT="${BUILD_ROOT}"
mkdir -p "${UNIVERSAL_OUTPUTFOLDER}"
rm -rf ./${C_PROJECT_NAME}.framework
cp -R ${BUILD_DIR}/${CONFIGURATION}${EFFECTIVE_PLATFORM_NAME}/${C_PROJECT_NAME}.framework ./
# Step 2. Create universal binary file using lipo
lipo -create -output "${UNIVERSAL_OUTPUTFOLDER}/${C_PROJECT_NAME}" "${BUILD_DIR}/${CONFIGURATION}-iphoneos/${C_PROJECT_NAME}.framework/${C_PROJECT_NAME}" "${BUILD_DIR}/${CONFIGURATION}-iphonesimulator/${C_PROJECT_NAME}.framework/${C_PROJECT_NAME}"
mv ${UNIVERSAL_OUTPUTFOLDER}/${C_PROJECT_NAME} ./${C_PROJECT_NAME}.framework/${C_PROJECT_NAME}

Cant add x86_64 support to the static library

i'v been working for hours for this 'little' problem.I tried to create a universal library and i managed to get 3 set of architecture, when i check my universal lib with lipo -info
armv7 i386 arm64
and with file command
Mach-O universal binary with 3 architectures
(for architecture armv7): current ar archive random library
(for architecture i386): current ar archive random library
(for architecture arm64): current ar archive random library
my shell script to create universal lib ;
# define output folder environment variable
UNIVERSAL_OUTPUTFOLDER=${BUILD_DIR}/${CONFIGURATION}-universal
# Step 1. Build Device and Simulator versions
xcodebuild -target libTest ONLY_ACTIVE_ARCH=NO -configuration ${CONFIGURATION} -sdk iphoneos BUILD_DIR="${BUILD_DIR}" BUILD_ROOT="${BUILD_ROOT}"
xcodebuild -target libTest ONLY_ACTIVE_ARCH=NO -configuration ${CONFIGURATION} -sdk iphonesimulator -arch i386 BUILD_DIR="${BUILD_DIR}" BUILD_ROOT="${BUILD_ROOT}"
# make sure the output directory exists
mkdir -p "${UNIVERSAL_OUTPUTFOLDER}"
# Step 2. Create universal binary file using lipo
lipo -create -output "${UNIVERSAL_OUTPUTFOLDER}/lib${PROJECT_NAME}.a" "${BUILD_DIR}/${CONFIGURATION}-iphoneos/lib${PROJECT_NAME}.a" "${BUILD_DIR}/${CONFIGURATION}-iphonesimulator/lib${PROJECT_NAME}.a"
# Last touch. copy the header files. Just for convenience
cp -R "${BUILD_DIR}/${CONFIGURATION}-iphoneos/include" "${UNIVERSAL_OUTPUTFOLDER}/"
my build settings;
build active architecture only - NO
Architectures;
$(ARCHS_STANDARD)
x86_64 (i added this)
Valid architectures;
armv7s
x86_64
armv7
arm64
i386
I tried everything and it still seems failed.How can I create a fat file with all these architectures?

How to update our static library architecture for suporting arm64 Build?

Few days ago i create static-library (Universal) that work's fine with Xcode5.0 SDK7. After Update Xcode5.1 with SDK7.1 that not work if i select simulator iPhone Retina(4-inch 64-bit). Then i am going to update my lib with Bellow setting change.
I do the same for three Target:-
For sporting simulator as well as device i put Universal lib and in to this i run script this:-
After this i Build Again lib and used as i done Before in to my project. But still getting same issue with iPhone Retina(4-inch 64-bit) Undefined symbols for architecture x86_64:
So, My question is that is there any additional change required for updating lib for arm64 or i did any mistake in above step. Please current me if i am wrong.
what change needed for update my static-library for supporting 64Bit architecture
NOTE:
I am asking for my own created Library Update. i am not using third-party Library.
Update
I used this lipo -info testingLibImport/libLibNSlog.a command in to my Terminal that output is:
Architectures in the fat file: testingLibImport/libLibNSlog.a are: armv7 armv7s i386 arm64
Another solution I found with XCode 6.4 is to add ONLY_ACTIVE_ARCH=NO and not specify the architecture. So
xcodebuild -target TargetName ONLY_ACTIVE_ARCH=NO -configuration ${CONFIGURATION} -sdk iphonesimulator BUILD_DIR="${BUILD_DIR}" BUILD_ROOT="${BUILD_ROOT}"
Will build i386 and x86_64 architectures in your library.
Here's my full universal lib run script to build all the architectures.
# define output folder environment variable
UNIVERSAL_OUTPUTFOLDER=${BUILD_DIR}/${CONFIGURATION}-universal
# Step 1. Build Device and Simulator versions
xcodebuild -target TargetName ONLY_ACTIVE_ARCH=NO -configuration ${CONFIGURATION} -sdk iphoneos BUILD_DIR="${BUILD_DIR}" BUILD_ROOT="${BUILD_ROOT}"
xcodebuild -target TargetName ONLY_ACTIVE_ARCH=NO -configuration ${CONFIGURATION} -sdk iphonesimulator BUILD_DIR="${BUILD_DIR}" BUILD_ROOT="${BUILD_ROOT}"
# make sure the output directory exists
mkdir -p "${UNIVERSAL_OUTPUTFOLDER}"
# Step 2. Create universal binary file using lipo
lipo -create -output "${UNIVERSAL_OUTPUTFOLDER}/lib${PROJECT_NAME}.a" "${BUILD_DIR}/${CONFIGURATION}-iphoneos/lib${PROJECT_NAME}.a" "${BUILD_DIR}/${CONFIGURATION}-iphonesimulator/lib${PROJECT_NAME}.a"
# Last touch. copy the header files. Just for convenience
cp -R "${BUILD_DIR}/${CONFIGURATION}-iphoneos/include" "${UNIVERSAL_OUTPUTFOLDER}/"
I too ran into the same problem yesterday and after lot of googling and trying on different solutions, i gave up and tried on my own. All i could understand from the different solutions provided was that when i run "lipo -info library.a" it was not built for x86_64 architecture. So, decided to give up the aggregate approach and made a simple attempt.
as advised in this post, i added armv7, armv7s and arm64 to the architectures.
build the static library project with iphone simulator (32 bit)
build the static library project with iphone simulator (64 bit)
build the static library project with iOS device
go to the build path (under derived data)
copied both simulator and device output to a common folder
used lipo command in terminal window to create the universal library
lipo command: lipo -create -output newlibraryname.a simulatorlibraryname.a devicelibraryname.a
integrated the newly created universal static library and it WORKED!!!
After lots of stuff i got solution. some of xcode dont know there is automatic appear Standard architectures (including 64-bit) (armv7,armv7s,arm64) but in my case there is not option into my Static Library Project. so i am going to add this Manually like:-
and select this Option:-
After this i re-Build My static Library and used in to in my project that working fine now. and I also checked with lipo command in to terminal that output going to different now:-
testingLibImport/libLibNSlog.a are: armv7 armv7s i386 x86_64 arm64
Sorry for posting another solution so late. I had found this solution long time back when i was trying to find a solution that would save me from the manual work of creating a universal library using lipo command every time i had to build the universal library.
So, here is the another approach, for those using aggregate approach to build the universal library
just make one small change as mentioned below in your aggregate script for simulator to build the universal library -
xcodebuild -target ProductName -configuration ${CONFIGURATION} -sdk iphonesimulator ARCHS="i386 x86_64" BUILD_DIR="${BUILD_DIR}" BUILD_ROOT="${BUILD_ROOT}" SYMROOT="${SYMROOT}"
Please observe the inclusion of multiple architectures instead of using single architecture approach -
xcodebuild -target ProductName -configuration ${CONFIGURATION} -sdk iphonesimulator -arch i386 BUILD_DIR="${BUILD_DIR}" BUILD_ROOT="${BUILD_ROOT}" SYMROOT="${SYMROOT}"
Just ARCHS="i386 x86_64" will do the magic for you.
You can confirm this by using the following lipo command
lipo -info newLibraryName.a
Hope this saves time for many others like me!!!

Apple Mach-O Linker Warning. lib/libxyz.a missing required architecture i386 in file lib/libxyz.a

i am new to Apple iOS development. I am trying to create static library and add it to Main application.
Created Library Project and added it as a dependency project to the Main application. It works.
Now I took the lib.a (static library) from the Library project (present under debug-iphoneos) and copied to Main application. Tested the Main application - it works.
Now when i tried to copy the Main application to some other location (or even change the folder name - in which Main application is present) and try to run on Simulator, then i get following error:
ignoring file /Users/.../lib.a, missing required architecture i386 in file /Users/.../lib.a
I don't really understand the relation/dependency on the path.
the problem is solved.
I am using XCode 5.0.2 and iOS 7. when ever i compile the static library, the Xcode says it is building a universal library (but it is actually not). The 'Products' directory shows libxyz.a (which is in iphoneos/ directory) - this is actually for ARM6 & ARM7 for iPhone device. So when i took this 'libxyz.a' file and used it in another projects the linker used to throw a warning ' missing required architecture i386 '.
i have followed http://www.raywenderlich.com/41377/creating-a-static-library-in-ios-tutorial
used the script to generate single binary which contains both simulator & iphone device binary.
# define output folder environment variable
UNIVERSAL_OUTPUTFOLDER=${BUILD_DIR}/${CONFIGURATION}-universal
# Step 1. Build Device and Simulator versions
xcodebuild -target ImageFilters ONLY_ACTIVE_ARCH=NO -configuration ${CONFIGURATION} -sdk iphoneos BUILD_DIR="${BUILD_DIR}" BUILD_ROOT="${BUILD_ROOT}"
xcodebuild -target ImageFilters -configuration ${CONFIGURATION} -sdk iphonesimulator -arch i386 BUILD_DIR="${BUILD_DIR}" BUILD_ROOT="${BUILD_ROOT}"
# make sure the output directory exists
mkdir -p "${UNIVERSAL_OUTPUTFOLDER}"
# Step 2. Create universal binary file using lipo
lipo -create -output "${UNIVERSAL_OUTPUTFOLDER}/lib${PROJECT_NAME}.a" "${BUILD_DIR}/${CONFIGURATION}-iphoneos/lib${PROJECT_NAME}.a" "${BUILD_DIR}/${CONFIGURATION}-iphonesimulator/lib${PROJECT_NAME}.a"
# Last touch. copy the header files. Just for convenience
cp -R "${BUILD_DIR}/${CONFIGURATION}-iphoneos/include" "${UNIVERSAL_OUTPUTFOLDER}/"

Resources