Skip to content

Instantly share code, notes, and snippets.

@Leedehai
Last active January 5, 2024 21:08
Show Gist options
  • Save Leedehai/5a0fba275543891f192b92868ee603c0 to your computer and use it in GitHub Desktop.
Save Leedehai/5a0fba275543891f192b92868ee603c0 to your computer and use it in GitHub Desktop.
Build system: Ninja and GN

Build system: Ninja and GN

Switching from Make to Ninja and GN across the board.

A build system is what coordinates the build process of various source files and libraries.

Make and CMake

Make is a tried and tested tool, but it does not scale well with large, collaborative projects that often require complicated build rules and maximum parallelism. In an attempt to augment it, GNU Autotools was introduced, but its complicated workflow is little short of intimidating.

Originally, Make has been my choice. It is familiar to most programmers and is (almost) ubiquitous in every *nix system. As time went by however, things get a little complicated, warranting a makefile generator. Taking cues from static HTML template engines, I rolled a custom one in Python, which takes a description file BUILD.mg in JSON, and a Makefile template. However, the generator needs to be constantly maintained to meet my growing demands.

For a while, I considered CMake, as it is the de facto standard used by popular projects in the open source community like LLVM, OpenCV, and PyTorch. However, its syntax is arguably inelegant, and my personal experience with it was painful during grad school.

Ninja and GN

Ninja is unfamiliar to most programmers. But this is not to say Ninja is any less capable. It began with Chromium, the open source web browser project initiated by Google. In a bid to accelerate the build process, Googlers noted that for a non-trivial project:

  • Make was designed in a way that makefiles are writable by hand, so it makes a lot of deductions at runtime, which is slow, and
  • The syntax makes it not easy to write rules that get the dependency correct; most of the time programmers add new rules haphazardly just to "make things work".

As a result, the Chromium team built Ninja, a build system that was designed with a focus on speed and dependency correctness.

Writing ninja files by hand is painful by design, because they are meant to be auto-generated. GN is such a generator, just like the role CMake plays for Make: it takes *.gn files and produces ninja files for the user. Additionally:

  • GN has lots of other useful functionalities baked inside.
  • Its declarative syntax is much more concise and tasteful than CMake, and arguably makes it easier to make changes.
  • It has the right amount of flexibility, but not too much. Writing build rules should not be a creative endeavor; ideally two people should produce the same results given the same requirements.

Bazel?

After the release of GN for Chromium, Google open-sourced Bazel, a distributed, cross-language build system based on its internal one. Though Bazel can replace GN and Ninja all at once and it is the official build system for a number of open source projects like Abseil and Tensorflow, I didn't choose Bazel because:

  • Bazel seems too heavy.
  • GN's syntax is similar to Bazel's, as GN was designed to mimic the latter.
  • GN is actively maintained by Chromium (and V8), and is used by Firefox and Fuschia as well.
  • The migration cost outweighs the benefits.

FAQ

Q: Have you tried other build tools, like XMake, SCons, and Meson?
A: No.

Q: Ahh.. I really do not want YET ANOTHER build tool!
A: ¯\_(ツ)_/¯.

@Leedehai
Copy link
Author

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment