ENABLE_BITCODE在xcode 7中做什么?


262

我对嵌入式位码术语有疑问。
什么是嵌入式位码?
何时启用,ENABLE_BITCODE在新的Xcode中?在Xcode 7中
启用该二进制文件后会发生什么ENABLE_BITCODE

Answers:


312

位代码是指发送到iTunes Connect的代码类型:“ LLVM位代码”。这使Apple可以使用某些计算来进一步重新优化应用程序(例如:可能缩小可执行文件的大小)。如果Apple需要更改您的可执行文件,那么他们可以在不上传新版本的情况下执行此操作。

这不同于: 切片是Apple根据设备的分辨率和体系结构为用户的设备优化应用程序的过程。切片不需要位码。(例如:仅包括5秒内的@ 2x图像)

App Thinning是切片,位码和按需资源的组合

位码是已编译程序的中间表示。您上载到iTunes Connect的包含位码的应用程序将在App Store上进行编译和链接。包含位码将使Apple将来可以重新优化您的应用二进制文件,而无需向商店提交新版本的应用。

Apple关于应用程序细化的文档


在您引用的内容中,没有什么表明启用位码会减少用户设备上应用程序的大小。位码与3x或2x之类​​的资源无关。
user102008 2015年

1
同样,资源与与代码无关的位码无关。用户仅下载某些体系结构的代码和资源的某些版本就是“切片”,这与位码无关。
user102008 2015年

7
我不同意它允许Apple缩减您的应用程序大小。它无处这么说。它说:“这将允许Apple将来重新优化您的应用二进制文件,而无需向商店提交新版本的应用”。我的意思是,它允许Apple重新编译您的应用,以适应新的体系结构。具有新架构的新设备问世,而您无需提交包含该架构的新版本。
user102008 2015年

2
不,切片是将您的应用程序资源分为特定设备的组。位代码使Apple可以为特定体系结构生成可执行文件。
乔恩·谢尔

2
@JonShier苹果说:“切片是为不同目标设备创建和交付应用程序捆绑软件变体的过程。变体仅包含目标设备所需的可执行体系结构和资源。”因此,切片仅具有可执行代码和资源对于某个设备。
keji 2015年

80

什么是嵌入式位码?

根据文档

位码是已编译程序的中间表示。您上载到iTunes Connect的包含位码的应用程序将在App Store上进行编译和链接。包含位码将使Apple将来可以重新优化您的应用二进制文件,而无需向商店提交新版本的应用。

更新:“ Xcode 7的新功能”中的这个短语使我很长时间以来一直认为,切片需要使用Bitcode来减小应用程序的大小:

当您存档提交给App Store时,Xcode会将您的应用编译为中间表示形式。然后,App Store会根据需要将位代码编译为64位或32位可执行文件。

但是,事实并非如此,BitcodeSlicing独立工作:Slicing与减小应用程序大小和生成应用程序包变体有关,Bitcode与某些二进制优化有关。我已经通过检查非位代码应用程序的可执行文件中包含的体系结构并发现它们仅包含必要的体系结构来验证了这一点。

位码允许其他名为“ 切片”的App Thinning组件生成具有特定可执行文件的App Bundle变体,以用于特定体系结构,例如,iPhone 5S变体将仅包含arm64可执行文件,iPad Mini armv7等。

何时在新的Xcode中启用ENABLE_BITCODE?

对于iOS应用,位码是默认值,但是可选的。如果提供位码,则应用程序捆绑包中的所有应用程序和框架都必须包含位码。对于watchOS和tvOS应用程序,需要位码。

在新的Xcode中启用ENABLE_BITCODE时,二进制文件会如何处理?

从Xcode 7参考:

激活此设置表示目标或项目应在编译期间为支持它的平台和体系结构生成位码。对于存档版本,将在链接的二进制文件中生成位代码,以提交到应用商店。对于其他构建,编译器和链接器将检查代码是否符合生成位代码的要求,但不会生成实际的位代码。

这里有几个链接,可以帮助您更深入地了解Bitcode


如果我有ENABLE_BITCODE,但是在提交到App Store之前取消选中“包括位码”,是否会包含位码?
allaire 2015年

“对于iOS应用程序,位码是默认值,但是可选的。” 嗯..?再来..?它是OR还是不是可选的..?
NpC0mpl3t3

@ NpC0mpl3t3如答案中所述,对于iOS应用程序是可选的,但对于watchOS和tvOS应用程序是必需的。
Maxim Pavlov

很好的帮助!这里的答案显示了如何禁用位码:stackoverflow.com/a/41418824/9190
Guerry

20

