Build framework with bitcode - ios

Im trying to create an universal framework from one of the targets in my project. I have used a few scripts, I have found on the internet, but I have one problem - the final framework, doesn't seem to include bitcode. This is the script, that I'm using to create this framework:
UNIVERSAL_OUTPUT_DIR=${BUILD_DIR}/${CONFIGURATION}-universal
RELEASE_DIR=${PROJECT_DIR}/build
TARGET="Observation"
mkdir -p "${UNIVERSAL_OUTPUT_DIR}"
xcodebuild BITCODE_GENERATION_MODE=bitcode -target "${TARGET}" ONLY_ACTIVE_ARCH=NO -configuration ${CONFIGURATION} BUILD_DIR="${BUILD_DIR}" BUILD_ROOT="${BUILD_ROOT}" clean build -sdk iphoneos
xcodebuild BITCODE_GENERATION_MODE=bitcode -target "${TARGET}" ONLY_ACTIVE_ARCH=NO -configuration ${CONFIGURATION} BUILD_DIR="${BUILD_DIR}" BUILD_ROOT="${BUILD_ROOT}" clean build -sdk iphonesimulator
cp -R "${BUILD_DIR}/${CONFIGURATION}-iphoneos/${TARGET}.framework" "${UNIVERSAL_OUTPUT_DIR}/"
SIMULATOR_SWIFT_MODULES_DIR="${BUILD_DIR}/${CONFIGURATION}-iphonesimulator/${TARGET}.framework/Modules/${TARGET}.swiftmodule/."
if [ -d "${SIMULATOR_SWIFT_MODULES_DIR}" ]; then
cp -R "${SIMULATOR_SWIFT_MODULES_DIR}" "${UNIVERSAL_OUTPUT_DIR}/${TARGET}.framework/Modules/${TARGET}.swiftmodule"
fi
lipo -create -output "${UNIVERSAL_OUTPUT_DIR}/${TARGET}.framework/${TARGET}" "${BUILD_DIR}/${CONFIGURATION}-iphonesimulator/${TARGET}.framework/${TARGET}" "${BUILD_DIR}/${CONFIGURATION}-iphoneos/${TARGET}.framework/${TARGET}"
cp -R "${UNIVERSAL_OUTPUT_DIR}/${TARGET}.framework" "${RELEASE_DIR}"
open "${RELEASE_DIR}"
And when I try to use it, I get this error:
ld: '/Users/homedudycz/Desktop/Test/Test/Observation.framework/Observation' does not contain bitcode. You must rebuild it with bitcode enabled (Xcode setting ENABLE_BITCODE), obtain an updated library from the vendor, or disable bitcode for this target. file '/Users/homedudycz/Desktop/Test/Test/Observation.framework/Observation' for architecture arm64
clang: error: linker command failed with exit code 1 (use -v to see invocation)
Can someone help me with this?

Related

is there any change with ios static library run script with xcode 10?

I have created a static ios library, and I have created Aggregate target to get an universal library as output for that i have included shell script in the build phase section:
# define output folder environment variable
UNIVERSAL_OUTPUTFOLDER=${BUILD_DIR}/${CONFIGURATION}-universal
# Step 1. Build Device and Simulator versions
xcodebuild -target OffsetCalLib-Universal ONLY_ACTIVE_ARCH=NO -configuration ${CONFIGURATION} -sdk iphoneos BUILD_DIR="${BUILD_DIR}" BUILD_ROOT="${BUILD_ROOT}"
xcodebuild -target OffsetCalLib-Universal -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}/"
But on build it throws error like:

iPhoneSimulator11.4.sdk/usr/include/sys/cdefs.h:763:2: error: Unsupported architecture

I am creating a universal framework by taking reference from https://agilewarrior.wordpress.com/2016/12/22/how-to-create-universal-static-library-ios/ but while running i am getting
Shell Script Invocation Error like below :
here is my configuration:
Here is my script for creating universal framework:
# define output folder environment variable
UNIVERSAL_OUTPUTFOLDER=${BUILD_DIR}/${CONFIGURATION}-universal
# 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}"
xcodebuild -target ${PROJECT_NAME} -configuration ${CONFIGURATION} -sdk iphonesimulator -arch x86_64 -arch i386 -arch armv7 -arch armv7s -arch arm64 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"
echo "Universal library can be found here:"
echo ${UNIVERSAL_OUTPUTFOLDER}/lib${PROJECT_NAME}.a
# Last touch. copy the header files. Just for convenience
cp -R "${BUILD_DIR}/${CONFIGURATION}-iphoneos/include" "${UNIVERSAL_OUTPUTFOLDER}/"
The above script is working in my another framework.but in current project it is giving error.

