ninja gn_用gn和ninja编译的v8 JavaScript引擎

本文介绍了如何使用gn和ninja来编译V8 JavaScript引擎,详细阐述了编译过程,帮助开发者理解相关工具的使用。
摘要由CSDN通过智能技术生成

ninja gn

I’m a compiler enthusiast, who has been learning how the V8 JavaScript Engine works. Of course, the best way to learn something is to write about it, so that’s why I’m sharing my experiences here. I hope this might be interesting to others too.

我是一个编译器爱好者,一直在学习 V8 JavaScript Engine的 工作方式。 当然,最好的学习方法是写一些东西,所以这就是我在这里分享经验的原因。 我希望这对其他人也可能很有趣。

This first blog post is an overview of how V8 is compiled. As you can see from the V8 source code repository, the V8 Engine is mostly written in C++, requiring source code to be compiled into executable files. This should be no surprise, given that V8’s primary purpose is fast compilation and execution of JavaScript programs.

第一篇博客文章概述了如何编译V8。 从V8源代码存储库中可以看到,V8 Engine主要是用C ++编写的,要求将源代码编译成可执行文件。 鉴于V8的主要目的是快速编译和执行JavaScript程序,这不足为奇。

I’ll be discussing three main topics related to compiling the V8 executables:

我将讨论与编译V8可执行文件有关的三个主要主题:

  • The gm.py wrapper script, providing a convenient approach to compile V8 from source, and for invoking the test suites.

    gm.py包装器脚本,提供了一种从源代码编译V8以及调用测试套件的便捷方法。

  • The GN meta-build system (invoked by gm.py) taking an easy-to-read description of the software components, then auto-generating a machine-readable build description suitable for the Ninja build tool.

    GN元构建系统 (由gm.py调用)采用易于理解的软件组件描述,然后自动生成适合Ninja构建工具的机器可读构建描述。

  • Finally, the Ninja build tool uses that same machine-readable build description to analyze inter-file dependencies and invoke the relevant compilers.

    最后, Ninja构建工具使用相同的机器可读构建描述来分析文件间的依赖关系并调用相关的编译器。

The earlier diagram (at the top of this blog post) illustrates the overall flow of tool invocation, and shows which files are read, generated, and invoked.

前面的图(在本博客文章的顶部)说明了工具调用的总体流程,并显示了读取生成调用哪些文件。

Let’s examine each step in detail. If you’re new to this type of compilation process, I’ll put in a shameless plug for this book on Software Build Systems. It’s been almost ten years since I wrote that book, but the underlying concepts remain the same.

让我们详细检查每个步骤。 如果您是这种编译过程的新手,那么我将为这本关于Software Build Systems的书提供一个无耻的插件。 自从我写那本书至今已经快十年了,但基本概念却保持不变。

Image for post

gm.py脚本 (The gm.py Script)

The first time you compile V8, you should use the recommended gm.py script to fully compile all the object files, libraries, and executables.

首次编译V8时,应使用推荐的gm.py脚本完全编译所有目标文件,库和可执行文件。

$ ./tools/dev/gm.py x64.release.check

This is described in the V8 documentation as a convenience script because it’s a one-step solution for all the steps you need to get started. It takes about 20 minutes to run to completion (on my MacBook). Here’s what it’s doing:

V8文档中将其描述为方便脚本,因为它是您入门所需的所有步骤的一步解决方案。 完成操作大约需要20分钟(在我的MacBook上)。 它在做什么:

1.创建和配置构建输出目录 (1. Creating and Configuring the Build Output Directories)

Using the best practice that object and executable files should be stored separately from the source code, the gm.py script creates the v8/out/x64.release directory. In this example, we’ve asked for V8 to be compiled for the x64.release target (Intel x86 64-bit for release images), although if you also want to compile for different targets (such as x64.debug or arm64.debug), separate directories would be created for those.

