JHHK

欢迎来到我的个人网站
行者常至 为者常成

bitcode

目录

简介

先来看个llvm的经典图片

img

bitcode是由LLVM引入的一种中间代码(Intermediate Representation,简称IR),它是源代码被编译为二进制机器码过程中的中间表示形态,它既不是源代码,也不是机器码。从代码组织结构上看它比较接近机器码,但是在函数和指令层面使用了很多高级语言的特性。

作用

在这个体系中,不同语言的源代码将会被转化为统一的bitcode格式,三个模块可以充分复用,防止重复造轮子。如果要开发一门新的x语言,只需要造一个x语言的前端,将x语言的源代码编译为bitcode,优化和后端的事情完全不用管。同理,如果新的芯片架构问世,则只需要基于LLVM重新写一套目标平台的后端,非常方便。

生成.ll文件

既然bitcode是代码的一种表示形式,因此它也会有自己的一套独立的语法,可以通过一个简单的例子来一探究竟,这里以clang为例,swift的操作和结果可能稍有不同。

test.c文件

#include <stdio.h>
int main(void) {
    printf("hello, world.\n");
    return 0;
}

通过以下命令可以将源代码编译为object文件:

$ clang -c test.c -o test.o
$ file test.o
test.o: Mach-O 64-bit object x86_64

其实,这个命令同时完成了前端、优化、后端三个部分,可以通过 -emit-llvm -c 将前端这一步单独拆出来,这样就可以看到bitcode了:

$ clang -emit-llvm -c test.c -o test.bc # 将源代码编译为bitcode
$ file test.bc
test.bc: LLVM bitcode, wrapper x86_64
$ clang -c test.bc -o test.bc.o # 将bitcode编译为object
$ file test.bc.o
test.bc.o: Mach-O 64-bit object x86_64

对比

$ md5 test.bc.o test.o
MD5 (test.bc.o) = 70ea3a520c26df84d1f7ca552e8e6620
MD5 (test.o) = 70ea3a520c26df84d1f7ca552e8e6620

Enable Bitcode

一、开关设置

开启此设置将会在支持的平台和架构中开启bitcode,进行Archive时,bitcode会被嵌入到链接后的二进制文件中,用于提交给App Store。这也是为什么出了新架构的机器后开发者不需要重新上传可执行文件到App Store,我们的APP也能在新架构的机器上顺利执行,因为上传到App Store的bitcode能为新架构的机器生成相应的可执行文件。

Enable Bitcode 设置为 YES 时,从编译日志中可以看出,Archive时多了一个编译参数 -fembed-bitcode。

进行其他类型的Build(非Archive)时,编译器只会检查是否满足开启bitcode的条件,但并不会真正生成bitcode。

非Archive编译时,Enable Bitcode 将会增加编译参数 -fembed-bitcode-marker, 只是在object文件中做了标记,表明我可以有bitcode,但是现在暂时没有带上它。因为本地编译调试时并不需要bitcode,只有AppStore需要这玩意儿,去掉这个不必要的步骤,会加快编译速度。

这就是为什么有的同学在开发SDK时,明明开启了Enable Bitcode,交给客户后客户却说:你的sdk里没有bitcode,因为你没有使用Archive方式打包。当然,你可以将 Enable Bitcode 设置为NO, 然后在Other Compiler Flags 和 Other Linker Flags 中手动为真机架构添加-fembed-bitcode 参数,这样任何类型的Build都会带上bitcode。

二、如何判断是否开启bitcode

可以通过otool检查二进制文件,网上有很多类似这样的方法:

otool -arch armv7 -l xxxx.a | grep __LLVM | wc -l

通过判断是否包含 __LLVM 或者关键字来判断是否支持bitcode,其实这种方式是完全错误的,通过前面的测试可以知道,这种方式区分不了bitcode和bitcode-marker,确定是否包含bitcode,还需要检查otool输出中__LLVM Segment 的长度,如果长度只有1个字节,则并不能代表真正开启了bitcode:

$ otool -l test_bitcode.o | grep -A 2  __LLVM | grep size
      size 0x0000000000000b10
      size 0x0000000000000042
$ otool -l test_bitcode_marker.o | grep -A 2  __LLVM | grep size
      size 0x0000000000000001
      size 0x0000000000000001

行者常至,为者常成!





R
Valine - A simple comment system based on Leancloud.