How to support both armv6 and armv7s for release build in xcode 4.5

I’ve been able to do this successfully with my app that’s in the App Store. It supports armv6, armv7, and armv7s and iOS versions from 4.2 to 6.0. I’ve verified that it runs on older devices (iPhone 3G, iPod touch 2g) all the way through the iPhone 5.

This method requires having both Xcode 4.5 and an older version of Xcode installed simultaneously. I’m still on 4.3.2 for my older version, but 4.4 should work as well.

I had screenshots for this answer, but Stack Overflow won’t let me post them because I’m new. 🙁

Setup in Xcode 4.5

  1. Add a new build configuration for your armv6 build. I duplicated the Release config and named it Release_armv6.

  2. Set the Architectures and Valid Architectures for your build configurations. For all but Release_armv6, use the default. For Release_armv6, manually set it to armv6.
    http://i.stack.imgur.com/h8Mpl.png

  3. If you’re using iOS 6 features that Xcode 4.4 and below won’t understand, you’ll need to #ifdef these out for your armv6 build. In Build Settings under Other C Flags and Other C++ Flags I added -DARMV6_ONLY to my Release_armv6 config. Then wherever the code uses a new iOS 6 API, I do something like #ifndef ARMV6_ONLY / #endif as appropriate.
    http://i.stack.imgur.com/czF6J.png

  4. Add a new scheme and set it to use the Release_armv6 build configuration in all cases.

  5. Under Build Phases, add a Run Script Build Phase with the following script (set the Shell to /bin/csh). This is where the magic happens. Edit the Configuration section: Determine your full path to the Release_armv6 build and substitute it for ARMV6_EXECUTABLE_PATH. Also set MINIMUM_OS.



    #
    # Script to add armv6 architecture to iOS executable built with Xcode 4.5
    #

    #################
    # Configuration #
    #################
    # Change this to the full path where Xcode 4.4 (or below) puts your armv6 output
    setenv ARMV6_EXECUTABLE_PATH "$BUILD_ROOT/Release_armv6-iphoneos/$EXECUTABLE_PATH"

    # Your "real" minimum OS version since Xcode 4.5 wants to make it iOS 4.3
    # Must be 4.2 or below if you are supporting armv6...
    setenv MINIMUM_OS 4.2
    #####################
    # End configuration #
    #####################


    # For debugging
    echo CURRENT_ARCH = $CURRENT_ARCH
    echo CONFIGURATION = $CONFIGURATION

    # Don't need to do this for armv6 (built in older Xcode), simulator (i386), or debug build
    if ("$CURRENT_ARCH" == "armv6") exit 0
    if ("$CURRENT_ARCH" == "i386") exit 0
    if ("$CONFIGURATION" != "Release" && "$CONFIGURATION" != "Beta Test") exit 0

    # Paths
    setenv LIPO_PATH "$CODESIGNING_FOLDER_PATH/${EXECUTABLE_NAME}.lipo"
    setenv FINAL_PATH "$CODESIGNING_FOLDER_PATH/$EXECUTABLE_NAME"
    setenv FULL_INFO_PLIST_PATH "$CONFIGURATION_BUILD_DIR/$INFOPLIST_PATH"

    # Debug / sanity check
    lipo -info "$FINAL_PATH"
    ls -l "$ARMV6_EXECUTABLE_PATH"

    # Make sure something exists at $LIPO_PATH even if the next command fails
    cp -pv "$FINAL_PATH" "$LIPO_PATH"

    # If rebuilding without cleaning first, old armv6 might already be there so remove it
    # If not, lipo won't output anything (thus the cp command just above)
    lipo -remove armv6 -output "$LIPO_PATH" "$FINAL_PATH"

    # Add armv6 to the fat binary, show that it worked for debugging, then remove temp file
    lipo -create -output "$FINAL_PATH" "$ARMV6_EXECUTABLE_PATH" "$LIPO_PATH"
    lipo -info "$FINAL_PATH"
    rm -f "$LIPO_PATH"

    # Change Info.plist to set minimum OS version to 4.2 (instead of 4.3 which Xcode 4.5 wants)
    /usr/libexec/PlistBuddy -c "Set :MinimumOSVersion $MINIMUM_OS" "$FULL_INFO_PLIST_PATH"
    plutil -convert binary1 "$FULL_INFO_PLIST_PATH"

Build Process

When you’re ready to create a release build, do it in the following order:

  1. Close Xcode 4.5 and open Xcode 4.4 or below. Select your armv6 scheme and build it.

  2. Close Xcode 4.4 or below and open Xcode 4.5. Select your Release scheme and build it.

That’s pretty much it. Check the build output to verify that you got what you want – an executable with three architectures in it. The last output from the run script should tell you this.

If anyone has ideas to improve this, please feel free. I imagine you might be able to get fancy and call Xcode 4.4’s “xcodebuild” command from within the build script, alleviating the need to switch between Xcode versions at all. But this works well enough for me. 😉

Caveats:

  • Just to be safe, you might want to edit your xib files in the older version of Xcode. So far it seems like 4.5 is backwards compatible, but you never know.

  • In fact, you might consider just doing most of your development, except for iOS 6-specific stuff, in the older Xcode. Depends on whatever’s easiest for you.

Leave a Comment