Building Chromium & V8 with Visual Studio 2026: December 2025

I don’t have to build Chrome (or v8) regularly. But I’ve had a recent occasion to look in the source code to explain an odd behaviour that I was seeing. In doing so, I revisited the steps for how to build Chrome on Windows. The steps evolve over time. This time around I decided that I would use Visual Studio 2026 to perform the build. I’ve now got a script that requires less interaction, which is great given how long a compilation takes. Don’t be surprised if it takes 10-20 hours for the code to compile depending on various factors (such as drive speed, internet bandwidth, processor speed, and other performance characteristics).

I have a build script for Windows and Visual Studio 2026. Unlike a previous version of this script from a post earlier this year, you don’t have to come along to click on an OK mutton to keep the process moving. It should run from beginning to end. This script assume that you already have Visual Studio 2026 and git installed. I’ve got two entry points for the process. One version of a script will run the Visual Studio installer to add the components that are needed (in case you haven’t added them) before starting the build process. Then it runs the steps to check out and start building. The other script only runs the steps necessary to checkout and start building, assuming that you already have the necessary Visual Studio components installed.

If you look in the scripts, you will see that the call command is used a lot. This is because many of the commands for google’s build tools are themselves bath files. If a batch file is invoked without the call command, when it gets done, control does not return to the batch file that was invoking it. If it is invoked with the call command, then control return to the line after the one that invoked it.

The script that installs the Visual Studio components invokes the vs_installer.exe with several arguments to install the various component. I call it with the start /wait command so that the batch file will pause. I’m using the Community edition of Visual Studio. If you are using a different edition, you’ll need to replace instances of the word “Community” with whatever is appropriate for your edition (“Enterprise” or “Professional”). The --passive argument tells the installer to run in passive mode. In this mode it will perform its tasks without requesting any input from the user. The argument --quiet could also work here. But --passive lets you see that the script is doing something.

 
pushd C:\Program Files (x86)\Microsoft Visual Studio\Installer\
start /wait vs_installer.exe install --passive --productid Microsoft.VisualStudio.Product.Community --ChannelId VisualStudio.18.Release --add Microsoft.VisualStudio.Workload.NativeDesktop  --add Microsoft.VisualStudio.Component.VC.ATLMFC  --add Microsoft.VisualStudio.Component.VC.Tools.ARM64 --add Microsoft.VisualStudio.Component.VC.MFC.ARM64  --add Microsoft.VisualStudio.Component.VC.Llvm.Clang --add Microsoft.VisualStudio.Component.VC.Llvm.ClangToolset --add Microsoft.VisualStudio.ComponentGroup.NativeDesktop.Llvm.Clang  --includeRecommended
popd
call checkout-chromium-and-build.cmd

Once the VS components are there, we are ready to start building. The Chromium build steps rely on git and some other tools/scripts from google. Those tools haven’t been installed yet. But that doesn’t prevent environment variables from being created for where these tools will be. Since I only need to have these environment variables set for compilation of Chrome and v8, I find it easier to keep them in the batch file rather than set them on the system. In the following, I setup these environment variables to compile on the C: drive. On that drive, I’m putting the tools and the compiled code in child folders of \shares\projects\google. From there, Google’s tools will be in a subfolder called depot_tools and the Chromium and V8 code will be in a subfolder named chromium. The top of the second script sets up all of these environment variables.

ECHO ON
timeout /t 2100 /nobreak 
SET drive=c:
set googlePath=%drive%\shares\projects\google\
SET VS_EDITION=Community
SET NINJA_SUMMARIZE_BUILD=1
set PATH=%googlePath%depot_tools;%PATH%
SET DEPOT_TOOLS_WIN_TOOLCHAIN=0
SET vs2022_install=%drive%\Program Files\Microsoft Visual Studio\18\%VS_EDITION%

SET PARALLEL_JOBS=8
IF(%PARALLEL_JOBS% EQU 0) (
    SET JOBS_PARAMETER=-j%PARALLEL_JOBS%    
) else (
    SET JOBS_PARAMETER=
)

Checking out Chromium/V8

