Why scons is cool

I’ve recently started playing with scons a little for some small personal projects. It’s not perfect, but I’ve rapidly come to the conclusion that it’s a probably far better choice than make in many cases. The main exceptions would be cases where you need to integrate into legacy build systems, or if asking or expecting developers to have scons installed is unreasonable for some reason.

The main reason that scons is cool to me, and the thing that makes it fundamentally different from make, is the introduction of actual scoping.

make has a single global scope. This is one of the main reasons that people write recursive Makefiles; By giving you one file per directory, you get one scope per directory, which makes it possible to have per-directory pattern rules, variables, and all that other stuff, without driving yourself insane.

make‘s awful syntax, confusing varieties of variable, whitespace-sensitivity, and all the other things that people love to bitch about are annoying, but to my mind, the single scope that makes recursive Makefiles the dominant (and, really, the only scalable) paradigm is the one thing that really sucks.

scons solves this by baking various kinds of scoping into the tool. scons lets you include sub-build-scripts (typically named SConscript, by convention). Those scripts run in their own namespace and can establish their own variables, rules, etc., but the end result is then merged back into the global rule list (handling sub-directory paths intelligently), so that the scheduler can work globally, instead of having to recurse.

Furthermore, because of this explicit scoping, you can pass variables, including targets, between build files, letting you explicitly set up cross-directory dependencies or share CFLAGS or other variables, making it easy for different directories to share exactly as much or as little configuration as you want.

In addition, scons has the concept of “build environments”, which are objects that include build rules, variables, and so on. By reifying what make just represents as the global environment into objects, it makes it much easier to scope and program things. For example, if you have a set of targets that should be built using the global default rules, except with debugging enabled, you can do:

myenv = env.Clone()
myenv.Append(CFLAGS = ['-g'])
myenv.Program(...)

By making it (optionally) explicit which sets of rules and variables are being used in each place, it becomes much easier to share multiple kinds of targets and rule sets in a single file, without necessitating lots of sub-files just for scoping, like make tends to lead to.

scons is cool for a bunch of reasons. It eliminates most of the stupid little annoyances you’ve probably had with make. But, in my mind, this is the thing that makes it cool. They’ve added sane scoping to the build tool, so that you can construct non-recursive build systems without going insane.

I’ll definitely be considering scons for any new projects I write going forward. I hate make, and this definitely feels like a path forward.

Nov 7th, 2010
Tags: , , , ,
  1. Nov 7th, 2010 at 19:19 | #1

    So for Mixxx (http://mixxx.org), we use SCons (+3000 lines of SConscript tools, builders, etc), and I’d add one case to your list of “times not to use it” and that’s when your development team doesn’t know or care to learn Python.

    Before I rewrote the entire build system to support cross-compilation from Linux to OSX and Windows, the entire SConscript was a giant mess of spaghetti code, mixes of tabs and spaces / indentation levels and totally wrong Python constructs.

    Another problem with SCons is that having a general purpose language is way too open ended. There’s no well-defined place for anything, it’s all by convention. This got us into serious trouble. Our solution today is to basically have a configuration system built on top of SCons that forces people who use it to organize things well.

    Finally, it’s just too damn slow for anything larger than a small project. We have 600 C++ source/header files and it takes scons about 5 seconds to figure out what it needs to build.

    There are redeeming qualities, and it’s not worth it to rewrite now, but basically given the chance, I’d switch us to qmake. We’re a Qt project so as a bonus, we’d get a lot of nice things from using qmake.

  2. Nov 7th, 2010 at 19:22 | #2

    “5 seconds to figure out what it needs to build” is after it has cached the entire configuration, after everything has already been built once, and with only one source file changed.

    It gets maddening after a while.

  3. Anatol
    Jan 29th, 2011 at 04:53 | #3

    2RJ.

    Yeah, all modern build tool suck when it comes to incremental builds. And SCons is a definitely one of the slowest build systems.

    I was looking for better make for years, and I think I found it. I suggest you to look at Tup tool. This is very interesting and very fast tool (it is written in pure C). Check this result for 100K files project [http://gittup.org/tup/make_vs_tup.html](http://gittup.org/tup/make_vs_tup.html) Can SCons handle it? I bet no.

    More numbers from [http://gittup.org/gittup/](http://gittup.org/gittup/) :

    [marf@captainfalcon gittup]$ vi nethack/src/spell.c
    [marf@captainfalcon gittup]$ vi busybox/coreutils/ls.c
    [marf@captainfalcon gittup]$ time tup upd -j2
    Executing Commands
    [    0/9    ] busybox/coreutils/CC ls.c
    [    1/9    ] nethack/CC src/spell.c
    [    2/9    ] busybox/coreutils/LD built-in.o
    [    3/9    ] busybox/LD busybox
    [    4/9    ] nethack/LD nethack
    [    5/9    ] initrd/bin/CP busybox
    [    6/9    ] initrd/bin/CP nethack
    [    7/9    ] initrd/MKINITRD
    [    8/9    ] initrd/GZIP initrd
    [    9/9    ]
    
    real    0m1.571s
    user    0m1.888s
    sys     0m0.269s
    

    It recompiles a Linux distro in 1.5 secs, isn’t it cool?

  4. Anatol
    Jan 29th, 2011 at 04:54 | #4

    The project page is http://gittup.org/tup/

  5. May 9th, 2012 at 18:41 | #5

    First of all, recursive make is an unmitigated evil. But you don’t need to use recursive make to have modular makefiles. Make should know everything, but individual makefiles only need to contain appropriate fragments of that everything. See the classic 1997 paper “Recursive Make Considered Harmful” for why and how to do this.

    Second, it’s the level above make, the imake/autotools/cmake level, that’s really God-awful. Chicken Scheme solves this problem by the following aggressive policy. “When you build Chicken, you tell us if your system is Linux, BSD, Solaris, Mac OS X, Cygwin, MinGW, MinGW+Msys, or Haiku. Then make will do the rest. If you are on some other (disgusting old) system, good luck — and send us your patches!”

Leave a comment

XHTML: You can use these tags: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>