Что ENABLE_BITCODE делает в xcode 7?

У меня проблема со встроенным термином битового кода.
Что такое встроенный битовый код?
Когда включить, ENABLE_BITCODE в новом Xcode?
Что происходит с бинарным при включении, ENABLE_BITCODE в Xcode 7?

7 ответов

Решение

Бит-код относится к типу кода: "Бит-код LLVM", который отправляется в iTunes Connect. Это позволяет Apple использовать определенные расчеты для дальнейшей повторной оптимизации приложений (например: возможно уменьшить размеры исполняемых файлов). Если Apple нужно изменить ваш исполняемый файл, они могут сделать это без загрузки новой сборки.

Это отличается от:нарезки, которая представляет собой процесс оптимизации Apple приложения для устройства пользователя на основе разрешения и архитектуры устройства. Нарезка не требует бит-кода. (Пример: только включая @2x изображения на 5 с)

Разреживаниеприложений - это комбинация ресурсов нарезки, бит-кода и ресурсов по требованию.

Биткод - это промежуточное представление скомпилированной программы. Приложения, которые вы загружаете в iTunes Connect и содержат битовый код, будут скомпилированы и связаны в App Store. Включение битового кода позволит Apple повторно оптимизировать двоичный файл вашего приложения в будущем без необходимости представлять новую версию вашего приложения в магазине.

Документация Apple по истончению приложений

Что такое встроенный битовый код?

Согласно документам:

Биткод - это промежуточное представление скомпилированной программы. Приложения, которые вы загружаете в iTunes Connect и содержат битовый код, будут скомпилированы и связаны в App Store. Включение битового кода позволит Apple повторно оптимизировать двоичный файл вашего приложения в будущем без необходимости представлять новую версию вашего приложения в магазине.

Обновление: эта фраза в "Новые функции в Xcode 7" заставила меня долго думать, что битовый код необходим для нарезки, чтобы уменьшить размер приложения:

Когда вы архивируете для отправки в App Store, Xcode скомпилирует ваше приложение в промежуточное представление. Затем App Store скомпилирует битовый код в 64- или 32-битные исполняемые файлы по мере необходимости.

Однако это не так, биткод и слайсинг работают независимо друг от друга: слайсинг - это уменьшение размера приложения и создание вариантов комплектов приложений, а биткод - это определенные бинарные оптимизации. Я проверил это, проверив включенные архитектуры в исполняемых файлах приложений без битового кода и обнаружив, что они включают только необходимые.

Биткод позволяет другому компоненту Разбавления приложений под названием Slicing генерировать варианты комплектов приложений с конкретными исполняемыми файлами для определенных архитектур, например, вариант iPhone 5S будет включать только исполняемый файл arm64, iPad Mini armv7 и так далее.

Когда включить ENABLE_BITCODE в новом Xcode?

Для приложений iOS битовый код используется по умолчанию, но не является обязательным. Если вы предоставляете битовый код, все приложения и платформы в комплекте приложений должны включать битовый код. Для приложений watchOS и tvOS требуется битовый код.

Что происходит с двоичным файлом, когда ENABLE_BITCODE включен в новом Xcode?

От ссылки Xcode 7:

Активация этого параметра означает, что цель или проект должны генерировать битовый код во время компиляции для платформ и архитектур, которые его поддерживают. Для сборок архива битовый код будет сгенерирован в связанном двоичном файле для отправки в магазин приложений. Для других сборок компилятор и компоновщик проверят, соответствует ли код требованиям генерации битового кода, но не будут генерировать фактический битовый код.

Вот пара ссылок, которые помогут в более глубоком понимании биткода:

Что касается битового кода и включения битового кода, первое, что необходимо понять, - это история, с которой все это началось.

Итак, в основном, если я говорю о ENABLE_BITCODE, который представлен в iOS 9, это часть процесса Разбавления приложений.

И это часть проблемы, которая отвечает: " Как Apple удалось уменьшить размер хранилища iOS 9 до 1 ГБ с 5 ГБ в iOS 8? "