Installing Google’s build tools (depot_tools) and the Chromium source occur in the following script. These steps will create the folders that contain both. The call to gclient initializes Google’s build tools after they are present on the drive. Once those are installed we can used the fetch command to retrieve the code for the repository of interest. We what the chromium source. We use fetch chromium to retrieve it. It will deposit the source code in the current folder. Before calling this command, we make a chromium folder to hold the source and call fetch from within it. Usually, after this command completes, the source code should be present in the folder. However, a few times during my tests encountered Google’s server failing to deliver the code. If this happens, then your source code folder ends up in a state in which only part of the code is checked out. If this happens, running gclient to perform a forced sync can resolve the problem. I’ve included a call to this time-consuming command in my script. Its presence is likely to just consume time without any real effect. But it will save some of you headaches. It’s up to you whether it gets removed. Once again, I decided to give weight to reliability over performance. After the source code is acquired, we can move into the src folder to configure and build.

%drive%
mkdir %googlePath%
cd %googlePath%
git clone https://chromium.googlesource.com/chromium/tools/depot_tools.git
pushd %googlePath%depot_tools

call gclient

popd
mkdir chromium && cd chromium
call fetch chromium
gclient sync -D --force --reset

Configuring and Compiling

I make several calls to configure and compile targets for the chromium code. The targets we care about are chromium and v8 for both release and debug modes. We use the gn command to generate build configurations. The command accepts as arguments the output folder and a string that has other project-specific build parameters. I call the command 5 times for 5 configurations.

gn gen out\Default 
gn gen out\v8Release --args="is_component_build=false is_debug=false symbol_level=1 v8_enable_object_print=true v8_enable_disassembler=true target_cpu=\"x64\" v8_static_library = true v8_use_external_startup_data=false v8_monolithic=true"
gn gen out\v8Debug --args="is_component_build=false is_debug=true  symbol_level=1 v8_enable_object_print=true v8_enable_disassembler=true target_cpu=\"x64\" v8_static_library = true v8_use_external_startup_data=false v8_monolithic=true"
gn gen out\ChromeDebug --args="is_debug=true"
gn gen out\ChromeRelease --args="is_debug=false symbol_level=1"

After configuration, I kick off the builds. Here, the JOBS_PARAMETER variable is used to limit the number of threads that spin-up for compilation. If you set the PARALLEL_JOBS variable to 0 earlier then the JOBS_PARAMETER variable will be blank. This will let the build system decide how many threads to use itself.

Adjustments for Memory Limitations

When I was first working on this script, I was switching between my primary desktop and primary laptop. The desktop has 160 gigs of RAM, the the laptop 72 gigs of RAM. After I had the script working, I wanted to try it on a variety of hardware. I started running it on other computers to confirm my expectation, which was that this script would obviously work on all these other systems. That thinking was incorrect. On one system it would reliably fail. On another system it would sometimes fail. When I traced through the error output, I came across a clear statement on the nature of the failure.

build step: cxx "./obj/v8/torque_generated_definitions/js-iterator-helpers-tq.obj"
stderr:
LLVM ERROR: out of memory
Allocation failed
PLEASE submit a bug report to https://crbug.com in the Tools>LLVM component, run tools/clang/scripts/process_crashreports.py (only if inside Google) to upload crash related files, and include the crash backtrace, preprocessed source, and associated run script.

The computer had run out of memory during the compilation. The compilation process runs many jobs (or threads) to perform the various steps of compilation in parallel. If you get jobs running, the system can exhaust its memory and memory allocations will fail. That’s what was happening on the other systems. The system with 16 gigs would sometimes fail. But if I restarted the build then it would usually be successful. The system with 8 gigs would always fail. To adjust for this, I can manually cap the number of threads allowed. Once I did this, I could get reliably get the script to compile successfully. In normal times I might use this as an opportunity to encourage others to upgrade their memory. When it comes to storage and RAM, my philosophy is “You don’t have enough until you have more than enough.” But in the last month or two several memory manufacturers have announced they will be emphasizing more profitable markets and withdrawing from consumer sales. Chances are that most of the people reading this don’t have the resources of a data center available and upgrading their memory just isn’t an option (unless they want to pay 200+% for memory). Accommodating for this, I’m setting a cap of 32 jobs for the compilation process. I think that will make the script successful for most. If you want to allow the compilation process to attempt to maximize the number of threads you can set the PARALLEL_JOBS variable in the script to 0. Yes, this will result in the compilation process being slower than maximum on well capable systems unless someone modifies the script. But I wanted this script to be more generally usable. Reliably was given more importance than performance.

