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
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
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
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.
scons has the concept of “build environments”, which
are objects that include build rules, variables, and so on. By
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.