苹果的要求

到此,让我们思考一下,为什么苹果默认要求watchOS和tvOS的App要上传bitcode?
因为把bitcode上传到他自己的中心服务器后,他可以为目标安装App的设备进行优化二进制,减小安装包的下载大小,当然iOS开发者也可以上传多个版本而不是打包到单个包里,但是这样会占用更多的存储空间.
最重要的是允许苹果可以在后台服务器对应用程序进行签名,而不用导出任何密钥到终端开发者那.

上传到服务器的bitcode给苹果带来更好处是:
以后新设计了新指令集的新CPU,可以继续从这份bitcode开始编译出新CPU上执行的可执行文件,以供用户下载安装.
但是bitcode给开发者带来的不便之处就是:
没用bitcode之前,当应用程序奔溃后,开发者可以根据获取的的奔溃日志再配上上传到苹果服务器的二进制文件的调试符号表信息可以还原程序运行过程到奔溃时后调用栈信息,对问题进行定位排查.但是用了bitcode之后,用户安装的二进制不是开发者这边生成的,而是苹果服务器经过优化后生成的,其对应的调试符号信息丢失了,也就无法进行前面说的还原奔溃现场找原因了.

目前,watchOS和tvOS应用发布必须上传带bitcode版本的包.iOS应用发布对bitcode的要求是可选的,用户可以在Xcode的项目设置中关闭.
相当于在编译的时候加一个标记:embed-bitcode-marker(调试构建)
embed-bitcode(打包/真机构建).这个在clang编译器的参数是-fembed-bitcode,swift编译器的参数是-embed-bitcode.

苹果的要求

到此,让我们思考一下,为什么苹果默认要求watchOS和tvOS的App要上传bitcode?
因为把bitcode上传到他自己的中心服务器后,他可以为目标安装App的设备进行优化二进制,减小安装包的下载大小,当然iOS开发者也可以上传多个版本而不是打包到单个包里,但是这样会占用更多的存储空间.
最重要的是允许苹果可以在后台服务器对应用程序进行签名,而不用导出任何密钥到终端开发者那.

上传到服务器的bitcode给苹果带来更好处是:
以后新设计了新指令集的新CPU,可以继续从这份bitcode开始编译出新CPU上执行的可执行文件,以供用户下载安装.
但是bitcode给开发者带来的不便之处就是:
没用bitcode之前,当应用程序奔溃后,开发者可以根据获取的的奔溃日志再配上上传到苹果服务器的二进制文件的调试符号表信息可以还原程序运行过程到奔溃时后调用栈信息,对问题进行定位排查.但是用了bitcode之后,用户安装的二进制不是开发者这边生成的,而是苹果服务器经过优化后生成的,其对应的调试符号信息丢失了,也就无法进行前面说的还原奔溃现场找原因了.

目前,watchOS和tvOS应用发布必须上传带bitcode版本的包.iOS应用发布对bitcode的要求是可选的,用户可以在Xcode的项目设置中关闭.
相当于在编译的时候加一个标记:embed-bitcode-marker(调试构建)
embed-bitcode(打包/真机构建).这个在clang编译器的参数是-fembed-bitcode,swift编译器的参数是-embed-bitcode.

问题:打包出来的IPA文件太大?libiPhone-lib.a竟然过1G!!!

解决:只需在xcode工程中 【build Settings】下的搜索
“bidcode”,把yes改为no重新打包就行了。

澳门新葡亰亚洲在线 1

01.png

bit code 解释:
就是链接了第三方二进制的库或者框架,而这些框架或者库恰好没有包含bitcode的东西(暂且称为东西),从而导致项目编译不成功.所以每当遇到这个情况时候大部分人都是直接设置Xcode关闭bitcode功能。
LLVM是目前苹果采用的编译器工具链,Bitcode是LLVM编译器的中间代码的一种编码,LLVM的前端可以理解为C/C++/OC/Swift等编程语言,LLVM的后端可以理解为各个芯片平台上的汇编指令或者可执行机器指令数据,那么,BitCode就是位于这两者直接的中间码.
LLVM的编译工作原理是前端负责把项目程序源代码翻译成Bitcode中间码,然后再根据不同目标机器芯片平台转换为相应的汇编指令以及翻译为机器码.这样设计就可以让LLVM成为了一个编译器架构,可以轻而易举的在LLVM架构之上发明新的语言(前端),以及在LLVM架构下面支持新的CPU(后端)指令输出,虽然Bitcode仅仅只是一个中间码不能在任何平台上运行,但是它可以转化为任何被支持的CPU架构,包括现在还没被发明的CPU架构,也就是说现在打开Bitcode功能提交一个App到应用商店,以后如果苹果新出了一款手机并CPU也是全新设计的,在苹果后台服务器一样可以从这个App的Bitcode开始编译转化为新CPU上的可执行程序,可供新手机用户下载运行这个App.

