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.
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.
“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.
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/) :
It recompiles a Linux distro in 1.5 secs, isn’t it cool?
The project page is http://gittup.org/tup/
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!”