使用最佳实践,即应将目标文件和可执行文件与源代码分开存储, gm.py脚本创建v8/out/x64.release目录。 在此示例中,尽管您还希望针对不同的目标(例如x64.debugarm64.debug进行编译,但我们仍要求为x64.release目标(英特尔x86 64位用于发行映像)编译arm64.debug ),则将为这些目录创建单独的目录。

This step also generates the args.gn file in the v8/out/x64.release directory, specifying the build options for this configuration (most notable are the is_debug and target_cpu options).

此步骤还将在v8/out/x64.release目录中生成args.gn文件,并指定此配置的构建选项(最著名的是is_debugtarget_cpu选项)。

is_component_build = false
is_debug = false
target_cpu = "x64"
use_goma = false
goma_dir = "None"
v8_enable_backtrace = true
v8_enable_disassembler = true
v8_enable_object_print = true
v8_enable_verify_heap = true

2.根据GN构建规范自动生成N inja文件 (2. Auto-Generating Ninja files from the GN Build Specification)

The next step in the build process is for gm.py to invoke the GN tool to translate the human-readable BUILD.gn file into lower-level files for the Ninja tool (with .ninja suffix).

生成过程的下一步是gm.py调用GN工具,将人类可读的BUILD.gn文件转换为Ninja工具(带有.ninja后缀)的较低级文件。

The BUILD.gn file contains easy-to-read directives specifying the content of each build target. In the following example, the d8 executable is constructed from a small number of C++ source files, linked together with additional libraries that contain the core JavaScript engine.

BUILD.gn文件包含易于阅读的指令,用于指定每个构建目标的内容。 在以下示例中, d8可执行文件由少量C ++源文件构造而成,并与包含核心JavaScript引擎的其他库链接在一起。

v8_executable("d8") {
sources = [
"src/d8/async-hooks-wrapper.cc",
"src/d8/async-hooks-wrapper.h",
"src/d8/d8-console.cc",
...
"src/d8/d8.cc",
"src/d8/d8.h",
] ... deps = [
":v8",
":v8_libbase",
":v8_libplatform",
...
]
}

Later in this blog post, there’ll be more detail about this file format. For now, let’s look at what happens when the gn gen command generates all the .ninja files from the hand-written BUILD.gn file.

在此博客文章的后面,将有关于此文件格式的更多详细信息。 现在,让我们来看看,当发生了什么gn gen命令生成的所有.ninja从手写文件BUILD.gn文件。

$ gn gen out/x64.release

This results in a collection of roughly 100 .ninja files in the out/x64.release directory. Each .ninja file corresponds to one of the build targets described in the BUILD.gn file.

这将导致out/x64.release目录中大约有100个.ninja文件的集合。 每个.ninja文件对应的描述构建目标之一BUILD.gn文件。

./toolchain.ninja
./build.ninja
./obj/d8.ninja
./obj/v8_libbase.ninja
./obj/v8_simple_wasm_compile_fuzzer.ninja
./obj/v8_libplatform.ninja
./obj/v8_simple_multi_return_fuzzer.ninja
...
./obj/test/unittests/cppgc_unittests_sources.ninja
./obj/test/unittests/unittests_sources.ninja
./obj/test/wasm-api-tests/wasm_api_tests.ninja
./obj/test/common_test_headers.ninja
./obj/test/cctest/generate-bytecode-expectations.ninja
./obj/test/cctest/cctest_sources.ninja
./obj/test/cctest/cctest_headers.ninja
./obj/test/cctest/cctest.ninja

As an example, here’s the content of the d8.ninja file. At first glance, this output is quite similar to an old-style Makefile — that is, not very readable!.

例如,这是d8.ninja文件的内容。 乍一看,此输出与旧式Makefile非常相似-即可读性不高!