Start, Sleep, Finish

The compilation process can take a long time. For v8, depending on your system, it can take an hour or more. For Chromium it can take much longer. This isn’t the type of compilation that that you could start, go get coffee, and expect it to be done when you get back. Rather, you could start it, go to bed, and wake up the next day having gotten plenty of rest only to find that the compilation process isn’t finished. The good news is that your first compilation will take this long, but subsequent ones could be faster, benefiting from the efforts of previous compilations. You’ll want to make sure that your computer doesn’t go to sleep during compilation. I’ve had this happen, even when I set the power policy for the computer to never go to sleep. I’m tempted to resurface a mouse-jiggler to keep the machine awake. Those devices tend to effective even when the computer is locked.

Given the massive amount of time this process can take, it is better if there is a specific machine designated to perform build tasks for Chromium and V8. You could do other work on a machine while compilation occurs. But you might find that your tasks compete with the build process.

How Long Did This Take?

Build times can have wide variance between systems of different performance characteristics. If you want to see how long the various steps of the build process took, the batch file is appending to a file named build_log.txt in the Google folder. You can view this file while the build is in process. But you will need to make sure you don’t lock the file. Some text editors lock a file when it is being viewed. The safest way to view the file is to open a command prompt and dump the contents of the file to the console (using the type command in the command prompt or the Get-Content command in PowerShell). You can review the output from it to see how any of the phases of the build process works.

What about Building V8 Only?

Previously I’ve shown how to check out the v8 code only to build it. I think I’m going to abandon that in favor of this approach, which can be used to build other project. The difference comes down to selecting a build target.


Posts may contain products with affiliate links. When you make purchases using these links, we receive a small commission at no extra cost to you. Thank you for your support.

Mastodon: @j2inet@masto.ai
Instagram: @j2inet
Facebook: @j2inet
YouTube: @j2inet
Telegram: j2inet
Bluesky: @j2i.net

Recompiling the V8 JavaScript Engine on Windows

Note Added 2025 March 10 – These instructions no longer work. Google has dropped support for using MSVC. It is still possible to build on Windows using Clang. But this presents new challenges, such as linking CLang binaries to MSVC binaries. More information on this change can be found in a Google Group discussion here.

Note Added 2024 September 3 – I tried to follow my own instructions on a whim today and found that some parts of the instructions don’t work. I made my way through them with adjustments to get to success.

I decided to compile the Google V8 JavaScript engine. Why? So that I could include it in another program. Google doesn’t distribute the binaries for V8, but they do make the source code available. Compiling it is, in my opinion, a bit complex. This isn’t a criticism. There are a lot of options for how V8 can be built. Rather than making available the permutations of these options for each version of V8, one could just set options themselves and build it for their platform of interest.

But Isn’t There Already Documentation on How to Do This?

There does exists documentation from Google on compiling Chrome. But there are variations from those instructions and what must actually be done. I found myself searching the Internet for a number of other issues that I encountered and made notes on what I had to do to get around compilation problems. The documentation comes close to what’s needed, but isn’t without error and deviation.

Setting Up Your Environment

Before touching the v8 source code, ensure that you have installed Microsoft Visual Studio. I am using Microsoft Visual Studio 2022 Community Edition. There are some additional components that must be installed. In an attempt to make this setup process as scriptable as possible, I’ve have a batch file that will have the Visual Studio Installer add the necessary components. If a component is already installed, no action is taken. Though the Google V8 instructions also offer a command to type to accomplish the same thing, this is where I encountered my first variation from their instructions. Their instructions assume that the name of the Visual Studio Installer command to be setup.exe (it probably was on a previous version of Visual Studio) where my installer is named vs_installer.exe. There were also additional parameters that I had to pass, possibly because I have more than one version of Visual Studio installed (Community Edition 2022, Preview Community Edition 2022, and a 2019 version).

pushd C:\Program Files (x86)\Microsoft Visual Studio\Installer\

