Можно ли создать универсальный фреймворк iOS с использованием битового кода?

Насколько я понял, битовый код позволяет создавать двоичные файлы с промежуточным двоичным форматом. Итак, это шаг перед компиляцией в архитектуру ARM или x64.

Начиная с iOS 8, можно создать «настоящий» .framework файл для iOS. Однако по умолчанию файлы фреймворка компилируются только для одной архитектуры (эмулятор, iPhone). Если кто-то хочет распространить .framework файл, лучше предоставить файл, совместимый с эмулятором iOS и также доступный для развертывания на iPhone. Можно найти различные примеры сценариев для создания такого толстого файла с помощью lipo.

Однако можно ли распространять только .framework, скомпилированный как битовый код, без необходимости создавать толстый файл с разными архитектурами?

К сожалению, даже с включенным битовым кодом для моего .framework:

  • разные файлы создаются по умолчанию в соответствии с целевой архитектурой
  • даже если кажется, что меню «архив» включено для целевой платформы, я не могу найти результат даже в моем представлении «Организатор»

Я что-то неправильно понимаю в концепции битового кода или я что-то упускаю?


person Vincent Hiribarren    schedule 23.02.2016    source источник


Ответы (2)


Вам необходимо предоставить универсальный плоский каркас. Который создан lipo.

  • Включить битовый код, от Targets->Build Setting->Enable Bitcode до Yes
  • Добавьте цель сборки, чтобы создать универсальный фреймворк

    Создайте цель Aggregate и скопируйте следующий скрипт в 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

Примечание

  • битовый код упакован только в archive сборку для iphoneos sdk

  • otool -l -arch arm64 <yourframework_binary>|grep __LLVM, чтобы проверить, включен ли битовый код, если вы не укажете параметр arch, не будет __LLVM, поскольку otool просто напечатает одну арку хоста (симулятор).

person xfdai    schedule 03.03.2016
comment
Прочтите, пожалуйста, еще раз вопрос. Это именно то, чего я хотел бы избежать (я упомянул lipo в своем вопросе). Я не понимаю цели компиляции чего-либо в виде битового кода, если мне все равно нужно создать универсальный двоичный файл. И я не могу найти файл фреймворка, созданный с помощью сборки archive. - person Vincent Hiribarren; 03.03.2016
comment
bitcode - это промежуточный LLVM IR, скомпилированный Xcode, и он зависит от архитектуры, в отличие от байт-кода java, поэтому каждому фрагменту нужен свой собственный раздел битового кода. Поскольку это промежуточный код, поэтому Apple может использовать его для оптимизации до конечного машинного кода в будущем без загрузки новой версии, это основная цель. - person xfdai; 04.03.2016
comment
И структура, созданная с помощью archive из сценария, находится на ${DEVICE_LIBRARY_PATH}/Modules/${FRAMEWORK_NAME} см. здесь - person xfdai; 04.03.2016
comment
Большое спасибо за этот сценарий! Также следует добавить 'Skip Install = yes', чтобы избежать удаления выпуска устройства из Build / Products / Release-iphoneos. - person Vadim; 24.12.2016

Я трачу много часов на исправление / изменение настройки ответа xfaid, чтобы наконец получить универсальный пакет с битовым кодом, работающий с XCode 10.

Мне не удалось заставить работать команду «xcodebuild archive», поэтому я использовал сборку с настройками, описанными по этой ссылке: http://iosre.com/t/enable-bitcode-for-frameworks-in-xcode/12581

Затем я немного изменил сценарий:

# 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

На всякий случай кому-то из вас это поможет :)

person Jeremy Cochoy    schedule 01.12.2019