0%

MAC 下 V8 Android编译指墙

1. V8编译历程

1.1 前言

  1. 编译V8第一步就是保证能访问Google,当然不仅仅是为了查阅资料,最最重要的是V8源码下载的需要。
  2. 访问 https://v8.dev/docs ,V8官网可查看到Building V8 from source 根据所写一步步来就好。

1.2 编译环境搭建

V8源码通过depot_tools工具来管理,首先下载这个工具,作者以/Users/*/Documents/test/v8 目录为工作目录。

由于需要访问国外站,在获取depot_tools前需要做一些不可描述的事情:

1
$ export http_proxy="http://127.0.0.1:8001"; export HTTP_PROXY="http://127.0.0.1:8001"; export https_proxy="http://127.0.0.1:8001"; export HTTPS_PROXY="http://127.0.0.1:8001"

开启代理后,将其假如环境变量。

进入/Users/*/Documents/test/v8 目录下:

1
$ git clone https://chromium.googlesource.com/chromium/tools/depot_tools.git

通过git下载depot_tools

将工具集假如环境变量:

1
$ export PATH=$PATH:/Users/*/Documents/test/v8/depot_tools

fetch V8源码,并同步,fetch命令即depot_tools中的命令:

1
2
$ fetch v8
$ gclient sync

详见:
https://commondatastorage.googleapis.com/chrome-infra-docs/flat/depot_tools/docs/html/depot_tools_tutorial.html#_setting_up

作者使用Mac,Xcode 为10.2.1,Xcode在10以后不支持32位的编译,一次需要同时安装10一下的版本。

到苹果下载官网 https://developer.apple.com/download/more/ 找到Xcode 10一下的版本并下载,我采用的是9.4.1。由于Xcode 体积比较大,通过浏览器下载比较慢。直接复制下载地址到下载器无法下载,需要将下载地址的请求头一并复制:打开chrome 开发者工具,点击下载后在Network可看到下载地址,右键下载地址,选择Copy-Copy as cURL,在终端粘贴后假如 -O 即可通过curl下载。

笔者将Xcode9.4.1 安装到:/Applications/Xcode9.4.1/Xcode.app

查看xcode的版本:

1
2
$ xcode-select -p
/Applications/Xcode.app/Contents/Developer

切换xcode的版本:

1
$ sudo xcode-select -s /Applications/Xcode9.4.1/Xcode.app/Contents/Developer

接下来进入编译的坑。

1.3 编译

1.3.1 编译V8可执行文件

通过 https://v8.dev/docs/cross-compile-arm 官网介绍的,在.gclient 中添加target_os = ['android'] ,再次执行gclient sync ,拉取与Android编译想过的模块,主要是NDK,如果本地有ndk,可以不用添加target_os = ['android'] ,以节约时间。即是加上,拉下来的NDK也是linux的,里面缺少很多Mac下的工具,因此,我单独自己下载的。

1
2
3
4
5
6
7
8
$ cd /Users/*/Documents/test/v8
$ curl -O https://dl.google.com/android/repository/android-ndk-r19c-darwin-x86_64.zip
$ unzip android-ndk-r19c-darwin-x86_64.zip -d ndkr19c
$ export ANDROID_NDK_HOME=`pwd`/ndkr19c/android-ndk-r19c
$ cd v8
$ mkdir third_party/android_tools
$ ln -s $ANDROID_NDK_HOME third_party/android_tools/ndk
$ ln -s $ANDROID_NDK_HOME third_party/android_ndk

通过 gm 工具编译

1
2
3
$ cd v8  # 进入v8代码目录
$ alias gm=/Users/*/Documents/test/v8/v8/tools/dev/gm.py
$ gm android_arm.release.check

执行完后,会生成 unittests cctest d8 三个执行文件,并需要电脑通过ADB连接Android手机,以测试生存文件是否存在问题。这里有个巨坑,在生成d8的最后一步,需要用到一个工具eu-strip,这个工具是linux的,导致最后一步无法通过。除此之外,在构建静态库时,需要用到llvm-ar工具,但是v8工具库里缺少这个文件,需要从ndk中拷贝一份。

1
2
3
4
5
$ cd /Users/*/Documents/test/v8
$ cp ndkr19c/android-ndk-r19c/toolchains/llvm/prebuilt/darwin-x86_64/bin/llvm-ar v8/third_party/llvm-build/Release+Asserts/bin/
$ cp ndkr19c/android-ndk-r19c/toolchains/llvm/prebuilt/darwin-x86_64/bin/ld.lld v8/third_party/llvm-build/Release+Asserts/bin/
$ mv v8/buildtools/third_party/eu-strip/bin/eu-strip v8/buildtools/third_party/eu-strip/bin/eu-strip.bak
$ cp ndkr19c/android-ndk-r19c/toolchains/llvm/prebuilt/darwin-x86_64/bin/llvm-strip v8/buildtools/third_party/eu-strip/bin/eu-strip

在链接过程中可能会报clang: error: invalid linker name in argument '-fuse-ld=lld' 这是因为缺少ld.lld 文件。

编译完成后,会自动通过adb下载到手机做测试。如果不想测试执行gm android_arm.release ,另外gm 命令会自动上传编译报告给google,如果link完后,提示ninjalog_uploader_wrapper.py 相关的错误可能时代理没设置,不过没关系,前面的那步一脚编译完成。