vs_installer.exe install --productid Microsoft.VisualStudio.Product.Community --ChannelId VisualStudio.17.Release --add Microsoft.VisualStudio.Workload.NativeDesktop  --add Microsoft.VisualStudio.Component.VC.ATLMFC  --add Microsoft.VisualStudio.Component.VC.Tools.ARM64 --add Microsoft.VisualStudio.Component.VC.MFC.ARM64 --add Microsoft.VisualStudio.Component.Windows10SDK.20348 --includeRecommended

popd

You may need to make adjustments if your installer is located in a different path.

While those components are installing, let’s get the code downloaded and put int place. I did the download and unpacking from powershell. All of the commands that follow were stored in a power shell script. Scripting the process makes it more repeatable and is easier to document (since the scripts are also a record of what was done). You do not have to use the same file paths that I do. But if you change them, you will need to make adjustments to the instructions when one of these paths is used.

I generally avoid placing folders directly in the root. The one exception to that being a folder I make called c:\shares. There’s a structure that I conform to when placing this folder on Windows machines. For this structure, Google’s code will be placed in subdirectories of c:\shares\projects\google. In the following script you’ll see that path used.

$depot_tools_source = "https://storage.googleapis.com/chrome-infra/depot_tools.zip"
$depot_tools_download_folder= "C:\shares\projects\google\temp\"
$depot_tools_download_path = $depot_tools_download_folder + "depot_tools.zip"
$depot_tools_path = "c:\shares\projects\google\depot_tools\"
$chromium_checkout_path = "c:\shares\projects\google\chromium"
$v8_checkout_path = "c:\shares\projects\google\"

mkdir $depot_tools_download_folder
mkdir $depot_tools_path
mkdir $chromium_checkout_path
mkdir $v8_checkout_path

pushd "C:\Program Files (x86)\Microsoft Visual Studio\Installer\"
.\vs_installer.exe install --productID Microsoft.VisualStudio.Product.Community --ChannelId VisualStudio.17.Release --add Microsoft.VisualStudio.Workload.NativeDesktop  --add Microsoft.VisualStudio.Component.VC.ATLMFC  --add Microsoft.VisualStudio.Component.VC.Tools.ARM64 --add Microsoft.VisualStudio.Component.VC.MFC.ARM64 --add Microsoft.VisualStudio.Component.Windows10SDK.20348 --includeRecommended
popd

Invoke-WebRequest -Uri $depot_tools_source -OutFile $depot_tools_download_path
Expand-Archive -LiteralPath $depot_tools_download_path -DestinationPath $depot_tools_path

After this script completes running, Visual Studio should have the necessary components and the V8/Chrome development tools are downloaded and in place.

There are some environment variables on which the build process is dependent. These variables could be set within batch files, could be set to be part of the environment for an instance of the command terminal, or set at the system level. I chose to set them at the system level. This was not my first approach. I set them at more local levels initially. But several times when I needed to open a new command terminal, I forgot to apply them, and just found it easier to set them globally.

ENVIRONMENT VARIABLEVALUE
DEPOT_TOOLS_WIN_TOOLCHAIN0
vs2022_installC:\Program Files\Microsoft Visual Studio\2022\Community
PATHc:\shares\projects\google\depot_tools\;%PATH%
Environment Variables that must be set

From here on, we will be using the command prompt, and not PowerShell. This is because some of the commands that are part of Google’s tools are batch files that only run properly in the command prompt.

From the command terminal, run the command gclient. This will initialize the Google Tools. Next, navigate to the folder in which you want the v8 code to download. For me, this will be c:\shares\projects\google. The download process will automatically make a subfolder named v8. Run the following command.

fetch --nohistory v8

This command can take a while to complete. After it completes you will have a new directory named v8 that contains the source code. Navigate to that directory.

cd v8

The online documentation that I see from Google for v8 is for version 9. I wanted to compiled version 12.0.174.

git checkout 12.0.174

Update 2025 March 7

Reviewing the instructions now, I find that the above command fails. It may be necessary to fetch the labels for the versions with the following commands to get version 13.6.9.

git fetch --tags
git checkout 13.6.9

Today I am trying to only rebuild v8 for Windows. Eventually I’ll rebuild it for ARM64 also. Run the following commands. It will make the build directories and configurations for different targets.

python3 .\tools\dev\v8gen.py x64.release
python3 .\tools\dev\v8gen.py x64.debug
python3 .\tools\dev\v8gen.py arm64.release
python3 .\tools\dev\v8gen.py arm64.debug