Это связано с новой технологией под названием "Разбавление приложений".

и что такое App Thinning?

Приложение Thinning снизило OTA-обновление iOS 9 с 4,6 до 1,3 ГБ, что на 71% меньше. Это поможет не только в будущих обновлениях OTA, но и для разработчиков, что позволит уменьшить объем памяти, необходимый сторонним приложениям.

У прореживания приложений есть три основных компонента, а именно: нарезка, битовый код и ресурсы по требованию.

Разрезание приложений: приложения для iOS разрабатываются для запуска на различных устройствах, поэтому они поставляются с кодом для поддержки всех их, независимо от того, требует ли оно ваше конкретное устройство. Приложение Slicing позволит вашему устройству загружать только те файлы, которые требуются нашему устройству. Пример: вам не нужны 3x iPhone 6 Plus, если вы используете 4-дюймовую модель.

Ресурсы по требованию (ODR): в основе его лежит идея о том, что приложению, вероятно, не требуется вся библиотека ресурсов в любой момент времени, поэтому его части можно загружать или удалять по мере необходимости. Developers will be able to specify what code is needed at what times by tagging sections of code as ODRs. These portions will be automatically downloaded from the App Store when they are required and deleted when they won't be needed again.

Bitcode: It refers to an "intermediate representation" of an app that developers will upload to the App Store rather than a pre-compiled binary. This works hand-in-hand with App Slicing, allowing the bitcode to be compiled on demand as 32-bit or 64-bit, depending on the downloading device. This will also allow any compiler improvements made by Apple to be implemented automatically, rather than having developers resubmit their apps.

введите описание изображения здесь

Поскольку точный вопрос заключается в том, "что позволяет делать битовый код", я хотел бы привести несколько тонких технических деталей, которые я выяснил до сих пор. Большинство из них практически невозможно понять со 100% уверенностью, пока Apple не выпустит исходный код для этого компилятора

Во-первых, битовый код Apple не похож на байт-код LLVM. По крайней мере, я не смог выяснить какое-либо сходство между ними. Кажется, что он имеет собственный заголовок (всегда начинается с "xar!") И, возможно, некоторую магию ссылок во время соединения, которая предотвращает дублирование данных. Если вы записываете жестко закодированную строку, эта строка будет помещена в данные только один раз, а не дважды, как ожидалось бы, если бы это был обычный байт-код LLVM.

Во-вторых, битовый код на самом деле не поставляется в двоичном архиве как отдельная архитектура, как можно было бы ожидать. Он поставляется не так, как, скажем, x86 и ARM помещены в один двоичный файл (архив FAT). Вместо этого они используют специальный раздел в специфичном для архитектуры двоичном файле MachO с именем __LLVM, который поставляется с каждой поддерживаемой архитектурой (т. Е. Дублируется). Я предполагаю, что это недочёт в их системе компиляции и может быть исправлено в будущем, чтобы избежать дублирования.

Код C (скомпилированный с clang -fembed-bitcode hi.c -S -emit-llvm):

#include <stdio.h>

int main() {
    printf("hi there!");
    return 0;
}

ИК выход LLVM:

; ModuleID = '/var/folders/rd/sv6v2_f50nzbrn4f64gnd4gh0000gq/T/hi-a8c16c.bc'
target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128"
target triple = "x86_64-apple-macosx10.10.0"

