Using Rust's Cargo as a build system

Around the beginning of 2020, I started using Rust’s cargo as my build system for a large repo. The repo has a couple of languages; Rust, Go, Javascript, Typescript, CSS, and some bash.

In the past I’ve used Maven, NPM, Pants, Bazel, and Make, but they all required a lot fo setup and maintenance for multi-language targets. Maven is java focused, and since I’m not using java at the moment, extending it is pretty awkward. NPM is upsetting because it’s just a proxy to scripts and commands - not much structure. Pants and Bazel both have pretty full features, but seem to be focused on large organizations. Make has always been great - but I’ve found Cargo to be even better.

Why not use the one that I’m already using to build Rust binaries? Cargo has a lot of good features that Make has, but with the benefit of being in a full-featured programming language I already know and use. Here’s a rough list of the benefits:

  • Checks dependency graph - bash and NPM can’t easily do this.
  • Extensible using Can easily run pre-build tasks, or if need be, use the build file that to call into shell scripts.
  • Already using cargo to manage dependencies, don’t need to install something else.
  • Can extend development tooling beyond build with cargo x by creating custom cargo commands.
  • Watch specific files through the use of cargo:rerun-if-changed - equally flexible to Make, if not more so.
  • Depend on non-rust languages and targets by just making them a dependency.

All of these taken together allow me to run cargo build -p x and build a package once, watching dependencies to see if they changed.

It’s nice to be able to build frontend targets by calling shell scripts from For example, since all my frontend code is built with esbuild, the cargo build script runs, which does some building and cp-ing of files.

If you’re already using Rust, give it a try. It’s simpler, easier, and far less time-consuming than almost all the other options.

programming | rust