Wednesday, 25 July 2012

C/C++ Build Systems

I've been looking a lot lately at build systems for developing C/C++ projects, and have come to a general state of despair about them.

I should say first that I am a professional Java developer, with some more recent experience with Groovy and Scala running on the JVM, and that some of this is likely coloured by that experience. In the Java/Groovy/Scala world there are a number of build systems that can be chosen from, chiefly Ant, Maven, Gradle, and SBT as the ones I've used. I've used Maven a whole lot, Ant a decent amount, and Gradle and SBT are both very new to me still. Gradle in particular I really like because of one overriding thing - it makes the simple case very very simple.

If you then go to look at the C/C++ ecosystem it's a very different story. Choices here that I've looked at include Make, Autotools, CMake, SCons, Waf, and Boost.Build. I'm very aware that this is an incomplete look,but it seems to be the major ones (Not counting Visual Studio, which isn't so much a build system as an entire environment that will also build your projects, but loses out on the fact that it's Windows only). Out of these build systems, the first thing to notice is that they all fail to make the simple case even remotely simple. In the case of SCons and Waf, which a lot of people champion as being very powerful and flexible, you need to first learn Python before you can use them because the build script is actually a python script! That - in my mind - is verging on insanity. The few examples of real projects using Waf and SCons have had build scripts over 1,000 lines long!

What I really want from a C/C++ build system isn't - in my opinion - all that difficult.
  • Make the simple case simple. The simplest case is no dependencies, and just compile every single source file in the project together into one binary (Executable or Library as appropriate). I see no reason why a build system couldn't achieve this off of at most a couple of lines of configuration.
  • Make simple dependency management simple. A lot of libraries out there make use of pkg-config. A lot of the ones that don't are the same library and path names across platforms anyway. I should be able to add a dependency on "zlib" - which is in my pkg-config list - as easily as just stating that I now depend on zlib, optionally with version requirements.
  • Make multi-module projects simple. I should be able to have a multi-module project - that is a project that builds more than one output, all of which work together - as simply as specifying the outputs - most likely as separate subdirectories with their own source trees under them - and have it just work. When I do this, dependencies between the different modules should still be simple.
Unless I'm missing something, none of this seems like rocket science.