If you ever built C/C++ programs, you probably know about Make
. But Make
has long been broken. Everybody knows that.
SCons
is an open source software construction tool – a next generation build tool.
You can think of SCons
as an improved, cross-platform substitute for Make
. One that also bakes in features from autoconf
/automake
and ccache
.
SCons
is my chosen C/C++ software build framework.
This is the first post in a series of SCons
posts. In the series I will describe SCons
, and analyze its strengths and weaknesses. I also explain how I use it (in DayJob) to build non-trivial software, and explore potential enhancements to optimize my workflow.
I open the series with an introduction to SCons
.
What Is SCons?
As mentioned in the intro, SCons
is an open source software construction tool, also known as build framework. A software developer uses a build framework to facilitate the process of turning a collection of source files into an executable program.
Technically speaking, it is not required to use any build framework in order to produce working program. It is possible to manually run the compiler and linker commands needed to build a program given its sources.
For instance, here is the eternal C++ Hello World program:
// hello.cpp #include <iostream> int main() { std::cout << "Hello, World.\n"; return 0; }
There is no need for any build framework to build this program. You can build it simply by running g++ hello.cpp -o hello
, and get an executable hello
program.
Of course, I’m assuming you have the g++
compiler installed, on a UNIX-like system (e.g. Linux, Mac OS X, Windows with Cygwin, etc.).
It’s not difficult to see how this approach doesn’t scale well to non-trivial programs. Programs consisting of multiple inter-dependent source files. Programs that use libraries, 3rd-party and internal. Programs that take hours to build from scratch, such that it is unpleasant to develop without incremental build support.
The original GNU Make
tried to solve this by providing a domain specific language (DSL) to describe targets, actions and rules. Rules specify relationships (“the hello
program depends on hello.o
object file”, “hello.o
object file depends on hello.cpp
source file”, etc.). Actions are shell commands. This means that as a developer, you are expected to learn both the Make
language, and some shell language.
The make
approach proved to be useful for small C programs, but quite hectic when it came to big programs. In addition, Make
is effectively not cross-platform.
So, SCons
is an alternative, next generation, build framework. It was designed to be cross platform from the ground up. It is meant to be easier to use and maintain, more reliable and faster.
SCons
is written in Python. The configuration files (Makefile
alternatives) are pure Python scripts. SCons
exposes a declarative API, used to describe relationships. The developer can write very simple configuration files, using only SCons
commands, while having the option to unleash the full power of Python.
Why Is SCons Better Than Make?
Here are a couple of reasons:
- SO MUCH SIMPLER to use and maintain! No more job security for the person maintaining the
Makefile
s. - Python!
- You can use a real programming language to solve build problems.
- Assuming you have Python installed, it’s super easy to install
SCons
(as easy asapt-get install scons
, or eveneasy_install scons
).
- Reliable, automatic dependency analysis built-in for several languages, with the ability to extend to more languages via user-defined scanners.
- Built-in support for building programs in many languages, also extensible via user-defined builders.
- Automatic detection of system build tools across platforms (be it GCC, or Visual Studio).
- Baked in features from complementing tools like
autoconf
,automake
,cache
, as we’ll see.
Show Me the Money
To demonstrate how much simpler SCons
is, let’s do the SCons
version of building the hello world program.
Same source file as above. We add a SConstruct
configuration file:
# SConstruct for "Hello World" CPP program Program('hello.cpp')
Executing the build is as easy as running scons
in a terminal:
itamar@legolas hello-scons $ scons scons: Reading SConscript files ... scons: done reading SConscript files. scons: Building targets ... g++ -o hello.o -c hello.cpp g++ -o hello hello.o scons: done building targets.
Of course, as long nothing changes in the source, there’s no need to rebuild anything:
itamar@legolas hello-scons $ scons scons: Reading SConscript files ... scons: done reading SConscript files. scons: Building targets ... scons: `.' is up to date. scons: done building targets.
I won’t blame you if you’re not too impressed by the simplicity of an already simple scenario. But contrast this against the Makefile
for the same scenario:
# Makefile for "Hello World" CPP program CC = g++ EXE = hello OBJ = ${EXE}.o ${EXE}: ${OBJ} .PHONY: clean clean: rm -f ${EXE} ${OBJ} # (note: the indent before rm must be a tab...)
Am I the only one who finds it unintuitive that the only thing this is actually an input to the build process (namely, hello.cpp
) is not mentioned in any way?
And all the voodoo that goes into defining a clean
target? In SCons
you get clean for free:
itamar@legolas hello-scons $ scons -c scons: Reading SConscript files ... scons: done reading SConscript files. scons: Cleaning targets ... Removed hello.o Removed hello scons: done cleaning targets.
If you need to customize clean
behavior – you can. Most of the times, the default behavior in SCons
is sufficient.
Anyhow, to be more impressed, you’ll have to see a more elaborate scenario. One that I leave for more advanced posts in the series, so this intro is not too intimidating.
In this example we needed only the SConstruct
configuration file. This is where SCons
starts processing. In projects with subdirectories, it is customary to have a SConscript
file each one. The main SConstruct
file would then include the SConscript
files from the subdirectories.
Is SCons the Only Solution?
SCons
is definitely not the only solution that offers to replace Make
(with or without autoconf
etc.); There are plenty of alternative build frameworks. Just to name a well known few: Ant, CMake, Maven, MakeIt, (Boost) Jam, Rake, built-in build system in IDEs.
I will not go into a detailed comparison (you can see one from Wikipedia, and another one from the SCons
wiki). This is mainly because I have never done the comparative research, and also because it will lengthen this post, and launch a flame war or two.
I will just say a couple of things regarding alternatives:
- If I was developing Java, I would probably not choose
SCons
. Maybe Maven, or Gradle, due to more natural integration with popular IDEs. - I may not have done detailed research on all options. I chose
SCons
based on previous experience withMake
, a littleAnt
, a little Boost.Build, and too much IDE-specific systems (Eclipse, Visual Studio). - One of my insights: XML is OK for machine-to-machine interactions. Human beings, on the other hand, should never need to read or write XML…
- Built-in IDE solutions are almost never a good alternative (exception: you write only
.Net
stuff in Visual Studio).
What About Non-C/C++ Projects?
SCons
has built-in support for couple of languages, including: C, C++, D, Java, Fortran, Yacc, Lex, Qt and SWIG, TeX and LaTeX documents.
It can also be extended with user-defined builders to support more languages. You can probably find what you need in the SCons
contributed builders wiki page, unless it’s esoteric.
Resources
- Official
SCons
site - Official
SCons
documentation SCons
user guideSCons
wiki- A nice presentation by Dr Russel Winder
Summary
This was a short introduction to the SCons
build framework. I tried to keep it short and simple. Maybe even too simple, so the advantages of using it are not yet clear. But worry not! For future posts in my SCons
series will bring enlightenment! The next post will provide a simple C++ example project with SCons
build. This simple example will be useful as a reference for future SCons
extensions I will describe in the series.
Leave a Reply