@.str = private unnamed_addr constant [10 x i8] c"hi there!\00", align 1
@llvm.embedded.module = appending constant [1600 x i8] c"\DE\C0\17\0B\00\00\00\00\14\00\00\00$\06\00\00\07\00\00\01BC\C0\DE!\0C\00\00\86\01\00\00\0B\82 \00\02\00\00\00\12\00\00\00\07\81#\91A\C8\04I\06\1029\92\01\84\0C%\05\08\19\1E\04\8Bb\80\10E\02B\92\0BB\84\102\148\08\18I\0A2D$H\0A\90!#\C4R\80\0C\19!r$\07\C8\08\11b\A8\A0\A8@\C6\F0\01\00\00\00Q\18\00\00\C7\00\00\00\1Bp$\F8\FF\FF\FF\FF\01\90\00\0D\08\03\82\1D\CAa\1E\E6\A1\0D\E0A\1E\CAa\1C\D2a\1E\CA\A1\0D\CC\01\1E\DA!\1C\C8\010\87p`\87y(\07\80p\87wh\03s\90\87ph\87rh\03xx\87tp\07z(\07yh\83r`\87th\07\80\1E\E4\A1\1E\CA\01\18\DC\E1\1D\DA\C0\1C\E4!\1C\DA\A1\1C\DA\00\1E\DE!\1D\DC\81\1E\CAA\1E\DA\A0\1C\D8!\1D\DA\A1\0D\DC\E1\1D\DC\A1\0D\D8\A1\1C\C2\C1\1C\00\C2\1D\DE\A1\0D\D2\C1\1D\CCa\1E\DA\C0\1C\E0\A1\0D\DA!\1C\E8\01\1D\00s\08\07v\98\87r\00\08wx\876p\87pp\87yh\03s\80\876h\87p\A0\07t\00\CC!\1C\D8a\1E\CA\01 \E6\81\1E\C2a\1C\D6\A1\0D\E0A\1E\DE\81\1E\CAa\1C\E8\E1\1D\E4\A1\0D\C4\A1\1E\CC\C1\1C\CAA\1E\DA`\1E\D2A\1F\CA\01\C0\03\80\A0\87p\90\87s(\07zh\83q\80\87z\00\C6\E1\1D\E4\A1\1C\E4\00 \E8!\1C\E4\E1\1C\CA\81\1E\DA\C0\1C\CA!\1C\E8\A1\1E\E4\A1\1C\E6\01X\83y\98\87y(\879`\835\18\07|\88\03;`\835\98\87y(\076X\83y\98\87r\90\036X\83y\98\87r\98\03\80\A8\07w\98\87p0\87rh\03s\80\876h\87p\A0\07t\00\CC!\1C\D8a\1E\CA\01 \EAa\1E\CA\A1\0D\E6\E1\1D\CC\81\1E\DA\C0\1C\D8\E1\1D\C2\81\1E\00s\08\07v\98\87r\006\C8\88\F0\FF\FF\FF\FF\03\C1\0E\E50\0F\F3\D0\06\F0 \0F\E50\0E\E90\0F\E5\D0\06\E6\00\0F\ED\10\0E\E4\00\98C8\B0\C3<\94\03@\B8\C3;\B4\819\C8C8\B4C9\B4\01<\BCC:\B8\03=\94\83<\B4A9\B0C:\B4\03@\0F\F2P\0F\E5\00\0C\EE\F0\0Em`\0E\F2\10\0E\EDP\0Em\00\0F\EF\90\0E\EE@\0F\E5 \0FmP\0E\EC\90\0E\ED\D0\06\EE\F0\0E\EE\D0\06\ECP\0E\E1`\0E\00\E1\0E\EF\D0\06\E9\E0\0E\E60\0Fm`\0E\F0\D0\06\ED\10\0E\F4\80\0E\809\84\03;\CCC9\00\84;\BCC\1B\B8C8\B8\C3<\B4\819\C0C\1B\B4C8\D0\03:\00\E6\10\0E\EC0\0F\E5\00\10\F3@\0F\E10\0E\EB\D0\06\F0 \0F\EF@\0F\E50\0E\F4\F0\0E\F2\D0\06\E2P\0F\E6`\0E\E5 \0Fm0\0F\E9\A0\0F\E5\00\E0\01@\D0C8\C8\C39\94\03=\B4\C18\C0C=\00\E3\F0\0E\F2P\0Er\00\10\F4\10\0E\F2p\0E\E5@\0Fm`\0E\E5\10\0E\F4P\0F\F2P\0E\F3\00\AC\C1<\CC\C3<\94\C3\1C\B0\C1\1A\8C\03>\C4\81\1D\B0\C1\1A\CC\C3<\94\03\1B\AC\C1<\CCC9\C8\01\1B\AC\C1<\CCC9\CC\01@\D4\83;\CCC8\98C9\B4\819\C0C\1B\B4C8\D0\03:\00\E6\10\0E\EC0\0F\E5\00\10\F50\0F\E5\D0\06\F3\F0\0E\E6@\0Fm`\0E\EC\F0\0E\E1@\0F\809\84\03;\CCC9\00\00I\18\00\00\02\00\00\00\13\82`B \00\00\00\89 \00\00\0D\00\00\002\22\08\09 d\85\04\13\22\A4\84\04\13\22\E3\84\A1\90\14\12L\88\8C\0B\84\84L\100s\04H*\00\C5\1C\01\18\94`\88\08\AA0F7\10@3\02\00\134|\C0\03;\F8\05;\A0\836\08\07x\80\07v(\876h\87p\18\87w\98\07|\88\038p\838\80\037\80\83\0DeP\0Em\D0\0Ez\F0\0Em\90\0Ev@\07z`\07t\D0\06\E6\80\07p\A0\07q \07x\D0\06\EE\80\07z\10\07v\A0\07s \07z`\07t\D0\06\B3\10\07r\80\07:\0FDH #EB\80\1D\8C\10\18I\00\00@\00\00\C0\10\A7\00\00 \00\00\00\00\00\00\00\868\08\10\00\02\00\00\00\00\00\00\90\05\02\00\00\08\00\00\002\1E\98\0C\19\11L\90\8C\09&G\C6\04C\9A\22(\01\0AM\D0i\10\1D]\96\97C\00\00\00y\18\00\00\1C\00\00\00\1A\03L\90F\02\134A\18\08&PIC Level\13\84a\D80\04\C2\C05\08\82\83c+\03ab\B2j\02\B1+\93\9BK{s\03\B9q\81q\81\01A\19c\0Bs;k\B9\81\81q\81q\A9\99q\99I\D9\10\14\8D\D8\D8\EC\DA\5C\DA\DE\C8\EA\D8\CA\5C\CC\D8\C2\CE\E6\A6\04C\1566\BB6\974\B227\BA)A\01\00y\18\00\002\00\00\003\08\80\1C\C4\E1\1Cf\14\01=\88C8\84\C3\8CB\80\07yx\07s\98q\0C\E6\00\0F\ED\10\0E\F4\80\0E3\0CB\1E\C2\C1\1D\CE\A1\1Cf0\05=\88C8\84\83\1B\CC\03=\C8C=\8C\03=\CCx\8Ctp\07{\08\07yH\87pp\07zp\03vx\87p \87\19\CC\11\0E\EC\90\0E\E10\0Fn0\0F\E3\F0\0E\F0P\0E3\10\C4\1D\DE!\1C\D8!\1D\C2a\1Ef0\89;\BC\83;\D0C9\B4\03<\BC\83<\84\03;\CC\F0\14v`\07{h\077h\87rh\077\80\87p\90\87p`\07v(\07v\F8\05vx\87w\80\87_\08\87q\18\87r\98\87y\98\81,\EE\F0\0E\EE\E0\0E\F5\C0\0E\EC\00q \00\00\05\00\00\00&`<\11\D2L\85\05\10\0C\804\06@\F8\D2\14\01\00\00a \00\00\0B\00\00\00\13\04A,\10\00\00\00\03\00\00\004#\00dC\19\020\18\83\01\003\11\CA@\0C\83\11\C1\00\00#\06\04\00\1CB\12\00\00\00\00\00\00\00\00\00\00\00\00\00\00\00", section "__LLVM,__bitcode"
@llvm.cmdline = appending constant [67 x i8] c"-triple\00x86_64-apple-macosx10.10.0\00-emit-llvm\00-disable-llvm-optzns\00", section "__LLVM,__cmdline"