xcode相关设置:http://blog.csdn.NET/skylin19840101/article/details/51452594

实际上在Xcode
7中,我们新建一个iOS程序时,bitcode选项默认是设置为YES的。我们可以在”Build
Settings”->”Enable Bitcode”选项中看到这个设置。

不过,我们现在需要考虑的是三个平台:iOS,Mac OS,watchOS。

对应iOS,bitcode是可选的。
对于watchOS,bitcode是必须的。
Mac OS不支持bitcode。

此文之初衷

最近在辅导我戴维营战友们做手机音视频直播的App,调试的时候手机采集音视频,视频用h264编码,音频采用aac编码,通过RTMP协议往斗鱼直播频道发布媒体流,项目需要用FFMPEGlibx264两个开源项目,在编译为iOS框架库提供给学生用的时候,他们遇到了bitcode的问题,虽然可以采取直接关闭bitcode来避免错误,但是战友的求知欲必须满足,格物致知,必须让其知其究竟.

libx264是VideoLan基金会管理的一个视频编解码的开源项目,其大量使用了各个平台的多媒体汇编指令进行了优化,在编译为不带bitcode的库的时候,完全按官方autotools编译方法是没有任何问题的;编译全带bitcode的库的时候我们不得不关闭汇编优化,在执行./configure阶段可以加上--disable-asm参数来禁用汇编.但是,这个选项在configure脚本中的实现机制有问题.导致其仍然调用了汇编的函数,但是汇编的代码却没有编译进去,从而会导致项目为真机构建和打包的链接阶段会爆出找不到符号的错误,这样就不能做到两全其美.出于轻微程度的强迫症影响,故把之前的FFMPEGlibx264项目的编译脚本进行了改进和打补丁.目前已经可以做到一键编译出带全部bitcode的FFMPEG和libx264的框架了.

FFmpeg需要依赖libx264.

自动编译脚本项目位置放在github:
https://github.com/Diveinedu-CN/FFmpeg-iOS-build-script.git

由于时间和篇幅原因,关于其他更多详细的信息就不细细道来了.

戴维营教育Slogan: Dive in educationwww.88850.com ,!

更多iOS开发精品文章:澳门新葡亰亚洲在线 ,戴维营技术博客

2.下面把其中一个demo.m换成汇编语言再参与编译:

用下面的命令把demo.m的C代码转换为ARM64汇编语言格式demo.s:

$ xcrun -sdk iphoneos clang -arch arm64 -S demo.m
$ cat demo.s
# Prints:
    .section    __TEXT,__text,regular,pure_instructions
    .ios_version_min 9, 2
    .globl    _demo
    .align    2
_demo:                                  ; @demo
    .cfi_startproc