defines = -D_LIBCPP_HAS_NO_ALIGNED_ALLOCATION -DCR_XCODE_VERSION=1160 -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -D_FORTIFY_SOURCE=2 -D_LIB
CPP_ABI_UNSTABLE -D_LIBCPP_DISABLE_VISIBILITY_ANNOTATIONS -D_LIBCXXABI_DISABLE_VISIBILITY_ANNOTATIONS -D_LIBCPP_ENABLE_NODISCARD -DCR_LIBCXX_REVISION=375504 ...include_dirs = -I../.. -Igen -I../.. -I../../include -Igen -I../../include -Igen/include -I../../third_party/icu/source/common -I../../third_party/icu/source/i18n -I../../include
cflags = -fno-strict-aliasing -fstack-protector -fcolor-diagnostics -fmerge-all-constants -fcrash-diagnostics-dir=../../tools/clang/crashreports -mllvm -instcombine-lower-dbg-declare=0 -fcomplete-member-pointers -arch x86_64 -Wno-builtin-macro-redefined ...build obj/d8/async-hooks-wrapper.o: cxx ../../src/d8/async-hooks-wrapper.cc || obj/d8.inputdeps.stamp
build obj/d8/d8-console.o: cxx ../../src/d8/d8-console.cc || obj/d8.inputdeps.stamp
build obj/d8/d8-js.o: cxx ../../src/d8/d8-js.cc || obj/d8.inputdeps.stamp
build obj/d8/d8-platforms.o: cxx ../../src/d8/d8-platforms.cc || obj/d8.inputdeps.stamp
build obj/d8/d8.o: cxx ../../src/d8/d8.cc || obj/d8.inputdeps.stamp
build obj/d8/d8-posix.o: cxx ../../src/d8/d8-posix.cc || obj/d8.inputdeps.stamp
...

Now that we have all the .ninja files, we can start to compile the source code.

现在我们有了所有的.ninja文件,我们可以开始编译源代码了。

3.使用Ninja Build Tool编译对象和可执行文件 (3. Using the Ninja Build Tool to Compile the Objects and Executables)

The next step in the build process is for gm.py to invoke the C++ compiler (amongst other tools). This is done by invoking the autoninja command, which itself is a wrapper for the ninja command.

构建过程的下一步是让gm.py调用C ++编译器(以及其他工具)。 这是通过调用autoninja命令完成的,该命令本身是ninja命令的包装器。

$ autoninja -C out/x64.release d8

This command reads the relevant .ninja files, determines which object files are missing (or out of date), then invokes the C++ compiler to create them. This process is familiar to anyone who has used the Make build tool (or similar).

该命令读取相关的.ninja文件,确定缺少(或已过期)的目标文件,然后调用C ++编译器来创建它们。 使用过Make构建工具(或类似工具)的任何人都熟悉此过程。

After roughly 20 minutes (on my MacBook), we end up with a fully populated build tree of roughly 2700 files, including auto-generated source files ( .cc and .h suffix), object files (.o suffix), library files (.a suffix), and a small number of executable files:

经过大约20分钟的时间(在我的MacBook上),我们得到了大约2700个文件的完全填充的构建树,其中包括自动生成的源文件( .cc.h后缀),目标文件( .o后缀),库文件( .a后缀)和少量可执行文件:

out/x64.release/obj
out/x64.release/obj/v8_libbase/time.o
out/x64.release/obj/v8_libbase/semaphore.o
out/x64.release/obj/v8_libbase/platform-macos.o
out/x64.release/obj/v8_libbase/condition-variable.o
out/x64.release/obj/v8_libbase/ieee754.o
out/x64.release/obj/v8_libbase/file-utils.o
...
out/x64.release/obj/v8_compiler/effect-control-linearizer.o
out/x64.release/obj/v8_compiler/js-native-context-specialization.o
out/x64.release/obj/v8_compiler/store-store-elimination.o
out/x64.release/obj/v8_compiler/code-assembler.o
...
out/x64.release/gen/torque-generated/src/wasm/wasm-objects-tq-csa.h
out/x64.release/gen/torque-generated/src/wasm/wasm-objects-tq-csa.cc
out/x64.release/gen/torque-generated/src/objects/map-tq-csa.h
out/x64.release/gen/torque-generated/src/objects/code-tq-csa.h
...
out/x64.release/obj/libv8_libplatform.a
out/x64.release/obj/libwee8.a
out/x64.release/obj/third_party/zlib/libchrome_zlib.a
out/x64.release/obj/third_party/icu/libicui18n.a
out/x64.release/obj/third_party/icu/libicuuc.a
out/x64.release/obj/libv8_libbase.a
...
out/x64.release/obj/d8/d8.o
out/x64.release/obj/d8/d8-posix.o
out/x64.release/obj/d8/d8-console.o
out/x64.release/obj/d8/async-hooks-wrapper.o
out/x64.release/obj/d8/d8-js.o
out/x64.release/obj/d8/d8-platforms.o
out/x64.release/d8
...

