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

262

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

damithH
источник

Ответы:

312

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

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

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

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

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

Keji
источник
Ничто из того, что вы цитировали, не говорит о том, что включение битового кода уменьшает размер приложения на устройстве пользователя. Биткод не имеет ничего общего с такими ресурсами, как 3x или 2x.
user102008
1
Опять же, ресурсы не имеют ничего общего с биткодом, который касается кода. Загрузка пользователями только определенных архитектур кода и определенных версий ресурсов является Slicing, которая не имеет ничего общего с битовым кодом.
user102008
7
Я не согласен с тем, что это позволяет Apple сократить размер вашего приложения. Нигде так не сказано. В нем говорится «позволит Apple повторно оптимизировать бинарный файл вашего приложения в будущем без необходимости отправлять новую версию вашего приложения в магазин», что, как я понимаю, означает, что Apple позволяет перекомпилировать ваше приложение для новой архитектуры, если выходит новое устройство с новой архитектурой, без необходимости представлять новую версию, которая включает эту архитектуру.
user102008
2
Нет, нарезка разделяет ресурсы ваших приложений на группы для определенных устройств. Биткод - это то, что позволяет Apple генерировать исполняемый файл для конкретной архитектуры.
Джон Шир
2
@JonShier Apple говорит: «Слайсинг - это процесс создания и доставки вариантов комплекта приложений для разных целевых устройств. Вариант содержит только исполняемую архитектуру и ресурсы, необходимые для целевого устройства» для определенного устройства.
кеджи
80

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

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

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

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

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

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

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

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

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

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

От ссылки Xcode 7:

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

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

Максим Павлов
источник
Будет ли включен битовый код, если у меня есть ENABLE_BITCODE, но снимите флажок «Включая битовый код» перед отправкой в ​​App Store?
allaire
«Для приложений iOS битовый код используется по умолчанию, но не обязательно». Да ..? Приходи еще..? ИЛИ ИЛИ НЕ ФАКУЛЬТАТИВНО?
NpC0mpl3t3
@ NpC0mpl3t3, как указано в ответе, это необязательно для приложений iOS, но необходимо для приложений watchOS и tvOS.
Максим Павлов
Отличная помощь! Этот ответ здесь показано , как отключить битового кода: stackoverflow.com/a/41418824/9190
Герри
20

Поскольку точный вопрос заключается в том, «что позволяет делать битовый код», я хотел бы привести несколько тонких технических деталей, которые я выяснил до сих пор. Большинство из них практически невозможно понять со 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.

Earlz
источник
Можно ли декомпилировать битовый код Apple? Т.е. теперь Apple может увидеть наш исходный код?
Малхал
@malcolmhall, если это похоже на код LLVM, то только вроде. Байт-код LLVM содержит информацию о типе и другие подсказки, которые могут сделать декомпиляцию намного проще и полезнее. Тем не менее, я не знаю, что в коде Apple. Это, вероятно, по крайней мере, несколько более полезно, но на данный момент неизвестно, насколько это будет полезно. В любом случае, я сильно сомневаюсь, что информация будет настолько сильна, как, скажем, .NET IL позволяет почти идеальную декомпиляцию в код C #
Earlz
Вы видели формат файла битового кода LLVM ? Магическое число отличается, но Apple настоятельно намекает, что это формат битового кода.
Джеффри Томас
«который поставляется с каждой поддерживаемой архитектурой (т. е. дублируется)», он не дублируется, потому что битовый код различен для каждого фрагмента
машины
2
Согласно twitter.com/mistydemeo/status/644555663373307904 , xar!это формат архивных файлов Apple.
Riking
14

Биткод (iOS, watchOS)

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


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

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

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

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

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

Индер Кумар Раторе
источник
@ user102008 Нарезка является результатом включения
биткода
@kdogisthebest: Нет, это не так. Нигде так не сказано. И я смотрел видео WWDC о нарезке, и там не все упоминают о включении биткода.
user102008
Inder Kumar Rathore, когда дело доходит до Enterprise App Store Как с этим справиться? поддерживает ли эта функция корпоративный магазин приложений?
damithH
@damithH Нет магазина корпоративных приложений, мы должны хранить приложения на наших серверах. Я не уверен, будет ли прореживание приложений работать на корпоративных приложениях или нет. Но, насколько мне известно, этого не должно быть для корпоративных приложений
Inder Kumar Rathore
Пожалуйста, обновите изображение в своем ответе, это не связано с биткодом.
Сшафарья
5

Обновить

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

оригинал

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

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

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

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

Бен Флинн
источник
В руководстве «Разбавление приложений» ( developer.apple.com/library/prerelease/ios/documentation/IDEs/… ) «Разрезание - это процесс создания и доставки вариантов комплекта приложений для разных целевых устройств. Вариант содержит только исполняемую архитектуру и ресурсы, которые необходимы для целевого устройства. " Загрузчики вашего приложения, получающие только свою архитектуру, являются частью Slicing.
user102008