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.
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:
- Write programs that do one thing and do it well.
- Write programs to work together.
- 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 has been hired to write several "missing" rulesets.
For example, rules_distroless, rules_apko, and rules_sol.
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.
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 that as of Fall 2024, Google is donating some of their repositories to the Linux Foundation, see the spreadsheet.
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.
Simplest: Download a Bazel release binary and put it on your
PATH
- Not recommended as it risks version drift against coworkers and CI
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
- A version-aware wrapper that downloads the correct Bazel version. Typically on the path as
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 example. - We'll call out any features which are only in the Aspect CLI and not in vanilla
bazel
.
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.
Aspect CLI
This repository is configured to use the Aspect CLI rather than "vanilla Bazel". It's meant to improve your experience, while remaining fully backwards compatible. You could go back to "vanilla Bazel" at any time.
Any commands in the course that aren't present on "vanilla Bazel" will be noted like this:
The bazel docs
command opens documentation in your browser.
For example, run bazel docs glossary
to learn all of Bazel's terminology.
Run bazel docs aspect_rules_js
to see documentation for @aspect_rules_js
loads.
Try it: bazel version
Run bazel help
to get familiar with it.
This is much more readable if you use the Aspect CLI.
If you'd like to follow along with the 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 exercises in action.