aboutsummaryrefslogtreecommitdiffhomepage
path: root/site/blog/_posts/2015-07-23-tree-trimming.md
blob: 203785aa35ff6fcf223a803aa2b912fd2598d87b (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
---
layout: posts
title: Trimming your (build) tree
---

_Reposted from [@kchodorow's blog](http://www.kchodorow.com/blog/2015/07/23/trimming-the-build-tree-with-bazel/)._

[Jonathan Lange](https://twitter.com/mumak) wrote a [great blog
post](https://jml.io/2015/07/bazel-correct-reproducible-fast-builds.html) about
how Bazel caches tests. Basically: if you run a test, change your code, then run
a test again, the test will only be rerun if you changed something that could
actually change the outcome of the test.  Bazel takes this concept pretty far to
minimize the work your build needs to do, in some ways that aren't immediately
obvious.

Let's take an example. Say you're using Bazel to "build" rigatoni arrabiata,
which could be represented as having the following dependencies:

<img src="/assets/recipe.png"/>

Each food is a library which depends on the libraries below it.  Suppose you
change a dependency, like the garlic:

<img src="/assets/change-garlic.png"/>

Bazel will stat the files of the "garlic" library and notice this change, and
then make a note that the things that depend on "garlic" may have also changed:

<img src="/assets/dirty.png"/>

The fancy term for this is "invalidating the upward transitive closure" of the
build graph, aka "everything that depends on a thing might be dirty."  Note that
Bazel already knows that this change doesn't affect several of the libraries
(rigatoni, tomato-puree, and red-pepper), so they definitely don't have to be
rebuilt.

Bazel will then evaluate the "sauce" node and figures out if its output has
changed.  This is where the secret sauce (ha!) happens: if the output of the
"sauce" node hasn't changed, Bazel knows that it doesn't have to recompile
rigatoni-arrabiata (the top node), because none of its direct dependencies
changed!

<img src="/assets/dirty-unmark.png"/>

The sauce node is no longer “maybe dirty” and so its reverse dependencies
(rigatoni-arrabiata) can also be marked as clean.

In general, of course, changing the code for a library will change its compiled
form, so the "maybe dirty" node will end up being marked as "yes, dirty" and
re-evaluated (and so on up the tree).  However, Bazel's build graph lets you
compile the bare minimum for a well-structured library, and in some cases avoid
compilations altogether.