Creating iOS Framework for device and Universal configuration with bitcode enable and bitcode disable from Command Line terminal

#!/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 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}"
I have above shell script to create framework for device and universal from Xcode build options.
Is is possible to create/Generate iOS Framework from Command terminal with above shell script with below configuration???
1) Create framework for device bitcode disable
2) Create framework for device bitcode enable
3) Create framework for Universal bitcode disable
4) Create framework for Universal bitcode enable
Please let me know the steps to create/generate iOS Framework from
command terminal. Must appreciate for the best explanation
Just add the argument to your xcodebuild
ENABLE_BITCODE=NO for disabling bitcode
ENABLE_BITCODE=YES for enabling bitcode
For example
xcodebuild -target "${PROJECT_NAME}" ONLY_ACTIVE_ARCH=NO -configuration ${CONFIGURATION} -sdk iphoneos BUILD_DIR="${BUILD_DIR}" BUILD_ROOT="${BUILD_ROOT}" clean build ENABLE_BITCODE=NO
In the shell script you posted, replace the code under # Step 1. Build Device and Simulator versions with the following appropriately.
1) Create framework for device bitcode disable:
xcodebuild -target "${PROJECT_NAME}" ONLY_ACTIVE_ARCH=NO \
-configuration ${CONFIGURATION} -sdk iphoneos \
BUILD_DIR="${BUILD_DIR}" BUILD_ROOT="${BUILD_ROOT}" clean build ENABLE_BITCODE=NO
xcodebuild -target "${PROJECT_NAME}" -configuration ${CONFIGURATION} \
-sdk iphonesimulator ONLY_ACTIVE_ARCH=NO BUILD_DIR="${BUILD_DIR}" \
BUILD_ROOT="${BUILD_ROOT}" clean build ENABLE_BITCODE=YES
2) Create framework for device bitcode enable
xcodebuild -target "${PROJECT_NAME}" ONLY_ACTIVE_ARCH=NO \
-configuration ${CONFIGURATION} -sdk iphoneos \
BUILD_DIR="${BUILD_DIR}" BUILD_ROOT="${BUILD_ROOT}" clean build ENABLE_BITCODE=YES
xcodebuild -target "${PROJECT_NAME}" -configuration ${CONFIGURATION} \
-sdk iphonesimulator ONLY_ACTIVE_ARCH=NO BUILD_DIR="${BUILD_DIR}" \
BUILD_ROOT="${BUILD_ROOT}" clean build ENABLE_BITCODE=YES
3) Create framework for Universal bitcode disable
xcodebuild -target "${PROJECT_NAME}" ONLY_ACTIVE_ARCH=NO \
-configuration ${CONFIGURATION} -sdk iphoneos \
BUILD_DIR="${BUILD_DIR}" BUILD_ROOT="${BUILD_ROOT}" clean build ENABLE_BITCODE=NO
xcodebuild -target "${PROJECT_NAME}" -configuration ${CONFIGURATION} \
-sdk iphonesimulator ONLY_ACTIVE_ARCH=NO BUILD_DIR="${BUILD_DIR}" \
BUILD_ROOT="${BUILD_ROOT}" clean build ENABLE_BITCODE=NO
4) Create framework for Universal bitcode enable
xcodebuild -target "${PROJECT_NAME}" ONLY_ACTIVE_ARCH=NO \
-configuration ${CONFIGURATION} -sdk iphoneos \
BUILD_DIR="${BUILD_DIR}" BUILD_ROOT="${BUILD_ROOT}" clean build ENABLE_BITCODE=YES
xcodebuild -target "${PROJECT_NAME}" -configuration ${CONFIGURATION} \
-sdk iphonesimulator ONLY_ACTIVE_ARCH=NO BUILD_DIR="${BUILD_DIR}" \
BUILD_ROOT="${BUILD_ROOT}" clean build ENABLE_BITCODE=YES
EDIT:
To build the framework, you can do either of the below:
1. Replacing the code for each config, go to terminal and run the shell script by navigating to the folder containing the shell script and running ./<nameOfTheShellScriptFile>.sh. But make sure you have the build settings available there. That will create the framework with the appropriate configuration in the directory ${BUILD_DIR}/${CONFIGURATION}-universal.
2. Add a run script in the Xcode. Open your project in Xcode, click on the schemes dropdown (beside Stop button) and choose your framework scheme. Open the dropdown again and click on "Edit Scheme...". You see 6 actions to the left. You choose which action makes more sense to add the script to (do you want to create this universal framework on every Run action or only when you archive?). Drop down that action and click on Post-actions. Click on + button to add a new action and click on "New Run Script Action". Set the "Provide build settings from" to your framework target to get the appropriate build settings. Paste the script in the text area and click close. Now after every time you perform the action you put the script under, the script runs and builds the framework again for both device and simulator architectures and puts the universal framework in your project directory. It takes some time for this to complete especially if your project is big so wait patiently until the finder opens up to reveal your project directory containing the framework. Now you can either change the code in the script every time you want a different config (bitcode enabled or disabled), or add different schemes for different config and follow this whole step for each of the schemes with appropriate script.