Everything is now compiled, so I can run the d8 program to execute some JavaScript code:

现在一切都已编译,因此我可以运行d8程序来执行一些JavaScript代码:

$ ./out/x64.release/d8 
V8 version 8.6.0 (candidate)
d8> console.log(2 + 2);
4
undefined
d8>

Looking at this example output, you might think that d8 is actually the same thing as NodeJS (and the node command), but it’s actually a simple wrapper around the core V8 libraries. It doesn’t add any of the additional functionality that NodeJS provides, but instead just supports the core JavaScript language. It’s this core library that’s linked into NodeJS, the Chrome browser, and any other software that needs to compile JavaScript.

查看此示例输出,您可能会认为d8实际上与NodeJS(和node命令)相同,但实际上是围绕V8核心库的简单包装。 它没有添加NodeJS提供的任何其他功能,而是仅支持核心JavaScript语言。 正是这个核心库链接到NodeJS,Chrome浏览器和任何其他需要编译JavaScript的软件。

4.执行单元测试 (4. Executing the Unit Tests)

The final step of the gm.py wrapper script is to execute the unit tests. This is done using the run-tests.py script.

gm.py包装器脚本的最后一步是执行单元测试。 这是使用run-tests.py脚本完成的。

$ ./tools/run-tests.py --outdir=out/x64.release \
debugger intl mjsunit cctest message unittests

I plan to talk about V8 testing in another blog post, so I won’t give more detail here. Let’s instead dig deeper into both the GN build tool, and the Ninja build tool.

我计划在另一篇博客文章中讨论V8测试,因此在此不再赘述。 相反,让我们更深入地研究GN构建工具和Ninja构建工具。

Image for post

GN元构建工具 (The GN Meta Build Tool)

The GN Build Tool is classified as a “meta build” tool in that it doesn’t actually invoke the C++ compiler directly, but instead converts a human-readable build description into a lower-level format suitable for the Ninja build tool. This concept was popularized by CMake, which (amongst other things) is capable of auto-generating a tree ofMakefile files, to be used by the Make tool

GN Build Tool被归类为“元构建”工具,因为它实际上并不直接调用C ++编译器,而是将人类可读的构建描述转换为适合Ninja构建工具的较低级格式。 这个概念由CMake普及, CMake能够自动生成Makefile文件树,供Make工具使用。

GN命令行选项 (GN Command Line Options)

We’ve already seen how GN is used (with the gn gen option) to generate all the .ninja files, but what else can it do? Here are some interesting examples:

我们已经了解了如何使用GN(带有gn gen选项)来生成所有.ninja文件,但是它还能做什么? 以下是一些有趣的示例:

First, we can list all the possible build targets for V8:

首先,我们可以列出V8的所有可能的构建目标:

$ gn ls out/x64.release//:bytecode_builtins_list_generator
//:cppgc
//:cppgc_base
//:cppgc_for_testing
//:cppgc_for_v8_embedders
//:cppgc_standalone
//:d8
//:fuzzer_support
//:gen-regexp-special-case
//:generate_bytecode_builtins_list
//:gn_all
//:json_fuzzer
//:lib_wasm_fuzzer_common
...

Next, we can show all the compilation flags, input files, and dependent libraries for one of these targets:

