Build systems

In the past weeks, I was looking at several build systems. As it turned out, there is not a single sane generic build system out there.

Autotools: Autotools are ugly, slow, and require an immense amount of code copies in the source tree.

WAF: WAF is not as ugly as autools and it’s faster and does not generate Makefiles or stuff like this. But it has serious issues: It requires one to copy it to the source tarball, has no stable API, and requires Python for building. Furthermore, support for unit testing is broken: It runs the unit tests, but does not abort the build process if the tests fail and does not display why the tests fail.

CMake: The syntax is ugly, it generates Makefiles, and support for pkg-config seems to be very very basic.

So how should a build system look like?

  • It should be installed in the system and not require code copies in the source tree (and thus no pre-build actions)
  • It should not generate Makefiles, but build the project itself.
  • It should not require more than a standard C library.
  • It should support pkg-config out of the box.
  • It should support SONAMEs for libraries.
  • It should detect dependencies on headers automatically.
  • It should support unit testing and abort if the tests fail.
  • It should not require developers to specify how to do things, only what to do.

So, why is there no sane build system?

26 thoughts on “Build systems

  1. BuilDJ is still using WAF underneath.

    “the current reference implementation is being done with waf”

  2. Autotools is really the only thing out there that is at least half sane. It would be nice if someone that understands autotools would write something not so portable (say only SUS) to get rid of all the uglyness following from being portable.

    What I really miss with most modern build system, where autotools really are good is supporting not only the developer of some software but also the user of the software. Especially your “no Makefile” requirement is most likely incompatible with it. At least all those I saw had the “works for me, you must be doing something wrong” attitude…

  3. Autotols is the only sane build system. You only end up copying loads of crap into your source tree if you Do It Wrong and cargo-cult poorly written examples from others rather than RTFM.🙂

    Autotools is the only build system (that I have run into) that adequately meets the needs of the four classes of users: developers, end users, translators, and distribution packagers.

    1. > Autotols is the only sane build system. You only end up
      > copying loads of crap into your source tree if you Do
      > It Wrong and cargo-cult poorly written examples from
      > others rather than RTFM.

      configure scripts, config.guess, etc. qualify as code copies and are always there.

      1. They are not really code copies. You never modify them. They are not stored in your VCS. They are only present in the exported form of your project that you crate as a convenience for users who don’t have autoconf/automake installed themselves.

        I agree it’s desirable to have the build system build the project itself, without any intermediate files (Makefile.in, Makefile, etc) being dropped in the source tree, but then you require everyone who wants to build your project to also have your build tool installed. Autotools only require that you have a compiler, a shall, and make installed–and they go to great lengths to work with many different shells and make implementations.

        If your hypothetical build system is written in Python then before I can even think about porting your project to my system, I first have to port Python… madness!

  4. I would go for waf and try to solve the problems it has. I never used waf, but SCons. IIRC, waf is derived from SCons. That waf is based on Python I see as an advantage, but YMMV :~)

  5. As with Waf, SCons ticks many but not all of your boxes. Waf may originally have come from SCons in some sense, but they have travelled two very different roads since, and so are now totally different.

    I think with a little configuration boths SCons and Waf could be made to fit all but one of your boxes: you appear to rule out anything other than native code solutions.

      1. SCons is evil. Don’t use it if you want to be reimplementing autotools features like DESTDIR until the cows come home.

  6. I don’t really see what the big deal against autotools is.

    If used properly, It Just Works(TM). Every other build system I’ve seen out there was based on the presumption that the authors could do a better job than the autotools authors, and they were all wrong. Autotools was written the way it was so that it would work everywhere, and it does; I’ve tried it on an ages-old unix system, and it did just what it was supposed to do (of course, things didn’t build because this ages-old unix system was some pre-POSIX System V that the actual C code didn’t cater for, but that’s a different matter)

    The only problem with autotools is that it has a long history, therefore a long list of deprecated interfaces likely to confuse cargo-cult programmers who don’t want to understand how the thing works, and therefore is often made to break by novice users. But once you actually start reading its excellent documentation, the pieces just fall together.

    As for code copies, that’s a feature, not a bug. Every build-time dependency is something that hurts someone who doesn’t yet have that dependency installed and wants to install your code on some system that doesn’t have that dependency yet. This is not a problem for binary distributions (mostly), but it can be for source distributions (compile and install a 30M dependency just so you can build a 3k binary) and for those of us wanting to bootstrap a system (for some new port, or so).

    As for those suggesting SCons (or anything based on it): put away the crack pipe. Really. It doesn’t halfway implement the features required of a real build system (like, say, proper crosscompiling) and breaks more often than not. At least in my experience.

    1. autotools doesn’t generate IDE projects, which is a majorly important feature for portability.

      1. Actually generating IDE projects is absolutely useless feature for portability, because IDEs are generally not portable. While makefile can be used with any compiler, even *all* those that come with IDEs.

  7. I use scons, and it’s alright for C and C++ projects. I think WAF is a derivative of scons. I think scons is a bit more mature, and has a stable API.

    pkg-config seems to work fine:
    http://www.scons.org/wiki/UsingPkgConfig

    Python is hardly a dependency, as it is an integral part of most Linux distributions and osx as well. Windows is the only common platform where python isn’t installed out of the box.

    The major complaint I have about scons is that its support for languages other than C and C++ isn’t as reliable as the documentation claims. Specifically, their java parser isn’t reliable. You are probably better off using ant or maven for java.

    I don’t think there’s one true build system. For instance, autotools seems geared towards people who care about ancient Unix platforms, whereas most modern Linux developers don’t give a crap if something ports to AIX or whatever, and don’t want the complexity necessary to make that work. Scons is more geared towards people who just want to minimize the time they spend dinking around with their build system.

  8. Quite an interesting discussion, guys! I’m currently developing a scene graph using OpenGL and C++. It’s the most intricate piece of software I think I’ve written, not only because of all the matrix mathematics, but also the build dependencies and amount of classes. Previously I’ve done development in Java and C where the bulk of compiling was done like so:

    $ javac *.java # and,
    $ gcc -Wall -o *.c

    and later in my education I was using apache ant to compile my Java projects and writing Makefiles to compile my C projects. But this project that I’m working on now just got too complicated to maintain writing Makefiles manually. I entered CMake; what a blessing. However, I’ve become very prodded to learn about autotools upon reading the comments.🙂 When I have time, I guess!

    1. Riight. Obviously you wouldn’t go gcc -o *.c. I used less than and greater than characters and the comment field interpreted it as XML tags thus removing them. But y’get me.

  9. I’ve been thinking about a system for quite some time now. The “dammit” package in Debian is sort of what I’m thinking of, except that it’s overengineered in a lot of places.

    Basically, a “project” for me is something that has a set of related outputs (i.e. a single program, or a library and its headers), and building works by building a list of all files, then hypothetically compiling them, seeing what files are generated, and thus building a dependency tree. This tree is then anchored at the list of output files, and everything that is not referenced from there is dropped.

    The downside to this system is that the amount of glue magic to keep it all together is staggering, and it is fairly inflexible regarding project types.

  10. waf – hands down
    I picked waf for my companies build system after extensive comparison and research on various build system.

    Simple API:
    way simpler than autotools

    Stable:
    1.5.X is in maintenance mode(is what i use)
    1.6.X is active development

    perforamance:
    http://retropaganda.info/~bohan/work/sf/psycle/branches/bohan/wonderbuild/benchmarks/time.xml

    Extensibility:
    In under 500 lines of extra code I replaced bitbake with waf as well

    The one build system to rule them all

  11. Well, it *is* possible to write Autofools in a way that works. Sadly enough, not many people know how to do it.

    Important things are also: the ability to be used by packagers (things like DESTDIR, which were often broken in ac2.13/am1.4 times, but also forcefully override things like CC, CXX, CFLAGS, etc. where a target platform – like BSD – may have certain requirements) and portability.

    Of course, the best thing to use on a bsd is and (no pkgconfig there though – but then, pkgconfig is ALSO a nightmare).

    ciruZ has made https://webkeks.org/hg/buildsys/ (you may need to use IPv4 forcefully for his website, as he seems to have trouble with IPv6 – maybe MTU…) which I don’t fully like but is relatively simple and clean.

    I’ve gained a lot of experience fixing bad autotools usage over the years as BSD porter (shows up in a bunch of security NMUs in Debian too), but of the things you mentioned it’s really probably the best, considering the other things people here have said about it.

    My shell (a-g source mksh) uses its own portable build script (nicknamed mirtoconf😉 which does what autotools do, in small and targetted. It’s not very reusable though, and was not designed to be. (On the other hand, I’ve run it successfully on 4.3BSD-Quasijarus, Ultrix, Plan 9, Minix, Syllable, Haiku, and others.) It also does ONLY compile- and link-time checks, no run-time checks, which is crucial for cross-compiling (a proper build system – and compiler! – ought to behave the same whether cross or native and not even NEED to see which one it is). Can do that with autotools itself, but not many macropackages for them.

  12. Ah, well. As for not generating Makefiles: mirtoconf has recently gained an option to generate one, because some things like Android (AOSP) need it. They have no native way to extract the requisite CC, CFLAGS, CPPFLAGS to pass to Build.sh (so I use an evil hack to find them out, run Build.sh manually with it and let it generate a Makefile which I then transfer into an Android.mk file).

    Your limitations/requirements sound solid at first, but unfortunately, real life sometimes has demands…

  13. Ad: It should not require more than a standard C library.

    Well, it will always require a bit more. At least a shell (and the compiler, wich you’ll need anyway). In this respect autotools are as minimal as you can get. Their main problem is IMO the use of make.

    In my experience checking the dependencies with timestamps often proves unreliable during development. When builds are being interrupted, fail, crash, options are changed and such, the build tree sometimes gets into a state where make — or anything that just compares for newer rather than at least exact full stat data — gets it awfully wrong and you spend whole day debugging problems caused by miscompile.

    This happened to me with make a few times and it happens to me regularly with visual stuido. The recursive makefiles generated by autotools only make things worse and slower. I had a project, where rewriting makefiles from recursive to inclusive made things order of magnitude faster (at the cost of not being compatible with old makes).

    Most of your points are fullfilled with waf, though.
    Even the first point partially is — when waf is included in the source package, it will extract itself automatically behind the scenes, so there is really no prebuild step. For windows, it would even be possible (it does not seem to be done though and would probably require a little bit of tweaking) to ship with waf.exe. I believe similar trick is possible for Max OS X and most unix machines will have python these days anyway.

Comments are closed.