Bazel’s philosophy strongly encourages binding to exact, specific versions of all
third-party dependencies to help ensure reproducible builds. As Bazel users,
we must remember to extend this philosophy to Bazel itself.
When setting up a Bazel-based build system, you should choose a specific version
of Bazel and require all developers and the build system to use it. This can
be done in a few ways:
Use Bazelisk and a .bazelversion file (recommended)
Installing a specific version of Bazel as part of your build and developer
VM images / docker containers
With the first approach, upgrades to Bazel can then be treated like any other
upgrade: submit a pull request to the repo which updates the value in the
.bazelversion file and runs the full continuous integration pipeline.
When writing custom Bazel rules, you spend a lot of time either
reading or writing Bazel File objects.
File objects have two properties for accessing the underlying
file path: File.path and File.short_path. When
writing custom rules, I often chose one of the two properties at
random, and switched to the other if it didn’t work right.
I wrote some simple custom rules to test the various combination
of rule types and file types to determine when I should use path
or short_path. The custom rules used bash script templates
that were populated with file paths, such as:
Bazel is a powerful yet complicated system, and it can be intimidating
to newcomers.
While the Bazel user guide and user manual preach the benefits
of giving Bazel full control over your build process by rewriting
all build processes using Bazel-native rulesets (as Google reportedly does
internally), this is an immense amount of work. Specifically, if you
are integrating third-party software into your Bazel-based build
process, reverse engineering and rewriting the third-party project’s
build system into Bazel can easily take days – and then you need to
maintain it.
In 2020, I led the redesign and re-implementation of the object storage
system behind RelativityOne.
As part of this project we reengineered the continuous delivery
pipeline of the service to embrace the philosophy of a service-wide
monorepo with a Bazel-based build system. We chose Bazel
because we wanted a build system that could support many different
languages (the service has code written in C, C#, Python, Go, Terraform,
Packer, and other languages…) while remaining fast and correct.
In 2020, I led the redesign and re-implementation of the object storage
system behind RelativityOne.
As part of this project we reengineered the continuous delivery
pipeline of the service to embrace the philosophy of a service-wide
monorepo with a Bazel-based build system. We chose Bazel
because we wanted a build system that could support many different
languages (the service has code written in C, C#, Python, Go, Terraform,
Packer, and other languages…) while remaining fast and correct.