接下来,我们可以显示这些目标之一的所有编译标志,输入文件和依赖库:

$ gn desc out/x64.release //:d8type: executable
toolchain: //build/toolchain/mac:clang_x64...sources
//src/d8/async-hooks-wrapper.cc
//src/d8/async-hooks-wrapper.h
//src/d8/d8-console.cc
//src/d8/d8-console.h
//src/d8/d8-js.cc
//src/d8/d8-platforms.cc
//src/d8/d8-platforms.h
//src/d8/d8.cc
//src/d8/d8.h
//src/d8/d8-posix.cc
...cflags
-fno-strict-aliasing
-fstack-protector
-fcolor-diagnostics
-fmerge-all-constants
...defines
_LIBCPP_HAS_NO_ALIGNED_ALLOCATION
CR_XCODE_VERSION=1160
CR_CLANG_REVISION="llvmorg-12-init-1771-g1bd7046e-3"
__STDC_CONSTANT_MACROS
__STDC_FORMAT_MACROS
...Direct dependencies
//:v8
//:v8_dump_build_config
//:v8_libbase
//:v8_libplatform
//:v8_tracing
//build/config:executable_deps
//build/win:default_exe_manifest

Finally, the reverse operation is to show which targets will be built from a specific source file.

最后,相反的操作是显示将根据特定的源文件构建哪些目标。

$ gn refs out/x64.release //src/d8/d8-platforms.cc//:d8
//tools/gcmole:v8_run_gcmole

Note that none of these commands actually tell you which targets are currently out of date. As we’ll see later, that’s the responsibility of the Ninja tool.

请注意,这些命令实际上都不会告诉您当前哪些目标已过期。 稍后我们将看到,这是Ninja工具的职责。

了解“ d8”目标的BUILD.gn (Understanding BUILD.gn for the “d8” Target)

The commands shown above are very useful, but how does GN know about the targets and their dependencies? Let’s spend some time looking at the highlights of the v8/BUILD.gn file. If you want more information on the BUILD.gn syntax, an excellent introductory presentation is also available.

上面显示的命令非常有用,但是GN如何知道目标及其依赖关系? 让我们花一些时间查看v8/BUILD.gn文件的v8/BUILD.gn 。 如果您需要有关BUILD.gn语法的更多信息,还可以提供出色的介绍性介绍

We’ll be looking at how the d8 executable is constructed. This following is the code starting at line 4744 of my copy of BUILD.gn (it’s a long file!). I’ve added the “section” comments to make the code easier to refer to.

我们将研究d8可执行文件的构造方式。 以下是从BUILD.gn副本的第4744行开始的代码(这是一个长文件!)。 我添加了“ section”注释,以使代码更易于引用。

# Section 1 - The v8_executable Template
v8_executable("d8") { # Section 2 - Defining the Sources
sources = [
"src/d8/async-hooks-wrapper.cc",
"src/d8/async-hooks-wrapper.h",
"src/d8/d8-console.cc",
"src/d8/d8-console.h",
"src/d8/d8-js.cc",
"src/d8/d8-platforms.cc",
"src/d8/d8-platforms.h",
"src/d8/d8.cc",
"src/d8/d8.h",
] # Section 3 - Optional Sources
if (v8_fuzzilli) {
sources += [
"src/d8/cov.cc",
"src/d8/cov.h",
]
} # Section 4 - Compilation Configuration
configs = [
":internal_config_base",
":v8_tracing_config",
] # Section 5 - Additional Dependencies
deps = [
":v8",
":v8_libbase",
":v8_libplatform",
":v8_tracing",
"//build/win:default_exe_manifest",
] ...
}

Let’s learn some of the main concepts of GN by walking through this example.

通过遍历此示例,让我们学习GN的一些主要概念。

Section 1 — The v8_executable Template:

第1节 v8_executable 模板:

Out of the box, GN provides the executable command for describing how to construct an executable program. For V8, we actually use the v8_executable “template” (a GN concept) that wraps the basic executable command, providing some additional functionality for compiling V8 executables. This template is defined by including import("gni/v8.gni") at the top of the BUILD.gn file. The v8.gni file itself contains this snippet of code:

GN提供了开箱即用的executable命令,用于描述如何构造可执行程序。 对于V8,我们实际上使用了v8_executable “模板”(GN概念),该模板包装了基本的executable命令,并提供了一些用于编译V8可执行文件的附加功能。 通过在BUILD.gn文件顶部包含import("gni/v8.gni")定义此模板。 v8.gni文件本身包含以下代码片段:

...template("v8_executable") {
executable(target_name) {
...
}
...
}...

This file also contains similar templates for v8_static_library, v8_shared_library, and v8_source_set that build upon the corresponding GN standard commands. In addition, the main BUILD.gn file also contains some template definitions, making the build description more concise by abstracting away the complexity.

该文件还包含基于相应GN标准命令的v8_static_libraryv8_shared_libraryv8_source_set类似模板。 此外,主BUILD.gn文件还包含一些模板定义,从而通过简化复杂性来使构建描述更加简洁。

Section 2 — Defining the Sources:

第2节-定义来源:

To specify the C++ source files to be included in the d8 executable, we define a variable that contains a list of file paths. The GN tool supports a simple programming language, including the concept of variables and values, as well as lists of values.

为了指定d8可执行文件中包含的C ++源文件,我们定义了一个包含文件路径列表的变量。 GN工具支持一种简单的编程语言,包括变量和值的概念以及值列表。

  sources = [
"src/d8/async-hooks-wrapper.cc",
"src/d8/async-hooks-wrapper.h",
...
]

Note that unlike many build tools, we’re only required to list the file paths. We don’t need to construct file name pattern matching, or specify dependencies between files. The mechanism for doing that is hidden from you in the auto-generated .ninja files.

请注意,与许多构建工具不同,我们只需要列出文件路径。 我们不需要构造文件名模式匹配,也不需要指定文件之间的依赖关系。 自动生成的.ninja文件中隐藏的操作机制。

Section 3 — Optional Sources:

第3节-可选来源:

There are numerous build variants for V8, supporting a wide range of host platforms, target CPUs, optimization choices, JavaScript language-level selection, and additional feature libraries. To support all these variants, GN provides an if statement for us to test variables and conditionally modify the list of sources (using sources +=)

V8有许多构建变体,支持各种主机平台,目标CPU,优化选择,JavaScript语言级选择以及其他功能库。 为了支持所有这些变体,GN为我们提供了一个if语句来测试变量并有条件地修改源列表(使用sources += )

  if (v8_fuzzilli) {
sources += [
"src/d8/cov.cc",
"src/d8/cov.h",
]
}

In this particular example, we’re adding support for the Fuzzilli fuzzing tool which requires additional code-coverage functionality.

在此特定示例中,我们添加了对Fuzzilli模糊测试工具的支持,该工具需要其他代码覆盖功能。

Section 4 — Compilation Configuration:

第4节-编译配置:

To specify additional compilation flags for the d8 target, we make reference to a couple of “configs”:

为了为d8目标指定其他编译标志,我们参考几个“ configs”:

configs = [
":internal_config_base",
":v8_tracing_config",
]

Here’s the definition of internal_config_base that appears earlier in the BUILD.gn file.

这是在BUILD.gn文件中较早出现的internal_config_base的定义。

config("internal_config_base") {
visibility = [ ":*" ] configs = [ ":v8_tracing_config" ] include_dirs = [
".",
"include",
"$target_gen_dir",
]
}

A “config” is a way to package together include paths, C++ symbol definitions, compiler flags, and additional libraries. These configs can obviously become quite complex, especially with support for multiple host platforms. But luckily, build targets simply need to reference the config by name, rather than worrying about all of those details.

