How Chromium Strips Debug Symbols and Compresses PAK Files
This article explains the final stages of the Chromium build process, focusing on how the browser reduces its file size for end-user distribution. It covers the automated stripping of bulky debugging symbols from compiled binaries and the aggregation and compression of static assets—such as user interface elements, strings, and images—into optimized PAK files before packaging everything into a final installer.
Configuring the Release Build
Chromium uses GN (Generate Ninja) to generate its build files and
Ninja to execute the build. When preparing Chromium for final
distribution, developers configure GN with specific release flags, most
notably is_official_build = true and
is_debug = false.
These flags instruct the compiler (Clang) and the linker (LLD) to optimize the code for size and speed, while simultaneously triggering the post-processing pipelines responsible for stripping symbols and compressing resources.
Stripping Unneeded Debug Symbols
When Chromium's C++ source code is compiled, the resulting binaries contain massive amounts of debugging information. This data maps compiled machine code back to the original source code lines, variable names, and function calls. While essential for developers, this data can make a binary several gigabytes in size, which is impractical for end-user downloads.
Chromium separates and removes this data differently depending on the target operating system, ensuring the final executable remains small while preserving the symbols separately for crash reporting tools like Crashpad.
Linux and Android
On Linux and Android, debugging information is stored directly inside the compiled ELF binaries using the DWARF format. During an official build, Ninja runs a two-step extraction and stripping process using LLVM toolchain utilities:
- Extraction: The build system uses
llvm-objcopy(oreu-strip) to copy the debugging sections out of the main binary (e.g.,chromeorlibchrome.so) and into a separate symbol file (e.g.,chrome.debug). - Stripping: The build system then runs
llvm-stripon the main binary. This removes all.debug_*sections and unneeded symbol tables, reducing the binary size by up to 90%. A small build ID is left behind so crash reports can later be matched to the external.debugfile on a symbol server.
Windows
On Windows, Chromium avoids embedding debug symbols into the main
executables (.exe and .dll) altogether. When
lld-link links the binaries, it automatically generates
Program Database (.pdb) files alongside the
executables.
Because the symbols are already separated into .pdb
files, no explicit "stripping" tool needs to be run on the executable.
The build system simply excludes the .pdb files when
gathering files for the final installer.
macOS
On macOS, the compiler embeds DWARF debug data into the object files.
During the build process, a tool called dsymutil links
these debug sections into an external .dSYM bundle.
Afterward, the standard strip command is executed on the
main Chromium Mach-O binary to remove the local symbol table entries
before the .app bundle is finalized.
Compressing Resources into PAK Files
A web browser requires thousands of static files to function,
including HTML, CSS, and JavaScript for internal pages (like
chrome://settings), UI icons, and localized text strings
for dozens of languages. Reading thousands of individual files from the
hard drive at startup would severely degrade performance. Chromium
solves this by packing these assets into single-file archives with the
.pak extension.
The Role of GRIT
Chromium uses a custom Python-based tool called GRIT (Google Resource and Internationalization Tool) to manage and compile static resources.
- Resource Definitions: Developers list all required
assets in XML-based
.grd(GRIT Resource Description) files. These files define where an asset is located, its unique ID, and how it should be processed. - Inlining and Minification: When the build starts,
GRIT reads the
.grdfiles. If an HTML file references external CSS or JavaScript files, GRIT flattens them by inlining the code into a single file. It also strips out comments and unnecessary whitespace to reduce file size. - Individual Asset Compression: Before packing the
files together, GRIT compresses individual text and web assets. In the
.grdfile, assets are tagged with compression attributes (such ascompress="brotli"orcompress="gzip"). GRIT compresses these specific files in memory using Brotli (preferred for its high compression ratio and fast decompression) or Gzip. Images like PNGs are also optimized using internal build scripts to strip metadata and reduce color palettes without losing quality. - Header Generation: GRIT generates C++ header files
(
.h) that map human-readable resource names (e.g.,IDR_NEW_TAB_HTML) to numerical IDs. The Chromium C++ code uses these IDs to request the exact resource at runtime.
The Repack Step
During the compilation of Chromium's various sub-components (like the
Blink rendering engine, the V8 JavaScript engine, and the browser UI),
GRIT generates dozens of intermediate .pak files.
To optimize file system performance, the build system executes a
repack step near the end of the build. A script merges
these dozens of smaller .pak files into a few master
files:
resources.pak: Contains non-image resources like internal HTML, JS, and CSS.chrome_100_percent.pakandchrome_200_percent.pak: Contain UI images and icons scaled for standard and high-DPI displays.locales/[lang].pak: Contains translated strings for specific languages (e.g.,en-US.pak).
The .pak format itself is a simple binary structure
consisting of a file header, an index mapping numerical IDs to byte
offsets, and the contiguous block of raw (or pre-compressed Brotli/Gzip)
data. Because the .pak container itself is not compressed
as a whole, Chromium can memory-map the file at startup, jump directly
to a specific byte offset using the index, and read a single resource
into memory instantly without decompressing the entire archive.
Final Installer Distribution
Once the binaries are stripped of their debug symbols and the static
resources are repacked into .pak files, the build system
stages the required files into a clean directory.
As a final step, a platform-specific packaging script compresses this
entire directory into a distributable installer. On Windows, for
example, the staged files are archived into chrome.7z using
LZMA compression and bundled into mini_installer.exe. When
a user runs the installer, it extracts the clean binaries and the
.pak files directly to the user's hard drive, resulting in
a fast, lightweight installation.