Bazel performance comparison with CMake
  • April 16, 2021 by Kai Wolf

Google released an open-source version of its internal build system named Bazel already six years ago. This system is advertised (and used effectively) to build billions of lines of code. My fundamental interest in this tool was fueled by two key promises according to their release notes for the 1.0 version: Hermetic and reproducible builds. Hermetic build in this context means that everything depends on a known set of inputs, which is essential for ensuring that builds are reproducible. This is achieved through several techniques such as sandboxing. For instance, Bazel tries hard to not be dependent on anything on the host system.

Reproducibility for builds on the other hand is also a must for any serious software system used by real customers. Without it, there is no way to go back in time and reproduce the state of the software to any previous version in time. However, there are actually few shops out there I’ve come to known personally where this is really achieved. Frankly, this is not too easy to setup in the first place.

I did port some internal projects as well as a customer project from CMake to Bazel in the last year. All those projects were of reasonable size (meaning lines of code) and had several external dependencies. I think this is mandatory to really get to know a new tool and push its boundaries quite a bit.

Build time benchmarks

One of the things I was most interested in are the build times. Suffice to say that large C++ projects have a strong tendency to build very slowly, due to tooling and certain language features (templates) that have never really got up to speed since the 80s. For a build time benchmark there are three different use-cases I’ve looked into: Fresh builds from scratch, rebuilds without any changes and finally rebuilds with one file touched:

Build time benchmark

For testing I’ve used the most recent versions of both Bazel (3.7.2) and CMake (3.19). This code base in particular made heavy use of Eigen included as an external dependency and CMake spent some time configuring this header-only library. Hence, this benchmark is arguably a bit skewed. However, this is a software project I’ve had at hand and at the end of the day these numbers count. Even if a fresh build is not considered here, Bazel still wins in terms of performance by being twice as fast for a rebuild and as fast as factor 17 for detecting a change (touch) and rebuilding again. This looks promising.

I’m also available for software consultancy, training and mentoring. Please contact me, if you are interested in my services.