上篇文章我们尝试在Mac上成功编译了V8,不过编译生成的d8只能运行在Mac主机上运行,具体请参考「Mac上如何编译V8」。如果想要编译出能在Android上运行的d8该怎么做呢?这就要用到传说中的cross compile了。
V8交叉编译
请参考官方文档https://v8.dev/docs/cross-compile-arm
修改gclient配置文件
在.gclient文件里添加target_os=['android'],问题来了,这个.gclient文件在哪,笔者在V8源码文件夹下一顿找,居然没找到这货。假设你源码路径为/path/to/v8/v8,这货在/path/to/v8下,改完之后应该类似下图
下载Android相关依赖
在/path/to/v8下执行gclient sync命令
生成ninja文件
执行tools/dev/v8gen.py list,结果如下
这里我选择arm64架构的,执行tools/dev/v8gen.py arm64.release,会生成out.gn/arm64.release文件夹,目录结构如下图
执行gn args out.gn/arm64.release查看生成的默认参数配置,可根据需要修改默认参数,笔者的配置如下图
执行gn args out.gn/arm64.release/ --list命令可以查看支持的所有参数及每个参数的说明,如果只想看某个参数的说明,例如只想看symbol_level参数的说明可执行gn args out.gn/arm64.release/ --list=symbol_level,结果如下图
编译
执行ninja -C out.gn/arm64.release/ d8,即可启动编译。
编译过程碰到的问题
1. fatal error: 'features.h' file not found
我们搜下v8源码目录下是否有features.h文件,find . -name features.h,可以看到toolchains下只有linux-x86_64,但编译用的确是third_party/android_ndk/toolchains/llvm/prebuilt/darwin-x86_64/sysroot
解决方法
1. 先看下v8里的ndk的版本,cat third_party/android_ndk/source.properties
2. 下载这个版本的ndk(如果本地有其他版本的ndk可先尝试),并在ndk目录下搜索features.h,find . -name features.h
3. 把红框拷贝到v8下的ndk里,执行cp -rv 20.0.5594570/toolchains/llvm/prebuilt/darwin-x86_64/ /path/to/v8/v8/third_party/android_ndk/toolchains/llvm/prebuilt/darwin-x86_64/,darwin-x86_64已经有了
4. 再启动编译
2. llvm-ar: No such file or directory
报错是因为llvm-ar这个文件不存在
解决方法
1. 同上一个问题,在ndk目录下搜索llvm-ar,find . -name llvm-ar
2. 把红框文件拷贝过去,cp ./20.0.5594570/toolchains/llvm/prebuilt/darwin-x86_64/bin/llvm-ar /path/to/v8/v8/third_party/llvm-build/Release+Asserts/bin/
3. 再启动编译
3. invalid linker name in argument '-fuse-ld=lld'
解决方法
参考https://lld.llvm.org/
猜测应该是因为ld.lld这个文件找不到,在v8源码目录下执行find . -name ld.lld
尝试拷贝这个文件,执行cp ./third_party/android_ndk/toolchains/llvm/prebuilt/darwin-x86_64/bin/ld.lld third_party/llvm-build/Release+Asserts/bin/
再启动编译
4. OSError: [Errno 8] Exec format error
解决方法
1. 调试gcc_link_wrapper.py发现是执行strip的时候出错了,错误显示「Exec format error」
2. 看下eu-strip文件的格式,执行file buildtools/third_party/eu-strip/bin/eu-strip,可以看到这个文件是Linux上的可执行格式,Mac的可执行文件格式应该是「Mach-O」这种格式的。
3. 在third_party/android_ndk/toolchains/llvm/prebuilt/darwin-x86_64下搜索stripe命令,find . -name *strip*
4. 尝试把eu-strip换成llvm-strip试下,v8源码目录下搜索eu-strip,grep -nr 'eu-strip' *,strip工具应该是在build/toolchain/android/BUILD.gn里配置的。
4. 修改build/toolchain/android/BUILD.gn,替换eu-strip为llvm-strip
5. 再启动编译,终于编译成功。
运行
cd out.gn/arm64.release
adb push d8 /data/local/tmp/v8/bin/,android上成功运行
总结
编译过程中碰到了4个问题,可以看到都是环境问题,而且网上相关的资料比较少,笔者在这里还折腾了不少时间,好在最终都成功解决了。难怪网上很多人都推荐用Linux去编译V8,如果用Linux编译的话应该不会有这些问题吧,但笔者手上只有Mac环境,也不想倒腾虚拟机,就硬着头皮在Mac上开干了。人生在于折腾,一分折腾一分收获,谨以此与大家共勉。