Skip to main content

Introduction to Bazel

Welcome to the Bazel 101 training course by Aspect!

We'll touch on what Bazel is and what advantages it has over alternatives.

By the end of this section, you should have Bazel installed so you can run bazel version and feel comfortable explaining to a co-worker why your organization chose to use it.

What is a Build System?

Whatever language or framework you use, it has a Getting Started page. This always provides the simplest "quickstart", and includes whatever compilers or other tools are needed to run the code.

Quickstart tools are generally:

  • tied to a specific language, sometimes at one version
  • integrated with a single toolchain for simplicity
  • designed for small- to medium-scale applications

Many projects are still using these tools even as the codebase and team grow, and the full-stack spans multiple languages. As you run into limitations, the "band-aid" approach is to script around the tools, for example with a Bash program that:

  • encodes some common commands needed to get your machine in the "right state" for the tools to work
  • builds some libraries, then afterwards an application
  • checks what files were changed to reduce how many test cases to run
  • much more!

This ad-hoc solution only buys a small amount of time. In contrast, a general purpose build system is meant to solve for all your developer workflows, while scaling to really large codebases in many languages.

There are a few options:

  • Bazel: we'll learn about it in this course!
  • Make: very mature, and shares some properties with Bazel. However it doesn't enforce layering between describing the code and listing commands to run, so it's brittle.
  • Buck: a Bazel clone developed at Facebook. The new Buck2 rewrite seems very promising and we plan to track development over 2024-2025.
  • Pants: a Bazel clone developed at Twitter, but now seemingly EOL
  • MSBuild: not adopted much outside Visual Studio.
Read More

Research paper: Build Systems a la carte

Mental model

At the highest level, using Bazel is like making the following deal:

You provide: a description of your code and its dependencies, in BUILD files. These can be 80% automated, but the other 20% is up to you.

You get: a continually updated transformation from your source tree to a bazel-out/ folder, containing build outputs and test results.

Essential Properties

We'll start learning about Bazel by describing our goals at a high level, and point out what's required of us as developers to get Bazel's guarantees.

Incremental

Rebuild or re-test time is proportional to what you changed.

Comment-only source changes should be nearly instant, but changing the version of an SDK might require re-building the whole application.

Requires: breaking up a monolithic app into modules/libraries without cyclic dependencies.

Correct

You should not get in the habit of running a "clean" when you distrust a build or test result, which slows down development with a slow "retry" when your code isn't working. You can trust that the incrementality will rebuild anything required, so the outputs are up-to-date.

Requires: care from the beginning. Correctness is very difficult to retrofit onto an existing build tool!

Cached

Can re-use outputs of previous builds, even those performed on a different computer. The build should be a "pure function" from inputs to outputs.

Requires: determinism. given the same inputs, tools write identical output, regardless of where they run. For example, the compiler should not write an absolute file path into the output.

Without determinism, later build steps will always get a cache miss due to changed inputs.

Note, as a side-effect, it's also isolated: Tool run-times are in ephemeral sub-processes, defending against resource leaks and statefulness bugs. "Persistent Workers" are a notable exception, however.

Parallel and Fast

Schedule as much work concurrently as possible, given multiple local or remote CPUs.

Note that Bazel can't be faster than the underlying tool it calls: the goal is to add the minimal overhead, and avoid calling those tools at all.

Requires: hermeticity. All dependencies are known to the build system, including tools, environment variables, and third-party libraries.

Note that some execution strategies have stricter hermeticity requirements than others.

Reproducible

Thanks to hermeticity and determinism, we know all the build inputs and are guaranteed to get identical outputs.

This allows you to demonstrate that your binaries were built from the sources you claim. It also means you can safely cherry-pick a hotfix onto a months-old release and be assured it still builds, and everything else will be identical.

Composable

Allows reuse of existing build rules and creating new ones by combining them. Bazel follows the Unix Philosophy which says to:

  1. Write programs that do one thing and do it well.
  2. Write programs to work together.
  3. Write programs to handle text streams, because that is a universal interface.

Bazel models your build and test the same way, except that instead of "text streams", the universal interface is files.

Universal

Bazel supports Build and test of nearly every language and framework. When one is missing, developers add a "ruleset" to support it.

Aspect.dev

Aspect has been hired to write several "missing" rulesets.

Industrial

Googlers have beat on this thing in every way at large scale. As of 2015 "google3" was 2 billion SLOC!

The Bazel Ecosystem

Google provides governance and maintenance of the "core" engine. In time, this will include NO languages. There is a major release every year or so. This course is updated for Bazel 7 which was released November 2023.

Using modern Bazel features

Bazel improved how you install rulesets, with a package manager called "bzlmod". This feature is enabled by default in Bazel 7.

We use that in the training, because it's a better use of your time to learn the future state. For a while, you'll still see projects that have long WORKSPACE files and don't use bzlmod.

"Rulesets" provide the plugins to add support for more languages and frameworks. Google provides a few of these, but the quality of maintenance and releases varies a lot. Some are "abandonware". Always take care when depending on third-party code, including Bazel rulesets!

note

33% of the ruleset releases on the Bazel Central Registry are from Aspect!

Of course, there is ongoing work as new versions are released. A language may have a new release, which means the compiler has a new version, and it may increase the "lower-bound" of some system library like glibc. Then the Bazel rulesets need to be released with support for it, and those need to keep up with releases of Bazel itself. This "churn" contributes to the Total Cost of Ownership.

Installing Bazel

There are a few ways to setup Bazel. You should expect the bazel command to work, and ideally command-line completion should work in your shell.

  1. Simplest: Download a Bazel release binary and put it on your PATH

    • Not recommended as it risks version drift against coworkers and CI
  2. Install Bazelisk https://bazel.build/install/bazelisk

    • A version-aware wrapper that downloads the correct Bazel version. Typically on the path as bazel so you don't need to think about the distinction.
    • Recommended by Google
    • MacOS: brew install bazelisk
    • npm: npm install -g @bazel/bazelisk
  3. Optional: use the Aspect CLI

    • It has features to make Bazel easier to learn.
    • You can install just for yourself, or use the .bazeliskrc file checked into source control to install it for your team. We'll use this in the codelab.
    • We'll call out any features which are only in the Aspect CLI and not in vanilla bazel.
note

Your DevInfra team may have already setup a specific way Bazel should be used for the project you're coding on. Take care not to change the setup of your computer in a way that interferes with doing your work!

Instructor-led training courses may customize this section for your corporate environment.

Try it: bazel version

If you'd like to follow along with the codelab exercises, you should run bazel version to verify the installation.

If you see WARNING: Invoking Bazel in batch mode since it is not invoked from within a workspace don't worry, we'll fix that in the next section.

You can also just follow along with the instructor to see these codelab exercises in action.

You can also run bazel help to get familiar with it.