The build arguments for each environment are in a file named args.gn. Let’s update the configuration for the x64 debug build. To open the build configuration, type the following.

notepad out.gn\x64.debug\args.gn

This will open the configuration in notepad. Replace the contents with the following.

is_debug = true
target_cpu = "x64"
v8_enable_backtrace = true
v8_enable_slow_dchecks = true
v8_optimized_debug = false
v8_monolithic = true
v8_use_external_startup_data = false
is_component_build = false
is_clang = false

Chances are the only difference between the above and the initial version of the file are from the line v8_monolithic onwards. Save the file. You are ready to start your build. To kick off the build, use the following command.

ninja -C out.gn\x64.debug v8_monolith

Update 2024 September 3 – Compiling this now, I’m encountering a different error. It appears the compilier I’m using takes issues with some of the nested #if directives in the source code. There was in in src/execution/frames.h around line 1274 that was problematic. It involved a line concerning enabling V8 Drumbrake. Nope, I don’t know what that is. This was for a call to DCHECK, which is not used in production builds. I just removed it. I encountered similar errors in src/diagnostics/objects-debug.cc, src\wasm\wasm-objects.cc,

This will also take a while to run, but this will fail. There is a third party component that will fail concerning a line in a file named fmtable.cpp. You’ll have to alter a function to fix the problem. Open the file in the path .\v8\third_party\icu\source\i18n\fmtable.cpp. Around line 59, you will find the following code.

static inline UBool objectEquals(const UObject* a, const UObject* b) {
     // LATER: return *a == *b
     return *((const Measure*)a) == ((const Measure*)b);
}

You’ll need to change it so that it contains the following.

static inline UBool objectEquals(const UObject* a, const UObject* b) {
     // LATER: return *a == *b
     return *((const Measure*)a) == *b;
}

Save the file, and run the build command again. While that’s running, go find something else to do. Have a meal, fly a kite, read a book. You’ve got time. When you return, the build should have been successful.

Hello World

Now, let’s make a hellow world program. Google already has a v8 hellow would example that we can use to see that our build was successful. We will use it for now, as I’ve not discussed anything about the v8 object library yet. Open Microsoft Visual Studio and create a new C++ Console application. Replace te code in the cpp file that it provides with Google’s code.

// Copyright 2015 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include "libplatform/libplatform.h"
#include "v8-context.h"
#include "v8-initialization.h"
#include "v8-isolate.h"
#include "v8-local-handle.h"
#include "v8-primitive.h"
#include "v8-script.h"

int main(int argc, char* argv[]) {
    // Initialize V8.
    v8::V8::InitializeICUDefaultLocation(argv[0]);
    v8::V8::InitializeExternalStartupData(argv[0]);
    std::unique_ptr<v8::Platform> platform = v8::platform::NewDefaultPlatform();
    v8::V8::InitializePlatform(platform.get());
    v8::V8::Initialize();

    // Create a new Isolate and make it the current one.
    v8::Isolate::CreateParams create_params;
    create_params.array_buffer_allocator =
        v8::ArrayBuffer::Allocator::NewDefaultAllocator();
    v8::Isolate* isolate = v8::Isolate::New(create_params);
    {
        v8::Isolate::Scope isolate_scope(isolate);

        // Create a stack-allocated handle scope.
        v8::HandleScope handle_scope(isolate);

        // Create a new context.
        v8::Local<v8::Context> context = v8::Context::New(isolate);

        // Enter the context for compiling and running the hello world script.
        v8::Context::Scope context_scope(context);

        {
            // Create a string containing the JavaScript source code.
            v8::Local<v8::String> source =
                v8::String::NewFromUtf8Literal(isolate, "'Hello' + ', World!'");

            // Compile the source code.
            v8::Local<v8::Script> script =
                v8::Script::Compile(context, source).ToLocalChecked();

            // Run the script to get the result.
            v8::Local<v8::Value> result = script->Run(context).ToLocalChecked();

            // Convert the result to an UTF8 string and print it.
            v8::String::Utf8Value utf8(isolate, result);
            printf("%s\n", *utf8);
        }

        {
            // Use the JavaScript API to generate a WebAssembly module.
            //
            // |bytes| contains the binary format for the following module:
            //
            //     (func (export "add") (param i32 i32) (result i32)
            //       get_local 0
            //       get_local 1
            //       i32.add)
            //
            const char csource[] = R"(
        let bytes = new Uint8Array([
          0x00, 0x61, 0x73, 0x6d, 0x01, 0x00, 0x00, 0x00, 0x01, 0x07, 0x01,
          0x60, 0x02, 0x7f, 0x7f, 0x01, 0x7f, 0x03, 0x02, 0x01, 0x00, 0x07,
          0x07, 0x01, 0x03, 0x61, 0x64, 0x64, 0x00, 0x00, 0x0a, 0x09, 0x01,
          0x07, 0x00, 0x20, 0x00, 0x20, 0x01, 0x6a, 0x0b
        ]);
        let module = new WebAssembly.Module(bytes);
        let instance = new WebAssembly.Instance(module);
        instance.exports.add(3, 4);
      )";

            // Create a string containing the JavaScript source code.
            v8::Local<v8::String> source =
                v8::String::NewFromUtf8Literal(isolate, csource);

            // Compile the source code.
            v8::Local<v8::Script> script =
                v8::Script::Compile(context, source).ToLocalChecked();

            // Run the script to get the result.
            v8::Local<v8::Value> result = script->Run(context).ToLocalChecked();

            // Convert the result to a uint32 and print it.
            uint32_t number = result->Uint32Value(context).ToChecked();
            printf("3 + 4 = %u\n", number);
        }
    }

    // Dispose the isolate and tear down V8.
    isolate->Dispose();
    v8::V8::Dispose();
    v8::V8::DisposePlatform();
    delete create_params.array_buffer_allocator;
    return 0;
}

