I heard a joke on Twitter. It went like this.
Interview question: "What is your favorite build system?" Acceptable answers are: a) Rage face b) None of them c) Literal table flip
Why are build systems so hateful? I can think of three possible reasons to reject a build system:
- It is slow or faulty when operating on large projects.
- It is not portable enough, because it needs to be installed, possibly with dependencies.
- It is not flexible enough.
The first and second are solvable given enough effort. The build system can be engineered well, and it can be reduced to a single executable that can be downloaded and run, though not all are that easy to install. The third is a more systematic problem, and is one that almost all build systems share, because they use Makefile syntax. Makefiles have become more powerful over the years, with variables, macros, globbing, and rule patterns, but they lack the flexibility of a real programming language. Most notably, Makefiles cannot accept custom command-line options, and they cannot easily detect system settings and configure the project accordingly. Their lack of flexibility also leads to large amounts of string-substitution programming, which can make the files tangled and difficult to understand.
I have created, and am still creating, a build system that aims to solve the third problem of flexibility, while still doing well on the first and second. It is called make.pl, after the recommended filename of its build scripts. Said build scripts are written in pure Perl, with a Ruby-inspired declarative interface. The expert system is robust and handles distributed build scripts in multiple directories well. Its only dependency is Perl and its core libraries, which are installed by default on almost all UNIX-like systems, and for which there exist well-tested Windows installers.
Since the build script and its recipes are written in a real first-class programming language, a far higher level of flexibility is achieved than is available with traditional Makefiles. Build targets and dependencies can be generated from regular expressions. Common rules can be abstracted out to functions. Files of any source language can be scanned for dependencies, not just C. Command-line options can be processed for arbitrary purposes. Finally, you can reduce your dependency on the native shell, making it easier to support both *NIX and Windows. The only disadvantages of using a first-class programming language are that the build script will be more verbose than a custom DSL, and that you must be well-versed in the given programming language, in this case Perl.
If you are interested in taking a look, see the latest version at Github.