Building with Bazel
Jul 8 2022 · Starlark, Bazel 5.1, Visual Studo Code 1.66
Part 1: Learning Bazel
Leave a rating/review
Episode 1 - Introduction
Building code is a critical aspect of software development. Your choice build system can determine how productive you and your team will be on any particular project. If you are solo developer or working on a small team, than a build system say built into Xcode will be just fine for your purposes. But, as your team scales from the dozens to the hundreds and your codebase expands from hundreds of thousands to millions of lines of code, you’ll need a build system that won’t bottleneck your team. Rather, you need a build system that scales with your team. This means a build system that works better and faster the people more people who use it. Think of highway to gets faster with more cars, and is blazing fast during peak usage.
Google invented such a system and called it Blaze. Blaze became the standard tool for compiling all their code. This meant it needed to support a multitude of different languages while also providing consistent build results. Using such a build system enabled Google to put all of their code - that is - millions upon millions of lines of code into a single albeit massive monorepo with Blaze being the key to unlock the thousands and thousands of build targets.
Blaze was such a success, Google decided to share it with the rest of the world with exception of some proprietary components.
Blaze thereby became Bazel and it was released to the public in 2015.
By default, Bazel supports a few programming languages out of the box.
For example, it supports Java (which is the source language of Bazel), C, C++, Objective-C and Python. To use other languages, you incorporate community supported rules and of course, if you are using a custom language or an unsupported one, you can always write your own custom ruleset.
Bazel is classifies itself as an artifact based build system. The Bazel documentation breaks this down really nicely.
When you first start writing code, you typically call the compiler via. the command line. But as your application grows, this approach isn’t very sustainable so
you may switch to shell scripts. While shell scripts provide greater flexibility that just command line compiling, the build process becomes dependent on the system settings. It requires each builder to have the same exact configuration or the build will fail. Scripts will build everything from the scratch, requiring you to create some caching mechanism.
Thus you move to a task based system like Gradle or Maven. These systems breakdown each step of the build process as a task and the runs those tasks based on dependencies. While they get the job done, the build system tends to favor imperative based task design based where developers can dictate each step of the build. Because of this, the build system doesn’t understand the necessary order of compilation ie, whether a task can be built concurrently thus wasting processing power.
Bazel is an artifact based build system. In this system, developers define the tasks, but Bazel defines how those tasks will be built. This means our targets are written in a declarative manner. By analyzing all the various components of a build, Bazel can optimize the build process. If nothing was previously changed, Bazel will not rebuild. Better still, it will analyze the various inputs of all the running tasks. If there isn’t a dependency from previous tasks, then Bazel will run build targets in parallel. This build can expand to other developer machine, creating a distributed build network. In fact, Bazel even leverages remote building which you’ll discover later in this course.
In this regard, you can classify Bazel as a functional or deterministic build system. That is, when you provide the same inputs, the build system will always produce the same output. This requires some more bookkeeping on our parts as a developer but it ensures reliability in our builds. This means, you’ll never end up with a breaking build because a thirty party dependency changed without you being aware of it. When you create a target that is compiled using a specific JDK, that build will always used that version of that JDK, no matter how is building it.
So Bazel is a great tool for large development team but it’s not ideal for all situations. For instance, if you are part of a small team, then Bazel may take too much developer time as opposed to using something like just using Xcode. Bazel also requires a bit of knowledge investment. Whereas using the default compiler in your IDE, you’ll need to know how to configure your builds for Bazel. Also, Bazel requires a lot of dependency management. But remember, all this comes at the cost of blazing fast builds that can be distributed through your whole developer network. So as you can see, for some developers these cons may be roadblock whereas other may seem at slight irritations with the benefit being less time waiting for code to compile and more time writing code.