If you try to build this now, it will fail. You need to do some configuration. Here is a quick list of the configuration changes. If you don’t understand what to do with these, that’s find. I’ll will walk you through applying them.

VC++ Directories : 
	Include : v8\include
	Library Directories<Debug>: v8\out.gn\x64.debug\obj
	Library Directories<Release>: v8\out.gn\x64.release\obj

C/C++
	Code Generation
		Runtime Library <Debug>: /MTd
		Runtime Library <Release> /Mt
	Preprocessors
		V8_ENABLE_SANDBOX;V8_COMPRESS_POINTERS;_ITERATOR_DEBUG_LEVEL=0;
		
Linker
	Input
		Additional Dependencies: v8_monolith.lib;dbghelp.lib;Winmm.lib;

Right-click on the project file and select “Properties.” From the pane on the left, select VC++ Directories. In the drop-down on the top, select All Configurations. On the right there is a field named Include. Select it, and add the full path to your v8\include directory. For me, this will be c:\shares\projects\google\v8\include. If you build in a different path, it will be different for you. After adding the value, select Apply. You will generally want to press Apply after each field that you’ve changed.

Change the Configuration drop-down at the top to Debug. In the Library Directories entry, add the full path to your v8\out.gn\x64.debug\obj folder and click Apple. Change the Configuration dropdown to Release and in Library Directories add the full path to your v8\out\gn\x64.release\obj folder.

From the pane on the left, expand C/C++ and select Code Generation. On the right, set the Debug value for Runtime Library to /MTd and set the Release value for the field to /Mt.

Change the Configurations option to All and set add the following values to Preprocessors

V8_ENABLE_SANDBOX;V8_COMPRESS_POINTERS;_ITERATOR_DEBUG_LEVEL=0;

Keep the Configurations option on ALL. Expand Linker and select Input. For Additional Dependencies enter v8_monolith.lib;dbghelp.lib;Winmm.lib;

With that entered, press Okay. You should now be able to run the program. It will pass some values to the JavaScript engine to execute and print out the values.

What’s Next

My next set of objectives is to demonstrate how to project a C++ object into JavaScript. I also want to start thinning out the size of these files. On a machine that is using the v8 binaries, the entire build tools are not needed. At the end of the above process the b8 folder has 12 gigs of files. If you copy out only the build files and headers needed for other projects, the file size is reduced to 3 gigs. Further reductions could occur through changing some of the compilation options.


Mastodon: @j2inet@masto.ai
Instagram: @j2inet
Facebook: @j2inet
YouTube: @j2inet
Telegram: j2inet
Twitter: @j2inet