; Function Attrs: nounwind ssp uwtable
define i32 @main() #0 {
  %1 = alloca i32, align 4
  store i32 0, i32* %1
  %2 = call i32 (i8*, ...)* @printf(i8* getelementptr inbounds ([10 x i8]* @.str, i32 0, i32 0))
  ret i32 0
}

declare i32 @printf(i8*, ...) #1

attributes #0 = { nounwind ssp uwtable "less-precise-fpmad"="false" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="core2" "target-features"="+ssse3,+cx16,+sse,+sse2,+sse3" "unsafe-fp-math"="false" "use-soft-float"="false" }
attributes #1 = { "less-precise-fpmad"="false" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="core2" "target-features"="+ssse3,+cx16,+sse,+sse2,+sse3" "unsafe-fp-math"="false" "use-soft-float"="false" }

!llvm.module.flags = !{!0}
!llvm.ident = !{!1}

!0 = !{i32 1, !"PIC Level", i32 2}
!1 = !{!"Apple LLVM version 7.0.0 (clang-700.0.53.3)"}

Массив данных, который находится в IR, также изменяется в зависимости от оптимизации и других настроек генерации кода в clang. Мне совершенно неизвестно, в каком формате или в каком-либо другом формате.

РЕДАКТИРОВАТЬ:

