如何用GN编译V8引擎

在v8引擎的6.5版本以上,google采用了GN+Ninja的编译组合,因此本文主要是基于GN+Ninjia的编译方式进行说明。

获取源码

在官方文档中,还特别提示了避免HFS环境下的unicode问题,需要额外配置一下:

1
$ git config --global core.precomposeUnicode true

现在v8在github上面有源码镜像,你只需要git clone下来即可。

1
$ git clone [email protected]:v8/v8.git

获取依赖

depot_tools

首先git clone如下的仓库:

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

Note: 国内用户可以clonegithub上面的镜像代码:
git clone [email protected]:cybertk/depot_tools.git

然后将depot_tools加入你的PATH环境变量中(通常会加到.bashrc或者.zshrc中):

1
export PATH="$PATH:/path/to/depot_tools"

gclient

取得depot_tools之后,需要取得大量编译依赖,google提供了一个比较方便的工具gclient来获取依赖。

1
gclient sync

尴尬的一点在于,由于众所周知的原因,依赖下载十分缓慢。现在我给出一些解决方案:

方案A: 设置代码镜像
在获取到的v8代码中,第一级目录下有一个DEPS文件,通过修改其中的代码源实现加速:

1
$ vim DEPS

内容如下

1
2
3
4
5
6
7
8
vars = {
  'build_for_node': False,
  'checkout_instrumented_libraries': False,
  'chromium_url': 'https://chromium.googlesource.com',
  'download_gcmole': False,
  'download_jsfunfuzz': False,
  'download_mips_toolchain': False,
}

chromium_url的值修改为:https://source.codeaurora.org/quic/lc

Note: 请注意,这个chromium源码镜像并不全,没有python相关的库,但是大部分库都有,可以先把大部分代码下载下来,再使用代理把剩下的下载下来。

方案B: 设置代理

这是根治的方法,至于代理是如何设置本文不涉及。

1
2
export http_proxy=127.0.0.1:1080 
export https_proxy=127.0.0.1:1080

Note:请注意http_proxy一定要小写。

编译初始化

v8使用Ninja作为编译工具,同时使用GN来生成.ninja文件。

使用GN可以生成不同平台的编译配置文件:

1
gn gen out.gn/x64.release

当然你也可以在生成编译配置的时候传入一些参数:

1
gn gen out.gn/foo --args='is_debug=false target_cpu="x64" v8_target_cpu="arm64" use_goma=true'

使用如下参数加速编译:

  1. is_debug = false 编译成release版本
  2. is_component_build = true 编译成动态链接库而不是很大的可执行文件
  3. symbol_level = 0 将所有的debug符号放在一起,可以加速二次编译,并加速链接过程
  4. 可以使用ccache加速编译过程,安装ccache, 可以传入参数cc_wrapper="ccache",参考这里
  5. 使用jumbo

编译选项参考chromium编译方式

例如我的编译生成命令是:

1
gn gen out.gn/x64.release --args='is_debug=false is_component_build=true symbol_level=0 cc_wrapper="ccache" target_cpu="x64" '

或者你可以使用 gn args out/x64.yourdir 这样的方式配置编译选项文件,如果你想编译一个简单的静态库,你可以用如下参数:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
is_component_build = false
is_debug = false
libcpp_is_static = false
symbol_level = 1
treat_warnings_as_errors = false
use_custom_libcxx = false
use_sysroot = false
v8_deprecation_warnings = false
v8_embedder_string = "-v8_Your_Define_String"
v8_enable_gdbjit = false
v8_enable_i18n_support = false
v8_enable_test_features = false
v8_experimental_extra_library_files = []
v8_extra_library_files = []
v8_imminent_deprecation_warnings = false
v8_monolithic = true
v8_static_library = false
v8_target_cpu = "x64"
v8_untrusted_code_mitigations = false
v8_use_external_startup_data = false
v8_use_snapshot = true

请注意,官方wiki文档中使用的tools/dev/v8gen.py x64.release一直由于缺少什么文件导致无法运行,如果你也遇到本问题,请参考本文。

编译

编译完整的V8代码(假设是x64.relrease)

1
ninja -C out.gn/x64.release

如果想编译特定目标,比如d8

1
ninja -C out.gn/x64.release d8

生成开发项目

如果想使用xcode进行开发,你可以这样做:

1
gn gen out/gn --ide=xcode

然后用xcode打开即可

open out/gn/ninja/all.xcworkspace

有关 xcode 调试代码的说明

有朋友反馈上述编译得到的 xcode 项目调试时无法看到源码, 该朋友的解决方案是如下:

原因:

在 xcode 的设置里面, 断点的标记形式, 是以绝对路径的形式的, 而 v8/chrome 默认的配置 (配置文件: compiler.gni) 会删掉绝对路径的符号, 这样与 xcode 就无法找到对应符号, 所以看不到源码。

1
2
3
4
5
6
7
8
9
# If the platform uses stripped absolute paths by default, then we don't expose
# it as a configuration option. If this is causing problems, please file a bug.
if (strip_absolute_paths_from_debug_symbols_default) {
  strip_absolute_paths_from_debug_symbols = true
} else {
  declare_args() {
    strip_absolute_paths_from_debug_symbols = false
  }
}

参考这个链接: https://groups.google.com/a/chromium.org/g/chromium-dev/c/kE1HeGL4mj0/m/TOKsRsyTEwAJ.

gn 编译时添加参数:

1
gn gen out/Default --args="strip_absolute_paths_from_debug_symbols=false”

这样就可以让 xcode 调试的时候看到到项目的源代码了。