Enable Bitcode in iOS Framework

I am building an iOS Framework via a build script. It builds fine. When I include it to my project, archive it and try to publish it for Enterprise I get the following error in the logs
NSLocalizedDescription=Failed to verify bitcode in...
I am building via a script
xcodebuild -project "${PROJECT_FILE_PATH}" -target "${TARGET_NAME}" -configuration "${CONFIGURATION}" -sdk iphoneos BUILD_DIR="${BUILD_DIR}" OBJROOT="${OBJROOT}" BUILD_ROOT="${BUILD_ROOT}" CONFIGURATION_BUILD_DIR="${IPHONE_DEVICE_BUILD_DIR}/arm64" SYMROOT="${SYMROOT}" BITCODE_GENERATION_MODE=bitcode OTHER_CFLAGS="-fembed-bitcode" ARCHS='arm64' VALID_ARCHS='arm64' $ACTION
xcodebuild -project "${PROJECT_FILE_PATH}" -target "${TARGET_NAME}" -configuration "${CONFIGURATION}" -sdk iphoneos BUILD_DIR="${BUILD_DIR}" OBJROOT="${OBJROOT}" BUILD_ROOT="${BUILD_ROOT}" CONFIGURATION_BUILD_DIR="${IPHONE_DEVICE_BUILD_DIR}/armv7" SYMROOT="${SYMROOT}" BITCODE_GENERATION_MODE=bitcode OTHER_CFLAGS="-fembed-bitcode" ARCHS='armv7 armv7s' VALID_ARCHS='armv7 armv7s' $ACTION
rm -rf "${UNIVERSAL_OUTPUTFOLDER}"
mkdir -p "${UNIVERSAL_OUTPUTFOLDER}"
cp -R "${BUILD_DIR}/${CONFIGURATION}-iphonesimulator/${PROJECT_NAME}.framework" "${UNIVERSAL_OUTPUTFOLDER}/${PROJECT_NAME}.framework"
lipo -create "${BUILD_DIR}/${CONFIGURATION}-iphonesimulator/${PROJECT_NAME}.framework/${PROJECT_NAME}" "${BUILD_DIR}/${CONFIGURATION}-iphoneos/arm64/${PROJECT_NAME}.framework/${PROJECT_NAME}" "${BUILD_DIR}/${CONFIGURATION}-iphoneos/armv7/${PROJECT_NAME}.framework/${PROJECT_NAME}" -output "${UNIVERSAL_OUTPUTFOLDER}/${PROJECT_NAME}.framework/${PROJECT_NAME}"
defaults write "${UNIVERSAL_OUTPUTFOLDER}/${PROJECT_NAME}.framework/Info.plist" CFBundleSupportedPlatforms -array 'iPhoneOS'
The last line is there to change the key in the plist to iPhoneOS (I was getting another error without it).
I am enabling OTHER_CFLAGS="-fembed-bitcode" but I still get the error. Any ideas?

How do i make fat framework with bitcode option?