Следуя подсказке в Твиттере, я решил вернуться и подтвердить это. Я последовал за этой записью в блоге и использовал его инструмент для извлечения бит-кода, чтобы извлечь двоичный файл Apple Archive из исполняемого файла MachO. И после распаковки Apple Archive с помощью утилиты xar, я получил это (конечно, преобразованный в текст с помощью llvm-dis)

; ModuleID = '1'
target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128"
target triple = "x86_64-apple-macosx10.10.0"

@.str = private unnamed_addr constant [10 x i8] c"hi there!\00", align 1

; Function Attrs: nounwind ssp uwtable
define i32 @main() #0 {
  %1 = alloca i32, align 4
  store i32 0, i32* %1
  %2 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([10 x i8], [10 x i8]* @.str, i32 0, i32 0))
  ret i32 0
}

declare i32 @printf(i8*, ...) #1

attributes #0 = { nounwind ssp uwtable "less-precise-fpmad"="false" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="core2" "target-features"="+ssse3,+cx16,+sse,+sse2,+sse3" "unsafe-fp-math"="false" "use-soft-float"="false" }
attributes #1 = { "less-precise-fpmad"="false" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="core2" "target-features"="+ssse3,+cx16,+sse,+sse2,+sse3" "unsafe-fp-math"="false" "use-soft-float"="false" }

!llvm.module.flags = !{!0}
!llvm.ident = !{!1}

!0 = !{i32 1, !"PIC Level", i32 2}
!1 = !{!"Apple LLVM version 7.0.0 (clang-700.1.76)"}

Единственное заметное различие между IR без битового кода и IR с битовым кодом заключается в том, что имена файлов были сокращены до 1, 2 и т. Д. Для каждой архитектуры.

Я также подтвердил, что битовый код, встроенный в двоичный файл, генерируется после оптимизации. Если вы скомпилируете с -O3 и извлеките битовый код, он будет отличаться от того, если вы скомпилируете с -O0.

И только для того, чтобы получить дополнительный кредит, я также подтвердил, что Apple не отправляет битовый код на устройства при загрузке приложения для iOS 9. Они включают в себя ряд других странных разделов, которые я не распознал, например __LINKEDIT, но они не включают в себя пакет __LLVM.__ и, следовательно, не включают в себя битовый код в конечном двоичном файле, который выполняется на устройстве. Как ни странно, Apple все еще поставляет толстые двоичные файлы с отдельным 32/64-битным кодом на устройства iOS 8.

Биткод (iOS, watchOS)

Биткод - это промежуточное представление скомпилированной программы. Приложения, которые вы загружаете в iTunes Connect и содержат битовый код, будут скомпилированы и связаны в App Store. Включение битового кода позволит Apple повторно оптимизировать двоичный файл вашего приложения в будущем без необходимости представлять новую версию вашего приложения в магазине.


По сути, эта концепция чем-то похожа на Java, где байт-код запускается на разных JVM, и в этом случае битовый код помещается в хранилище iTune, и вместо передачи промежуточного кода различным платформам (устройствам) он предоставляет скомпилированный код, который не требуется. любая виртуальная машина для запуска.

