blob: a940e3e5cad520731a31704f60d6ddbb31349e47 [file] [log] [blame] [view]
---
layout: documentation
title: Hermeticity
category: getting-started
---
# Hermeticity
This page covers hermeticity, the benefits of using hermetic builds, and
strategies for identifying non-hermetic behavior in your builds.
## Overview
When given the same input source code and product configuration, a hermetic
build system always returns the same output by isolating the build from changes
to the host system.
In order to isolate the build, hermetic builds are insensitive to libraries and
other software installed on the local or remote host machine. They depend on
specific versions of build tools, such as compilers, and dependencies, such as
libraries. This makes the build process self-contained as it doesn't rely on
services external to the build environment.
The two important aspects of hermeticity are:
* **Isolation**: Hermetic build systems treat tools as source code. They
download copies of tools and manage their storage and use inside managed file
trees. This creates isolation between the host machine and local user,
including installed versions of languages.
* **Source identity**: Hermetic build systems try to ensure the sameness of
inputs. Code repositories, such as Git, identify sets of code mutations with a
unique hash code. Hermetic build systems use this hash to identify changes to
the build's input.
## Benefits
The major benefits of hermetic builds are:
* **Speed**: The output of an action can be cached, and the action need not be
run again unless inputs change.
* **Parallel execution**: For given input and output, the build system can
construct a graph of all actions to calculate efficient and parallel
execution. The build system loads the rules and calculates an action graph
and hash inputs to look up in the cache.
* **Multiple builds**: You can build multiple hermetic builds on the same
machine, each build using different tools and versions.
* **Reproducibility**: Hermetic builds are good for troubleshooting because you
know the exact conditions that produced the build.
## Identifying non-hermeticity
If you are preparing to switch to Bazel, migration is easier if you improve
your existing builds' hermeticity in advance. Some common sources of
non-hermeticity in builds are:
* Arbitrary processing in `.mk` files
* Actions or tooling that create files non-deterministically, usually involving
build IDs or timestamps
* System binaries that differ across hosts (e.g. `/usr/bin` binaries, absolute
paths, system C++ compilers for native C++ rules autoconfiguration)
* Writing to the source tree during the build. This prevents the same source
tree from being used for another target. The first build writes to the source
tree, fixing the source tree for target A. Then trying to build target B may
fail.
## Troubleshooting non-hermetic builds
Starting with local execution, issues that affect local cache hits reveal
non-hermetic actions.
* Ensure null sequential builds: If you run `make` and get a successful build,
running the build again should not rebuild any targets. If you run each build
step twice or on different systems, compare a hash of the file contents and
get results that differ, the build is not reproducible.
* Run steps to
[debug local cache hits](remote-execution-caching-debug.html#troubleshooting-cache-hits)
from a variety of potential client machines to ensure that you catch any
cases of client environment leaking into the actions.
* Execute a build within a Docker container that contains nothing but the
checked-out source tree and explicit list of host tools. Build breakages and
error messages will catch implicit system dependencies.
* Discover and fix hermeticity problems using
[remote execution rules](remote-execution-rules.html#overview).
* Enable strict [sandboxing](sandboxing.html)
at the per-action level, since actions in a build can be stateful and affect
the build or the output.
* [Workspace rules](workspace-log.html)
allow developers to add dependencies to external workspaces, but they are
rich enough to allow arbitrary processing to happen in the process. You can
get a log of some potentially non-hermetic actions in Bazel workspace rules by
adding the flag `--experimental_workspace_rules_log_file=[PATH]` to your Bazel
command.
Note: Make your build fully hermetic when mixing remote and local execution,
using Bazel’s _dynamic strategy_ functionality. Running Bazel inside the remote
Docker container enables the build to execute the same in both environments.
## Hermeticity with Bazel
For more information about how other projects have had success using hermetic
builds with Bazel, see these BazelCon talks:
* [Building Real-time Systems with Bazel](https://www.youtube.com/watch?v=t_3bckhV_YI) (SpaceX)
* [Bazel Remote Execution and Remote Caching](https://www.youtube.com/watch?v=_bPyEbAyC0s) (Uber and TwoSigma)
* [Faster Builds With Remote Execution and Caching](https://www.youtube.com/watch?v=MyuJRUwT5LI)
* [Fusing Bazel: Faster Incremental Builds](https://www.youtube.com/watch?v=rQd9Zd1ONOw)
* [Remote Execution vs Local Execution](https://www.youtube.com/watch?v=C8wHmIln--g)
* [Improving the Usability of Remote Caching](https://www.youtube.com/watch?v=u5m7V3ZRHLA) (IBM)
* [Building Self Driving Cars with Bazel](https://www.youtube.com/watch?v=Gh4SJuYUoQI&list=PLxNYxgaZ8Rsf-7g43Z8LyXct9ax6egdSj&index=4&t=0s) (BMW)
* [Building Self Driving Cars with Bazel + Q&A](https://www.youtube.com/watch?v=fjfFe98LTm8&list=PLxNYxgaZ8Rsf-7g43Z8LyXct9ax6egdSj&index=29) (GM Cruise)