“配置”是一种将包含路径,C ++符号定义,编译器标志和其他库打包在一起的方法。 这些配置显然会变得非常复杂,尤其是在支持多个主机平台的情况下。 但是幸运的是,构建目标只需要按名称引用配置,而不用担心所有这些细节。

Section 5 — Additional Dependencies:

第5节-其他依赖关系:

Finally, to specify additional source files, or libraries to be linked into the d8 executable, we define the deps variable. Each entry in the list specifies a V8 build target, which itself provides a static/shared library, or a set of source files to include.

最后,要指定其他源文件或要链接到d8可执行文件的库,我们定义deps变量。 列表中的每个条目都指定一个V8构建目标,该目标本身提供了一个静态/共享库或要包含的一组源文件。

deps = [
":v8",
":v8_libbase",
":v8_libplatform",
":v8_tracing",
"//build/win:default_exe_manifest",
]

That’s it! A relatively simple way of specifying how to construct the d8 executable, without burdening the developer with the complexities of compilation flags, dependencies, and file pattern matching. There are plenty of other GN commands/directives that we haven’t discussed, but the GN documentation shows them all.

而已! 一种指定如何构造d8可执行文件的相对简单的方法,而不会给开发人员增加编译标志,依赖项和文件模式匹配的复杂性。 我们还没有讨论很多其他的GN命令/指令,但是GN文档显示了所有这些信息。

Image for post

忍者制作工具 (The Ninja Build Tool)

The last step in the V8 build process (with the exception of running tests) is to invoke the Ninja Build Tool to generate the object files, libraries, and executables. Given that users aren’t expected to look at the auto-generated .ninja files, there’s no need to look at further examples. However, it’s interesting to learn more about invoking Ninja, and the various command-line options available.

V8构建过程的最后一步(运行测试除外)是调用Ninja Build Tool来生成目标文件,库和可执行文件。 鉴于不希望用户查看自动生成的.ninja文件,因此无需查看其他示例。 但是,了解有关调用忍者的更多信息以及可用的各种命令行选项很有趣。

速度就是一切 (Speed is Everything)

One of the interesting selling points of Ninja is its raw speed. Given my extensive history of using build tools like Make, I was very curious about what makes Ninja so responsive. When dealing with hundreds (or thousands) of source files, a lot of build tools will “pause” for 20–30 seconds as they determine which files are out of date. With Ninja, incremental builds seem to start instantly.

忍者有趣的卖点之一是它的原始速度。 考虑到我使用Make等构建工具的悠久历史,我对Ninja为何具有如此高的响应能力感到非常好奇。 当处理数百(或数千)个源文件时,许多构建工具将“暂停” 20-30秒,因为它们确定哪些文件已过期。 使用Ninja,增量构建似乎可以立即开始。

Here are some interesting facts about Ninja:

以下是有关忍者的一些有趣的事实:

  • First, the build description files (with .ninja suffix) are very simplistic. There is no complicated language to be parsed, and no advanced features requiring time to execute. For this reason, the documentation describes the syntax as “machine code”. The .ninja files are also very compact, often with minimal white space. Keeping them small and simple makes them fast to read into memory, and to parse.

    首先,构建描述文件(带.ninja后缀)非常简单。 无需解析复杂的语言,也不需要高级功能才能执行。 因此,文档将语法描述为“机器代码”。 .ninja文件也非常紧凑,通常只有很少的空白。 保持它们的小巧简单可以使它们快速地读入内存并进行解析。

  • Second, implicit dependencies are stored in a single cache file, the .ninja_deps file (a 2MB binary file on my computer). In a Make-based environment, it’s common to have a unique .d file corresponding to each .cc file to store the list of C++ header files depended-on by the main .cc file. As a result, the build tool parses a very large number of files each time an incremental build is invoked. However, for Ninja, reading the one-and-only .ninja_deps file is extremely fast!

    其次,隐式依赖项存储在单个缓存文件中,即.ninja_deps文件(我计算机上的2MB二进制文件)。 在基于Make的环境中,通常有一个与每个.cc文件相对应的唯一.d文件,以存储主要.cc文件所依赖的C ++头文件的列表。 结果,每次调用增量构建时,构建工具都会解析大量文件。 但是,对于Ninja来说,读取一个唯一的.ninja_deps文件非常快!