Таким образом, нам нужно создать битовый код один раз, и он будет доступен для существующих или будущих устройств. Это головная боль Apple, чтобы сделать его совместимым с каждой имеющейся платформой.

Разработчикам не нужно вносить изменения и повторно отправлять приложение для поддержки новых платформ.

Давайте возьмем пример iPhone 5s, когда появилось яблоко x64 фишка в этом. Хотя x86 приложения были полностью совместимы с x64 архитектура, но в полной мере использовать x64 Платформа разработчик должен изменить архитектуру или некоторый код. После того, как он / она закончит, приложение отправляется в магазин приложений для проверки.

Если эта концепция битового кода была запущена ранее, то нам, разработчикам, не нужно вносить какие-либо изменения для поддержки x64 немного архитектуры

Обновить

Apple уточнила, что нарезка происходит независимо от включения битового кода. Я наблюдал это на практике также, когда приложение без поддержки битового кода будет загружаться только как архитектура, соответствующая целевому устройству.

оригинал

Более конкретно:

Битовый код. Архивируйте ваше приложение для отправки в App Store в промежуточном представлении, которое при доставке компилируется в 64- или 32-разрядные исполняемые файлы для целевых устройств.

Нарезка. Иллюстрации, включенные в каталог активов и помеченные для платформы, позволяют App Store предоставлять только то, что необходимо для установки.

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

Битовый код

официальная страница

Bitcode(представление битового кода на диске, формат файла битового кода, двоичный формат).

Это одна из трех форм представления [ Intermediate Representation (IR) в LLVM] . Это формат файла битового потока (двоичного кодирования) для LLVM IR. Это результат IR-сериализации LLVM. Он может быть дополнительно встроен в Wrapper или Native Object File( Mach-Oвнутри сырых данных сегмента [О программе]). Подходит для компилятора Just-In-Time.

Еще одно преимущество, которое использует Apple, - это возможность перекомпилировать двоичный файл для другой (новой) архитектуры без внимания разработчика. Также в качестве небольшого дополнения, которое позволяет Apple легче анализировать двоичный файл, но, с другой стороны, это недостаток, который может быть использован злоумышленником. Также это увеличивает время сборки

Xcode использует битовый код в следующих сценариях:

флаги:

  • - встроить битовый код
  • - просто отметьте, где он будет расположен. __LLVM сегмент пустой, без данных

С использованием:

  • Enable Bitcode ( ENABLE_BITCODE)
    • использует для регулярной сборки
    • использует встраивание битового кода в архив(Продукт -> Архив)
  • Явно добавить флаг в Other C Flags( OTHER_CFLAGS) а также Other Linker Flags ( OTHER_LDFLAGS) (например)
  • Пользовательская настройка BITCODE_GENERATION_MODE
    • marker - добавляет -fembed-bitcode-marker
    • bitcode - добавляет -fembed-bitcode
  • xcodebuild с соответствующими вариантами выше
      xcodebuild OTHER_CFLAGS="-fembed-bitcode" OTHER_LDFLAGS="-fembed-bitcode"...

Если вы используете embed bitcode в приложении, но не все библиотеки поддерживают его, вы получаете

      ld: bitcode bundle could not be generated because '<path>' was built without full bitcode. All frameworks and dylibs for bitcode must be generated from Xcode Archive or Install build file '<path>' for architecture <arch>

Проверьте, содержит ли двоичный код битовый код

Битовый код должен храниться в разделе объектного файла с именем __LLVM,__bitcode для MachO и .llvmbc для других объектных форматов.

найти бикод

      otool -l libName.o | grep __bitcode
//otool -l libName.o | grep __LLVM

//-l print the load commands

Извлечь биткод ebcutil

Двоичный размер

Нарезку можно производить с помощью [липо], которое можно заменить на XCFramework

      Library developer - XCFramework
App developer - enable bitcode

[Словарь]

Другие вопросы по тегам