V8 Engine · Lesson 3 · Embedding Track

Build V8 from Source

Why this lesson: Your mission says "build V8 from source (depot_tools + GN + ninja) and run d8 and the hello-world embedder." This is that milestone. By the end you'll own a compiled V8 and a working d8 shell — the foundation for every embedding lesson that follows.

Until now you've borrowed V8 from Node. To embed V8 you need the engine as a library you compile and link against. That means checking out the real source and building it with Google's toolchain. Heads-up before you start:

This is a slog — that's expected. The checkout pulls a large dependency tree and the first compile takes a while. Rough estimate (not an official figure): on the order of ~10–15 GB of disk and tens of minutes for the first build on Apple Silicon; incremental builds afterward are fast. Make sure you have the disk and the time before you begin. The official docs don't publish a size/time number — treat this as an estimate.

Step 0 · Prerequisites (macOS)

You already have these from our setup check — verify them:

xcode-select --install        # Xcode Command Line Tools (you have Xcode)
sudo xcodebuild -license accept
git --version  &&  python3 --version

Per v8.dev/docs/build: install Xcode and accept its license. Do not run the Linux-only install-build-deps.sh on macOS.

1Install depot_tools and put it on your PATH

depot_tools is Google's wrapper around git/gn/ninja. It even vendors its own Python, so there's nothing else to install.

cd ~
git clone https://chromium.googlesource.com/chromium/tools/depot_tools.git
echo 'export PATH="$HOME/depot_tools:$PATH"' >> ~/.zshrc
source ~/.zshrc

Source: v8.dev/docs/source-code → depot_tools tutorial.

2Fetch the V8 source

fetch v8 is the one-time checkout — it configures gclient and pulls V8 plus all its dependencies. (Later, gclient sync re-syncs deps after you git pull.)

mkdir ~/v8
cd ~/v8
fetch v8        # one-time; this is the long download
cd v8

Source: v8.dev/docs/source-code (verbatim).

3Build d8 the easy way: gm

tools/dev/gm.py ("gm") is V8's all-in-one helper: it generates build files, builds, and can run tests. On Apple Silicon, the native target is arm64.release (the docs' examples say x64 because they're written for Intel).

alias gm=~/v8/v8/tools/dev/gm.py
gm arm64.release          # builds default targets incl. d8 → out/arm64.release/

When it finishes, your shell is here:

out/arm64.release/d8 --version
echo "1 + 1" | out/arm64.release/d8        # prints 2
out/arm64.release/d8                              # interactive REPL — Ctrl-D to exit

Source: v8.dev/docs/build-gn. The gm default targets include d8; to build only it, use the manual path below.

The manual GN + ninja path (good to understand). gm wraps these two steps:
gn gen out/arm64.release --args='is_debug=false target_cpu="arm64"'
ninja -C out/arm64.release d8
GN generates the build config from your args; ninja does the actual compiling. On native Apple Silicon use target_cpu="arm64" — not v8_target_cpu, which the docs use only for the cross-compiling simulator.

4Build the monolith library (for embedding)

To link V8 into your own C++ program (next lesson), you need it as one static library — the "monolith". A predefined config sets the right GN args for you:

tools/dev/v8gen.py arm64.release.sample
ninja -C out.gn/arm64.release.sample v8_monolith

The .sample config expands to exactly these four args (you could spell them out with gn gen instead — equivalent):

v8_monolithic=true  is_component_build=false
v8_use_external_startup_data=false  use_custom_libcxx=false

This produces out.gn/arm64.release.sample/obj/libv8_monolith.a — the library you'll link in Lesson 4.

Source: v8.dev/docs/embed; the four-arg expansion confirmed in V8's infra/mb/mb_config.pyl.

Two traps that waste hours. (1) Don't git clone https://github.com/v8/v8 and try to build it — that mirror has no dependencies. You must use fetch v8 via depot_tools. (2) Keep your -L library path consistent with how you generated: v8gen.py writes to out.gn/…, a bare gn gen writes to wherever you point it (out/…). Mixing them up = "library not found".

What you just built

ArtifactWhat it is
depot_toolsGoogle's build toolchain wrapper (git helpers, gn, ninja, vendored Python).
fetch v8The checkout command — pulls V8 + all deps. One-time; gclient sync updates later.
GNMeta-build system: turns build args into ninja files. (gn gen.)
ninjaThe fast build executor that actually compiles. (ninja -C out/… target.)
d8V8's developer shell — a minimal embedder. Runs JS files, has a REPL, exposes all the flags from Lessons 1–2 & 7–8.
libv8_monolith.aV8 as a single static library, ready to link into your own C++ host (Lesson 4).
Bonus: re-run your earlier experiments on d8. Everything you did in Node now works on your own engine: out/arm64.release/d8 --print-bytecode --print-bytecode-filter=add /tmp/v8demo.js. Same flags, but now it's your build. See the flags cheat sheet.

Check yourself feedback loop

1. Why can't you just git clone github.com/v8/v8 and build it?
2. What's the division of labor between GN and ninja?
3. On a native Apple Silicon build, which GN arg selects the architecture?
Ask me anything — especially here. Builds break in colorful ways. If fetch v8 stalls, gm errors, or a flag isn't recognized, paste the output to me and I'll help debug. Also good: "Walk me through what gclient actually did," or "How do I update my checkout later?" If you'd rather not spend the disk/time right now, tell me and we can keep using Node's V8 for the embedding lessons' concepts and you can build later.

Where this lands you

You have a compiled V8, a working d8, and libv8_monolith.a ready to link. Next: Lesson 4 — the Hello-World Embedder. You'll compile a ~60-line C++ program that creates its own V8 engine instance, runs a script, and prints the result — your first time driving V8 from the outside.

Reference: V8 Glossary · Inspection Flags (now work on d8)

V8 Engine learning track · Lesson 3 · Embedding track begins. Commands quoted from the official v8.dev docs.