如果需要测试v8编译是否成功,可参考官方文档 https://v8.dev/docs/cross-compile-arm 自己上传d8及需要的文件至手机测试。

如果自定测试提示adb未找到,需要将adb添加到下面目录(v8下载的android_tools中的adb为linux版的):

1
/Users/*/Documents/test/v8/v8/third_party/android_tools/sdk/platform-tools/adb

如果不行,直接改代码

/Users/*/Documents/test/v8/v8/third_party/catapult/devil/devil/android/sdk/adb_wrapper.py:

1
2
def _FindAdb():
return os.path.join("/Users/*/Documents/test/v8/v8/third_party/android_tools/sdk/platform-tools/adb")

自己简单测一下;

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
adb shell 'mkdir -p /data/local/tmp/v8/bin'
adb push out.gn/arm.release/d8 /data/local/tmp/v8/bin
adb push out.gn/arm.release/icudtl.dat /data/local/tmp/v8/bin
adb push out.gn/arm.release/natives_blob.bin /data/local/tmp/v8/bin
adb push out.gn/arm.release/snapshot_blob.bin /data/local/tmp/v8/bin


rebuffat:~/src/v8$ adb shell
bullhead:/ $ cd /data/local/tmp/v8/bin
bullhead:/data/local/tmp/v8/bin $ ls
v8 natives_blob.bin snapshot_blob.bin
bullhead:/data/local/tmp/v8/bin $ ./d8
V8 version 5.8.0 (candidate)
d8> 'w00t!'
"w00t!"
d8>
1.3.2 编译配置

可按自己的需求修改编译配置,通过v8gen.py工具可查看内置默认编译配置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
$ cd /Users/*/Documents/test/v8/v8
$ tools/dev/v8gen.py list
android.arm.debug
android.arm.optdebug
android.arm.release
arm.debug
arm.optdebug
arm.release
arm64.debug
arm64.optdebug
arm64.release
ia32.debug
ia32.optdebug
ia32.release
mips64el.debug
mips64el.optdebug
mips64el.release
mipsel.debug
mipsel.optdebug
mipsel.release
ppc64.debug
ppc64.debug.sim
ppc64.optdebug
ppc64.optdebug.sim
ppc64.release
ppc64.release.sim
s390x.debug
s390x.debug.sim
s390x.optdebug
s390x.optdebug.sim
s390x.release
s390x.release.sim
x64.debug
x64.optdebug
x64.release
x64.release.sample
$ tools/dev/v8gen.py arm.release

通过tools/dev/v8gen.py arm.release 命令可以生存对应的问价,文件在 out.gn 目录内,通过gm 生成的文件在 out 内。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
is_component_build = false
is_debug = false
target_cpu = "arm"
v8_target_cpu = "arm"
target_os = "android"
use_goma = false
goma_dir = "None"
v8_enable_backtrace = true
v8_enable_disassembler = true
v8_enable_object_print = true
v8_enable_verify_heap = true
v8_use_snapshot=true
v8_enable_embedded_builtins=true
is_official_build=true
use_thin_lto=false
v8_enable_i18n_support=true
symbol_level=0
v8_android_log_stdout=true

is_component_build true 生存动态库,false 生成可执行文件

v8_static_library=true 生成静态库

v8_enable_i18n_support=false 是否支持i18n

1.3.3 编译静态库

出了通过配置编译外,还可以自己通过llvm-ar 命令来生存静态库。

1
2
3
$ cd /Users/*/Documents/test/v8/v8/out/android_arm.release/obj
$ export armar=$ANDROID_NDK_HOME/toolchains/arm-linux-androideabi-4.9/prebuilt/darwin-x86_64/arm-linux-androideabi/bin/ar
$ $armar r libv8all.a v8_libsampler/*.o v8_libplatform/*.o v8_libbase/*.o v8_external_snapshot/*.o v8_compiler/*.o v8_base_without_compiler/*.o torque_generated_definitions/*.o third_party/icu/icui18n/*.o third_party/icu/icuuc/*.o third_party/inspector_protocol/encoding/*.o buildtools/third_party/libc++/libc++/*.o buildtools/third_party/libc++abi/libc++abi/*.o

得到的libv8all.a 即为链接了所有.o 的静态库。

1.3.4 其他问题
  1. “stddef.h: No such file or directory”

    这个是clang++ 的一个bug,在拷贝llvm-ar时,确保 v8/third_party/llvm-build/Release+Asserts/bin/ 目录中的clang++ 没被替换,用v8自己的。

  2. 在Android项目中引入v8静态库做开发时,出现 std::__ndk1:: 想关错误

    1. NDK的libc++的C++11命名空间为std::__ndk1
    2. NDK的gnustl的C++11命名空间为std
    3. 安卓系统的libc++的C++11命名空间为std::__1

    https://zhuanlan.zhihu.com/p/31025055

    需要将obj下的libc++相关的库一起引入,通过ar命令打包时,需要一起打包。

  3. 发现v8下的内容被玩坏了?

    删掉对应内容的git仓库, gclient sync 一下 。gclient sync 提示其他库有内容未提交,删掉其他库,一起gclient sync 😋。

  4. 怎么都不行?

    请使用ubuntu!!!