In the case of V8, the ninja tool starts reading build.ninja, which then imports the toolchain.ninja file. It’s this second file that recursively imports all the other .ninja files in the out/x64.release directory (shown earlier). Despite having roughly 100 .ninja files, reading and processing them is very fast.

对于V8, ninja工具开始读取build.ninja ,然后将其导入toolchain.ninja文件。 这是第二个文件,它递归导入out/x64.release目录(如前所示)中的所有其他.ninja文件。 尽管有大约100个.ninja文件,但读取和处理它们非常快。

忍者命令行选项 (Ninja Command-Line Options)

To finish off, let’s show some of the commonly-used Ninja commands. To list all the available built targets, use the targets command:

最后,让我们展示一些常用的忍者命令。 要列出所有可用的已构建目标,请使用targets命令:

$ ninja -t targetsbuild.ninja: gn
obj/test/common_test_headers.inputdeps.stamp: stamp
obj/test/unittests/unittests.inputdeps.stamp: stamp
cppgc: phony
cppgc_base: phony
cppgc_for_testing: phony
fuzzer_support: phony
generate_bytecode_builtins_list: phony
...
:d8: phony
:fuzzer_support: phony
:gen-regexp-special-case: phony
:generate_bytecode_builtins_list: phony
:gn_all: phony

Naturally, these build targets are similar to what was shown in the BUILD.gn file, and reported by the gn ls command.

自然,这些构建目标类似于BUILD.gn文件中显示的BUILD.gn ,并由gn ls命令报告。

To compile a specific target, just mention it on the command line, optionally with the -v flag if you want to see the underlying C++ compiler invocations.

要编译特定目标,只需在命令行中提及它即可,如果要查看基础C ​​++编译器调用,可以选择使用-v标志。

$ ninja -v d8[1/1506] ../../third_party/llvm-build/Release+Asserts/bin/clang++ -MMD -MF ...
[2/1506] ../../third_party/llvm-build/Release+Asserts/bin/clang++ -MMD -MF ......[1506/1506] ...

To show all of the compilation commands required to build a target, without actually invoking the compiler, use the commands option:

要显示构建目标所需的所有编译命令,而无需实际调用编译器,请使用commands选项:

$ ninja -t commands d8...

Finally, to show where a particular file is used (that is, which libraries or executables depend on it), use the query command:

最后,要显示使用特定文件的位置(即哪个库或可执行文件依赖于该文件),请使用query命令:

$ ninja -t query ./obj/v8_libbase/mutex.oobj/v8_libbase/mutex.o:
input: cxx
../../src/base/platform/mutex.cc
outputs:
obj/libv8_libbase.a
obj/libwee8.a

These are the basics, but for more advanced options, see the Ninja documentation for further detail.

这些是基础知识,但是有关更多高级选项,请参阅Ninja文档以获取更多详细信息。

Image for post

摘要 (Summary)

The V8 JavaScript engine has an excellent build system, comprised of a top-level convenience script (gm.py), which invokes the GN meta-build tool to generate lower-level build description files to be executed by the Ninja build tool. This combination of tools allows developers to work with the human-readable BUILD.gn file format, while allowing for a fast execution of the build steps, especially for incremental build.

V8 JavaScript引擎具有出色的构建系统,该构建系统由顶级便捷脚本( gm.py )组成,该脚本调用GN元构建工具来生成要由Ninja构建工具执行的较低级构建描述文件。 这种工具组合使开发人员可以使用人类可读的BUILD.gn文件格式,同时允许快速执行构建步骤,尤其是增量构建。

翻译自: https://medium.com/compilers/v8-javascript-engine-compiling-with-gn-and-ninja-8673e7c5e14a

ninja gn

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值