Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is it possible to create a universal iOS framework using bitcode?

Tags:

xcode

ios

bitcode

From what I understood, bitcode allows to generate binaries with an intermediary binary format. So it is the step before compiling to an ARM or x64 architecture.

It is possible to create "real" .framework file for iOS since iOS 8. However, framework files are compiled for only one architecture by default (emulator, iPhone). When one wants to distribute a .framework file, it is better to provide a file compatible with the iOS emulator and also deployable to an iPhone. Different examples of scripts can be found to create such a fat file using lipo.

However, would it be possible to only distribute a .framework compiled as bitcode without having to create a fat file with different architectures?

Unfortunately, even with bitcode enabled for my .framework:

  • different files are created by default according to the targeted architecture
  • even if the "archive" menu seems to be enabled for a framework target, I cannot find the result, even in my Organizer view

Do I misunderstand something in the concept of bitcode, or do I miss something?

like image 526
Vincent Hiribarren Avatar asked Feb 23 '16 19:02

Vincent Hiribarren


2 Answers

I spend many hours fixing / changing the setup of xfaid's answer to have finaly a universal package with bitcode working with XCode 10.

I couldn't get the "xcodebuild archive" command work, so I used build with the settings described at this link: http://iosre.com/t/enable-bitcode-for-frameworks-in-xcode/12581

I then changed a little the script to:

# Fix for bitcode:
unset TOOLCHAINS

######################
# Options
######################

#verbose
#set -x

REVEAL_ARCHIVE_IN_FINDER=true

FRAMEWORK_NAME="${PROJECT_NAME}"

SIMULATOR_LIBRARY_PATH="${BUILD_DIR}/${CONFIGURATION}-iphonesimulator/${FRAMEWORK_NAME}.framework"

DEVICE_LIBRARY_PATH="${BUILD_DIR}/${CONFIGURATION}-iphoneos/${FRAMEWORK_NAME}.framework"

UNIVERSAL_LIBRARY_DIR="${BUILD_DIR}/${CONFIGURATION}-iphoneuniversal"

FRAMEWORK="${UNIVERSAL_LIBRARY_DIR}/${FRAMEWORK_NAME}.framework"


######################
# Build Frameworks
######################
# Build for simulator
xcodebuild -target ${PROJECT_NAME} -sdk iphonesimulator -configuration ${CONFIGURATION} ARCHS="i386 x86_64" ONLY_ACTIVE_ARCH=NO clean build CONFIGURATION_BUILD_DIR=${BUILD_DIR}/${CONFIGURATION}-iphonesimulator
# Build for device
xcodebuild -scheme ${PROJECT_NAME} -sdk iphoneos -configuration ${CONFIGURATION} ARCHS="armv7 armv7s arm64" ONLY_ACTIVE_ARCH=NO build  ENABLE_BITCODE=YES OTHER_CFLAGS="-fembed-bitcode"  OBJROOT="${OBJROOT}/DependantBuilds" CONFIGURATION_BUILD_DIR=${BUILD_DIR}/${CONFIGURATION}-iphoneos

######################
# Create directory for universal
######################

rm -rf "${UNIVERSAL_LIBRARY_DIR}"

mkdir "${UNIVERSAL_LIBRARY_DIR}"

mkdir "${FRAMEWORK}"


######################
# Copy files Framework
######################

cp -r "${DEVICE_LIBRARY_PATH}/." "${FRAMEWORK}"


######################
# Make an universal binary
######################

lipo "${SIMULATOR_LIBRARY_PATH}/${FRAMEWORK_NAME}" "${DEVICE_LIBRARY_PATH}/${FRAMEWORK_NAME}" -create -output "${FRAMEWORK}/${FRAMEWORK_NAME}" | echo

# For Swift framework, Swiftmodule needs to be copied in the universal framework
if [ -d "${SIMULATOR_LIBRARY_PATH}/Modules/${FRAMEWORK_NAME}.swiftmodule/" ]; then
cp -f ${SIMULATOR_LIBRARY_PATH}/Modules/${FRAMEWORK_NAME}.swiftmodule/* "${FRAMEWORK}/Modules/${FRAMEWORK_NAME}.swiftmodule/" | echo
fi

if [ -d "${DEVICE_LIBRARY_PATH}/Modules/${FRAMEWORK_NAME}.swiftmodule/" ]; then
cp -f ${DEVICE_LIBRARY_PATH}/Modules/${FRAMEWORK_NAME}.swiftmodule/* "${FRAMEWORK}/Modules/${FRAMEWORK_NAME}.swiftmodule/" | echo
fi

######################
# On Release, copy the result to release directory
######################
OUTPUT_DIR="${PROJECT_DIR}/build/${FRAMEWORK_NAME}-${CONFIGURATION}-iphoneuniversal/"

rm -rf "$OUTPUT_DIR"
mkdir -p "$OUTPUT_DIR"

cp -r "${FRAMEWORK}" "$OUTPUT_DIR"

if [ ${REVEAL_ARCHIVE_IN_FINDER} = true ]; then
open "${OUTPUT_DIR}/"
fi

Just in case it can helps some of you :)

like image 80
Jeremy Cochoy Avatar answered Oct 13 '22 22:10

Jeremy Cochoy


You need to provide a universal flat framework. Which is created by lipo.

  • Enable Bitcode, Targets->Build Setting->Enable Bitcode to Yes
  • Add build target to create universal framework

    Create a Aggregate target and copy following script to Build Phrase -> Run Script:


    ######################
    # Options
    ######################

    #verbose
    set -x

    REVEAL_ARCHIVE_IN_FINDER=false

    FRAMEWORK_NAME="${PROJECT_NAME}"

    SIMULATOR_LIBRARY_PATH="${BUILD_DIR}/${CONFIGURATION}-iphonesimulator/${FRAMEWORK_NAME}.framework"

    DEVICE_LIBRARY_PATH="${BUILD_DIR}/${CONFIGURATION}-iphoneos/${FRAMEWORK_NAME}.framework"

    UNIVERSAL_LIBRARY_DIR="${BUILD_DIR}/${CONFIGURATION}-iphoneuniversal"

    FRAMEWORK="${UNIVERSAL_LIBRARY_DIR}/${FRAMEWORK_NAME}.framework"


    ######################
    # Build Frameworks
    ######################
    # Build for simulator
    xcodebuild -target ${PROJECT_NAME} -sdk iphonesimulator -configuration ${CONFIGURATION} ARCHS="i386 x86_64" ONLY_ACTIVE_ARCH=NO clean build CONFIGURATION_BUILD_DIR=${BUILD_DIR}/${CONFIGURATION}-iphonesimulator
    # Build for device
    xcodebuild -scheme ${PROJECT_NAME} -sdk iphoneos -configuration ${CONFIGURATION} ARCHS="armv7 armv7s arm64" ONLY_ACTIVE_ARCH=NO clean archive CONFIGURATION_BUILD_DIR=${BUILD_DIR}/${CONFIGURATION}-iphoneos

    ######################
    # Create directory for universal
    ######################

    rm -rf "${UNIVERSAL_LIBRARY_DIR}"

    mkdir "${UNIVERSAL_LIBRARY_DIR}"

    mkdir "${FRAMEWORK}"


    ######################
    # Copy files Framework
    ######################

    cp -r "${DEVICE_LIBRARY_PATH}/." "${FRAMEWORK}"


    ######################
    # Make an universal binary
    ######################

    lipo "${SIMULATOR_LIBRARY_PATH}/${FRAMEWORK_NAME}" "${DEVICE_LIBRARY_PATH}/${FRAMEWORK_NAME}" -create -output "${FRAMEWORK}/${FRAMEWORK_NAME}" | echo

    # For Swift framework, Swiftmodule needs to be copied in the universal framework
    if [ -d "${SIMULATOR_LIBRARY_PATH}/Modules/${FRAMEWORK_NAME}.swiftmodule/" ]; then
    cp -f ${SIMULATOR_LIBRARY_PATH}/Modules/${FRAMEWORK_NAME}.swiftmodule/* "${FRAMEWORK}/Modules/${FRAMEWORK_NAME}.swiftmodule/" | echo
    fi

    if [ -d "${DEVICE_LIBRARY_PATH}/Modules/${FRAMEWORK_NAME}.swiftmodule/" ]; then
    cp -f ${DEVICE_LIBRARY_PATH}/Modules/${FRAMEWORK_NAME}.swiftmodule/* "${FRAMEWORK}/Modules/${FRAMEWORK_NAME}.swiftmodule/" | echo
    fi

    ######################
    # On Release, copy the result to release directory
    ######################
    OUTPUT_DIR="${PROJECT_DIR}/build/${FRAMEWORK_NAME}-${CONFIGURATION}-iphoneuniversal/"

    rm -rf "$OUTPUT_DIR"
    mkdir -p "$OUTPUT_DIR"

    cp -r "${FRAMEWORK}" "$OUTPUT_DIR"

    if [ ${REVEAL_ARCHIVE_IN_FINDER} = true ]; then
    open "${OUTPUT_DIR}/"
    fi

Note

  • bitcode is only packed on archive build for iphoneos sdk

  • otool -l -arch arm64 <yourframework_binary>|grep __LLVM to check whether bitcode is included, if you don't specify the arch parameter, there will be no __LLVM, since otool just print one host arch(simulator).

like image 28
xfdai Avatar answered Oct 13 '22 22:10

xfdai