frameworksxcode10fat-binaries

Fat Framework Script for Xcode 10?


I used this script in the post-action of the archive in my scheme to make a FAT binary framework. One that will work on the simulator and actual device.

https://gist.github.com/gauravkeshre/eabb2a13ef6d673fadec84ca60b56b05

Does anyone know how to convert it to work with Xcode 10?

Using the legacy build system fixes the errors, but I would rather not rely on it.

Here is the script itself:

exec > /tmp/${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 XS' 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}/${FULL_PRODUCT_NAME}" "${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
echo "Copying to project dir"
yes | cp -Rf "${UNIVERSAL_OUTPUTFOLDER}/${FULL_PRODUCT_NAME}" "${PROJECT_DIR}"

open "${PROJECT_DIR}"

fi

The errors in the output log after ** BUILD SUCCEEDED **:

Copying to output folder
cp: /Users/aaronbratcher/Library/Developer/Xcode/DerivedData/iOS-Messaging-SDK-dnynwhbesxdjhmedgaxbdcjgaksx/Build/Intermediates.noindex/ArchiveIntermediates/ContactAtOnceMessaging/BuildProductsPath/Release-universal/ContactAtOnceMessaging.framework/Modules/ContactAtOnceMessaging.swiftmodule: No such file or directory
cp: /Users/aaronbratcher/Library/Developer/Xcode/DerivedData/iOS-Messaging-SDK-dnynwhbesxdjhmedgaxbdcjgaksx/Build/Intermediates.noindex/ArchiveIntermediates/ContactAtOnceMessaging/BuildProductsPath/Release-iphonesimulator/ContactAtOnceMessaging.framework/Modules/ContactAtOnceMessaging.swiftmodule/.: unable to copy extended attributes to /Users/aaronbratcher/Library/Developer/Xcode/DerivedData/iOS-Messaging-SDK-dnynwhbesxdjhmedgaxbdcjgaksx/Build/Intermediates.noindex/ArchiveIntermediates/ContactAtOnceMessaging/BuildProductsPath/Release-universal/ContactAtOnceMessaging.framework/Modules/ContactAtOnceMessaging.swiftmodule: No such file or directory
cp: /Users/aaronbratcher/Library/Developer/Xcode/DerivedData/iOS-Messaging-SDK-dnynwhbesxdjhmedgaxbdcjgaksx/Build/Intermediates.noindex/ArchiveIntermediates/ContactAtOnceMessaging/BuildProductsPath/Release-universal/ContactAtOnceMessaging.framework/Modules/ContactAtOnceMessaging.swiftmodule/i386.swiftmodule: No such file or directory
cp: /Users/aaronbratcher/Library/Developer/Xcode/DerivedData/iOS-Messaging-SDK-dnynwhbesxdjhmedgaxbdcjgaksx/Build/Intermediates.noindex/ArchiveIntermediates/ContactAtOnceMessaging/BuildProductsPath/Release-universal/ContactAtOnceMessaging.framework/Modules/ContactAtOnceMessaging.swiftmodule/x86_64.swiftdoc: No such file or directory
cp: /Users/aaronbratcher/Library/Developer/Xcode/DerivedData/iOS-Messaging-SDK-dnynwhbesxdjhmedgaxbdcjgaksx/Build/Intermediates.noindex/ArchiveIntermediates/ContactAtOnceMessaging/BuildProductsPath/Release-universal/ContactAtOnceMessaging.framework/Modules/ContactAtOnceMessaging.swiftmodule/x86_64.swiftmodule: No such file or directory
cp: /Users/aaronbratcher/Library/Developer/Xcode/DerivedData/iOS-Messaging-SDK-dnynwhbesxdjhmedgaxbdcjgaksx/Build/Intermediates.noindex/ArchiveIntermediates/ContactAtOnceMessaging/BuildProductsPath/Release-universal/ContactAtOnceMessaging.framework/Modules/ContactAtOnceMessaging.swiftmodule/i386.swiftdoc: No such file or directory

and then:

fatal error: /Applications/Xcode 10.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/lipo: can't create temporary output file: /Users/aaronbratcher/Library/Developer/Xcode/DerivedData/iOS-Messaging-SDK-dnynwhbesxdjhmedgaxbdcjgaksx/Build/Intermediates.noindex/ArchiveIntermediates/ContactAtOnceMessaging/BuildProductsPath/Release-universal/ContactAtOnceMessaging.framework/ContactAtOnceMessaging.lipo (No such file or directory)
ls: /Users/aaronbratcher/Library/Developer/Xcode/DerivedData/iOS-Messaging-SDK-dnynwhbesxdjhmedgaxbdcjgaksx/Build/Intermediates.noindex/ArchiveIntermediates/ContactAtOnceMessaging/BuildProductsPath/Release-universal/ContactAtOnceMessaging.framework/Frameworks: No such file or directory
Copying to project dir
cp: /Users/aaronbratcher/Library/Developer/Xcode/DerivedData/iOS-Messaging-SDK-dnynwhbesxdjhmedgaxbdcjgaksx/Build/Intermediates.noindex/ArchiveIntermediates/ContactAtOnceMessaging/BuildProductsPath/Release-universal/ContactAtOnceMessaging.framework: No such file or directory

The first path falters once you get inside the Release-universal folder because there is no .framework folder. Instead, the contents of the framework are there.


Solution

  • You don't need to change anything. Just set skip_install to NO in the build setting of the framework target. Also remove the .framework from ${PROJECT_DIR} before archiving.

    If it still doesn't work, edit your question with what the ${PROJECT_NAME}_archive.log says went wrong.

    Edit: Also try building with legacy system in xcode 10. File -> Workspace Settings -> Build System

    Edit 2: For some reason Xcode 10 post action bash scripts behave differently for previous Xcode versions. Especially the line:

    cp -R "${ARCHIVE_PRODUCTS_PATH}${INSTALL_PATH}/${FULL_PRODUCT_NAME}" "${UNIVERSAL_OUTPUTFOLDER}/"
    

    In Xcode 10 this will copy the contents of the .framework to the ${UNIVERSAL_OUTPUTFOLDER}, whereas in Xcode 9.3 it will copy the whole .framework to the folder.

    So if you change this line to:

    cp -R "${ARCHIVE_PRODUCTS_PATH}${INSTALL_PATH}/" "${UNIVERSAL_OUTPUTFOLDER}"
    

    The script will work fine in Xcode 10.

    Script i used:

    exec > /tmp/${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}"
    #mkdir -p "${UNIVERSAL_OUTPUTFOLDER}/${TARGET_NAME}.framework" 
    
    echo "Building for iPhoneSimulator"
    xcodebuild -workspace "${WORKSPACE_PATH}" -scheme "${TARGET_NAME}" -configuration ${CONFIGURATION} -sdk iphonesimulator -destination 'platform=iOS Simulator,name=iPhone XS' 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}"
    
    echo "Combining executables end"
    
    # Step 4. Create universal binaries for embedded frameworks
    for SUB_FRAMEWORK in $( ls "${UNIVERSAL_OUTPUTFOLDER}/${TARGET_NAME}.framework/Frameworks" ); do
    BINARY_NAME="${SUB_FRAMEWORK%.*}"
    echo "${ARCHIVE_PRODUCTS_PATH}${INSTALL_PATH}/${TARGET_NAME}.framework/Frameworks/${SUB_FRAMEWORK}/${BINARY_NAME}"
    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
    echo "Copying to project dir"
    yes | cp -Rf "${UNIVERSAL_OUTPUTFOLDER}/${FULL_PRODUCT_NAME}" "${PROJECT_DIR}"
    
    open "${PROJECT_DIR}"
    
    fi