Environment: XCode 7.0.1
Module: Objective-C
Bundle Type: Framework
Hi, I am trying to create a framework to support armv7, armv7s, arm64, i386 and x86_64. I am using aggregate to make the fat library. Inside the aggregate script, i am running two xcodebuild commands 1. for armv7, armv7s and arm64 and 2. for i386 and x86_64 architectures. Also, I have set Enable Bitcode=YES and Other C Flags=-fembed-bitcode under target build settings. As a precautionary mesasure, i am adding ENABLE_BITCODE=YES and OTHER_CFLAGS="-fembed-bitcode" options to the xcodebuild command
My xcode build commands are as follows -
#Build The framework Target for iPhoneOS
xcodebuild -project "${PROJECT_FILE_PATH}" -target "${AN_TARGET}"
ONLY_ACTIVE_ARCH=NO -configuration "${CONFIGURATION}" -sdk iphoneos
BUILD_DIR="${BUILD_DIR}" OBJROOT="${OBJROOT}" BUILD_ROOT="${BUILD_ROOT}"
CONFIGURATION_BUILD_DIR="${IPHONE_DEVICE_BUILD_DIR}" SYMROOT="${SYMROOT}"
ARCHS="armv7 armv7s arm64" ENABLE_BITCODE=YES OTHER_CFLAGS="-fembed-bitcode" $ACTION
#Build The framework Target for iPhoneSimulator
xcodebuild -project "${PROJECT_FILE_PATH}" -target "${AN_TARGET}"
ONLY_ACTIVE_ARCH=NO -configuration "${CONFIGURATION}" -sdk iphonesimulator
BUILD_DIR="${BUILD_DIR}" OBJROOT="${OBJROOT}" BUILD_ROOT="${BUILD_ROOT}"
CONFIGURATION_BUILD_DIR="${IPHONE_SIMULATOR_BUILD_DIR}" SYMROOT="${SYMROOT}"
ARCHS="i386 x86_64" ENABLE_BITCODE=YES OTHER_CFLAGS="-fembed-bitcode" $ACTION
after running the above two commands, i am combining these two builds to make a fat framework binary using the below command
# create a fat Framework
lipo -create
"${IPHONE_DEVICE_BUILD_DIR}/${PROJECT_NAME}.framework/${PROJECT_NAME}"
"${IPHONE_SIMULATOR_BUILD_DIR}/${PROJECT_NAME}.framework/${PROJECT_NAME}" -
output "${FRAMEWORK_FOLDER}/${AN_END_USER_FRAMEWORK_NAME}"
The issue iam facing is after the lipo is created, i am unable to use it in the bitcode enabled application. After running the otool -l framework_binary | grep -LLVM, i do not see the bitcode enabled flags or __LLVM.
Lipo removes bitcode from the fat binary. Is there a way i can retain bitcode while running the lipo command?
Correction: Based on the reply from Nestor, i ran the otool command as otool -l -arch armv7 framework_binary | grep LLVM and much to my surprise, i could see the segname __LLVM clang. However when i integrate the same fat framework binary into my project, it builds fine on simulator however throws the following error while running on device - ld: 'MyBinary' does not contain bitcode. You must rebuild it with bitcode enabled (Xcode setting ENABLE_BITCODE), obtain an updated library from the vendor, or disable bitcode for this target. for architecture armv7
Happily it's just a problem with otool's reporting, not lipo; you have to add the -arch parameter:
otool -arch arm64 -l myLipoOutput.a
Source: http://www.openradar.me/radar?id=6301306440384512
This is something weird, there are not many documentation for do this, at the end I use this command:
xcodebuild -project ${PROJECT_NAME}.xcodeproj -target ${FRAMEWORK_NAME} ONLY_ACTIVE_ARCH=NO BITCODE_GENERATION_MODE=bitcode FRAMEWORK_SEARCH_PATHS="${FRAMEWORK_SEARCH_PARTH} ${SRCROOT}/**" -sdk ${SIMULATOR_SDK} -configuration ${CONFIGURATION} clean build CONFIGURATION_BUILD_DIR=${BUILD_DIR}/${CONFIGURATION}-${SIMULATOR_SDK} 2>&1
xcodebuild -project ${PROJECT_NAME}.xcodeproj -target ${FRAMEWORK_NAME} -sdk ${DEVICE_SDK} ONLY_ACTIVE_ARCH=NO BITCODE_GENERATION_MODE=bitcode FRAMEWORK_SEARCH_PATHS="${FRAMEWORK_SEARCH_PARTH} ${SRCROOT}/**" -configuration ${CONFIGURATION} clean build CONFIGURATION_BUILD_DIR=${BUILD_DIR}/${CONFIGURATION}-${DEVICE_SDK} 2>&1
Add the BITCODE_GENERATION_MODE=bitcode flag to the xcodebuild command
Try to use archive for the arm slices instead of build
xcodebuild -scheme "${SCHEME}" -workspace "${WORKSPACE}" -configuration "${CONFIGURATION}" -sdk iphoneos ARCHS="arm64 armv7 armv7s" CONFIGURATION_BUILD_DIR="${CONFIGURATION_BUILD_DIR}/arm" CODE_SIGN_IDENTITY="" CODE_SIGNING_REQUIRED=NO ONLY_ACTIVE_ARCH=NO archive
After that run lipo to merge the simulator and the arm ones.
And after that run otool -arch arm64 -l myLipoOutput.a and it should work.
It looks like a bug in Xcode 7.0.1 . I've had the same issue and downgrading Xcode to version 7 fixed it.
Update:
Actually it may be a bug in Xcode 7 that was fixed in 7.0.1 - this SO answer solved the issue for me.

Resources