Thanks to the xz backdoor, many people are now talking about the state of Linux packaging tools, and in particular build systems. As a maintainer of Void Linux and packager of many things, I have my five cents to add, so today I’ll be the contrarian and argue what autoconf got right. This is not an apology for GNU autotools; we are all well familiar with the issues they bring—yet some prospective replacements manage to be worse in certain aspects.
It provides a standardized interface.
This is of course the hardest point to tackle for any new contestor that has not reached a critical mass.
In Void Linux, the GNU configure build style is the most popular; roughly 2250 of about 14300 package template use it, and an additional 120 use the generic configure build style, which works similarily.
As a packager, the worst thing is to find a custom made build system
that behaves totally different from what we know—if you decide to
write your own ./configure
scripts, please stick to the conventions!
We packagers really have better things to do than figure out yet another
homebrew build system that’s used exactly once.
These conventions are standardized as part of the GNU Coding
Standards
and they specify many features that packagers expect, but developers
without own packaging experience are likely to miss. One example
is support for staged installation, i.e. DESTDIR
. This is essential
for building packages that only contain the files that package
actually ships. And no, support for --prefix
is not enough to
make up for this (if you wonder why, please read up the standards).
It is based on checking features.
People who have been staring at ./configure
output for too long may
want to disagree, but let me make my point: check-based configuration
is the only way to write software that will continue to work properly
in the future. If you instead keep a table of broken systems and
workarounds, it a) will not be updated for future systems, b) doesn’t
detect if the system was actually fixed (either by patching a bug, or
adding a missing feature). It’s also very unlikely the software
builds on an system unknown to the build system, even if it’s
standards-compliant otherwise.
Of course, the checks should be reasonable (and in practice, often are
excessive). If your code assumes a C99 environment, you don’t need to
check whether all C99 functions you use are available. Likewise, if
you don’t need macros for certain sizeof
values, you don’t need to
check for them, either. And you never need to check if sizeof char
is actually 1—it literally can’t be anything else. Also, checking
for functions can be done incorrectly.
Overrides are possible.
While checks are good, sometimes they are broken or a certain
configuration needs special override, because a feature can’t be
checked (for example, when cross-compiling). In this case, autoconf
scripts provide options to override checks with a predetermined
result; usually you can set an environment variable like
gt_cv_func_printf_posix=yes
.
Likewise, if a library is installed at a special location, it’s also
easy to tell configure
to use it.
The config.log tells what happened.
Many other systems do checks, but only tell that something has failed.
Debugging this can be difficult. Autoconf writes what it does into a
config.log
file, which is sometimes helpful to debug a check.
There is support for cross-compiling and for host/target separation.
Cross-compilation is a build system feature that is often put in
second place, but as a maintainer of a system that heavily makes use
of it, I have a fair share of experience and can say that autotools
are one of the best systems to support cross-compilation. Especially
custom-made build systems are often very lacking. Cross-compilation
of C programs is not particularly hard in principle, but your build
system needs to know which code is going to run on the target, and
that programs which need to run during compilation (e.g. to precompute
tables or something) need to be compiled for the host (with different
CFLAGS
and so on).
It has few runtime dependencies.
This is also a defining feature of autoconf, as usually a basic POSIX shell environment (or, say, something busybox) is enough to run the configure scripts. This is in particular important for packages needed for bootstrapping. If your build system needs Python, well, then you need to compile Python first; but to compile Python, you need to compile all of its dependencies, which hopefully don’t need Python then themselves to build…
However, for packages not directly relevant to bootstrapping a system this is not such an essential feature.
NP: Policy of 3—Let It Build