由于确切的问题是“什么能启用位码”,因此,我想提供一些到目前为止我已经弄清楚的技术细节。实际上,在Apple发布此编译器的源代码之前,几乎不可能100%地确定所有这些内容。

首先,苹果的位码不显示是同样的事情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 IR输出:

; 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的优化和其他代码生成设置而变化。我完全不知道这是什么格式或任何格式。

编辑:

根据Twitter上的提示,我决定重新审视并确认。我关注了这篇博客文章,并使用他的位码提取器工具从MachO可执行文件中获取了Apple Archive二进制文件。在使用xar实用程序提取了Apple Archive之后,我得到了它(当然是用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进行编译的情况将有所不同。

只是为了获得额外的信誉,我还确认,当您下载iOS 9应用程序时,Apple不会将比特码发送到设备。它们包括许多我不认识的其他奇怪的部分,例如__LINKEDIT,但它们不包括__LLVM .__ bundle,因此似乎没有在设备上运行的最终二进制文件中包含位码。奇怪的是,Apple仍然将带有单独的32/64位代码的胖二进制文件运送到iOS 8设备。


苹果的位码可以反编译吗?即Apple现在可以看到我们的源代码吗?
malhal 2015年

@malcolmhall如果它与LLVM代码相似,则只能算是。LLVM字节码具有类型信息和其他提示,这些提示可以使反编译更加容易和有用。但是,我不知道Apple的位代码中包含什么。它可能至少有用一些,但是目前尚不知道它是否有用。无论哪种方式,我都非常怀疑信息的强度是否会像.NET IL如何允许几乎完美地反编译为C#代码一样
Earlz 2015年

您看过LLVM的位码文件格式吗?不可思议的数字不同,但是Apple 强烈暗示这是位码格式。
杰弗里·托马斯

“每个支持的体系结构附带的(即重复的)”都不会重复,因为每个mach-o slice的位代码都不同
AlexDenisov 2015年

2
根据twitter.com/mistydemeo/status/644555663373307904xar!是Apple的存档文件格式。
Riking

14

位码(iOS,watchOS)

位码是已编译程序的中间表示。您上载到iTunes Connect的包含位码的应用程序将在App Store上进行编译和链接。包含位码将使Apple将来可以重新优化您的应用二进制文件,而无需向商店提交新版本的应用。


基本上,此概念与Java有点类似,在Java中字节代码在不同的JVM上运行,在这种情况下,位代码放置在iTune存储上,而不是将中间代码提供给不同的平台(设备),而是提供了不需要的已编译代码任何要运行的虚拟机。

因此,我们需要创建一次比特码,并且该比特码将可用于现有或即将推出的设备。编译使其与他们拥有的每个平台兼容的Apple头疼。

开发人员无需进行更改即可再次提交应用程序以支持新平台。

让我们以苹果x64在其中引入芯片的iPhone 5s 为例。尽管x86应用程序与x64体系结构完全兼容,但是要充分利用x64平台,开发人员必须更改体系结构或某些代码。完成后,该应用程序将提交给应用程序商店进行审查。

如果此位码概念是较早推出的,那么我们开发人员无需进行任何更改即可支持x64位架构。


@ user102008切片是使位码的结果
可骑

@kdogisthebest:不,不是。它无处这么说。而且我已经看过WWDC切片视频,但并不是每个提及启用Bitcode的视频。
user102008 2015年

Inder Kumar Rathore谈到Enterprise App Store时如何处理?企业应用商店是否支持此功能?
damithH

@damithH没有企业应用商店,我们必须将应用保留在服务器上。我不确定应用程序细化功能是否可以在企业应用程序上使用。但据我所知,企业应用程序不应该存在这些内容
Inder Kumar Rathore

请更新您答案中的图片,它与位码无关。
hsafarya

5

更新资料

苹果已经澄清,切片与启用位码无关。在实践中,我也观察到了这一点,在这种情况下,将仅下载不支持位码的应用程序作为适用于目标设备的体系结构。

原版的

更具体地说

位码。将您的应用存档,以中间表示形式提交到App Store,该中间表示在交付时会被编译为目标设备的64位或32位可执行文件。

切片。合并到资产目录中并为平台标记的插图允许App Store仅提供安装所需的内容。

按照我的理解,如果您支持位码,则应用程序的下载者只会获得他们自己设备所需的编译架构。


在“应用程序精简指南”(developer.apple.com/library/prerelease/ios/documentation/IDEs/…)中,“切片是为不同目标设备创建和交付应用程序包变体的过程。变体仅包含可执行体系结构和目标设备所需的资源。” 您的应用下载程序仅了解其体系结构是Slicing的一部分。
user102008 2015年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.