; BB#0:
    stp    x29, x30, [sp, #-16]!
    mov     x29, sp
Ltmp0:
    .cfi_def_cfa w29, 16
Ltmp1:
    .cfi_offset w30, -8
Ltmp2:
    .cfi_offset w29, -16
    adrp    x0, L__unnamed_cfstring_@PAGE
    add    x0, x0, L__unnamed_cfstring_@PAGEOFF
    bl    _NSLog
    ldp    x29, x30, [sp], #16
    ret
    .cfi_endproc

    .section    __TEXT,__cstring,cstring_literals
L_.str:                                 ; @.str
    .asciz    "demo func"

    .section    __DATA,__cfstring
    .align    4                       ; @_unnamed_cfstring_
L__unnamed_cfstring_:
    .quad    ___CFConstantStringClassReference
    .long    1992                    ; 0x7c8
    .space    4
    .quad    L_.str
    .quad    9                       ; 0x9

    .section    __DATA,__objc_imageinfo,regular,no_dead_strip
L_OBJC_IMAGE_INFO:
    .long    0
    .long    0
    .subsections_via_symbol

然后删除demo.m这个C源代码,仅留下test.m和demo.s:

$ rm demo.m

现在,我们来把test.m这个C源代码和dmeo.s这个汇编源代码来一起带着-fembed-bitcode参数来生成目标代码并打包为一个静态库:

$ xcrun -sdk iphoneos clang -arch arm64 -fembed-bitcode -c test.m demo.s
$ xcrun -sdk iphoneos ar -r libTest.a test.o demo.o

然后我们再运行otool工具来检查这个新的静态库中包含的2个目标文件是否都带有bitcode段:

$ ar -t libTest.a
# Prints:
# __.SYMDEF SORTED
# test.o
# demo.o
$ otool -l libTest.a | grep bitcode
# Prints:
#  sectname __bitcode

很意外,这一次,只有一行sectname
__bitcode输出,这就说明这两个目标文件,有一个不带有bitcode段,哪怕我们在编译的时候指定了参数-fembed-bitcode也没有用.至于具体是哪一个不带bitcode段,我们肯定知道就是那个从ARM64汇编语言编译过来的目标文件不带.

那么就得出一个结论,bitcode的生成,是由汇编语言以上的上层语言编译而来,和最前面所说的那样,他是上层语言与汇编语言(机器语言)之间的一个中间码.

目前我们日常的iOS应用开发中,一般不会需要用到汇编层面去优化的代码.所以我们主要关注第三方(开源)C代码,尤其是音视频编码解码这些计算密集型项目代码,关键计算的代码针对特定平台都有对应平台的汇编版本实现,当然也有C的实现,但是默认编译一般都是用的汇编版本,这样就会导致我们在编译这个开源代码的时候哪怕你带了-fembed-bitcode参数也仅仅只是让项目中的部分C代码的目标文件带了bitcode段,而那小数的汇编代码的目标文件一样不带bitcode段,这样编译出这个库交给上层开发者使用的时候,就会出现在打包上传或者真机调试的时候因为Xcode默认开了bitcode功能而链接失败,导致不能真机调试或者不能上传应用到AppStore.

实践出真知

我们还是应该实际弄两个测试代码进行实践和检验一下比较好.做两次测试,第一次准备两个C语言源代码继续测试;第二次把其中一个转变为汇编语言源代码后再一个C代码和一个汇编代码一起重复之前的测试步骤进行对比校验差异.

  • 1 . 如下两个全部是Objective-C代码:

test.m :

#import <Foundation/Foundation.h>
void greeting(void)
{
    NSLog(@"hello world!");
}

demo.m :

#import <Foundation/Foundation.h>
void demo(void)
{
    NSLog(@"demo func");
}

用Clang编译成 ARM64 格式且带bitcode的目标文件test.o demo.o:

wuqiong:~ apple$ xcrun -sdk iphoneos clang -arch arm64 -fembed-bitcode -c test.m demo.m

然后把两个目标文件打包为一个静态库文件:

wuqiong:~ apple$ xcrun -sdk iphoneos ar  -r libTest.a test.o demo.o
ar: creating archive libTest.a

用Shell命令otool查看目标文件中是否包含bitcode段:

wuqiong:~ apple$ otool -l test.o |grep bitcode
  sectname __bitcode
  sectname __bitcode

如果看到输出了2行sectname __bitcode,就是说明这静态库中的两个目标文件包含了bitcode.

  • 2.下面把其中一个demo.m换成汇编语言再参与编译:

用下面的命令把demo.m的C代码转换为ARM64汇编语言格式demo.s:

wuqiong:~ apple$ xcrun -sdk iphoneos clang -arch arm64 -S demo.m
wuqiong:~ apple$ cat demo.s
    .section    __TEXT,__text,regular,pure_instructions
    .ios_version_min 9, 2
    .globl  _demo
    .align  2
_demo:                                  ; @demo
    .cfi_startproc
; BB#0:
    stp x29, x30, [sp, #-16]!
    mov  x29, sp
Ltmp0:
    .cfi_def_cfa w29, 16
Ltmp1:
    .cfi_offset w30, -8
Ltmp2:
    .cfi_offset w29, -16
    adrp    x0, L__unnamed_cfstring_@PAGE
    add x0, x0, L__unnamed_cfstring_@PAGEOFF
    bl  _NSLog
    ldp x29, x30, [sp], #16
    ret
    .cfi_endproc

    .section    __TEXT,__cstring,cstring_literals
L_.str:                                 ; @.str
    .asciz  "demo func"

    .section    __DATA,__cfstring
    .align  4                       ; @_unnamed_cfstring_
L__unnamed_cfstring_:
    .quad   ___CFConstantStringClassReference
    .long   1992                    ; 0x7c8
    .space  4
    .quad   L_.str
    .quad   9                       ; 0x9

    .section    __DATA,__objc_imageinfo,regular,no_dead_strip
L_OBJC_IMAGE_INFO:
    .long   0
    .long   0


.subsections_via_symbol

然后删除demo.m这个C源代码,仅留下test.mdemo.s:

wuqiong:~ apple$ rm demo.m

现在,我们来把test.m这个C源代码和dmeo.s这个汇编源代码来一起带着-fembed-bitcode参数来生成目标代码并打包为一个静态库:

wuqiong:~ apple$ xcrun -sdk iphoneos clang -arch arm64 -fembed-bitcode -c test.m demo.s
wuqiong:~ apple$ xcrun -sdk iphoneos ar -r libTest.a test.o demo.o

然后我们再运行otool工具来检查这个新的静态库中包含的2个目标文件是否都带有bitcode段:

wuqiong:~ apple$ ar -t libTest.a
__.SYMDEF SORTED
test.o
demo.o
wuqiong:~ apple$ otool -l libTest.a | grep bitcode
  sectname __bitcode

很意外,这一次,只有一行sectname __bitcode输出,这就说明这两个目标文件,有一个不带有bitcode段,哪怕我们在编译的时候指定了参数-fembed-bitcode也没有用.至于具体是哪一个不带bitcode段,我们肯定知道就是那个从ARM64汇编语言编译过来的目标文件不带.

那么就得出一个结论,bitcode的生成,是由汇编语言以上的上层语言编译而来,和最前面所说的那样,他是上层语言与汇编语言(机器语言)之间的一个中间码.

目前我们日常的iOS应用开发中,一般不会需要用到汇编层面去优化的代码.所以我们主要关注第三方(开源)C代码,尤其是音视频编码解码这些计算密集型项目代码,关键计算的代码针对特定平台都有对应平台的汇编版本实现,当然也有C的实现,但是默认编译一般都是用的汇编版本,这样就会导致我们在编译这个开源代码的时候哪怕你带了-fembed-bitcode参数也仅仅只是让项目中的部分C代码的目标文件带了bitcode段,而那小数的汇编代码的目标文件一样不带bitcode段,这样编译出这个库交给上层开发者使用的时候,就会出现在打包上传或者真机调试的时候因为Xcode默认开了bitcode功能而链接失败,导致不能真机调试或者不能上传应用到AppStore.

1 . 如下两个全部是Objective-C代码:

test.m :

#import <Foundation/Foundation.h>
void greeting(void)
{
    NSLog(@"hello world!");
}

demo.m :

#import <Foundation/Foundation.h>
void demo(void)
{
    NSLog(@"demo func");
}

用Clang编译成 ARM64 格式且带bitcode的目标文件test.o demo.o:

$ xcrun -sdk iphoneos clang -arch arm64 -fembed-bitcode -c test.m demo.m

然后把两个目标文件打包为一个静态库文件:

$ xcrun -sdk iphoneos ar  -r libTest.a test.o demo.o
# ar: creating archive libTest.a

用Shell命令otool查看目标文件中是否包含bitcode段:

$ otool -l test.o |grep bitcode
# Prints:
#   sectname __bitcode
#   sectname __bitcode

如果看到输出了2行sectname
__bitcode,就是说明这静态库中的两个目标文件包含了bitcode.

相关文章

发表评论

电子邮件地址不会被公开。 必填项已用*标注

网站地图xml地图